This commit is contained in:
mubai
2024-10-30 23:41:50 +08:00
parent d1433e4b5b
commit 57323dae2f
48 changed files with 1134 additions and 425 deletions

View File

@@ -40,14 +40,14 @@
>新增内容:
>
>- 新增详细部署说明文档, 以及 `1Panel部署方式` , [点击查看](https://blog.mubai.link/2024/04/21/Docs/gofilm/)
>- 影片分类界面 `二级分类` 展示开关修改为 屏蔽 和 恢复 效果, 点击可对所属分类影片进行屏蔽和恢复
>- 影片信息界面删除按钮功能生效, 可删除单一影片信息 (删除后暂无设置恢复效果)
>- 修复部分按钮点击后褐色边框问题
>- 管理后台新增轮播组件管理功能 (细节图片上传本地服务器功能暂未完善)
>- 采集管理新增 数据重置 以及 全站点自动采集 功能
>
>后续计划:
>
>- 优先针对手机端主页以及导航做修改
>- 同步手机端历史记录功能
>- 采集方式细节化, 实现定向采集以及单一影片的实时手动更新功能
## 目录结构

View File

@@ -21,7 +21,6 @@ declare module '@vue/runtime-core' {
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@@ -45,6 +44,7 @@ declare module '@vue/runtime-core' {
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSelectV2: typeof import('element-plus/es')['ElSelectV2']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']

View File

@@ -90,7 +90,6 @@ const form = reactive({
// 校验密码一致性
const regex = `^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,12}$`
const validateNewPwd = (rule: any, value: any, callback: any) => {
console.log(value)
if (value === '') {
callback(new Error('新密码不能为空'))
} else if (!value.match(regex)) {

View File

@@ -163,6 +163,11 @@ button:focus-visible {
--el-text-color-primary: #5e1e99b8;
}
.el-input-number .el-input__inner {
--el-input-text-color: #999999;
--el-text-color-regular: #999999;
}
.el-dialog__header {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
margin-right: 0 !important;
@@ -179,7 +184,16 @@ button:focus-visible {
}
/*表格底部工具栏*/
.cus_util {
display: flex;
padding: 10px 8px;
border-left: 2px solid #9b49e733;
border-right: 2px solid #9b49e733;
border-bottom: 2px solid #9b49e733;
background: #ffffff;
justify-content: end;
}

View File

@@ -1,8 +1,8 @@
<template>
<el-container>
<el-header>
<!--<Header/>-->
<NewHeader />
<Header/>
<!--<NewHeader />-->
</el-header>
<el-main>
<router-view></router-view>

View File

@@ -105,7 +105,6 @@ const getFilmData = () => {
d.page = resp.data.page
d.search = resp.data.search
d.searchParams = resp.data.params
console.log(d)
} else {
ElMessage.error({message: "影片搜索结果异常,请稍后刷新重试", duration: 1000})
}

View File

@@ -1,19 +1,19 @@
<template>
<div class="container">
<div v-if="true" class="hidden-sm-and-up banner_wrap" @touchstart="touchS" @touchend="touchE" >
<el-carousel v-model="data.banner.current" ref="wrap" :pause-on-hover="false" :interval="5000" trigger="hover" height="200px" arrow="never" >
<el-carousel-item v-for="item in banners" :key="item" >
<el-image style="width: 100%; height: 100%;" :src="item.picture" fit="fill"/>
<div v-if="true" class="hidden-sm-and-up banner_wrap" @touchstart="touchS" @touchend="touchE" @click="skipLink" >
<el-carousel v-model="data.banner.current" ref="wrap" :pause-on-hover="false" :interval="5000" trigger="hover" height="200px" arrow="never" @change="carousel" >
<el-carousel-item v-for="item in data.info.banners" :key="item" >
<el-image style="width: 100%; height: 100%;" :src="item.poster" fit="fill"/>
<p class="carousel-title">{{ item.name }}</p>
</el-carousel-item>
</el-carousel>
</div>
<div v-if="true" class="banner hidden-sm-and-down"
:style="{background:`url(${data.banner.current.picture})`, backgroundRepeat: 'no-repeat', backgroundSize: 'cover'}">
:style="{background:`url(${data.banner.current.poster})`, backgroundRepeat: 'no-repeat', backgroundSize: 'cover'}" @click="skipLink">
<div class="preview">
<el-carousel @change="carousel" :interval="5000" height="240px" arrow="always">
<el-carousel-item v-for="item in banners" :key="item">
<el-image style="width: 60%; height: 80%;border-radius: 5px;" :src="item.poster" fit="contain"/>
<el-carousel-item v-for="item in data.info.banners" :key="item.id">
<el-image style="width: 60%; height: 80%;border-radius: 5px;" :src="item.picture" fit="contain"/>
<div class="carousel-tags">
<span>{{ item.year }}</span>
<span>{{ item.cName }}</span>
@@ -69,8 +69,16 @@ import {onBeforeMount, reactive, ref} from "vue";
import {ApiGet} from "../../utils/request";
import FilmList from "../../components/index/FilmList.vue";
import {ElMessage} from "element-plus";
import {useRouter} from "vue-router";
const data = reactive({
info: {},
banner: {
current: {},
touch: {index: 0, star: 0, end: 0,}
}
})
const router = useRouter()
// 轮播数据拟态
let banners = [
@@ -106,7 +114,12 @@ let banners = [
// pc 背景图同步响应
const carousel = (index: number) => {
data.banner.current = banners[index]
data.banner.current = data.info.banners[index]
}
const skipLink = ()=>{
if (data.banner.current.mid) {
router.push(`/filmDetail?link=`+data.banner.current.mid)
}
}
// 滑动开始
@@ -132,18 +145,11 @@ const touchE = (e:any)=>{
// wrap.value?.setActiveItem(data.banner.touch.index)
}
const data = reactive({
info: {},
banner: {
current: {name: '', year: 2024, cName: '', poster: '', picture: ''},
touch: {index: 0, star: 0, end: 0,}
}
})
onBeforeMount(() => {
data.banner.current = banners[0]
ApiGet('/index').then((resp: any) => {
if (resp.code == 0) {
data.info = resp.data
data.banner.current = data.info.banners[0]
} else {
ElMessage.error({message: resp.msg})
}

View File

@@ -88,7 +88,6 @@ const searchMovie = ()=>{
// 执行搜索请求
const refreshPage = (keyword: any, current: any) => {
ApiGet('/searchFilm', {keyword: keyword, current: current}).then((resp: any) => {
console.log(resp)
if (resp.code == 0) {
data.list = resp.data.list
data.page = resp.data.page

View File

@@ -197,7 +197,7 @@
<el-dialog v-model="dialogV.clear" title="是否清除所有影视数据 ?" width="500">
<el-form :model="form">
<el-form-item label="确认密码" >
<el-input v-model="data.password" type="password" placeholder="请输入账户密码并开确认执行" autocomplete="off" />
<el-input v-model="data.password" type="password" placeholder="请输入账户密码并开确认执行" autocomplete="off" show-password />
</el-form-item>
</el-form>
<template #footer>
@@ -212,7 +212,7 @@
<el-dialog v-model="dialogV.reCollect" title="是否清除影片数据并重新采集 ?" width="500">
<el-form :model="form">
<el-form-item label="确认密码" >
<el-input v-model="data.password" type="password" placeholder="请输入账户密码并开确认执行" autocomplete="off" />
<el-input v-model="data.password" type="password" placeholder="请输入账户密码并开确认执行" autocomplete="off" show-password />
</el-form-item>
</el-form>
<template #footer>
@@ -477,14 +477,6 @@ onMounted(() => {
<style scoped>
.cus_util {
display: flex;
padding: 10px 8px;
border-left: 2px solid #9b49e733;
border-right: 2px solid #9b49e733;
border-bottom: 2px solid #9b49e733;
background: #ffffff;
justify-content: end;
}
</style>

View File

@@ -155,7 +155,6 @@ const addTask = ()=>{
}
const updateTask = ()=>{
console.log(form.edit)
ApiPost(`/manage/cron/update`, {id: form.edit.id, ids: form.edit.ids, time: form.edit.time, state: form.edit.state, remark: form.edit.remark}).then((resp:any)=>{
if (resp.code === 0) {
ElMessage.success({message: resp.msg})

View File

@@ -49,8 +49,6 @@ const data = reactive({
imgList:[""]
})
const customUpload = (options:any)=>{
console.log(options)
console.log(options.file)
let file = options.file
let formData = new FormData();
formData.append("file", file)

View File

@@ -162,7 +162,6 @@ const changeClass = (value: any) => {
// 匹配成功则设置对应的options参数
if (t) {
data.options.Plot = t['Plot']
console.log(data.options.Plot)
data.options.Area = t['Area']
data.options.Language = t['Language']
} else {
@@ -233,7 +232,6 @@ onMounted(() => {
// 删除影片信息
const delFilm = (id:number) =>{
console.log(id)
ApiGet( `/manage/film/search/del`, {id: id}).then((resp: any) => {
if (resp.code === 0) {
ElMessage.success({message: resp.msg})

View File

@@ -170,8 +170,6 @@ const data = reactive({
})
const customUpload = (options:any)=>{
console.log(options)
console.log(options.file)
let file = options.file
let formData = new FormData();
formData.append("file", file)

View File

@@ -65,14 +65,6 @@ const data = reactive({
classTree: []
})
//
const confirmShield = (id:any)=>{
ElMessageBox.confirm('Are you sure to close this dialog?').then(() => {
console.log(id)
}).catch(() => {
// catch error
})
}
// dialog 弹窗数据
const dialog = reactive({

View File

@@ -16,7 +16,7 @@
</el-table-column>
<el-table-column prop="collectType" align="center" label="影片海报">
<template #default="scope">
<el-image style="width: 120px; height: 80px" :src="scope.row.poster" :preview-src-list="[scope.row.poster]" preview-teleported fit="contain" />
<el-image style="width: 180px; height: 80px" :src="scope.row.poster" :preview-src-list="[scope.row.poster]" preview-teleported fit="contain" />
</template>
</el-table-column>
<el-table-column prop="collectType" align="center" label="影片封面">
@@ -37,25 +37,346 @@
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="success" :icon="SwitchButton" plain circle @click="" />
<el-button type="primary" :icon="Edit" plain circle @click="" />
<el-button type="danger" :icon="Delete" plain circle @click="" />
<el-tooltip content="绑定影片信息" placement="top">
<el-button type="success" :icon="Link" plain circle @click="openBindV(scope.row)" />
</el-tooltip>
<el-tooltip content="修改海报信息" placement="top">
<el-button type="primary" :icon="Edit" plain circle @click="openEditV(scope.row)" />
</el-tooltip>
<el-tooltip content="删除海报信息" placement="top">
<el-button type="danger" :icon="Delete" plain circle @click="delBanner(scope.row)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="cus_util">
<el-button color="#9b49e7" :icon="CirclePlus" @click="openAddV">添加海报</el-button>
<el-button color="#9b49e7" :icon="CirclePlus" @click="clearCache">清除缓存</el-button>
</div>
<!--Banner添加弹窗-->
<el-dialog v-model="data.dialogV.addV" width="680px" title="添加海报">
<el-form :model="data.banner">
<el-form-item label="影片ID&emsp;">
<el-input v-model="data.banner.mid" placeholder="影片唯一ID"/>
</el-form-item>
<el-form-item label="影片名称">
<el-input v-model="data.banner.name" placeholder="影片名称"/>
</el-form-item>
<el-form-item label="影片分类">
<el-input v-model="data.banner.cName" placeholder="影片所属分类"/>
</el-form-item>
<el-form-item label="影片海报">
<el-input v-model="data.banner.poster" placeholder="影片海报访问URL"/>
</el-form-item>
<el-form-item label="影片封面">
<el-input v-model="data.banner.picture" placeholder="影片封面访问URL"/>
</el-form-item>
<el-form-item label="更新状态">
<el-input v-model="data.banner.remark" placeholder="影片更新状态"/>
</el-form-item>
<el-form-item label="上映年份">
<el-input-number v-model="data.banner.year" :min="0" :step="1" :max="2100" step-strictly />
</el-form-item>
<el-form-item label="排序分值">
<el-input-number v-model="data.banner.sort" :min="-100" :step="1" :max="100" step-strictly />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button color="#cf48be" @click="data.dialogV.addBindV = true" >绑定影片</el-button>
<el-button color="#9b49e7" @click="add" >确认添加</el-button>
<el-button @click="data.dialogV.addV = false">取消</el-button>
</span>
</template>
<!--影片绑定弹窗-->
<el-dialog v-model="data.dialogV.addBindV" width="620px" title="绑定影片" align-center >
<el-form :model="data.banner">
<el-form-item label="搜索影片">
<el-select-v2 v-model="data.FilmId" filterable :props="{label:'name', value: 'id'}" remote :remote-method="loadingFilm" clearable
:options="data.options" :loading="data.loading" placeholder="请输入需要绑定的影片名称" @change="changeFilm" >
</el-select-v2>
</el-form-item>
<el-form-item v-if="data.film.id">
<div class="film_view">
<a href="javascript:void(0);" :style="{backgroundImage: `url('${data.film.picture}')`}"></a>
<div class="film_intro">
<h3>{{ data.film.name }}</h3>
<p class="tags">
<span class="tag_c">{{ data.film.cName }}</span>
<span>{{ data.film.year }}</span>
<span>{{ data.film.area }}</span>
</p>
<p><em>导演:</em>{{ data.film.director }}</p>
<p><em>主演:</em>{{ data.film.actor }}</p>
<p class="blurb"><em>剧情:</em>{{ (data.film.blurb+'').replaceAll('  ', '') }}</p>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button color="#9b49e7" @click="bindAddBanner" >确认绑定</el-button>
<el-button @click="data.dialogV.addBindV = false">取消</el-button>
</span>
</template>
</el-dialog>
</el-dialog>
<!--影片修改搜索弹窗-->
<el-dialog v-model="data.dialogV.editV" width="680px" title="修改海报信息">
<el-form :model="data.banner">
<el-form-item label="影片ID&emsp;">
<el-input v-model="data.banner.mid" placeholder="影片唯一ID"/>
</el-form-item>
<el-form-item label="影片名称">
<el-input v-model="data.banner.name" placeholder="影片名称"/>
</el-form-item>
<el-form-item label="影片分类">
<el-input v-model="data.banner.cName" placeholder="影片所属分类"/>
</el-form-item>
<el-form-item label="影片海报">
<el-input v-model="data.banner.poster" placeholder="影片海报访问URL"/>
</el-form-item>
<el-form-item label="影片封面">
<el-input v-model="data.banner.picture" placeholder="影片封面访问URL"/>
</el-form-item>
<el-form-item label="更新状态">
<el-input v-model="data.banner.remark" placeholder="影片更新状态"/>
</el-form-item>
<el-form-item label="上映年份">
<el-input-number v-model="data.banner.year" :min="0" :step="1" :max="2100" step-strictly />
</el-form-item>
<el-form-item label="排序分值">
<el-input-number v-model="data.banner.sort" :min="-100" :step="1" :max="100" step-strictly />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button color="#cf48be" @click="data.dialogV.editBindV = true" >绑定影片</el-button>
<el-button color="#9b49e7" @click="edit" >保存</el-button>
<el-button @click="data.dialogV.editV = false">取消</el-button>
</span>
</template>
<!--重新绑定影片-->
<el-dialog v-model="data.dialogV.editBindV" width="620px" title="绑定影片" align-center >
<el-form :model="data.banner">
<el-form-item label="搜索影片">
<el-select-v2 v-model="data.FilmId" filterable :props="{label:'name', value: 'id'}" remote :remote-method="loadingFilm" clearable
:options="data.options" :loading="data.loading" placeholder="请输入需要绑定的影片名称" @change="changeFilm" >
</el-select-v2>
</el-form-item>
<el-form-item v-if="data.film.id">
<div class="film_view">
<a href="javascript:void(0);" :style="{backgroundImage: `url('${data.film.picture}')`}"></a>
<div class="film_intro">
<h3>{{ data.film.name }}</h3>
<p class="tags">
<span class="tag_c">{{ data.film.cName }}</span>
<span>{{ data.film.year }}</span>
<span>{{ data.film.area }}</span>
</p>
<p><em>导演:</em>{{ data.film.director }}</p>
<p><em>主演:</em>{{ data.film.actor }}</p>
<p class="blurb"><em>剧情:</em>{{ (data.film.blurb+'').replaceAll('  ', '') }}</p>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button color="#9b49e7" @click="bindAddBanner" >确认绑定</el-button>
<el-button @click="data.dialogV.addBindV = false">取消</el-button>
</span>
</template>
</el-dialog>
</el-dialog>
<!--搜索绑定的影片-->
<el-dialog v-model="data.dialogV.bindV" width="680px" title="绑定影片">
<el-form :model="data.banner">
<el-form-item label="搜索影片">
<el-select-v2 v-model="data.FilmId" filterable :props="{label:'name', value: 'id'}" remote :remote-method="loadingFilm" clearable
:options="data.options" :loading="data.loading" placeholder="请输入需要绑定的影片名称" @change="changeFilm" >
</el-select-v2>
</el-form-item>
<el-form-item v-if="data.film.id">
<div class="film_view">
<a :href="`/filmDetail?link=${data.film.id}`" :style="{backgroundImage: `url('${data.film.picture}')`}"></a>
<div class="film_intro">
<h3>{{ data.film.name }}</h3>
<p class="tags">
<span class="tag_c">{{ data.film.cName }}</span>
<span>{{ data.film.year }}</span>
<span>{{ data.film.area }}</span>
</p>
<p><em>导演:</em>{{ data.film.director }}</p>
<p><em>主演:</em>{{ data.film.actor }}</p>
<p class="blurb"><em>剧情:</em>{{ (data.film.blurb+'').replaceAll('  ', '') }}</p>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button color="#9b49e7" @click="bindFilm" >确认绑定</el-button>
<el-button @click="data.dialogV.bindV = false">取消</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {Delete, Edit, SwitchButton} from "@element-plus/icons-vue";
import {
CirclePlus,
Delete,
Edit,
Link,
} from "@element-plus/icons-vue";
import {onMounted, reactive} from "vue";
import {ApiGet} from "../../../utils/request";
import {ApiGet, ApiPost} from "../../../utils/request";
import {ElMessage} from "element-plus";
// 渲染数据维护
const data = reactive({
banners: [],
banner: {id: '', mid: 0, name: '', cName: '', poster: '', picture: '', year: 0, remark: '', sort: 0},
loading: false,
FilmId: '',
film: {},
options: [{}],
dialogV: {
addV: false,
editV: false,
bindV: false,
addBindV: false,
editBindV: false,
}
})
// banner添加功能组
const openAddV = ()=>{
data.banner = {id: '', mid: 0, name: '', cName: '', poster: '', picture: '', year: 0, remark: '', sort: 0}
data.dialogV.addV = true
}
const bindAddBanner = ()=>{
// 同步绑定的影片信息到当前Banner
data.banner.mid = data.film.id
data.banner.name = data.film.name
data.banner.cName = data.film.cName
data.banner.picture = data.film.picture
data.banner.year = parseInt(data.film.year)
data.banner.remark = data.film.remarks
data.dialogV.addBindV = false
data.dialogV.editBindV = false
ElMessage.success({message: "影片信息绑定成功!!!"})
}
const add = ()=>{
ApiPost('/manage/banner/add', data.banner).then((resp:any)=>{
if (resp.code === 0) {
ElMessage.success({message: resp.msg})
data.banner = {id: '', mid: 0, name: '', cName: '', poster: '', picture: '', year: 0, remark: '', sort: 0}
data.dialogV.addV = false
getBanners()
} else {
ElMessage.error({message: resp.msg})
}
})
}
// 修改功能组
const openEditV = (b:any)=> {
data.banner = b
data.dialogV.editV = true
}
const edit = ()=>{
ApiPost('/manage/banner/update', data.banner).then((resp:any)=>{
if (resp.code === 0) {
ElMessage.success({message: resp.msg})
data.banner = {id: '', mid: 0, name: '', cName: '', poster: '', picture: '', year: 0, remark: '', sort: 0}
data.dialogV.editV = false
getBanners()
} else {
ElMessage.error({message: resp.msg})
}
})
}
// 绑定功能组
const openBindV = (b:any)=>{
data.banner = b
data.dialogV.bindV = true
}
const loadingFilm = (query:string)=>{
if(query){
data.loading = true
setTimeout(()=>{
data.loading = false
ApiGet('/searchFilm', {keyword: query, current: 0}).then((resp: any) => {
if (resp.code == 0) {
data.options = resp.data.list
} else {
ElMessage.warning({message: resp.msg, duration: 1000})
data.options = []
}
})
},1500)
}
}
const changeFilm = (val:any)=>{
data.options.forEach(item=>{
if (item.id==val) {
data.film = item
}
})
}
const bindFilm = ()=>{
// 同步绑定的影片信息到当前Banner
data.banner.mid = data.film.id
data.banner.name = data.film.name
data.banner.cName = data.film.cName
data.banner.picture = data.film.picture
data.banner.year = parseInt(data.film.year)
data.banner.remark = data.film.remarks
ApiPost('/manage/banner/update', data.banner).then((resp:any)=>{
if (resp.code === 0) {
ElMessage.success({message: resp.msg})
data.banner = {id: '', mid: 0, name: '', cName: '', poster: '', picture: '', year: 0, remark: '', sort: 0}
data.dialogV.bindV = false
getBanners()
} else {
ElMessage.error({message: resp.msg})
}
})
}
// 删除海报信息
const delBanner = (b:any)=>{
ApiGet('/manage/banner/del', {id:b.id}).then((resp:any)=>{
if (resp.code === 0) {
ElMessage.success({message: resp.msg})
getBanners()
} else {
ElMessage.error({message: resp.msg})
}
})
}
// 清除海报信息
const clearCache = ()=>{
ApiGet('/cache/del').then((resp:any)=> {
if (resp.code == 0) {
ElMessage.success({message: resp.msg})
} else {
ElMessage.error({message: resp.msg})
}
})
}
const getBanners = ()=>{
ApiGet(`/manage/banner/list`).then((resp:any)=>{
if(resp.code === 0){
@@ -75,5 +396,74 @@ onMounted(()=>{
</script>
<style scoped>
.film_view {
max-width: 100%;
display: flex;
background: rgba(255,255,255,0.25);
padding: 16px;
min-height: 200px;
max-height: 200px;
border-radius: 10px;
margin: 16px 0;
}
.film_view a {
flex: 1;
border-radius: 8px;
background-size: cover;
}
.film_intro {
max-width: 75%;
margin-left: 10px;
flex: 3;
/*flex-grow: 4;*/
text-align: left;
padding: 0 10px;
font-size: 15px;
position: relative;
}
.film_view h3, p, button {
margin: 3px 0 3px 0;
}
.film_view p {
max-width: 90%;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
}
.film_view p em {
font-weight: bold;
margin-right: 8px;
}
.film_view button {
background-color: orange;
border-radius: 20px;
border: none !important;
color: #ffffff;
font-weight: bold;
position: absolute;
margin-bottom: 2px;
bottom: 0;
}
.tags {
display: flex;
width: 90%;
justify-content: space-between;
}
.tags .tag_c{
background: rgba(155, 73, 231, 0.72);
}
.tags span {
border-radius: 5px;
padding: 3px 5px;
background: rgba(66, 66, 66);
color: #c9c4c4;
margin-right: 10px;
}
</style>

View File

@@ -7,32 +7,32 @@ import {ElementPlusResolver} from "unplugin-vue-components/resolvers";
export default defineConfig({
// 本地测试环境
server: {
host: '0.0.0.0',
port: 3600,
proxy: {
"/api": {
target: `http://127.0.0.1:3601`,
// target: `http://1.94.30.26:3601`,
changeOrigin: true, // 允许跨域
rewrite: path => path.replace(/^\/api/, '')
}
},
},
// nginx发布构建时使用此配置
// server: {
// host: 'localhost',
// host: '0.0.0.0',
// port: 3600,
// proxy: {
// "/api": {
// target: `http://localhost`,
// target: `http://127.0.0.1:3601`,
// // target: `http://1.94.30.26:3601`,
// changeOrigin: true, // 允许跨域
// rewrite: path => path.replace(/^\/api/,'')
// rewrite: path => path.replace(/^\/api/, '')
// }
// },
// },
// nginx发布构建时使用此配置
server: {
host: 'localhost',
port: 3600,
proxy: {
"/api": {
target: `http://localhost`,
changeOrigin: true, // 允许跨域
rewrite: path => path.replace(/^\/api/,'')
}
},
},
plugins: [
vue(),
AutoImport({

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,8 +11,8 @@
<meta charset="UTF-8"/>
<title>(╥﹏╥)</title>
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3992367_cesmizkmqka.css">
<script type="module" crossorigin src="/assets/index-73b7bf54.js"></script>
<link rel="stylesheet" href="/assets/index-c3496d45.css">
<script type="module" crossorigin src="/assets/index-34def5c2.js"></script>
<link rel="stylesheet" href="/assets/index-a1e7ed01.css">
</head>
<body>
<div id="app"></div>

View File

@@ -23,8 +23,8 @@ const (
// -------------------------redis key-----------------------------------
const (
// CategoryTreeKey 分类树 key
CategoryTreeKey = "CategoryTree"
CategoryTreeExpired = time.Hour * 24 * 90
CategoryTreeKey = "CategoryTree"
FilmExpired = time.Hour * 24 * 365 * 10
// MovieListInfoKey movies分类列表 key
MovieListInfoKey = "MovieList:Cid%d"
@@ -62,6 +62,8 @@ const (
ManageConfigExpired = time.Hour * 24 * 365 * 10
// SiteConfigBasic 网站参数配置
SiteConfigBasic = "SystemConfig:SiteConfig:Basic"
// BannersKey 轮播组件key 你
BannersKey = "SystemConfig:Banners"
// FilmCrontabKey 定时任务列表信息
FilmCrontabKey = "Cron:Task:Film"

View File

@@ -162,3 +162,10 @@ func FilmClassify(c *gin.Context) {
"content": logic.IL.GetFilmClassify(pid, &page),
}, "分类影片信息获取成功", c)
}
// IndexCacheDel 删除首页缓存数据
func IndexCacheDel(c *gin.Context) {
// 删除首页缓存
logic.IL.ClearIndexCache()
system.SuccessOnlyMsg("首页缓存数据已清除!!!", c)
}

View File

@@ -235,6 +235,95 @@ func ResetSiteBasic(c *gin.Context) {
system.SuccessOnlyMsg("配置信息重置成功", c)
}
// ------------------------------------------------------ 轮播数据配置 ------------------------------------------------------
// BannerList 获取轮播图数据
func BannerList(c *gin.Context) {
bl := logic.ML.GetBanners()
system.Success(bl, "配置信息重置成功", c)
}
// BannerFind 返回ID对应的横幅信息
func BannerFind(c *gin.Context) {
id := c.Query("id")
if id == "" {
system.Failed("Banner信息获取失败, ID信息异常", c)
return
}
bl := logic.ML.GetBanners()
for _, b := range bl {
if b.Id == id {
system.Success(b, "Banner信息获取成功", c)
return
}
}
system.Failed("Banner信息获取失败", c)
}
// BannerAdd 添加海报数据
func BannerAdd(c *gin.Context) {
var b system.Banner
if err := c.ShouldBindJSON(&b); err != nil {
system.Failed("Banner参数提交异常", c)
return
}
// 为新增的banner生成Id
b.Id = util.GenerateSalt()
bl := logic.ML.GetBanners()
if len(bl) > 6 {
system.Failed("Banners最大阈值为6, 无法添加新的banner信息", c)
return
}
bl = append(bl, b)
if err := logic.ML.SaveBanners(bl); err != nil {
system.Failed(fmt.Sprintln("Banners信息添加失败,", err), c)
return
}
system.SuccessOnlyMsg("海报信息添加成功", c)
}
// BannerUpdate 更新海报数据
func BannerUpdate(c *gin.Context) {
var banner system.Banner
if err := c.ShouldBindJSON(&banner); err != nil {
system.Failed("Banner参数提交异常", c)
return
}
bl := logic.ML.GetBanners()
for i, b := range bl {
if b.Id == banner.Id {
bl[i] = banner
if err := logic.ML.SaveBanners(bl); err != nil {
system.Failed("海报信息更新失败", c)
} else {
system.SuccessOnlyMsg("海报信息更新成功", c)
return
}
}
}
system.Failed("海报信息更新失败, 未匹配对应Banner信息", c)
}
// BannerDel 删除海报数据
func BannerDel(c *gin.Context) {
id := c.Query("id")
if id == "" {
system.Failed("Banner信息获取失败, ID信息异常", c)
return
}
bl := logic.ML.GetBanners()
for i, b := range bl {
if b.Id == id {
bl = append(bl[:i], bl[i+1:]...)
_ = logic.ML.SaveBanners(bl)
system.SuccessOnlyMsg("海报信息删除成功", c)
return
}
}
system.Failed("海报信息删除失败", c)
}
// ------------------------------------------------------ 参数校验 ------------------------------------------------------
func validFilmSource(fs system.FilmSource) error {
// 资源名称不能为空 且长度不能超过20

View File

@@ -3,6 +3,7 @@ package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"server/config"
"server/logic"
"server/model/system"
"strconv"
@@ -64,13 +65,27 @@ func StarSpider(c *gin.Context) {
system.SuccessOnlyMsg("采集任务已成功开启!!!", c)
}
// ClearAllFilm 删除所有film信息
func ClearAllFilm(c *gin.Context) {
// 清空采集数据进行重新采集前校验输入的密码是否正确
pwd := c.DefaultQuery("password", "")
// 如密码错误则不执行后续操作
if !verifyPassword(c, pwd) {
system.Failed("重置失败, 密钥校验失败!!!", c)
return
}
// 删除已采集的所有影片信息
logic.SL.ClearFilms()
system.SuccessOnlyMsg("影视数据已删除!!!", c)
}
// SpiderReset 重置影视数据, 清空库存, 从零开始
func SpiderReset(c *gin.Context) {
// 清空采集数据进行重新采集前校验输入的密码是否正确
key := c.DefaultQuery("accessKey", "")
pwd := c.DefaultQuery("password", "")
// 如密码错误则不执行后续操作
if len(key) <= 0 || key != "Re0" {
system.Failed("重置失败, 密校验失败!!!", c)
if !verifyPassword(c, pwd) {
system.Failed("重置失败, 密校验失败!!!", c)
return
}
// 前置校验通过则清空采集数据并对已启用站点进行 全量采集
@@ -87,3 +102,33 @@ func CoverFilmClass(c *gin.Context) {
}
system.SuccessOnlyMsg("影视分类信息重置成功, 请稍等片刻后刷新页面", c)
}
// DirectedSpider 采集指定的影片
func DirectedSpider(c *gin.Context) {
}
// SingleUpdateSpider 单一影片更新采集
func SingleUpdateSpider(c *gin.Context) {
// 获取影片对应的唯一标识
id := c.Query("id")
if id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
// 通过ID对指定影片进行同步更新
}
// 校验密码有效性
func verifyPassword(c *gin.Context, password string) bool {
// 获取已登录的用户信息
v, ok := c.Get(config.AuthUserClaims)
if !ok {
system.Failed("操作失败,登录信息异常!!!", c)
return false
}
// 从context中获取用户的登录信息
uc := v.(*system.UserClaims)
// 校验密码
return logic.UL.VerifyUserPassword(uc.UserID, password)
}

View File

@@ -7,6 +7,7 @@ import (
"server/config"
"server/model/system"
"server/plugin/db"
"server/plugin/spider"
"strings"
)
@@ -52,11 +53,19 @@ func (i *IndexLogic) IndexPage() map[string]interface{} {
list = append(list, item)
}
Info["content"] = list
// 3. 获取首页轮播数据
Info["banners"] = system.GetBanners()
// 不存在首页数据缓存时将查询数据缓存到redis中
system.DataCache(config.IndexCacheKey, Info)
return Info
}
// ClearIndexCache 删除首页数据缓存
func (i *IndexLogic) ClearIndexCache() {
// 更新成功后删除首页缓存
spider.ClearCache()
}
// GetFilmDetail 影片详情信息页面处理
func (i *IndexLogic) GetFilmDetail(id int) system.MovieDetailVo {
// 通过Id 获取影片search信息

View File

@@ -16,18 +16,22 @@ func (ml *ManageLogic) GetFilmSourceList() []system.FilmSource {
return system.GetCollectSourceList()
}
// GetFilmSource 获取ID对应的采集源信息
func (ml *ManageLogic) GetFilmSource(id string) *system.FilmSource {
return system.FindCollectSourceById(id)
}
// UpdateFilmSource 更新采集源信息
func (ml *ManageLogic) UpdateFilmSource(s system.FilmSource) error {
return system.UpdateCollectSource(s)
}
// SaveFilmSource 保存采集源信息
func (ml *ManageLogic) SaveFilmSource(s system.FilmSource) error {
return system.AddCollectSource(s)
}
// DelFilmSource 删除采集源信息
func (ml *ManageLogic) DelFilmSource(id string) error {
// 先查找是否存在对应ID的站点信息
s := system.FindCollectSourceById(id)
@@ -51,3 +55,13 @@ func (ml *ManageLogic) GetSiteBasicConfig() system.BasicConfig {
func (ml *ManageLogic) UpdateSiteBasic(c system.BasicConfig) error {
return system.SaveSiteBasic(c)
}
// GetBanners 获取轮播组件信息
func (ml *ManageLogic) GetBanners() system.Banners {
return system.GetBanners()
}
// SaveBanners 保存轮播信息
func (ml *ManageLogic) SaveBanners(bl system.Banners) error {
return system.SaveBanners(bl)
}

View File

@@ -38,6 +38,11 @@ func (sl *SpiderLogic) AutoCollect(time int) {
go spider.AutoCollect(time)
}
// ClearFilms 删除采集的数据信息
func (sl *SpiderLogic) ClearFilms() {
go spider.ClearSpider()
}
// ZeroCollect 数据清除从零开始采集
func (sl *SpiderLogic) ZeroCollect(time int) {
go spider.StarZero(time)

View File

@@ -57,6 +57,7 @@ func (ul *UserLogic) ChangePassword(account, password, newPassword string) error
return nil
}
// GetUserInfo 获取用户基本信息
func (ul *UserLogic) GetUserInfo(id uint) system.UserInfoVo {
// 通过用户ID查询对应的用户信息
u := system.GetUserById(id)
@@ -64,3 +65,11 @@ func (ul *UserLogic) GetUserInfo(id uint) system.UserInfoVo {
var vo = system.UserInfoVo{Id: u.ID, UserName: u.UserName, Email: u.Email, Gender: u.Gender, NickName: u.NickName, Avatar: u.Avatar, Status: u.Status}
return vo
}
// VerifyUserPassword 校验密码
func (ul *UserLogic) VerifyUserPassword(id uint, password string) bool {
// 获取当前登录的用户全部信息
u := system.GetUserById(id)
// 校验密码是否正确
return util.PasswordEncrypt(password, u.Salt) == u.Password
}

View File

@@ -30,7 +30,6 @@ func main() {
}
func start() {
// 启动前先执行数据库内容的初始化工作
DefaultDataInit()
// 开启路由监听
@@ -45,7 +44,9 @@ func DefaultDataInit() {
SystemInit.TableInIt()
// 初始化网站基本配置信息
SystemInit.BasicConfigInit()
// 初始化影视来源列表信息
SystemInit.SpiderInit()
// 初始化轮播组件信息
SystemInit.BannersInit()
}
// 初始化影视来源列表信息
SystemInit.SpiderInit()
}

View File

@@ -26,7 +26,7 @@ type CategoryTree struct {
// SaveCategoryTree 保存影片分类信息
func SaveCategoryTree(tree *CategoryTree) error {
data, _ := json.Marshal(tree)
return db.Rdb.Set(db.Cxt, config.CategoryTreeKey, data, config.CategoryTreeExpired).Err()
return db.Rdb.Set(db.Cxt, config.CategoryTreeKey, data, config.FilmExpired).Err()
}
// GetCategoryTree 获取影片分类信息

View File

@@ -5,8 +5,10 @@ import (
"log"
"server/config"
"server/plugin/db"
"sort"
)
// BasicConfig 网站基本信息
type BasicConfig struct {
SiteName string `json:"siteName"` // 网站名称
Domain string `json:"domain"` // 网站域名
@@ -17,6 +19,31 @@ type BasicConfig struct {
Hint string `json:"hint"` // 网站关闭提示
}
// Banner 首页横幅信息
type Banner struct {
Id string `json:"id"` // 唯一标识
Mid int64 `json:"mid"` // 绑定所属影片Id
Name string `json:"name"` // 影片名称
Year int64 `json:"year"` // 上映年份
CName string `json:"cName"` // 分类名称
Poster string `json:"poster"` // 海报图片链接
Picture string `json:"picture"` // 横幅大图链接
Remark string `json:"remark"` // 更新状态描述信息
Sort int64 `json:"sort"` // 排序分值
}
type Banners []Banner
func (bl Banners) Len() int {
return len(bl)
}
func (bl Banners) Less(i, j int) bool {
return bl[i].Sort < bl[j].Sort
}
func (bl Banners) Swap(i, j int) {
bl[i], bl[j] = bl[j], bl[i]
}
// ------------------------------------------------------ Redis ------------------------------------------------------
// SaveSiteBasic 保存网站基本配置信息
@@ -34,3 +61,21 @@ func GetSiteBasic() BasicConfig {
}
return c
}
// GetBanners 获取轮播配置信息
func GetBanners() Banners {
var bl Banners
data := db.Rdb.Get(db.Cxt, config.BannersKey).Val()
if err := json.Unmarshal([]byte(data), &bl); err != nil {
log.Println("Get Banners Error", err)
}
// 通过 sort 对banners进行排序
sort.Sort(bl)
return bl
}
// SaveBanners 保存轮播配置信息
func SaveBanners(bl Banners) error {
data, _ := json.Marshal(bl)
return db.Rdb.Set(db.Cxt, config.BannersKey, data, config.ManageConfigExpired).Err()
}

View File

@@ -99,7 +99,7 @@ func SaveDetails(list []MovieDetail) (err error) {
data, _ := json.Marshal(detail)
// 1. 原使用Zset存储, 但是不便于单个检索 db.Rdb.ZAdd(db.Cxt, fmt.Sprintf("%s:Cid%d", config.MovieDetailKey, detail.Cid), redis.Z{Score: float64(detail.Id), Member: member}).Err()
// 改为普通 k v 存储, k-> id关键字, v json序列化的结果
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.FilmExpired).Err()
// 2. 同步保存简略信息到redis中
SaveMovieBasicInfo(detail)
// 3. 保存 Search tag redis中
@@ -121,7 +121,7 @@ func SaveDetail(detail MovieDetail) (err error) {
// 序列化影片详情信息
data, _ := json.Marshal(detail)
// 保存影片信息到Redis
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.FilmExpired).Err()
if err != nil {
return err
}
@@ -156,7 +156,7 @@ func SaveMovieBasicInfo(detail MovieDetail) {
Year: detail.Year,
}
data, _ := json.Marshal(basicInfo)
_ = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieBasicInfoKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
_ = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieBasicInfoKey, detail.Cid, detail.Id), data, config.FilmExpired).Err()
}
// SaveSitePlayList 仅保存播放url列表信息到当前站点

View File

@@ -399,7 +399,7 @@ func GetMovieListByPid(pid int64, page *Page) []MovieBasicInfo {
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 进行具体的信息查询
var s []SearchInfo
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("pid", pid).Order("year DESC, update_stamp DESC").Find(&s).Error; err != nil {
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("pid", pid).Order("update_stamp DESC").Find(&s).Error; err != nil {
log.Println(err)
return nil
}
@@ -421,7 +421,7 @@ func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 进行具体的信息查询
var s []SearchInfo
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid", cid).Order("year DESC, update_stamp DESC").Find(&s).Error; err != nil {
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid", cid).Order("update_stamp DESC").Find(&s).Error; err != nil {
log.Println(err)
return nil
}
@@ -437,10 +437,10 @@ func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
// GetHotMovieByPid 获取指定类别的热门影片
func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
// 返回分页参数
var count int64
db.Mdb.Model(&SearchInfo{}).Where("pid", pid).Count(&count)
page.Total = int(count)
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
//var count int64
//db.Mdb.Model(&SearchInfo{}).Where("pid", pid).Count(&count)
//page.Total = int(count)
//page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 进行具体的信息查询
var s []SearchInfo
// 当前时间偏移一个月
@@ -462,7 +462,7 @@ func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 2. 获取满足条件的数据
db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).
Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Or("sub_title LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Order("year DESC, update_stamp DESC").Find(&searchList)
Where("name LIKE ?", fmt.Sprintf(`%%%s%%`, keyword)).Or("sub_title LIKE ?", fmt.Sprintf(`%%%s%%`, keyword)).Order("year DESC, update_stamp DESC").Find(&searchList)
return searchList
}
@@ -513,7 +513,8 @@ func GetRelateMovieBasicInfo(search SearchInfo, page *Page) []MovieBasicInfo {
sql = fmt.Sprintf(`%s class_tag like "%%%s%%"`, sql, search.ClassTag)
}
// 除名称外的相似影片使用随机排序
sql = fmt.Sprintf("%s ORDER BY RAND() limit %d,%d)", sql, page.Current, page.PageSize)
//sql = fmt.Sprintf("%s ORDER BY RAND() limit %d,%d)", sql, page.Current, page.PageSize)
sql = fmt.Sprintf("%s limit %d,%d)", sql, page.Current, page.PageSize)
// 条件拼接完成后加上limit参数
sql = fmt.Sprintf("(%s) limit %d,%d", sql, page.Current, page.PageSize)
// 执行sql
@@ -676,13 +677,13 @@ func GetMovieListBySort(t int, pid int64, page *Page) []MovieBasicInfo {
switch t {
case 0:
// 最新上映 (上映时间)
qw.Order("year DESC, release_stamp DESC")
qw.Order("release_stamp DESC")
case 1:
// 排行榜 (暂定为热度排行)
qw.Order("year DESC, hits DESC")
qw.Order("hits DESC")
case 2:
// 最近更新 (更新时间)
qw.Order("year DESC, update_stamp DESC")
qw.Order("update_stamp DESC")
}
if err := qw.Find(&sl).Error; err != nil {
log.Println(err)

View File

@@ -21,11 +21,16 @@ func FilmSourceInit() {
return
}
var l []system.FilmSource = []system.FilmSource{
{Id: util.GenerateSalt(), Name: "HD(lz)", Uri: `https://cj.lziapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(sn)", Uri: `https://suoniapi.com/api.php/provide/vod/from/snm3u8/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2000},
{Id: util.GenerateSalt(), Name: "HD(bf)", Uri: `https://bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2500},
{Id: util.GenerateSalt(), Name: "HD(ff)", Uri: `http://cj.ffzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(LZ)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(BF)", Uri: `https://bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2500},
{Id: util.GenerateSalt(), Name: "HD(FF)", Uri: `http://cj.ffzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(OK)", Uri: `https://okzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(HM)", Uri: `https://json.heimuer.xyz/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(LY)", Uri: `https://360zy.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(YZ)", Uri: `https://api.1080zyku.com/inc/apijson.php`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(kk)", Uri: `https://kuaikan-api.com/api.php/provide/vod/from/kuaikan/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(SN)", Uri: `https://suoniapi.com/api.php/provide/vod/from/snm3u8/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2000},
//{Id: util.GenerateSalt(), Name: "HD(LZ)", Uri: `https://cj.lziapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(lzBk)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(fs)", Uri: `https://www.feisuzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(bfApp)", Uri: `http://app.bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},

View File

@@ -1,6 +1,9 @@
package SystemInit
import "server/model/system"
import (
"server/model/system"
"server/plugin/common/util"
)
// SiteConfigInit 网站配置初始化
func SiteConfigInit() {
@@ -20,3 +23,13 @@ func BasicConfigInit() {
}
_ = system.SaveSiteBasic(bc)
}
func BannersInit() {
var bl = system.Banners{
system.Banner{Id: util.GenerateSalt(), Name: "樱花庄的宠物女孩", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "从零开始的异世界生活", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/UkpdhIRO12fsy6C.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "五等分的花嫁", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/wXJr59Zuv4tcKNp.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "我的青春恋爱物语果然有问题", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/oMAGzSliK2YbhRu.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
}
_ = system.SaveBanners(bl)
}

View File

@@ -229,6 +229,11 @@ func AutoCollect(h int) {
}
}
// ClearSpider 删除已采集的影片信息
func ClearSpider() {
system.FilmZero()
}
// StarZero 情况站点内所有影片信息
func StarZero(h int) {
// 首先清除影视信息

View File

@@ -113,6 +113,25 @@ func (jc *JsonCollect) GetFilmDetail(r util.RequestInfo) (list []system.MovieDet
return
}
// CustomSearch 自定义搜索, 通过特定的搜索参数获取满足条件的影片数据
func (jc *JsonCollect) CustomSearch(r util.RequestInfo) {
// 设置固定参数 ac 请求类型 pg 页数
if len(r.Params.Get("ac")) <= 0 {
r.Params.Set("ac", "detail")
}
r.Params.Set("pg", "1")
// 设置搜索参数 wd (影片名模糊搜索)
}
// GetSingleFilm 获取单一影片信息
func (jc *JsonCollect) GetSingleFilm(r util.RequestInfo, ids string) {
// 设置固定参数 ac 请求类型 pg 页数
r.Params.Set("ac", "detail")
r.Params.Set("pg", "1")
r.Params.Set("ids", ids)
//
}
// ------------------------------------------------- XML Collect -------------------------------------------------
// XmlCollect 处理返回值为XML格式的采集数据

View File

@@ -17,6 +17,7 @@ func SetupRouter() *gin.Engine {
r.Static(config.FilmPictureUrlPath, config.FilmPictureUploadDir)
r.GET(`/index`, controller.Index)
r.GET(`/cache/del`, controller.IndexCacheDel)
r.GET(`/config/basic`, controller.SiteBasicConfig)
r.GET(`/navCategory`, controller.CategoriesInfo)
r.GET(`/filmDetail`, controller.FilmDetail)
@@ -34,14 +35,26 @@ func SetupRouter() *gin.Engine {
manageRoute.Use(middleware.AuthToken())
{
manageRoute.GET(`/index`, controller.ManageIndex)
// 系统相关
sysConfig := manageRoute.Group(`/config`)
{
sysConfig.GET("/basic", controller.SiteBasicConfig)
sysConfig.POST("/basic/update", controller.UpdateSiteBasic)
sysConfig.GET("/basic/reset", controller.ResetSiteBasic)
sysConfig.GET(`/basic`, controller.SiteBasicConfig)
sysConfig.POST(`/basic/update`, controller.UpdateSiteBasic)
sysConfig.GET(`/basic/reset`, controller.ResetSiteBasic)
}
// 轮播相关
banner := manageRoute.Group(`banner`)
{
banner.GET(`/list`, controller.BannerList)
banner.GET(`/find`, controller.BannerFind)
banner.POST(`/add`, controller.BannerAdd)
banner.POST(`/update`, controller.BannerUpdate)
banner.GET(`/del`, controller.BannerDel)
}
// 用户相关
userRoute := manageRoute.Group(`/user`)
{
userRoute.GET(`/info`, controller.UserInfo)
@@ -77,6 +90,7 @@ func SetupRouter() *gin.Engine {
{
spiderRoute.POST(`/start`, controller.StarSpider)
spiderRoute.GET(`/zero`, controller.SpiderReset)
spiderRoute.GET(`/clear`, controller.ClearAllFilm)
spiderRoute.GET(`/class/cover`, controller.CoverFilmClass)
}
// filmManage 影视管理

View File

@@ -162,3 +162,10 @@ func FilmClassify(c *gin.Context) {
"content": logic.IL.GetFilmClassify(pid, &page),
}, "分类影片信息获取成功", c)
}
// IndexCacheDel 删除首页缓存数据
func IndexCacheDel(c *gin.Context) {
// 删除首页缓存
logic.IL.ClearIndexCache()
system.SuccessOnlyMsg("首页缓存数据已清除!!!", c)
}

View File

@@ -9,7 +9,6 @@ import (
"server/plugin/SystemInit"
"server/plugin/common/util"
"server/plugin/spider"
"strconv"
)
func ManageIndex(c *gin.Context) {
@@ -246,16 +245,11 @@ func BannerList(c *gin.Context) {
// BannerFind 返回ID对应的横幅信息
func BannerFind(c *gin.Context) {
idStr := c.Query("id")
if idStr == "" {
id := c.Query("id")
if id == "" {
system.Failed("Banner信息获取失败, ID信息异常", c)
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
system.Failed("删除失败,参数类型异常", c)
return
}
bl := logic.ML.GetBanners()
for _, b := range bl {
if b.Id == id {
@@ -273,7 +267,13 @@ func BannerAdd(c *gin.Context) {
system.Failed("Banner参数提交异常", c)
return
}
// 为新增的banner生成Id
b.Id = util.GenerateSalt()
bl := logic.ML.GetBanners()
if len(bl) > 6 {
system.Failed("Banners最大阈值为6, 无法添加新的banner信息", c)
return
}
bl = append(bl, b)
if err := logic.ML.SaveBanners(bl); err != nil {
system.Failed(fmt.Sprintln("Banners信息添加失败,", err), c)
@@ -307,16 +307,11 @@ func BannerUpdate(c *gin.Context) {
// BannerDel 删除海报数据
func BannerDel(c *gin.Context) {
idStr := c.Query("id")
if idStr == "" {
id := c.Query("id")
if id == "" {
system.Failed("Banner信息获取失败, ID信息异常", c)
return
}
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
system.Failed("删除失败,参数类型异常", c)
return
}
bl := logic.ML.GetBanners()
for i, b := range bl {
if b.Id == id {

View File

@@ -103,6 +103,22 @@ func CoverFilmClass(c *gin.Context) {
system.SuccessOnlyMsg("影视分类信息重置成功, 请稍等片刻后刷新页面", c)
}
// DirectedSpider 采集指定的影片
func DirectedSpider(c *gin.Context) {
}
// SingleUpdateSpider 单一影片更新采集
func SingleUpdateSpider(c *gin.Context) {
// 获取影片对应的唯一标识
id := c.Query("id")
if id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
// 通过ID对指定影片进行同步更新
}
// 校验密码有效性
func verifyPassword(c *gin.Context, password string) bool {
// 获取已登录的用户信息

View File

@@ -7,6 +7,7 @@ import (
"server/config"
"server/model/system"
"server/plugin/db"
"server/plugin/spider"
"strings"
)
@@ -52,11 +53,19 @@ func (i *IndexLogic) IndexPage() map[string]interface{} {
list = append(list, item)
}
Info["content"] = list
// 3. 获取首页轮播数据
Info["banners"] = system.GetBanners()
// 不存在首页数据缓存时将查询数据缓存到redis中
system.DataCache(config.IndexCacheKey, Info)
return Info
}
// ClearIndexCache 删除首页数据缓存
func (i *IndexLogic) ClearIndexCache() {
// 更新成功后删除首页缓存
spider.ClearCache()
}
// GetFilmDetail 影片详情信息页面处理
func (i *IndexLogic) GetFilmDetail(id int) system.MovieDetailVo {
// 通过Id 获取影片search信息

View File

@@ -29,10 +29,8 @@ func main() {
}
func start() {
// 启动前先执行数据库内容的初始化工作
DefaultDataInit()
SystemInit.BannersInit()
// 开启路由监听
r := router.SetupRouter()
_ = r.Run(fmt.Sprintf(":%s", config.ListenerPort))
@@ -45,7 +43,9 @@ func DefaultDataInit() {
SystemInit.TableInIt()
// 初始化网站基本配置信息
SystemInit.BasicConfigInit()
// 初始化影视来源列表信息
SystemInit.SpiderInit()
// 初始化轮播组件信息
SystemInit.BannersInit()
}
// 初始化影视来源列表信息
SystemInit.SpiderInit()
}

View File

@@ -21,7 +21,8 @@ type BasicConfig struct {
// Banner 首页横幅信息
type Banner struct {
Id int64 `json:"id"` // 绑定所属影片Id
Id string `json:"id"` // 唯一标识
Mid int64 `json:"mid"` // 绑定所属影片Id
Name string `json:"name"` // 影片名称
Year int64 `json:"year"` // 上映年份
CName string `json:"cName"` // 分类名称

View File

@@ -1,6 +1,9 @@
package SystemInit
import "server/model/system"
import (
"server/model/system"
"server/plugin/common/util"
)
// SiteConfigInit 网站配置初始化
func SiteConfigInit() {
@@ -23,10 +26,10 @@ func BasicConfigInit() {
func BannersInit() {
var bl = system.Banners{
system.Banner{Name: "樱花庄的宠物女孩", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Name: "从零开始的异世界生活", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Name: "五等分的花嫁", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Name: "我的青春恋爱物语果然有问题", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "樱花庄的宠物女孩", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/Wt1QDhabdEI7HcL.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "从零开始的异世界生活", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/UkpdhIRO12fsy6C.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "五等分的花嫁", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/wXJr59Zuv4tcKNp.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
system.Banner{Id: util.GenerateSalt(), Name: "我的青春恋爱物语果然有问题", Year: 2020, CName: "日韩动漫", Poster: "https://s2.loli.net/2024/02/21/oMAGzSliK2YbhRu.jpg", Picture: "https://img.bfzypic.com/upload/vod/20230424-43/06e79232a4650aea00f7476356a49847.jpg", Remark: "已完结"},
}
_ = system.SaveBanners(bl)
}

View File

@@ -123,6 +123,15 @@ func (jc *JsonCollect) CustomSearch(r util.RequestInfo) {
// 设置搜索参数 wd (影片名模糊搜索)
}
// GetSingleFilm 获取单一影片信息
func (jc *JsonCollect) GetSingleFilm(r util.RequestInfo, ids string) {
// 设置固定参数 ac 请求类型 pg 页数
r.Params.Set("ac", "detail")
r.Params.Set("pg", "1")
r.Params.Set("ids", ids)
//
}
// ------------------------------------------------- XML Collect -------------------------------------------------
// XmlCollect 处理返回值为XML格式的采集数据

View File

@@ -17,6 +17,7 @@ func SetupRouter() *gin.Engine {
r.Static(config.FilmPictureUrlPath, config.FilmPictureUploadDir)
r.GET(`/index`, controller.Index)
r.GET(`/cache/del`, controller.IndexCacheDel)
r.GET(`/config/basic`, controller.SiteBasicConfig)
r.GET(`/navCategory`, controller.CategoriesInfo)
r.GET(`/filmDetail`, controller.FilmDetail)
@@ -49,7 +50,7 @@ func SetupRouter() *gin.Engine {
banner.GET(`/list`, controller.BannerList)
banner.GET(`/find`, controller.BannerFind)
banner.POST(`/add`, controller.BannerAdd)
banner.GET(`/update`, controller.BannerUpdate)
banner.POST(`/update`, controller.BannerUpdate)
banner.GET(`/del`, controller.BannerDel)
}