hookehuyr

✨ feat: 新增搜索页面

1 /* 1 /*
2 * @Date: 2022-05-26 19:50:27 2 * @Date: 2022-05-26 19:50:27
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2022-06-18 00:15:08 4 + * @LastEditTime: 2024-12-03 11:23:55
5 * @FilePath: /tswj/src/api/C/book.js 5 * @FilePath: /tswj/src/api/C/book.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -10,6 +10,7 @@ import { fn, fetch } from '@/api/fn'; ...@@ -10,6 +10,7 @@ import { fn, fetch } from '@/api/fn';
10 const Api = { 10 const Api = {
11 ADD_SUBSCRIBE: '/srv/?a=add_subscribe', 11 ADD_SUBSCRIBE: '/srv/?a=add_subscribe',
12 BOOK_INFO: '/srv/?a=book_info', 12 BOOK_INFO: '/srv/?a=book_info',
13 + PROD_LIST: '/srv/?a=prod_list',
13 } 14 }
14 15
15 /** 16 /**
...@@ -28,3 +29,14 @@ export const addSubscribeAPI = (params) => fn(fetch.post(Api.ADD_SUBSCRIBE, para ...@@ -28,3 +29,14 @@ export const addSubscribeAPI = (params) => fn(fetch.post(Api.ADD_SUBSCRIBE, para
28 * @returns 29 * @returns
29 */ 30 */
30 export const bookInfoAPI = (params) => fn(fetch.get(Api.BOOK_INFO, params)); 31 export const bookInfoAPI = (params) => fn(fetch.get(Api.BOOK_INFO, params));
32 +
33 +/**
34 + * @description: 作品列表
35 + * @param {String} book_id 书籍 ID
36 + * @param {String} localism_type 方言类型
37 + * @param {String} performer_name 搜索表演者姓名
38 + * @param {*} limit
39 + * @param {*} offset
40 + * @returns
41 + */
42 +export const prodListAPI = (params) => fn(fetch.get(Api.PROD_LIST, params));
......
1 <!-- 1 <!--
2 * @Date: 2022-05-11 11:19:14 2 * @Date: 2022-05-11 11:19:14
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-11-13 15:39:03 4 + * @LastEditTime: 2024-12-03 15:07:53
5 * @FilePath: /tswj/src/components/ShortcutFixed/index.vue 5 * @FilePath: /tswj/src/components/ShortcutFixed/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -37,12 +37,35 @@ ...@@ -37,12 +37,35 @@
37 </div> 37 </div>
38 </template> 38 </template>
39 </van-popover> 39 </van-popover>
40 + <van-image v-if="isSearch" class="icon-box" :src="icon_search" @click="toSearch" />
40 </div> 41 </div>
41 </template> 42 </template>
42 43
43 <script setup> 44 <script setup>
44 import Cookies from 'js-cookie' 45 import Cookies from 'js-cookie'
45 -import { icon_me, icon_home, icon_rank, icon_contact } from '@/utils/generateIcons.js' 46 +import { icon_me, icon_home, icon_rank, icon_contact, icon_search } from '@/utils/generateIcons.js'
47 +import { useRoute, useRouter } from 'vue-router'
48 +import { killPages, store } from '@/hooks/useKeepAlive';
49 +
50 +// 删除所有的 keep-alive 缓存
51 +killPages();
52 +// 清空记录位置
53 +store.changeScrollTop(0);
54 +
55 +const $route = useRoute();
56 +const $router = useRouter();
57 +
58 +const toSearch = () => {
59 + // 清空记录位置
60 + store.changeScrollTop(0);
61 + $router.push({
62 + path: '/client/searchPage',
63 + query: {
64 + book_id: $route.query.id,
65 + kg_id: $route.query.kg_id
66 + }
67 + });
68 + }
46 </script> 69 </script>
47 70
48 <script> 71 <script>
...@@ -67,6 +90,9 @@ export default { ...@@ -67,6 +90,9 @@ export default {
67 isRank() { 90 isRank() {
68 return this.item.indexOf('rank') !== -1 ? true : false 91 return this.item.indexOf('rank') !== -1 ? true : false
69 }, 92 },
93 + isSearch() {
94 + return this.item.indexOf('search') !== -1 ? true : false
95 + },
70 }, 96 },
71 mounted() { 97 mounted() {
72 }, 98 },
......
1 <template> 1 <template>
2 <div class="video-wrapper"> 2 <div class="video-wrapper">
3 - <div :id="'mui-player-' + item.id" class="video-div" /> 3 + <div :id="'mui-player-' + item.id + affix" class="video-div" />
4 <div class="normal-module"> 4 <div class="normal-module">
5 <div class="video-bar"> 5 <div class="video-bar">
6 <van-row> 6 <van-row>
...@@ -43,6 +43,7 @@ import MuiPlayer from 'mui-player' ...@@ -43,6 +43,7 @@ import MuiPlayer from 'mui-player'
43 import { prodActionAPI, prodInfoAPI } from '@/api/C/prod.js' 43 import { prodActionAPI, prodInfoAPI } from '@/api/C/prod.js'
44 import { useDebounce } from '@/hooks/useDebounce.js' 44 import { useDebounce } from '@/hooks/useDebounce.js'
45 import { DEFAULT_COVER } from '@/constant' 45 import { DEFAULT_COVER } from '@/constant'
46 +import { v4 as uuidv4 } from 'uuid';
46 47
47 const $router = useRouter(); 48 const $router = useRouter();
48 const props = defineProps({ 49 const props = defineProps({
...@@ -85,10 +86,11 @@ const getProductDetail = async (action_type, prod_id) => { ...@@ -85,10 +86,11 @@ const getProductDetail = async (action_type, prod_id) => {
85 } 86 }
86 87
87 let detail = ref({}); 88 let detail = ref({});
89 +let affix = uuidv4();
88 90
89 onMounted(() => { 91 onMounted(() => {
90 const mp = new MuiPlayer({ 92 const mp = new MuiPlayer({
91 - container: '#mui-player-' + props.item.id, 93 + container: '#mui-player-' + props.item.id + affix,
92 title: props.item.title, 94 title: props.item.title,
93 src: props.item.video, 95 src: props.item.video,
94 poster: props.item.cover ? props.item.cover : DEFAULT_COVER, 96 poster: props.item.cover ? props.item.cover : DEFAULT_COVER,
...@@ -107,9 +109,9 @@ onMounted(() => { ...@@ -107,9 +109,9 @@ onMounted(() => {
107 handleAction('play', props.item.id) 109 handleAction('play', props.item.id)
108 }); 110 });
109 // 配置16:9高度比 111 // 配置16:9高度比
110 - const width = document.getElementById('mui-player-' + props.item.id).clientWidth; 112 + const width = document.getElementById('mui-player-' + props.item.id + affix).clientWidth;
111 const height = (width * 9) / 16; 113 const height = (width * 9) / 16;
112 - document.getElementById('mui-player-' + props.item.id).height = height; 114 + document.getElementById('mui-player-' + props.item.id + affix).height = height;
113 }); 115 });
114 116
115 const goTo = () => { // 跳转作品详情页 117 const goTo = () => { // 跳转作品详情页
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 * @Author: hookehuyr hookehuyr@gmail.com 2 * @Author: hookehuyr hookehuyr@gmail.com
3 * @Date: 2022-05-25 18:03:54 3 * @Date: 2022-05-25 18:03:54
4 * @LastEditors: hookehuyr hookehuyr@gmail.com 4 * @LastEditors: hookehuyr hookehuyr@gmail.com
5 - * @LastEditTime: 2022-05-31 17:42:23 5 + * @LastEditTime: 2024-12-03 14:54:21
6 * @FilePath: /tswj/src/router/routes/modules/client/index.js 6 * @FilePath: /tswj/src/router/routes/modules/client/index.js
7 * @Description: 家长端展示页路由表 7 * @Description: 家长端展示页路由表
8 */ 8 */
...@@ -90,6 +90,15 @@ const index = [{ ...@@ -90,6 +90,15 @@ const index = [{
90 name: 'personIndex' 90 name: 'personIndex'
91 }, 91 },
92 children: [] 92 children: []
93 +}, {
94 + path: '/client/searchPage',
95 + name: '搜索页面',
96 + component: () => import('@/views/client/searchPage.vue'),
97 + meta: {
98 + title: '搜索页面',
99 + name: 'searchPage'
100 + },
101 + children: []
93 }] 102 }]
94 103
95 export default index; 104 export default index;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 * @Author: hookehuyr hookehuyr@gmail.com 2 * @Author: hookehuyr hookehuyr@gmail.com
3 * @Date: 2022-05-17 11:34:35 3 * @Date: 2022-05-17 11:34:35
4 * @LastEditors: hookehuyr hookehuyr@gmail.com 4 * @LastEditors: hookehuyr hookehuyr@gmail.com
5 - * @LastEditTime: 2024-11-13 15:32:45 5 + * @LastEditTime: 2024-12-03 15:07:35
6 * @FilePath: /tswj/src/utils/generateIcons.js 6 * @FilePath: /tswj/src/utils/generateIcons.js
7 * @Description: 图标集合 7 * @Description: 图标集合
8 */ 8 */
...@@ -31,6 +31,7 @@ import icon_flower from '@images/xiaohua@2x.png' ...@@ -31,6 +31,7 @@ import icon_flower from '@images/xiaohua@2x.png'
31 import icon_refuse from '@images/icon-jujue@2x.png' 31 import icon_refuse from '@images/icon-jujue@2x.png'
32 import icon_apply from '@images/icon-shenhe@2x.png' 32 import icon_apply from '@images/icon-shenhe@2x.png'
33 import icon_enable from '@images/icon-tongguo@2x.png' 33 import icon_enable from '@images/icon-tongguo@2x.png'
34 +import icon_search from '@images/icon-search@2x.png'
34 35
35 export { 36 export {
36 icon_video, 37 icon_video,
...@@ -58,4 +59,5 @@ export { ...@@ -58,4 +59,5 @@ export {
58 icon_refuse, 59 icon_refuse,
59 icon_apply, 60 icon_apply,
60 icon_enable, 61 icon_enable,
62 + icon_search,
61 } 63 }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 * @Author: hookehuyr hookehuyr@gmail.com 2 * @Author: hookehuyr hookehuyr@gmail.com
3 * @Date: 2022-05-21 09:35:14 3 * @Date: 2022-05-21 09:35:14
4 * @LastEditors: hookehuyr hookehuyr@gmail.com 4 * @LastEditors: hookehuyr hookehuyr@gmail.com
5 - * @LastEditTime: 2024-11-27 09:39:44 5 + * @LastEditTime: 2024-12-03 15:02:57
6 * @FilePath: /tswj/src/views/client/bookDetail.vue 6 * @FilePath: /tswj/src/views/client/bookDetail.vue
7 * @Description: 7 * @Description:
8 --> 8 -->
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
105 <my-button type="primary" @on-click="showDonate=true">为活动助力</my-button> 105 <my-button type="primary" @on-click="showDonate=true">为活动助力</my-button>
106 </div> 106 </div>
107 </div> 107 </div>
108 - <shortcut-fixed :type="USER_ROLE.CLIENT" :item="['home', 'me']" :custom-style="customStyle" /> 108 + <shortcut-fixed :type="USER_ROLE.CLIENT" :item="['home', 'me', 'search']" :custom-style="customStyle" />
109 </div> 109 </div>
110 110
111 <!-- 上传时,如果没有默认儿童提示弹框, 如果没有实名认证提示弹框 --> 111 <!-- 上传时,如果没有默认儿童提示弹框, 如果没有实名认证提示弹框 -->
......
1 +<!--
2 + * @Date: 2024-12-03 10:35:15
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2024-12-03 15:15:45
5 + * @FilePath: /tswj/src/views/client/searchPage.vue
6 + * @Description: 文件描述
7 +-->
8 +<template>
9 + <div class="search-page">
10 + <div style="background-color: #F7F7F7; height: auto; padding: 1rem;">
11 + <div style="background-color: #FFF; border-radius: 1rem; padding: 0.5rem 1rem; display: flex; align-items: center; justify-content: space-between;">
12 + <input type="text" v-model="performer_name" placeholder="请输入要搜索的表演者姓名" @blur="onSearch" style="border: 0; width: 100%;">
13 + <van-icon name="search" />
14 + </div>
15 + </div>
16 + <div class="book-video-list">
17 + <!-- <van-list ref="listRef" v-model:loading="loading" :finished="finished" :finished-text="finishedTextStatus ? '没有更多了' : ''"
18 + @load="onLoad" :immediate-check="immediateCheck"> -->
19 + <template v-for="item in search_prod_list" :key="item">
20 + <video-card :item="item">
21 + <template #bookDetailSub>
22 + <div style="color: #999999; padding: 0px 1rem 0.5rem;" @click="setComment(item)">
23 + {{ item.kg_name }} | {{ item.localism_type }}
24 + </div>
25 + </template>
26 + </video-card>
27 + </template>
28 + <!-- </van-list> -->
29 + </div>
30 + <div style="height: 2rem;" />
31 + <van-empty v-if="emptyStatus" class="custom-image" :image="no_image" description="暂无作品信息" />
32 + </div>
33 +</template>
34 +
35 +<script setup>
36 +import { ref } from 'vue'
37 +import { useRoute, useRouter } from 'vue-router'
38 +
39 +import { Cookies, $, _, axios, storeToRefs, mainStore, useTitle } from '@/utils/generatePackage.js'
40 +//import { } from '@/utils/generateModules.js'
41 +import { no_image } from '@/utils/generateIcons.js'
42 +//import { } from '@/composables'
43 +import { VideoCard } from '@/utils/generateModules'
44 +import { prodListAPI } from '@/api/C/book'
45 +import { killPages, store } from '@/hooks/useKeepAlive';
46 +
47 +killPages()
48 +const $route = useRoute();
49 +const $router = useRouter();
50 +console.warn($route.meta.title);
51 +useTitle($route.meta.title);
52 +
53 +const search_prod_list = ref([]);
54 +const limit = ref(10)
55 +const offset = ref(0)
56 +
57 +// 处理书籍下作品列表
58 +const loading = ref(false);
59 +const finished = ref(false);
60 +const immediateCheck = ref(false);
61 +
62 +// 因为不能让空图标提前出来的写法
63 +const finishedTextStatus = ref(false);
64 +const emptyStatus = ref(false);
65 +
66 +const book_id = $route.query.book_id;
67 +const kg_id = $route.query.kg_id;
68 +
69 +
70 +// 定义一个变量来表示是否滚动到底部
71 +const isBottom = ref(false);
72 +
73 +// 标记是否是第一次进入页面
74 +const isFirstMount = ref(true);
75 +
76 +// 滚动事件处理函数,这里添加了触发回调的逻辑
77 +const handleScroll = () => {
78 + const scrollTop = window.scrollY; // 当前滚动距离
79 + const clientHeight = document.documentElement.clientHeight; // 视口高度
80 + const scrollHeight = document.documentElement.scrollHeight; // 页面总高度
81 +
82 + if (scrollTop + clientHeight >= scrollHeight) {
83 + // 在这里触发你的回调逻辑
84 + if (performer_name.value) {
85 + onLoad()
86 + }
87 + }
88 +};
89 +
90 +// 在组件挂载时添加滚动事件监听,并将第一次进入页面的标记设为false
91 +onMounted(() => {
92 + window.addEventListener('scroll', handleScroll);
93 +});
94 +
95 +// 在组件卸载时移除滚动事件监听
96 +onUnmounted(() => {
97 + window.removeEventListener('scroll', handleScroll);
98 +});
99 +
100 +const performer_name = ref('');
101 +
102 +/**
103 + * 向下滚动查询数据
104 + */
105 +const onLoad = async () => {
106 + // 异步更新数据
107 + const { data, code } = await prodListAPI({ book_id, kg_id, limit: limit.value, offset: offset.value, performer_name: performer_name.value })
108 + if (code === 1) {
109 + search_prod_list.value = _.concat(search_prod_list.value, data.prod_list);
110 + search_prod_list.value = _.uniqBy(search_prod_list.value, 'id');
111 + offset.value = search_prod_list.value.length;
112 + loading.value = false;
113 + // 数据全部加载完成
114 + if (!data.prod_list.length) {
115 + // 加载状态结束
116 + finished.value = true;
117 + }
118 + // 空数据提示
119 + if (!search_prod_list.value.length) {
120 + finishedTextStatus.value = false;
121 + }
122 + emptyStatus.value = Object.is(search_prod_list.value.length, 0);
123 + }
124 +};
125 +
126 +const onSearch = async() => {
127 + offset.value = 0
128 + search_prod_list.value = []
129 + loading.value = true;
130 + finished.value = false;
131 + onLoad()
132 +}
133 +
134 +</script>
135 +
136 +<style lang="less" scoped>
137 +
138 +.bottom-btn {
139 + position: fixed;
140 + bottom: 0;
141 + left: 0;
142 + right: 0;
143 + background-color: white;
144 + box-shadow: 0px -2px 4px 0px rgba(0, 0, 0, 0.07);
145 + z-index: 9999;
146 +
147 + .text {
148 + text-align: center;
149 + padding: 0.7rem;
150 + margin: 0.8rem;
151 + font-size: 1rem;
152 + font-weight: bold;
153 + border-radius: 24px;
154 + // border: 1px solid F7F7F7;
155 + color: @base-font-color;
156 + background-color: @base-color;
157 + box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.06);
158 + }
159 +}
160 +</style>