Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94dc723910 | ||
|
|
b4205dac90 |
+14
-14
@@ -11,12 +11,12 @@ const componentStore = useComponentStore()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-container>
|
<!-- <el-container> -->
|
||||||
<!-- left -->
|
<!-- left -->
|
||||||
<el-aside class="fixed top-0 left-0 h-full z-10 c-md:block c-sm:hidden c-xs:hidden" width="240px" v-show="!componentStore.leftCom">
|
<!-- <el-aside class="fixed top-0 left-0 h-full z-10 c-md:block c-sm:hidden c-xs:hidden" width="240px" v-show="!componentStore.leftCom">
|
||||||
<Left></Left>
|
<Left></Left>
|
||||||
</el-aside>
|
</el-aside> -->
|
||||||
<el-drawer
|
<!-- <el-drawer
|
||||||
show-close
|
show-close
|
||||||
size="240px"
|
size="240px"
|
||||||
:with-header="false"
|
:with-header="false"
|
||||||
@@ -24,26 +24,26 @@ const componentStore = useComponentStore()
|
|||||||
direction="ltr"
|
direction="ltr"
|
||||||
>
|
>
|
||||||
<Left bgColor="#fff"></Left>
|
<Left bgColor="#fff"></Left>
|
||||||
</el-drawer>
|
</el-drawer> -->
|
||||||
|
|
||||||
<!-- right -->
|
<!-- right -->
|
||||||
<el-container :class="!componentStore.leftCom ? 'c-md:ml-[240px]' : ''">
|
<!-- <el-container> -->
|
||||||
<el-header>
|
<!-- <el-header>
|
||||||
<Header/>
|
<Header/>
|
||||||
</el-header>
|
</el-header> -->
|
||||||
<el-main>
|
<!-- <el-main> -->
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition name="animation" mode="out-in">
|
<transition name="animation" mode="out-in">
|
||||||
<component :is="Component" :key="route.path"></component>
|
<component :is="Component" :key="route.path"></component>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
</el-main>
|
<!-- </el-main> -->
|
||||||
<el-footer class="md:mb-6 mt-12 c-xs:mb-12">
|
<!-- <el-footer class="md:mb-6 mt-12 c-xs:mb-12">
|
||||||
<Floor />
|
<Floor />
|
||||||
</el-footer>
|
</el-footer> -->
|
||||||
</el-container>
|
<!-- </el-container> -->
|
||||||
|
|
||||||
</el-container>
|
<!-- </el-container> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -3,3 +3,18 @@ export interface ResponseData {
|
|||||||
code: number,
|
code: number,
|
||||||
message: string,
|
message: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//分页
|
||||||
|
export interface PageData {
|
||||||
|
current_page: number,
|
||||||
|
first_page_url: string,
|
||||||
|
from: number,
|
||||||
|
last_page: number,
|
||||||
|
last_page_url: string,
|
||||||
|
next_page_url: string,
|
||||||
|
path: string,
|
||||||
|
per_page: number,
|
||||||
|
prev_page_url: string,
|
||||||
|
to: number,
|
||||||
|
total: number,
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
//统一管理咱们项目用户相关的接口
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ScanReqData,
|
||||||
|
UpdateTagReqData,
|
||||||
|
getScanResponseData,
|
||||||
|
getScanTagResponseData,
|
||||||
|
updateTagResponseData,
|
||||||
|
ScanInfoReqData,
|
||||||
|
ScanFileInfo
|
||||||
|
} from './type'
|
||||||
|
|
||||||
|
//项目用户相关的请求地址
|
||||||
|
|
||||||
|
enum API {
|
||||||
|
//获取scan列表
|
||||||
|
SCAN_FILE = '/scans',
|
||||||
|
//获取scan信息
|
||||||
|
SCAN_FILE_INFO = '/scans',
|
||||||
|
//获取标签
|
||||||
|
SCAN_TAGS = '/scan/tags',
|
||||||
|
//更新标签
|
||||||
|
UPDATE_TAG = '/scan/tag/updates',
|
||||||
|
}
|
||||||
|
//获取scan file
|
||||||
|
export const getList = (data: ScanReqData) => request.get<any, getScanResponseData>(API.SCAN_FILE, {
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
//获取scan file
|
||||||
|
export const getInfo = (data: ScanInfoReqData) => request.get<any, ScanFileInfo>(API.SCAN_FILE_INFO + '/' + data.fileId)
|
||||||
|
//获取scan tags
|
||||||
|
export const getTags = () => request.get<any, getScanTagResponseData>(API.SCAN_TAGS)
|
||||||
|
//更新标签
|
||||||
|
export const updateTag = (data: UpdateTagReqData) => request.post<any, updateTagResponseData>(API.UPDATE_TAG, data)
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { ResponseData, PageData } from "../common"
|
||||||
|
|
||||||
|
export interface ScanReqData {
|
||||||
|
title: string,
|
||||||
|
tags: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanInfoReqData {
|
||||||
|
fileId: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateTagReqData {
|
||||||
|
fileId: number,
|
||||||
|
tagId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanTagInfo {
|
||||||
|
id: number,
|
||||||
|
title: string,
|
||||||
|
pid: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
//file info
|
||||||
|
export interface ScanFileInfo {
|
||||||
|
id: number,
|
||||||
|
title: string,
|
||||||
|
path: string,
|
||||||
|
dir: string,
|
||||||
|
ext: string,
|
||||||
|
tags: number[],
|
||||||
|
scan_tag: ScanTagInfo[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanFilePage extends PageData {
|
||||||
|
data: ScanFileInfo[],
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag info
|
||||||
|
export interface ScanTagInfo {
|
||||||
|
id: number,
|
||||||
|
title: string,
|
||||||
|
pid: number,
|
||||||
|
childTags: ScanTagInfo[]
|
||||||
|
}
|
||||||
|
|
||||||
|
//响应格式 - scan file
|
||||||
|
export interface getScanResponseData extends ResponseData {
|
||||||
|
data: ScanFileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
//响应格式 - scan tag
|
||||||
|
export interface getScanTagResponseData extends ResponseData {
|
||||||
|
data: ScanTagInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
//响应格式 - update tag
|
||||||
|
export interface updateTagResponseData extends ResponseData {
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// import { ref } from 'vue'
|
||||||
|
// import { copy } from '@/utils/string'
|
||||||
|
// const info = reactive({
|
||||||
|
// title: "关于本站",
|
||||||
|
// })
|
||||||
|
const feedBackUrl = import.meta.env.VITE_FEEDBACK_URL
|
||||||
|
//copy
|
||||||
|
// const copyRes = async (resStr: string) => {
|
||||||
|
// copy(resStr)
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col mt-3 flex-1">
|
||||||
|
<div class="bg-white rounded-md p-5">
|
||||||
|
<br>
|
||||||
|
<p>本项目是一个开源工具站, 求星星</p>
|
||||||
|
<br>
|
||||||
|
<p>本项目开源地址:<el-link href="https://github.com/taoran1401/tools-web">https://github.com/taoran1401/tools-web</el-link></p>
|
||||||
|
<br>
|
||||||
|
<p class="font-bold">联系作者/问题反馈</p>
|
||||||
|
<br>
|
||||||
|
<p>反馈中心:<el-link :href="feedBackUrl">{{ feedBackUrl }}</el-link></p>
|
||||||
|
<br>
|
||||||
|
<p>邮箱:taoran0796@163.com</p>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,31 +1,100 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import { ref } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
// import { copy } from '@/utils/string'
|
// import { useRouter } from "vue-router"
|
||||||
// const info = reactive({
|
import { useScanStore } from '@/store/modules/scan'
|
||||||
// title: "关于本站",
|
|
||||||
// })
|
// const router = useRouter()
|
||||||
const feedBackUrl = import.meta.env.VITE_FEEDBACK_URL
|
const scanStore = useScanStore()
|
||||||
//copy
|
|
||||||
// const copyRes = async (resStr: string) => {
|
//video html element
|
||||||
// copy(resStr)
|
const videoPlayerRef = ref()
|
||||||
|
|
||||||
|
//上一个
|
||||||
|
const playPreviousVideo = () => {
|
||||||
|
var data = scanStore.historyList[scanStore.historyList.length - 2];
|
||||||
|
videoPlayerRef.value.src = scanStore.sourceUrl + data.title;
|
||||||
|
// console.log(videoPlayerRef.value.src)
|
||||||
|
videoPlayerRef.value.load();
|
||||||
|
videoPlayerRef.value.play();
|
||||||
|
//记录当期播放
|
||||||
|
scanStore.setNowPlay(data)
|
||||||
|
// scanStore.setNowIndex(nextIndex)
|
||||||
|
//刷新页面
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
//下一个
|
||||||
|
const playNextVideo = () => {
|
||||||
|
let nextIndex = scanStore.getNowIndex() + 1;
|
||||||
|
if (scanStore.isRandPlay === false) {
|
||||||
|
//随机播放,并且不能和当前相同TODO
|
||||||
|
nextIndex = Math.floor(Math.random() * scanStore.videoList.length);
|
||||||
|
}
|
||||||
|
if (nextIndex < scanStore.videoList.length) {
|
||||||
|
var data = scanStore.videoList[nextIndex];
|
||||||
|
videoPlayerRef.value.src = scanStore.sourceUrl + data.title;
|
||||||
|
videoPlayerRef.value.load();
|
||||||
|
videoPlayerRef.value.play();
|
||||||
|
//记录当期播放
|
||||||
|
scanStore.setNowPlay(data)
|
||||||
|
scanStore.setNowIndex(nextIndex)
|
||||||
|
//刷新页面
|
||||||
|
window.location.reload()
|
||||||
|
} else {
|
||||||
|
alert('没有下一个了')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//能播放时触发
|
||||||
|
const canplay = () => {
|
||||||
|
//更新历史播放
|
||||||
|
//过滤重复信息
|
||||||
|
let nowPlay = scanStore.getNowPlay()
|
||||||
|
console.log(nowPlay.id)
|
||||||
|
scanStore.historyList = scanStore.historyList.filter(item => item.id != nowPlay.id)
|
||||||
|
scanStore.historyList.push(scanStore.getNowPlay())
|
||||||
|
localStorage.setItem('historyList', JSON.stringify(scanStore.historyList))
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据索引获取文件信息
|
||||||
|
// const getInfoByIndex = () => {
|
||||||
|
// return scanStore.videoList[Number(scanStore.nowIndex)];
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
//播放结束时触发
|
||||||
|
const ended = () => {
|
||||||
|
//自动播放下一个
|
||||||
|
playNextVideo()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log(scanStore.getNowPlay())
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col mt-3 flex-1">
|
<div class="flex flex-col mt-3 flex-1">
|
||||||
<div class="bg-white rounded-md p-5">
|
<div class="ml-3">
|
||||||
<br>
|
<router-link to="/" class="mr-3">
|
||||||
<p>本项目是一个开源工具站, 求星星</p>
|
<el-button>首页</el-button>
|
||||||
<br>
|
</router-link>
|
||||||
<p>本项目开源地址:<el-link href="https://github.com/taoran1401/tools-web">https://github.com/taoran1401/tools-web</el-link></p>
|
<el-button @click="playPreviousVideo">上一个</el-button>
|
||||||
<br>
|
<el-button @click="playNextVideo">下一个</el-button>
|
||||||
<p class="font-bold">联系作者/问题反馈</p>
|
<div class="mt-3 mb-3">当前播放:{{ scanStore.getNowPlay().path }}</div>
|
||||||
<br>
|
<video
|
||||||
<p>反馈中心:<el-link :href="feedBackUrl">{{ feedBackUrl }}</el-link></p>
|
ref="videoPlayerRef"
|
||||||
<br>
|
:src="scanStore.sourceUrl + scanStore.getNowPlay().title" class="w-[850px] h-[500px]"
|
||||||
<p>邮箱:taoran0796@163.com</p>
|
:autoplay="false"
|
||||||
<br>
|
:playbackRate="scanStore.playbackRate"
|
||||||
|
@canplay="canplay"
|
||||||
|
@ended="ended"
|
||||||
|
controls>
|
||||||
|
您的浏览器不支持video
|
||||||
|
</video>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted,reactive } from 'vue';
|
||||||
|
import { RouterLink } from "vue-router"
|
||||||
|
import { Star } from '@element-plus/icons-vue'
|
||||||
|
import { useToolsStore } from '@/store/modules/tools'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
|
//store
|
||||||
|
const toolsStore = useToolsStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const route = useRoute()
|
||||||
|
// const getToolsCate = async () => {
|
||||||
|
// try {
|
||||||
|
// await toolsStore.getToolCate()
|
||||||
|
// } catch (error: any) {
|
||||||
|
// ElMessage.error(error.message)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
//收藏
|
||||||
|
const toolCollect = reactive({
|
||||||
|
toolId: 0
|
||||||
|
})
|
||||||
|
const collect = async (toolId) => {
|
||||||
|
try {
|
||||||
|
if (!userStore.isLogin()) {
|
||||||
|
//未登录,弹出登录窗口
|
||||||
|
ElMessage.error('请登录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toolCollect.toolId = toolId
|
||||||
|
await toolsStore.toolCollect(toolCollect)
|
||||||
|
// ElMessage.success('收藏成功')
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error.message)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// getToolsCate()
|
||||||
|
if (route.query && route.query.value) {//底部导航跳转过来的则定位到响应位置
|
||||||
|
document?.querySelector('#' + `${route.query.value}`)?.scrollIntoView();
|
||||||
|
} else {//其他位置跳转过来不需要定位的则定位到顶部
|
||||||
|
document?.querySelector('#collect')?.scrollIntoView()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="md:mr-6 c-xs:mr-0">
|
||||||
|
<!-- collect -->
|
||||||
|
<div id="collect">
|
||||||
|
<!-- cate title -->
|
||||||
|
<div class="md:mt-8 md:mb-8 c-xs:mt-1 c-xs:mb-4 text-xl font-bold text-[--base-black]">
|
||||||
|
我的收藏
|
||||||
|
</div>
|
||||||
|
<!-- card -->
|
||||||
|
<div class="flex justify-between flex-wrap self-card-div c-xs:ml-3" :gutter="10" v-if="toolsStore.collect.length > 0">
|
||||||
|
<router-link v-for="(item, index) in toolsStore.collect" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5">
|
||||||
|
<div class="flex items-center border-b pb-2">
|
||||||
|
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
||||||
|
<div class="flex flex-col ml-2 w-full">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="font-semibold text-lg line-clamp-1">{{ item.title }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<el-text size="small">{{ item.cate }}</el-text>
|
||||||
|
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between mt-2">
|
||||||
|
<el-text line-clamp="2">{{ item.desc }}</el-text>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
<!-- 占位 div -->
|
||||||
|
<div class="w-[24%] c-md:w-[24%] c-sm:w-[32%]"></div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="bg-white rounded-2xl">
|
||||||
|
<el-empty description="暂无收藏" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- list -->
|
||||||
|
<div v-for="(cate, index) in toolsStore.cates" :key="index">
|
||||||
|
<!-- cate title -->
|
||||||
|
<div class="mt-8 mb-3 text-xl font-bold text-[--base-black]" :id="'cate_' + cate.id">
|
||||||
|
{{ cate.title }}
|
||||||
|
</div>
|
||||||
|
<!-- card -->
|
||||||
|
<div class="flex justify-between flex-wrap self-card-div c-xs:ml-0" :gutter="10">
|
||||||
|
<router-link v-for="(item, index) in cate.list" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5 hover:-translate-y-2 duration-300">
|
||||||
|
<div class="flex items-center border-b pb-2">
|
||||||
|
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
||||||
|
<div class="flex flex-col ml-2 w-full">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="font-semibold text-lg line-clamp-1">{{ item.title }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<el-text size="small">{{ item.cate }}</el-text>
|
||||||
|
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning" :plain="!toolsStore.collectIds.includes(item.id)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between mt-2">
|
||||||
|
<el-text line-clamp="2">{{ item.desc }}</el-text>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
<!-- 占位 div -->
|
||||||
|
<div class="w-[24%] c-md:w-[24%] c-sm:w-[32%] "></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.self-card-div:after{
|
||||||
|
content: "";
|
||||||
|
width: 24%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+206
-83
@@ -1,15 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted,reactive } from 'vue';
|
import { onMounted,reactive, ref } from 'vue';
|
||||||
import { RouterLink } from "vue-router"
|
import { useScanStore } from '@/store/modules/scan'
|
||||||
import { Star } from '@element-plus/icons-vue'
|
// import { ElMessage } from 'element-plus'
|
||||||
import { useToolsStore } from '@/store/modules/tools'
|
import { Search } from '@element-plus/icons-vue';
|
||||||
import { useUserStore } from '@/store/modules/user'
|
import { useRouter } from "vue-router"
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { useRoute } from "vue-router"
|
|
||||||
//store
|
//store
|
||||||
const toolsStore = useToolsStore()
|
const scanStore = useScanStore()
|
||||||
const userStore = useUserStore()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
|
||||||
// const getToolsCate = async () => {
|
// const getToolsCate = async () => {
|
||||||
// try {
|
// try {
|
||||||
// await toolsStore.getToolCate()
|
// await toolsStore.getToolCate()
|
||||||
@@ -18,100 +15,226 @@ const route = useRoute()
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//收藏
|
const loading = ref(false)
|
||||||
const toolCollect = reactive({
|
const setTagsDialog = ref(false)
|
||||||
toolId: 0
|
// const checkedTags = reactive({})
|
||||||
|
//----- config -----
|
||||||
|
//----- ^ -----
|
||||||
|
|
||||||
|
//获取分类
|
||||||
|
//查询参数
|
||||||
|
const searchParam = reactive({
|
||||||
|
title: '',
|
||||||
|
tags: '',
|
||||||
|
page: 1,
|
||||||
})
|
})
|
||||||
const collect = async (toolId) => {
|
const getList = async (query) => {
|
||||||
try {
|
try {
|
||||||
if (!userStore.isLogin()) {
|
searchParam.title = query
|
||||||
//未登录,弹出登录窗口
|
await scanStore.getList(searchParam)
|
||||||
ElMessage.error('请登录')
|
} catch (error) {
|
||||||
return
|
console.log(error)
|
||||||
}
|
}
|
||||||
toolCollect.toolId = toolId
|
}
|
||||||
await toolsStore.toolCollect(toolCollect)
|
|
||||||
// ElMessage.success('收藏成功')
|
//获取标签
|
||||||
} catch (error: any) {
|
const getTags = async () => {
|
||||||
ElMessage.error(error.message)
|
try {
|
||||||
|
await scanStore.getTags()
|
||||||
|
//设置标签checked
|
||||||
|
// for (let index in scanStore.tags) {
|
||||||
|
// for (let childIndex in scanStore.tags[index].childTags) {
|
||||||
|
// let cheeckedTag = 'checkTag' + scanStore.tags[index].childTags[childIndex].id
|
||||||
|
// }
|
||||||
|
// console.log(scanStore.tags[index].childTags)
|
||||||
|
// }
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
}
|
}
|
||||||
return
|
}
|
||||||
|
|
||||||
|
const optionClick = (path: string) => {
|
||||||
|
console.log(path)
|
||||||
|
// router.push(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取文件信息
|
||||||
|
const getFileInfo = async (fileId: number) => {
|
||||||
|
try {
|
||||||
|
await scanStore.getInfo({
|
||||||
|
fileId: fileId,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//set tags
|
||||||
|
const setTagsDia = async (fileId: number) => {
|
||||||
|
//显示dialog
|
||||||
|
setTagsDialog.value = true
|
||||||
|
await getFileInfo(fileId)
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新标签
|
||||||
|
const updateTag = async (fileId: number, tagId: number) => {
|
||||||
|
console.log(fileId, tagId)
|
||||||
|
try {
|
||||||
|
await scanStore.updateTag({
|
||||||
|
fileId: fileId,
|
||||||
|
tagId: tagId
|
||||||
|
})
|
||||||
|
//获取当前文件标签
|
||||||
|
await getFileInfo(fileId)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//分页 - 页码改变时
|
||||||
|
const pageChange = async (nowPage: number) => {
|
||||||
|
searchParam.page = nowPage
|
||||||
|
console.log(nowPage)
|
||||||
|
await scanStore.getList(searchParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* open local app
|
||||||
|
*
|
||||||
|
* index: 索引
|
||||||
|
* data: 内容数据
|
||||||
|
*/
|
||||||
|
const open = (index: number, data: any) => {
|
||||||
|
//缓存当前播放和播放索引
|
||||||
|
scanStore.setNowPlay(data)
|
||||||
|
scanStore.setNowIndex(index)
|
||||||
|
router.push({
|
||||||
|
path: '/about',
|
||||||
|
})
|
||||||
|
|
||||||
|
// let addr = router.resolve({
|
||||||
|
// path: '/about',
|
||||||
|
// params: {
|
||||||
|
// url: url
|
||||||
|
// }
|
||||||
|
// }).href
|
||||||
|
// window.open(addr, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// getToolsCate()
|
getList('');
|
||||||
if (route.query && route.query.value) {//底部导航跳转过来的则定位到响应位置
|
getTags();
|
||||||
document?.querySelector('#' + `${route.query.value}`)?.scrollIntoView();
|
|
||||||
} else {//其他位置跳转过来不需要定位的则定位到顶部
|
|
||||||
document?.querySelector('#collect')?.scrollIntoView()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="md:mr-6 c-xs:mr-0">
|
<div>
|
||||||
<!-- collect -->
|
<div class="mt-3 flex items-center">
|
||||||
<div id="collect">
|
<el-select
|
||||||
<!-- cate title -->
|
v-model="searchParam.title"
|
||||||
<div class="md:mt-8 md:mb-8 c-xs:mt-1 c-xs:mb-4 text-xl font-bold text-[--base-black]">
|
filterable
|
||||||
我的收藏
|
remote
|
||||||
</div>
|
reserve-keyword
|
||||||
<!-- card -->
|
remote-show-suffix
|
||||||
<div class="flex justify-between flex-wrap self-card-div c-xs:ml-3" :gutter="10" v-if="toolsStore.collect.length > 0">
|
:suffix-transition="false"
|
||||||
<router-link v-for="(item, index) in toolsStore.collect" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5">
|
:suffix-icon="Search"
|
||||||
<div class="flex items-center border-b pb-2">
|
placeholder="输入关键词搜索"
|
||||||
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
:remote-method="getList"
|
||||||
<div class="flex flex-col ml-2 w-full">
|
:loading="loading"
|
||||||
<div class="flex">
|
class="ml-3 mr-3 md:w-80 c-xs:w-60"
|
||||||
<div class="font-semibold text-lg line-clamp-1">{{ item.title }}</div>
|
>
|
||||||
</div>
|
<el-optiond
|
||||||
<div class="flex justify-between">
|
v-for="item in scanStore.list.data"
|
||||||
<el-text size="small">{{ item.cate }}</el-text>
|
:key="item.id"
|
||||||
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning"/>
|
:label="item.title"
|
||||||
</div>
|
:value="item.id"
|
||||||
</div>
|
@click="optionClick(item.path)"
|
||||||
</div>
|
>
|
||||||
<div class="flex items-center justify-between mt-2">
|
</el-optiond>
|
||||||
<el-text line-clamp="2">{{ item.desc }}</el-text>
|
</el-select>
|
||||||
</div>
|
<!-- <el-button>扫描目录</el-button> -->
|
||||||
</router-link>
|
<el-button>随机预览</el-button>
|
||||||
<!-- 占位 div -->
|
<div class='ml-3'>
|
||||||
<div class="w-[24%] c-md:w-[24%] c-sm:w-[32%]"></div>
|
<el-text>数量:111</el-text>
|
||||||
</div>
|
|
||||||
<div v-else class="bg-white rounded-2xl">
|
|
||||||
<el-empty description="暂无收藏" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- list -->
|
<div class="flex w-full">
|
||||||
<div v-for="(cate, index) in toolsStore.cates" :key="index">
|
<!-- 左侧列表 -->
|
||||||
<!-- cate title -->
|
<div class="w-9/12">
|
||||||
<div class="mt-8 mb-3 text-xl font-bold text-[--base-black]" :id="'cate_' + cate.id">
|
<div class="flex items-center justify-between h-40 bg-white mt-3 ml-3 rounded-lg p-3" v-for="(item, index) in scanStore.list.data" :key="index">
|
||||||
{{ cate.title }}
|
<!-- left -->
|
||||||
|
<div class="flex items-center">
|
||||||
|
<!-- -->
|
||||||
|
<div>
|
||||||
|
<div v-if="scanStore.extVideo.includes(item.ext)">
|
||||||
|
<video :src="scanStore.sourceUrl + item.title" style="height:150px;width:270px;"></video>
|
||||||
</div>
|
</div>
|
||||||
<!-- card -->
|
<div v-else>
|
||||||
<div class="flex justify-between flex-wrap self-card-div c-xs:ml-0" :gutter="10">
|
<el-empty description="无预览" :image-size="100"/>
|
||||||
<router-link v-for="(item, index) in cate.list" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5 hover:-translate-y-2 duration-300">
|
|
||||||
<div class="flex items-center border-b pb-2">
|
|
||||||
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
|
|
||||||
<div class="flex flex-col ml-2 w-full">
|
|
||||||
<div class="flex">
|
|
||||||
<div class="font-semibold text-lg line-clamp-1">{{ item.title }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
</div>
|
||||||
<el-text size="small">{{ item.cate }}</el-text>
|
|
||||||
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning" :plain="!toolsStore.collectIds.includes(item.id)"/>
|
<!-- -->
|
||||||
|
<div class="ml-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<el-button class="mr-2" type="warning" size="small">{{ item.ext }}</el-button>
|
||||||
|
<el-text>{{item.title}}</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<el-text class="mt-3">{{ item.path }}</el-text>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<el-tag type="danger" class="mt-2 mr-2" v-for="(childItem, childIndex) in item.scan_tag" :key="childIndex">{{ childItem.title }}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between mt-2">
|
|
||||||
<el-text line-clamp="2">{{ item.desc }}</el-text>
|
<!-- right -->
|
||||||
</div>
|
<div class="flex flex-col justify-center">
|
||||||
</router-link>
|
<el-button size="small" type="primary" class="w-20" @click="open(index, item)">open</el-button>
|
||||||
<!-- 占位 div -->
|
<el-button size="small" type="primary" class="w-20 mt-2" style="margin-left: 0;" @click="setTagsDia(item.id)">set tags</el-button>
|
||||||
<div class="w-[24%] c-md:w-[24%] c-sm:w-[32%] "></div>
|
<!-- <el-button size="small" type="primary" class="w-20 mt-2" style="margin-left: 0;" >move</el-button> -->
|
||||||
|
<!-- <el-button size="small" type="primary" class="w-20 mt-2" style="margin-left: 0;">delete</el-button> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="mt-3 mb-3 ml-3 flex justify-end">
|
||||||
|
<el-pagination
|
||||||
|
background
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:page-count="scanStore.list.last_page"
|
||||||
|
:total="scanStore.list.total"
|
||||||
|
:default-page-size="scanStore.list.per_page"
|
||||||
|
@current-change="pageChange"
|
||||||
|
@size-change="pageChange"
|
||||||
|
@prev-click="pageChange"
|
||||||
|
@next-click="pageChange"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧栏目 -->
|
||||||
|
<div class="w-3/12 mt-3 ml-3 mr-3 rounded-lg">
|
||||||
|
<!-- tags -->
|
||||||
|
<div class="p-3 bg-white" v-for="(item, index) in scanStore.tags" :key="index">
|
||||||
|
<div>{{ item.title }}</div>
|
||||||
|
<div class="flex flex-wrap">
|
||||||
|
<el-tag type="danger" class="mt-2 mr-2" v-for="(childItem, childIndex) in item.childTags" :key="childIndex" @click="">{{ childItem.title }}</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- set tags dialog -->
|
||||||
|
<el-dialog v-model="setTagsDialog" title="set tags" width="800" @close="getList('')">
|
||||||
|
<!-- tags -->
|
||||||
|
<div class="p-3 bg-white" v-for="(item, index) in scanStore.tags" :key="index">
|
||||||
|
<div>{{ item.title }}</div>
|
||||||
|
<div class="flex flex-wrap">
|
||||||
|
<el-check-tag type="danger" :checked="scanStore.fileInfoTags.includes(childItem.id)" @change="updateTag(scanStore.fileInfo.id, childItem.id)" class="mt-2 mr-2" v-for="(childItem, childIndex) in item.childTags" :key="childIndex">{{ childItem.title }}</el-check-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <el-button class="ml-3 mt-3" type="primary">保存</el-button> -->
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
//创建tools相关的小工具
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { ScanReqData, ScanFilePage, ScanTagInfo, UpdateTagReqData, ScanInfoReqData, ScanFileInfo } from '@/api/scan/type'
|
||||||
|
import { getList, getTags, updateTag, getInfo } from '@/api/scan'
|
||||||
|
|
||||||
|
export const useScanStore = defineStore('scan', {
|
||||||
|
//用来存放变量
|
||||||
|
state: () => ({
|
||||||
|
list: {} as ScanFilePage,
|
||||||
|
fileInfo: {} as ScanFileInfo, //当前文件信息
|
||||||
|
fileInfoTags: [] as number[], //当期文件tags
|
||||||
|
tags: [] as ScanTagInfo[],
|
||||||
|
videoList: localStorage.getItem('videoList') !== null ? JSON.parse(localStorage.getItem('videoList') || '') : [], //播放列表,一般情况下同list
|
||||||
|
playbackRate: 1.5, //播放速度
|
||||||
|
isRandPlay: false, //是否随机播放
|
||||||
|
extVideo: ['ts', 'mp4', 'mkv', 'wmv', 'avi', 'flv', '3gp', 'dvd', 'mov', 'vob', 'webm'], //视频格式
|
||||||
|
sourceUrl: 'http://localhost:7881/', //资源服务地址
|
||||||
|
historyList: localStorage.getItem('historyList') !== null ? JSON.parse(localStorage.getItem('historyList') || '') : [], //历史播放
|
||||||
|
}),
|
||||||
|
//方法
|
||||||
|
actions: {
|
||||||
|
//获取scan file list
|
||||||
|
async getList(data: ScanReqData) {
|
||||||
|
//发送请求
|
||||||
|
const result: any = await getList(data)
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.list = result.data
|
||||||
|
localStorage.setItem('videoList', JSON.stringify(result.data.data))
|
||||||
|
console.log(localStorage.getItem('videoList'))
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//获取scan file list
|
||||||
|
async getInfo(data: ScanInfoReqData) {
|
||||||
|
//发送请求
|
||||||
|
const result: any = await getInfo(data)
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.fileInfo = result.data
|
||||||
|
this.fileInfoTags = this.fileInfo.tags
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//get tags
|
||||||
|
async getTags() {
|
||||||
|
//发送请求
|
||||||
|
const result: any = await getTags()
|
||||||
|
if (result.code == 200) {
|
||||||
|
this.tags = result.data
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//收藏工具
|
||||||
|
async updateTag(data: UpdateTagReqData) {
|
||||||
|
const result: any = await updateTag(data)
|
||||||
|
if (result.code == 200) {
|
||||||
|
return result.message
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(result.message))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//设置播放列表
|
||||||
|
// setVideoList() {
|
||||||
|
|
||||||
|
// },
|
||||||
|
//设置播放速度
|
||||||
|
setPlaybackRate(number) {
|
||||||
|
this.playbackRate = number
|
||||||
|
},
|
||||||
|
//当期那播放信息、索引获取和设置
|
||||||
|
getNowPlay() {
|
||||||
|
return localStorage.getItem('nowPlay') !== null ? JSON.parse(localStorage.getItem('nowPlay') || '') : {};
|
||||||
|
},
|
||||||
|
getNowIndex() {
|
||||||
|
return localStorage.getItem('nowIndex') !== null ? JSON.parse(localStorage.getItem('nowIndex') || '') : 0;
|
||||||
|
},
|
||||||
|
setNowPlay(data) {
|
||||||
|
localStorage.setItem('nowPlay', JSON.stringify(data))
|
||||||
|
},
|
||||||
|
setNowIndex(index) {
|
||||||
|
localStorage.setItem('nowIndex', JSON.stringify(index))
|
||||||
|
},
|
||||||
|
//清除缓存
|
||||||
|
cleanCache() {
|
||||||
|
localStorage.removeItem('videoList');
|
||||||
|
localStorage.removeItem('historyList');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user