mirror of
https://github.com/ProudMuBai/GoFilm.git
synced 2026-04-08 14:47:30 +08:00
add tag search api
This commit is contained in:
@@ -12,10 +12,10 @@
|
||||
<!--右侧顶级分类导航 -->
|
||||
<div class="nav_right">
|
||||
<el-link :underline="false" href="/">首页</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?pid=${nav.film.id}`">电影</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?pid=${nav.tv.id}`">剧集</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?pid=${nav.cartoon.id}`">动漫</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?pid=${nav.variety.id}`">综艺</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?Pid=${nav.film.id}`">电影</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?Pid=${nav.tv.id}`">剧集</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?Pid=${nav.cartoon.id}`">动漫</el-link>
|
||||
<el-link :underline="false" :href="`/categoryFilm?Pid=${nav.variety.id}`">综艺</el-link>
|
||||
<!-- <span style="color:#777; font-weight: bold">|</span>-->
|
||||
<el-link href="/search" class="hidden-md-and-up" :underline="false">
|
||||
<el-icon style="font-size: 18px">
|
||||
|
||||
@@ -1,53 +1,97 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<p>{{ d.category.name }}</p>
|
||||
<div class="c_header">
|
||||
<!--默认全部-->
|
||||
<a :class="`nav ${d.cid == -1?'active':''}`" :href="`/categoryFilm?pid=${d.category.id}`">全部{{d.category.name}}</a>
|
||||
<!--子分类-->
|
||||
<a :class="`nav ${d.cid == c.id?'active':''}`" :href="`/categoryFilm?pid=${c.pid}&cid=${c.id}¤t=1`"
|
||||
v-for="c in d.category.children">{{ c.name }}</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="h_title">
|
||||
<span class="header_t">{{ d.title.name }}</span>
|
||||
</div>
|
||||
<div v-if="false" class="c_header">
|
||||
<!--默认全部-->
|
||||
<a :class="`nav ${d.cid == -1?'active':''}`"
|
||||
:href="`/categoryFilm?pid=${d.category.id}`">全部{{ d.category.name }}</a>
|
||||
<!--子分类-->
|
||||
<a :class="`nav ${d.cid == c.id?'active':''}`" :href="`/categoryFilm?pid=${c.pid}&cid=${c.id}¤t=1`"
|
||||
v-for="c in d.category.children">{{ c.name }}</a>
|
||||
</div>
|
||||
<!--影片分类检索-->
|
||||
<div class="t_container">
|
||||
<div class="t_item" v-for="k in d.search.sortList ">
|
||||
<span class="t_title">{{d.search.titles[k]}}</span>
|
||||
<a href="javascript:void(false)" :class="`tag ${t['Value'] === d.searchParams[k]?'t_active':''}`" v-for="t in d.search.tags[k]" @click="handleTag(k,t['Value'])" >
|
||||
{{t['Name']}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--影片列表展示-->
|
||||
<FilmList :list="d.list"/>
|
||||
<!--分页展示区域-->
|
||||
<div class="pagination_container ">
|
||||
<el-pagination background layout="prev, pager, next"
|
||||
v-model:current-page="d.page.current"
|
||||
@current-change="changeCurrent"
|
||||
:pager-count="5"
|
||||
:background="true"
|
||||
:page-size="d.page.pageSize"
|
||||
:total="d.page.total"
|
||||
:prev-icon="ArrowLeftBold"
|
||||
:next-icon="ArrowRightBold"
|
||||
hide-on-single-page
|
||||
class="pagination"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--影片列表展示-->
|
||||
<FilmList :list="d.list"/>
|
||||
<!--分页展示区域-->
|
||||
<div class="pagination_container ">
|
||||
<el-pagination background layout="prev, pager, next"
|
||||
v-model:current-page="d.page.current"
|
||||
@current-change="changeCurrent"
|
||||
:pager-count="5"
|
||||
:background="true"
|
||||
:page-size="d.page.pageSize"
|
||||
:total="d.page.total"
|
||||
:prev-icon="ArrowLeftBold"
|
||||
:next-icon="ArrowRightBold"
|
||||
hide-on-single-page
|
||||
class="pagination"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
|
||||
import {onMounted, reactive} from "vue";
|
||||
import {onMounted, reactive, toRefs} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {ArrowRightBold, ArrowLeftBold} from '@element-plus/icons-vue'
|
||||
import FilmList from "../../components/FilmList.vue";
|
||||
|
||||
// 分类tag点击事件
|
||||
const handleTag = (k:string,v:string)=>{
|
||||
// 设置被点击的tag属性值
|
||||
d.searchParams[k as keyof typeof d.searchParams] = v
|
||||
// searchTag改变, 重置 current当前页码
|
||||
d.page.current = 1
|
||||
handleParams()
|
||||
}
|
||||
|
||||
const handleParams = ()=> {
|
||||
let q = ''
|
||||
for (let k in d.searchParams) {
|
||||
let val = d.searchParams[k as keyof typeof d.searchParams]
|
||||
if (val != '') {
|
||||
q += `&${k}=${val}`
|
||||
}
|
||||
}
|
||||
location.href = '/categoryFilm?'+q.slice(1)+`¤t=${d.page.current}`
|
||||
}
|
||||
|
||||
// 页面所需数据
|
||||
const d = reactive({
|
||||
category: {},
|
||||
list: [],
|
||||
page: {
|
||||
current: 0,
|
||||
},
|
||||
cid: -1
|
||||
title: {},
|
||||
list: [],
|
||||
search: {
|
||||
sortList:[],
|
||||
titles: [],
|
||||
tags: [],
|
||||
},
|
||||
page: {
|
||||
current: 0,
|
||||
},
|
||||
searchParams:{
|
||||
Pid: '',
|
||||
Category: '',
|
||||
Plot: '',
|
||||
Area: '',
|
||||
Language: '',
|
||||
Year: '',
|
||||
Sort: '',
|
||||
},
|
||||
|
||||
})
|
||||
// 获取路由参数查询对应数据
|
||||
@@ -55,285 +99,339 @@ const router = useRouter()
|
||||
|
||||
// 点击分页按钮事件 current-change
|
||||
const changeCurrent = (currentVal: number) => {
|
||||
let query = router.currentRoute.value.query
|
||||
// router.push({path: '/categoryFilm', query:{pid: query.pid, cid: query.cid, current: currentVal}})
|
||||
if (query.cid && query.cid != "") {
|
||||
location.href = `/categoryFilm?pid=${query.pid}&cid=${query.cid}¤t=${currentVal}`
|
||||
} else {
|
||||
location.href = `/categoryFilm?pid=${query.pid}&¤t=${currentVal}`
|
||||
}
|
||||
handleParams()
|
||||
}
|
||||
|
||||
// 点击分类事件
|
||||
// const changeCategory = (cid?: any) => {
|
||||
// let params = new URLSearchParams(location.search)
|
||||
// location.href = cid ? `/categoryFilm?pid=${params.get('pid')}&cid=${cid}¤t=1` : `/categoryFilm?pid=${params.get('pid')}`
|
||||
// }
|
||||
|
||||
|
||||
const getFilmData = (param: any) => {
|
||||
ApiGet('/filmCategory', {pid: param.pid, cid: param.cid, current: param.current}).then((resp: any) => {
|
||||
if (resp.status === 'ok') {
|
||||
d.category = resp.data.category
|
||||
d.list = resp.data.list
|
||||
d.page = resp.page
|
||||
// 设置当前请求的分类id
|
||||
d.cid = param.cid? param.cid:-1
|
||||
} else {
|
||||
ElMessage.error({message: "请先输入影片名称关键字再进行搜索", duration: 1000})
|
||||
}
|
||||
})
|
||||
const getFilmData = () => {
|
||||
let query = router.currentRoute.value.query
|
||||
ApiGet('/filmClassified', {...query}).then((resp: any) => {
|
||||
if (resp.status === 'ok') {
|
||||
d.title = resp.data.title
|
||||
d.list = resp.data.list
|
||||
d.page = resp.page
|
||||
d.search = resp.data.search
|
||||
d.searchParams = resp.data.params
|
||||
} else {
|
||||
ElMessage.error({message: "请先输入影片名称关键字再进行搜索", duration: 1000})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let query = router.currentRoute.value.query
|
||||
getFilmData({pid: query.pid, cid: query.cid, current: query.current})
|
||||
getFilmData()
|
||||
// let query = router.currentRoute.value.query
|
||||
// getFilmData({pid: query.pid, cid: query.cid, current: query.current})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.h_title {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #777777;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.h_title_active {
|
||||
color: #212121
|
||||
}
|
||||
.header_t {
|
||||
color: #a0a0a0;
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.t_container {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
padding: 20px 0;
|
||||
//background-color: rgb(117, 116, 116);
|
||||
}
|
||||
|
||||
.t_item {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin: 14px 0;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
|
||||
.t_title {
|
||||
display: inline-block;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
color: rgba(255,255,255,0.35);
|
||||
border-radius: 6px;
|
||||
margin-right: 12px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
border: 1px solid rgba(255,255,255,0.12);
|
||||
margin: 0 8px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.t_active {
|
||||
background: rgba(255,255,255,0.12);
|
||||
color: #ffa500cc!important;
|
||||
border: none!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
<!--移动端修改-->
|
||||
<style scoped>
|
||||
@media (max-width: 650px) {
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*顶部内容区域*/
|
||||
.header {
|
||||
width: 100%;
|
||||
margin-bottom: 100px;
|
||||
background: none !important;
|
||||
}
|
||||
/*顶部内容区域*/
|
||||
.header {
|
||||
width: 100%;
|
||||
margin-bottom: 100px;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.header p {
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
color: #c9c4c4;
|
||||
margin-top: 0;
|
||||
padding-left: 10px;
|
||||
height: 100%;
|
||||
/*background: rgb(34, 34, 34);*/
|
||||
}
|
||||
.header p {
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
color: #c9c4c4;
|
||||
margin-top: 0;
|
||||
padding-left: 10px;
|
||||
height: 100%;
|
||||
/*background: rgb(34, 34, 34);*/
|
||||
}
|
||||
|
||||
.c_header {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
/*justify-content: start;*/
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: scroll;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.c_header {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
/*justify-content: start;*/
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: scroll;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.c_header a {
|
||||
white-space: nowrap;
|
||||
margin-right: 10px;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
padding: 6px 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.c_header a {
|
||||
white-space: nowrap;
|
||||
margin-right: 10px;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
padding: 6px 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.c_header a:hover {
|
||||
color: orange;
|
||||
}
|
||||
.c_header a:hover {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.nav:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.5s ease-out;
|
||||
}
|
||||
.nav:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.5s ease-out;
|
||||
}
|
||||
|
||||
.nav:hover:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
.nav:hover:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.active {
|
||||
background: rgb(249 230 195) !important;
|
||||
color: #e52424 !important;
|
||||
}
|
||||
.active {
|
||||
background: rgb(249 230 195) !important;
|
||||
color: #e52424 !important;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
max-width: 100vw;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
@media (min-width: 650px) {
|
||||
|
||||
/*顶部内容区域*/
|
||||
.header {
|
||||
width: 100%;
|
||||
}
|
||||
/*顶部内容区域*/
|
||||
.header {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header p {
|
||||
text-align: left;
|
||||
font-weight: 800;
|
||||
font-size: 32px;
|
||||
color: #c9c4c4;
|
||||
margin-top: 0;
|
||||
/*border-bottom: 2px solid #ffffff;*/
|
||||
/*padding-bottom: 30px;*/
|
||||
}
|
||||
.header p {
|
||||
text-align: left;
|
||||
font-weight: 800;
|
||||
font-size: 32px;
|
||||
color: #c9c4c4;
|
||||
margin-top: 0;
|
||||
/*border-bottom: 2px solid #ffffff;*/
|
||||
/*padding-bottom: 30px;*/
|
||||
}
|
||||
|
||||
.c_header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.c_header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.c_header a {
|
||||
flex-basis: calc(14% - 16px);
|
||||
white-space: nowrap;
|
||||
margin-right: 20px;
|
||||
color: #000;
|
||||
font-weight: 800;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
padding: 1.35% 0;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
}
|
||||
.c_header a {
|
||||
flex-basis: calc(14% - 16px);
|
||||
white-space: nowrap;
|
||||
margin-right: 20px;
|
||||
color: #000;
|
||||
font-weight: 800;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
padding: 1.35% 0;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c_header a:hover {
|
||||
color: orange;
|
||||
}
|
||||
.c_header a:hover {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.nav:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.5s ease-out;
|
||||
}
|
||||
.nav:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(0);
|
||||
transition: transform 0.5s ease-out;
|
||||
}
|
||||
|
||||
.nav:hover:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
.nav:hover:before {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
background: orange;
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
bottom: 12px;
|
||||
border-radius: 50px;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.active {
|
||||
background: rgb(249 230 195) !important;
|
||||
color: #e52424 !important;
|
||||
}
|
||||
.active {
|
||||
background: rgb(249 230 195) !important;
|
||||
color: #e52424 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
/*分页插件区域*/
|
||||
.pagination_container {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
/*background: deepskyblue;*/
|
||||
text-align: center;
|
||||
/*display: flex;*/
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
/*background: deepskyblue;*/
|
||||
text-align: center;
|
||||
/*display: flex;*/
|
||||
}
|
||||
|
||||
:deep(.el-pagination) {
|
||||
width: 100% !important;
|
||||
margin: 0 auto !important;
|
||||
justify-content: center;
|
||||
width: 100% !important;
|
||||
margin: 0 auto !important;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/*分页器样式修改*/
|
||||
:deep(.number) {
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
/*margin: 0 3px!important;*/
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
/*margin: 0 3px!important;*/
|
||||
}
|
||||
|
||||
:deep(.number:hover) {
|
||||
color: #67d9e8;
|
||||
color: #67d9e8;
|
||||
}
|
||||
|
||||
:deep(.btn-prev) {
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
:deep(.btn-next) {
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
:deep(.more) {
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
background: #2e2e2e !important;
|
||||
color: #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
:deep(.is-active) {
|
||||
background: #67d9e8 !important;
|
||||
background: #67d9e8 !important;
|
||||
}
|
||||
|
||||
/*移动端缩小*/
|
||||
@media (max-width: 650px) {
|
||||
:deep(.number) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
:deep(.number) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
:deep(.btn-prev) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
:deep(.btn-prev) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
:deep(.btn-next) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
:deep(.btn-next) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
:deep(.more) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
:deep(.more) {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -140,9 +140,9 @@ func FilmCategory(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(pid, "pid", &page),
|
||||
"category": category,
|
||||
"searchTags": logic.IL.SearchTags(pid),
|
||||
"list": logic.IL.GetFilmCategory(pid, "pid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
@@ -153,9 +153,57 @@ func FilmCategory(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(cid, "cid", &page),
|
||||
"category": category,
|
||||
"searchTags": logic.IL.SearchTags(pid),
|
||||
"list": logic.IL.GetFilmCategory(cid, "cid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
|
||||
// 获取请求参数
|
||||
}
|
||||
|
||||
func FilmTagSearch(c *gin.Context) {
|
||||
params := model.SearchTagsVO{}
|
||||
pidStr := c.DefaultQuery("Pid", "")
|
||||
cidStr := c.DefaultQuery("Category", "")
|
||||
yStr := c.DefaultQuery("Year", "")
|
||||
if pidStr == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "缺少分类信息",
|
||||
})
|
||||
return
|
||||
}
|
||||
params.Pid, _ = strconv.ParseInt(pidStr, 10, 64)
|
||||
params.Cid, _ = strconv.ParseInt(cidStr, 10, 64)
|
||||
params.Plot = c.DefaultQuery("Plot", "")
|
||||
params.Area = c.DefaultQuery("Area", "")
|
||||
params.Language = c.DefaultQuery("Language", "")
|
||||
params.Year, _ = strconv.ParseInt(yStr, 10, 64)
|
||||
params.Sort = c.DefaultQuery("Sort", "update_stamp")
|
||||
|
||||
// 设置分页信息
|
||||
currentStr := c.DefaultQuery("current", "1")
|
||||
current, _ := strconv.Atoi(currentStr)
|
||||
page := model.Page{PageSize: 49, Current: current}
|
||||
logic.IL.GetFilmsByTags(params, &page)
|
||||
// 返回对应信息
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"title": logic.IL.GetPidCategory(params.Pid).Category,
|
||||
"list": logic.IL.GetFilmsByTags(params, &page),
|
||||
"search": logic.IL.SearchTags(params.Pid),
|
||||
"params": map[string]string{
|
||||
"Pid": pidStr,
|
||||
"Category": cidStr,
|
||||
"Plot": params.Plot,
|
||||
"Area": params.Area,
|
||||
"Language": params.Language,
|
||||
"Year": yStr,
|
||||
"Sort": params.Sort,
|
||||
},
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
|
||||
@@ -198,3 +198,15 @@ func multipleSource(detail *model.MovieDetail) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GetFilmsByTags 通过searchTag 返回满足条件的分页影片信息
|
||||
func (i *IndexLogic) GetFilmsByTags(st model.SearchTagsVO, page *model.Page) []model.MovieBasicInfo {
|
||||
// 获取满足条件的影片id 列表
|
||||
sl := model.GetSearchInfosByTags(st, page)
|
||||
// 通过key 获取对应影片的基本信息
|
||||
var list []model.MovieBasicInfo
|
||||
for _, s := range sl {
|
||||
list = append(list, model.GetBasicInfoByKey(fmt.Sprintf(config.MovieBasicInfoKey, s.Cid, s.Mid)))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
11
server/model/RequestParams.go
Normal file
11
server/model/RequestParams.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
type SearchTagsVO struct {
|
||||
Pid int64
|
||||
Cid int64
|
||||
Plot string
|
||||
Area string
|
||||
Language string
|
||||
Year int64
|
||||
Sort string
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"server/config"
|
||||
"server/plugin/common/param"
|
||||
"server/plugin/db"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -46,6 +47,12 @@ type Page struct {
|
||||
//List []interface{} `json:"list"` // 数据
|
||||
}
|
||||
|
||||
// Tag 影片分类标签结构体
|
||||
type Tag struct {
|
||||
Name string `json:"name"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
func (s *SearchInfo) TableName() string {
|
||||
return config.SearchTableName
|
||||
}
|
||||
@@ -115,6 +122,7 @@ func SaveSearchTag(search SearchInfo) {
|
||||
searchMap := db.Rdb.HGetAll(db.Cxt, key).Val()
|
||||
// 是否存储对应分类的map, 如果不存在则缓存一份
|
||||
if len(searchMap) == 0 {
|
||||
searchMap = make(map[string]string)
|
||||
searchMap["Category"] = "类型"
|
||||
searchMap["Plot"] = "剧情"
|
||||
searchMap["Area"] = "地区"
|
||||
@@ -132,37 +140,34 @@ func SaveSearchTag(search SearchInfo) {
|
||||
case "Category":
|
||||
// 获取 Category 数据, 如果不存在则缓存一份
|
||||
if tagCount == 0 {
|
||||
var tags []redis.Z
|
||||
for _, t := range GetChildrenTree(search.Pid) {
|
||||
tags = append(tags, redis.Z{Score: float64(-t.Id), Member: t.Name})
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(-t.Id), Member: fmt.Sprintf("%v:%v", t.Name, t.Id)})
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
case "Year":
|
||||
// 获取 Year 数据, 如果不存在则缓存一份
|
||||
if tagCount == 0 {
|
||||
var tags []redis.Z
|
||||
currentYear := time.Now().Year()
|
||||
for i := 0; i < 12; i++ {
|
||||
tags = append(tags, redis.Z{Score: float64(currentYear - i), Member: currentYear - i})
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(currentYear - i), Member: fmt.Sprintf("%v:%v", currentYear-i, currentYear-i)})
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
case "Initial":
|
||||
// 如果不存在 首字母 Tag 数据, 则缓存一份
|
||||
if tagCount == 0 {
|
||||
var tags []redis.Z
|
||||
for i := 65; i <= 90; i++ {
|
||||
tags = append(tags, redis.Z{Score: float64(90 - i), Member: fmt.Sprintf("%c", i)})
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(90 - i), Member: fmt.Sprintf("%c:%c", i, i)})
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
case "Sort":
|
||||
if tagCount == 0 {
|
||||
tags := []redis.Z{
|
||||
{2, "time"},
|
||||
{1, "hits"},
|
||||
{0, "score"},
|
||||
{2, "时间排序:update_stamp"},
|
||||
{1, "人气排序:hits"},
|
||||
{0, "评分排序:score"},
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
@@ -185,10 +190,9 @@ func HandleSearchTags(preTags string, k string) {
|
||||
f := func(sep string) {
|
||||
for _, t := range strings.Split(preTags, sep) {
|
||||
// 获取 tag对应的score
|
||||
score := db.Rdb.ZScore(db.Cxt, k, t).Val()
|
||||
score := db.Rdb.ZScore(db.Cxt, k, fmt.Sprintf("%v:%v", t, t)).Val()
|
||||
// 在原score的基础上+1 重新存入redis中
|
||||
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: t})
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: fmt.Sprintf("%v:%v", t, t)})
|
||||
}
|
||||
}
|
||||
switch {
|
||||
@@ -203,13 +207,18 @@ func HandleSearchTags(preTags string, k string) {
|
||||
default:
|
||||
// 获取 tag对应的score
|
||||
if len(preTags) == 0 || preTags == "其它" {
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: 0, Member: preTags})
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: 0, Member: fmt.Sprintf("%v:%v", preTags, preTags)})
|
||||
} else {
|
||||
score := db.Rdb.ZScore(db.Cxt, k, preTags).Val()
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: preTags})
|
||||
score := db.Rdb.ZScore(db.Cxt, k, fmt.Sprintf("%v:%v", preTags, preTags)).Val()
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: fmt.Sprintf("%v:%v", preTags, preTags)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BatchHandleSearchTag(infos ...SearchInfo) {
|
||||
for _, info := range infos {
|
||||
SaveSearchTag(info)
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= Spider 数据处理(mysql) =================================
|
||||
@@ -241,8 +250,8 @@ func BatchSave(list []SearchInfo) {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
// 插入成功后输出一下成功信息
|
||||
//log.Println("BatchSave SearchInfo Successful, Count: ", len(list))
|
||||
// 保存成功后将相应tag数据缓存到redis中
|
||||
BatchHandleSearchTag(list...)
|
||||
tx.Commit()
|
||||
}
|
||||
|
||||
@@ -253,7 +262,7 @@ func BatchSaveOrUpdate(list []SearchInfo) {
|
||||
var count int64
|
||||
// 通过当前影片id 对应的记录数
|
||||
tx.Model(&SearchInfo{}).Where("mid", info.Mid).Count(&count)
|
||||
// 如果存在对应数据则进行更新, 否则进行删除
|
||||
// 如果存在对应数据则进行更新, 否则保存相应数据
|
||||
if count > 0 {
|
||||
// 记录已经存在则执行更新部分内容
|
||||
err := tx.Model(&SearchInfo{}).Where("mid", info.Mid).Updates(SearchInfo{UpdateStamp: info.UpdateStamp, Hits: info.Hits, State: info.State,
|
||||
@@ -266,6 +275,8 @@ func BatchSaveOrUpdate(list []SearchInfo) {
|
||||
if err := tx.Create(&info).Error; err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
// 插入成功后保存一份tag信息到redis中
|
||||
BatchHandleSearchTag(info)
|
||||
}
|
||||
}
|
||||
// 提交事务
|
||||
@@ -450,35 +461,115 @@ func GetMultiplePlay(siteName, key string) []MovieUrlInfo {
|
||||
|
||||
// GetSearchTag 通过影片分类 Pid 返回对应分类的tag信息
|
||||
func GetSearchTag(pid int64) map[string]interface{} {
|
||||
// 整合searchTag相关内容
|
||||
res := make(map[string]interface{})
|
||||
titles := db.Rdb.HGetAll(db.Cxt, fmt.Sprintf(config.SearchTitle, pid)).Val()
|
||||
for k, v := range titles {
|
||||
res["titles"] = titles
|
||||
// 处理单一分类的数据格式
|
||||
tagMap := make(map[string]interface{})
|
||||
for k, _ := range titles {
|
||||
// 通过 k 获取对应的 tag , 并以score进行排序
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 10).Val()
|
||||
res[v] = tags
|
||||
|
||||
// 过滤分类tag
|
||||
switch k {
|
||||
case "Category", "Year", "Initial", "Sort":
|
||||
case "Category":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, -1).Val()
|
||||
res[v] = tags
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Plot":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 10).Val()
|
||||
res[v] = tags
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Area":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 11).Val()
|
||||
res[v] = tags
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Language":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 6).Val()
|
||||
res[v] = tags
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Year", "Initial", "Sort":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, -1).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
res["tags"] = tagMap
|
||||
// 分类列表展示的顺序
|
||||
res["sortList"] = []string{"Category", "Plot", "Area", "Language", "Year", "Sort"}
|
||||
return res
|
||||
}
|
||||
|
||||
// HandleTagStr 处理tag数据格式
|
||||
func HandleTagStr(title string, tags ...string) []map[string]string {
|
||||
var r []map[string]string
|
||||
if !strings.EqualFold(title, "Sort") {
|
||||
r = append(r, map[string]string{
|
||||
"Name": "全部",
|
||||
"Value": "",
|
||||
})
|
||||
}
|
||||
for _, t := range tags {
|
||||
if sl := strings.Split(t, ":"); len(sl) > 0 {
|
||||
r = append(r, map[string]string{
|
||||
"Name": sl[0],
|
||||
"Value": sl[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
if !strings.EqualFold(title, "Sort") && !strings.EqualFold(title, "Year") {
|
||||
r = append(r, map[string]string{
|
||||
"Name": "其它",
|
||||
"Value": "其它",
|
||||
})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GetSearchInfosByTags 查询满足searchTag条件的影片分页数据
|
||||
func GetSearchInfosByTags(st SearchTagsVO, page *Page) []SearchInfo {
|
||||
// 准备查询语句的条件
|
||||
qw := db.Mdb.Model(&SearchInfo{})
|
||||
// 通过searchTags的非空属性值, 拼接对应的查询条件
|
||||
t := reflect.TypeOf(st)
|
||||
v := reflect.ValueOf(st)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
// 如果字段值不为空
|
||||
value := v.Field(i).Interface()
|
||||
if !param.IsEmpty(value) {
|
||||
cName := strings.ToLower(t.Field(i).Name)
|
||||
switch cName {
|
||||
case "pid", "cid", "area", "language", "year":
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", cName), value)
|
||||
case "plot":
|
||||
qw = qw.Where("class_tag LIKE ?", fmt.Sprintf("%%%v%%", value))
|
||||
case "sort":
|
||||
qw.Order(fmt.Sprintf("%v Desc", value))
|
||||
default:
|
||||
break
|
||||
}
|
||||
//// 处理特殊条件
|
||||
//if strings.EqualFold(cName, "sort") {
|
||||
// qw.Order(fmt.Sprintf("year Desc, %v Desc", cName))
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回分页参数
|
||||
GetPage(qw, page)
|
||||
//
|
||||
var sl []SearchInfo
|
||||
if err := qw.Limit(page.PageSize).Offset((page.Current - 1) * page.PageSize).Find(&sl).Error; err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
return sl
|
||||
|
||||
}
|
||||
|
||||
func GetPage(db *gorm.DB, page *Page) {
|
||||
var count int64
|
||||
db.Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
}
|
||||
|
||||
// ================================= 接口数据缓存 =================================
|
||||
|
||||
// DataCache API请求 数据缓存
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package dp
|
||||
|
||||
import (
|
||||
"server/model"
|
||||
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package dp
|
||||
|
||||
import (
|
||||
"server/model"
|
||||
40
server/plugin/common/param/SimpleParam.go
Normal file
40
server/plugin/common/param/SimpleParam.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package param
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
简单参数处理
|
||||
*/
|
||||
|
||||
// IsEmpty 判断各种基本类型是否为空
|
||||
func IsEmpty(target any) bool {
|
||||
switch target.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
|
||||
log.Println(`target == 0`, target == 0)
|
||||
return target == reflect.Zero(reflect.TypeOf(target)).Interface()
|
||||
case string:
|
||||
return target == ""
|
||||
case bool:
|
||||
return target.(bool)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func IsEmptyRe[T ~int | ~uint | float32 | float64 | string | bool](target T) bool {
|
||||
v := reflect.ValueOf(target)
|
||||
switch v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32,
|
||||
reflect.Float64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return v.Interface() == 0
|
||||
case reflect.String:
|
||||
return v.String() == ""
|
||||
case reflect.Bool:
|
||||
return v.Bool()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func InitRedisConn() error {
|
||||
Addr: config.RedisAddr,
|
||||
Password: config.RedisPassword,
|
||||
DB: config.RedisDBNo,
|
||||
PoolSize: 10, // 默认连接数
|
||||
PoolSize: 10, // 最大连接数
|
||||
DialTimeout: time.Second * 10, // 超时时间
|
||||
})
|
||||
// 测试连接是否正常
|
||||
@@ -31,7 +31,7 @@ func InitRedisConn() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 关闭redis连接
|
||||
// CloseRedis 关闭redis连接
|
||||
func CloseRedis() error {
|
||||
return Rdb.Close()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"net/url"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/common"
|
||||
"server/plugin/common/dp"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -65,9 +65,9 @@ func StartSpider() {
|
||||
model.CreateSearchTable()
|
||||
SearchInfoToMdb()
|
||||
log.Println("SearchInfoToMdb 影片检索信息保存完毕")
|
||||
// 获取其他站点数据
|
||||
go MtSiteSpider()
|
||||
log.Println("Spider End , 数据保存执行完成")
|
||||
// 获取其他站点数据13
|
||||
//go MtSiteSpider()
|
||||
//log.Println("Spider End , 数据保存执行完成")
|
||||
//time.Sleep(time.Second * 10)
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func CategoryList() {
|
||||
// 获取分类列表信息
|
||||
classList := movieListInfo.Class
|
||||
// 组装分类数据信息树形结构
|
||||
categoryTree := common.CategoryTree(classList)
|
||||
categoryTree := dp.CategoryTree(classList)
|
||||
// 序列化tree
|
||||
data, _ := json.Marshal(categoryTree)
|
||||
// 保存 tree 到redis
|
||||
@@ -331,6 +331,6 @@ func GetMovieDetail(pageNumber int, r RequestInfo) (list []model.MovieDetail, er
|
||||
return
|
||||
}
|
||||
// 处理details信息
|
||||
list = common.ProcessMovieDetailList(details.List)
|
||||
list = dp.ProcessMovieDetailList(details.List)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ var (
|
||||
// RequestInfo 请求参数结构体
|
||||
type RequestInfo struct {
|
||||
Uri string `json:"uri"` // 请求url地址
|
||||
Params url.Values `json:"params"` // 请求参数
|
||||
Params url.Values `json:"param"` // 请求参数
|
||||
Header http.Header `json:"header"` // 请求头数据
|
||||
Resp []byte `json:"resp"` // 响应结果数据
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ func SetupRouter() *gin.Engine {
|
||||
r.GET(`/filmPlayInfo`, controller.FilmPlayInfo)
|
||||
r.GET(`/searchFilm`, controller.SearchFilm)
|
||||
r.GET(`/filmCategory`, controller.FilmCategory)
|
||||
r.GET(`/filmClassified`, controller.FilmTagSearch)
|
||||
|
||||
// 触发spider
|
||||
spiderRoute := r.Group(`/spider`)
|
||||
|
||||
Reference in New Issue
Block a user