mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-10 07:08:46 +08:00
format:format and fix code
This commit is contained in:
2
frontend/auto-imports.d.ts
vendored
2
frontend/auto-imports.d.ts
vendored
@@ -5,5 +5,5 @@
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const ElMessage: (typeof import("element-plus/es"))["ElMessage"]
|
||||
}
|
||||
|
||||
5
frontend/components.d.ts
vendored
5
frontend/components.d.ts
vendored
@@ -13,8 +13,6 @@ declare module 'vue' {
|
||||
ElBacktop: typeof import('element-plus/es')['ElBacktop']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: (typeof import("element-plus/es"))["ElCheckbox"]
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
@@ -30,8 +28,6 @@ declare module 'vue' {
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
@@ -43,7 +39,6 @@ declare module 'vue' {
|
||||
ElTree: typeof import('element-plus/es')['ElTree']
|
||||
FolderSelect: typeof import('./src/components/Home/FolderSelect.vue')['default']
|
||||
ResourceCard: typeof import('./src/components/Home/ResourceCard.vue')['default']
|
||||
ResourceList: typeof import('./src/components/Home/ResourceList.vue')['default']
|
||||
ResourceTable: typeof import('./src/components/Home/ResourceTable.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
|
||||
@@ -5,32 +5,32 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
:root {
|
||||
--theme-color: #3e3e3e;
|
||||
--theme-theme: #133ab3;
|
||||
--theme-background: #fafafa;
|
||||
--theme-other_background: #ffffff;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-family:
|
||||
v-sans,
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
Segoe UI,
|
||||
sans-serif,
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
Segoe UI Symbol;
|
||||
line-height: 1.6;
|
||||
color: var(--theme-color);
|
||||
background-color: var(--theme-background);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
:root {
|
||||
--theme-color: #3e3e3e;
|
||||
--theme-theme: #133ab3;
|
||||
--theme-background: #fafafa;
|
||||
--theme-other_background: #ffffff;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-family:
|
||||
v-sans,
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
Segoe UI,
|
||||
sans-serif,
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
Segoe UI Symbol;
|
||||
line-height: 1.6;
|
||||
color: var(--theme-color);
|
||||
background-color: var(--theme-background);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
@close="handleClose"
|
||||
>
|
||||
<template v-for="menu in menuList">
|
||||
<el-sub-menu :index="menu.index" v-if="menu.children">
|
||||
<el-sub-menu v-if="menu.children" :key="menu.index" :index="menu.index">
|
||||
<template #title>
|
||||
<el-icon><component :is="menu.icon" /></el-icon>
|
||||
<span>{{ menu.title }}</span>
|
||||
</template>
|
||||
<el-menu-item
|
||||
v-for="child in menu.children"
|
||||
:index="child.index"
|
||||
:key="child.index"
|
||||
:index="child.index"
|
||||
@click="handleMenuClick(child)"
|
||||
>
|
||||
{{ child.title }}
|
||||
@@ -28,9 +28,10 @@
|
||||
</el-sub-menu>
|
||||
<el-menu-item
|
||||
v-else
|
||||
:key="menu.router"
|
||||
:index="menu.index"
|
||||
@click="handleMenuClick(menu)"
|
||||
:disabled="menu.disabled"
|
||||
@click="handleMenuClick(menu)"
|
||||
>
|
||||
<el-icon><component :is="menu.icon" /></el-icon>
|
||||
<span>{{ menu.title }}</span>
|
||||
@@ -41,115 +42,108 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Search, Film, Setting } from "@element-plus/icons-vue";
|
||||
import logo from "@/assets/images/logo.png";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { computed } from "vue";
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
interface MenuItem {
|
||||
index: string;
|
||||
title: string;
|
||||
icon?: any;
|
||||
router?: string;
|
||||
children?: MenuItem[];
|
||||
disabled?: boolean;
|
||||
import { Search, Film, Setting } from "@element-plus/icons-vue";
|
||||
import logo from "@/assets/images/logo.png";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { computed } from "vue";
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
interface MenuItem {
|
||||
index: string;
|
||||
title: string;
|
||||
icon?: typeof Search | typeof Film | typeof Setting;
|
||||
router?: string;
|
||||
children?: MenuItem[];
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const menuList: MenuItem[] = [
|
||||
{
|
||||
index: "2",
|
||||
title: "资源搜索",
|
||||
icon: Search,
|
||||
router: "/",
|
||||
},
|
||||
{
|
||||
index: "1",
|
||||
title: "豆瓣榜单",
|
||||
icon: Film,
|
||||
children: [
|
||||
{
|
||||
index: "1-1",
|
||||
title: "热门电影",
|
||||
router: "/douban?type=movie",
|
||||
},
|
||||
{
|
||||
index: "1-2",
|
||||
title: "热门电视剧",
|
||||
router: "/douban?type=tv",
|
||||
},
|
||||
{
|
||||
index: "1-3",
|
||||
title: "最新电影",
|
||||
router: "/douban?type=movie&tag=最新",
|
||||
},
|
||||
{
|
||||
index: "1-4",
|
||||
title: "热门综艺",
|
||||
router: "/douban?type=tv&tag=综艺",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
index: "3",
|
||||
title: "设置",
|
||||
icon: Setting,
|
||||
router: "/setting",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const currentMenu = computed(() => {
|
||||
return menuList
|
||||
.reduce((pre: MenuItem[], cur: MenuItem) => {
|
||||
if (!cur.children) {
|
||||
pre.push(cur);
|
||||
} else {
|
||||
pre.push(...cur.children);
|
||||
}
|
||||
return pre;
|
||||
}, [])
|
||||
.find((x) => x.router === decodeURIComponent(route.fullPath));
|
||||
});
|
||||
const currentMenuOpen = computed(() => {
|
||||
if (currentMenu.value && currentMenu.value.index.length > 1) {
|
||||
return [currentMenu.value.index.split("-")[0]];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
const menuList: MenuItem[] = [
|
||||
{
|
||||
index: "2",
|
||||
title: "资源搜索",
|
||||
icon: Search,
|
||||
router: "/",
|
||||
},
|
||||
{
|
||||
index: "1",
|
||||
title: "豆瓣榜单",
|
||||
icon: Film,
|
||||
children: [
|
||||
{
|
||||
index: "1-1",
|
||||
title: "热门电影",
|
||||
router: "/douban?type=movie",
|
||||
},
|
||||
{
|
||||
index: "1-2",
|
||||
title: "热门电视剧",
|
||||
router: "/douban?type=tv",
|
||||
},
|
||||
{
|
||||
index: "1-3",
|
||||
title: "最新电影",
|
||||
router: "/douban?type=movie&tag=最新",
|
||||
},
|
||||
{
|
||||
index: "1-4",
|
||||
title: "热门综艺",
|
||||
router: "/douban?type=tv&tag=综艺",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
index: "3",
|
||||
title: "设置",
|
||||
icon: Setting,
|
||||
router: "/setting",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const currentMenu = computed(() => {
|
||||
console.log("route", decodeURIComponent(route.fullPath));
|
||||
return menuList
|
||||
.reduce((pre: MenuItem[], cur: MenuItem) => {
|
||||
if (!cur.children) {
|
||||
pre.push(cur);
|
||||
} else {
|
||||
pre.push(...cur.children);
|
||||
}
|
||||
return pre;
|
||||
}, [])
|
||||
.find((x) => x.router === decodeURIComponent(route.fullPath));
|
||||
});
|
||||
const currentMenuOpen = computed(() => {
|
||||
if (currentMenu.value && currentMenu.value.index.length > 1) {
|
||||
console.log([currentMenu.value.index.split("-")[0]]);
|
||||
return [currentMenu.value.index.split("-")[0]];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
const handleOpen = (key: string, keyPath: string[]) => {
|
||||
console.log(key, keyPath);
|
||||
};
|
||||
const handleClose = (key: string, keyPath: string[]) => {
|
||||
console.log(key, keyPath);
|
||||
};
|
||||
const handleMenuClick = (menu: any) => {
|
||||
console.log(menu);
|
||||
if (menu.router) {
|
||||
router.push(menu.router);
|
||||
}
|
||||
};
|
||||
});
|
||||
const handleOpen = (_key: string, _keyPath: string[]): void => {};
|
||||
const handleClose = (_key: string, _keyPath: string[]): void => {};
|
||||
const handleMenuClick = (menu: MenuItem): void => {
|
||||
if (menu.router) {
|
||||
router.push(menu.router);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.el-menu-vertical {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
.el-menu-vertical {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 0;
|
||||
.logo-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 0;
|
||||
.logo-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.logo-text {
|
||||
font-size: 20px;
|
||||
}
|
||||
.logo-text {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
node-key="cid"
|
||||
:load="loadNode"
|
||||
lazy
|
||||
@node-click="handleNodeClick"
|
||||
highlight-current
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<template #default="{ node }">
|
||||
<span class="folder-node">
|
||||
@@ -25,107 +25,107 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps } from "vue";
|
||||
import { cloud115Api } from "@/api/cloud115";
|
||||
import { quarkApi } from "@/api/quark";
|
||||
import type { TreeInstance } from "element-plus";
|
||||
import type { Folder } from "@/types";
|
||||
import { type RequestResult } from "@/types/response";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ref, defineProps } from "vue";
|
||||
import { cloud115Api } from "@/api/cloud115";
|
||||
import { quarkApi } from "@/api/quark";
|
||||
import type { TreeInstance } from "element-plus";
|
||||
import type { Folder } from "@/types";
|
||||
import { type RequestResult } from "@/types/response";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
cloudType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const props = defineProps({
|
||||
cloudType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const treeRef = ref<TreeInstance>();
|
||||
const folders = ref<Folder[]>([]);
|
||||
const selectedFolder = ref<Folder | null>(null);
|
||||
const emit = defineEmits<{
|
||||
(e: "select", folderId: string): void;
|
||||
(e: "close"): void;
|
||||
}>();
|
||||
const treeRef = ref<TreeInstance>();
|
||||
const folders = ref<Folder[]>([]);
|
||||
const selectedFolder = ref<Folder | null>(null);
|
||||
const emit = defineEmits<{
|
||||
(e: "select", folderId: string): void;
|
||||
(e: "close"): void;
|
||||
}>();
|
||||
|
||||
const defaultProps = {
|
||||
label: "name",
|
||||
children: "children",
|
||||
isLeaf: "leaf",
|
||||
};
|
||||
const defaultProps = {
|
||||
label: "name",
|
||||
children: "children",
|
||||
isLeaf: "leaf",
|
||||
};
|
||||
|
||||
const cloudTypeApiMap = {
|
||||
pan115: cloud115Api,
|
||||
quark: quarkApi,
|
||||
};
|
||||
const cloudTypeApiMap = {
|
||||
pan115: cloud115Api,
|
||||
quark: quarkApi,
|
||||
};
|
||||
|
||||
const loadNode = async (node: any, resolve: (list: Folder[]) => void) => {
|
||||
const api = cloudTypeApiMap[props.cloudType as keyof typeof cloudTypeApiMap];
|
||||
try {
|
||||
let res: RequestResult<Folder[]> = { code: 0, data: [] as Folder[], message: "" };
|
||||
if (node.level === 0) {
|
||||
if (api.getFolderList) {
|
||||
// 使用类型保护检查方法是否存在
|
||||
res = await api.getFolderList();
|
||||
}
|
||||
} else {
|
||||
if (api.getFolderList) {
|
||||
// 使用类型保护检查方法是否存在
|
||||
res = await api.getFolderList(node.data.cid);
|
||||
}
|
||||
const loadNode = async (node: any, resolve: (list: Folder[]) => void) => {
|
||||
const api = cloudTypeApiMap[props.cloudType as keyof typeof cloudTypeApiMap];
|
||||
try {
|
||||
let res: RequestResult<Folder[]> = { code: 0, data: [] as Folder[], message: "" };
|
||||
if (node.level === 0) {
|
||||
if (api.getFolderList) {
|
||||
// 使用类型保护检查方法是否存在
|
||||
res = await api.getFolderList();
|
||||
}
|
||||
if (res?.code === 0) {
|
||||
resolve(res.data.length ? res.data : []);
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
} else {
|
||||
if (api.getFolderList) {
|
||||
// 使用类型保护检查方法是否存在
|
||||
res = await api.getFolderList(node.data.cid);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? `${error.message}` : "获取目录失败");
|
||||
// 关闭模态框
|
||||
emit("close");
|
||||
resolve([]);
|
||||
}
|
||||
};
|
||||
if (res?.code === 0) {
|
||||
resolve(res.data.length ? res.data : []);
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? `${error.message}` : "获取目录失败");
|
||||
// 关闭模态框
|
||||
emit("close");
|
||||
resolve([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNodeClick = (data: Folder) => {
|
||||
selectedFolder.value = {
|
||||
...data,
|
||||
path: data.path ? [...data.path, data] : [data],
|
||||
};
|
||||
emit("select", data.cid);
|
||||
const handleNodeClick = (data: Folder) => {
|
||||
selectedFolder.value = {
|
||||
...data,
|
||||
path: data.path ? [...data.path, data] : [data],
|
||||
};
|
||||
emit("select", data.cid);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.folder-select {
|
||||
min-height: 300px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.folder-select {
|
||||
min-height: 300px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.folder-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.folder-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.folder-path {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.folder-path {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content) {
|
||||
height: 32px;
|
||||
}
|
||||
.folder-select-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #e5e6e8;
|
||||
border-radius: 8px;
|
||||
}
|
||||
:deep(.el-tree-node__content) {
|
||||
height: 32px;
|
||||
}
|
||||
.folder-select-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #e5e6e8;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
><ArrowDown
|
||||
/></el-icon>
|
||||
</div>
|
||||
<div class="card-item-list" v-show="group.displayList">
|
||||
<div v-show="group.displayList" class="card-item-list">
|
||||
<div v-for="resource in group.list" :key="resource.messageId" class="card-item-content">
|
||||
<el-card class="card-item">
|
||||
<el-image
|
||||
@@ -28,12 +28,12 @@
|
||||
><div class="item-name">{{ resource.title }}</div></el-link
|
||||
>
|
||||
<div class="item-description" v-html="resource.content"></div>
|
||||
<div class="tags-list" v-if="resource.tags && resource.tags.length">
|
||||
<div v-if="resource.tags && resource.tags.length" class="tags-list">
|
||||
<span>标签:</span>
|
||||
<el-tag
|
||||
v-for="item in resource.tags"
|
||||
class="resource_tag"
|
||||
:key="item"
|
||||
class="resource_tag"
|
||||
@click="searchMovieforTag(item)"
|
||||
>
|
||||
{{ item }}
|
||||
@@ -54,7 +54,7 @@
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="load-more" v-show="group.displayList">
|
||||
<div v-show="group.displayList" class="load-more">
|
||||
<el-button @click="handleLoadMore(group.id)"> 加载更多 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,128 +62,128 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { computed } from "vue";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { computed } from "vue";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
|
||||
const store = useResourceStore();
|
||||
const store = useResourceStore();
|
||||
|
||||
const location = computed(() => window.location);
|
||||
const location = computed(() => window.location);
|
||||
|
||||
const emit = defineEmits(["save", "loadMore", "searchMovieforTag"]);
|
||||
const emit = defineEmits(["save", "loadMore", "searchMovieforTag"]);
|
||||
|
||||
const handleSave = (resource: ResourceItem) => {
|
||||
emit("save", resource);
|
||||
};
|
||||
const handleSave = (resource: ResourceItem) => {
|
||||
emit("save", resource);
|
||||
};
|
||||
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
emit("searchMovieforTag", tag);
|
||||
};
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
emit("searchMovieforTag", tag);
|
||||
};
|
||||
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
emit("loadMore", channelId);
|
||||
};
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
emit("loadMore", channelId);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resource-list {
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
background-color: var(--theme-other_background);
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.resource-list {
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
background-color: var(--theme-other_background);
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.card-item-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 220px);
|
||||
grid-row-gap: 30px;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
/* grid-column-gap: auto-fill; */
|
||||
/* flex-wrap: wrap; */
|
||||
}
|
||||
.card-item-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 220px);
|
||||
grid-row-gap: 30px;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
/* grid-column-gap: auto-fill; */
|
||||
/* flex-wrap: wrap; */
|
||||
}
|
||||
.card-item-content {
|
||||
/* height: 520px; */
|
||||
}
|
||||
.channel-logo {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
}
|
||||
.load-more {
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.card-item {
|
||||
max-width: 480px;
|
||||
height: 100%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.card-item-image {
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
.item-name,
|
||||
.item-description {
|
||||
max-width: 100%;
|
||||
margin: 15px 0;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
white-space: all;
|
||||
}
|
||||
.item-description {
|
||||
-webkit-line-clamp: 4;
|
||||
margin-top: 0;
|
||||
height: 100px;
|
||||
}
|
||||
.item-name {
|
||||
height: 58px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.tags-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
height: 58px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.resource_tag {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.group-header {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: left;
|
||||
padding: 0 15px;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/* text-align: center; */
|
||||
.el-link {
|
||||
font-size: 22px;
|
||||
}
|
||||
.card-item-content {
|
||||
/* height: 520px; */
|
||||
}
|
||||
.channel-logo {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
}
|
||||
.load-more {
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.card-item {
|
||||
max-width: 480px;
|
||||
height: 100%;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.card-item-image {
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
.item-name,
|
||||
.item-description {
|
||||
max-width: 100%;
|
||||
margin: 15px 0;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
white-space: all;
|
||||
}
|
||||
.item-description {
|
||||
-webkit-line-clamp: 4;
|
||||
margin-top: 0;
|
||||
height: 100px;
|
||||
}
|
||||
.item-name {
|
||||
height: 58px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.tags-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
height: 58px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.resource_tag {
|
||||
.header-icon {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.group-header {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: left;
|
||||
padding: 0 15px;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/* text-align: center; */
|
||||
.el-link {
|
||||
font-size: 22px;
|
||||
}
|
||||
.header-icon {
|
||||
cursor: pointer;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
.item-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
.item-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
<el-table-column label="图片" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-image
|
||||
class="table-item-image"
|
||||
v-if="row.image"
|
||||
class="table-item-image"
|
||||
:src="`/tele-images/?url=${encodeURIComponent(row.image as string)}`"
|
||||
hide-on-click-modal
|
||||
:preview-src-list="[
|
||||
@@ -42,17 +42,17 @@
|
||||
</el-table-column>
|
||||
<el-table-column prop="title" label="描述">
|
||||
<template #default="{ row }">
|
||||
<div v-html="row.content" class="item-description"></div>
|
||||
<div class="item-description" v-html="row.content"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="tags" label="标签">
|
||||
<template #default="{ row }">
|
||||
<div class="tags-list" v-if="row.tags.length > 0">
|
||||
<div v-if="row.tags.length > 0" class="tags-list">
|
||||
<span>标签:</span>
|
||||
<el-tag
|
||||
v-for="item in row.tags"
|
||||
class="resource_tag"
|
||||
:key="item"
|
||||
class="resource_tag"
|
||||
@click="searchMovieforTag(item)"
|
||||
>
|
||||
{{ item }}
|
||||
@@ -102,96 +102,97 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import type { Resource, TagColor } from "@/types";
|
||||
import { computed } from "vue";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import type { Resource, TagColor } from "@/types";
|
||||
import { computed } from "vue";
|
||||
|
||||
const store = useResourceStore();
|
||||
const store = useResourceStore();
|
||||
|
||||
const emit = defineEmits(["save", "loadMore", "searchMovieforTag"]);
|
||||
const emit = defineEmits(["save", "loadMore", "searchMovieforTag"]);
|
||||
|
||||
const location = computed(() => window.location);
|
||||
const location = computed(() => window.location);
|
||||
|
||||
const handleSave = (resource: Resource) => {
|
||||
emit("save", resource);
|
||||
};
|
||||
const handleSave = (resource: Resource) => {
|
||||
emit("save", resource);
|
||||
};
|
||||
|
||||
// 添加加载更多处理函数
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
emit("loadMore", channelId);
|
||||
};
|
||||
// 添加加载更多处理函数
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
emit("loadMore", channelId);
|
||||
};
|
||||
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
emit("searchMovieforTag", tag);
|
||||
};
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
emit("searchMovieforTag", tag);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resource-list-table {
|
||||
border-radius: 15px;
|
||||
}
|
||||
.resource-list-table {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.channel-logo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.channel-logo {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-item-image {
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
.table-item-image {
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.item-count {
|
||||
color: #909399;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.tags-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.resource_tag {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.item-description {
|
||||
max-width: 100%;
|
||||
margin: 15px 0;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
overflow: hidden;
|
||||
white-space: all;
|
||||
}
|
||||
.item-count {
|
||||
color: #909399;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.tags-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.resource_tag {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.item-description {
|
||||
max-width: 100%;
|
||||
margin: 15px 0;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
line-clamp: 4;
|
||||
-webkit-line-clamp: 4;
|
||||
overflow: hidden;
|
||||
white-space: all;
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-column) {
|
||||
.cell {
|
||||
padding: 0 !important;
|
||||
}
|
||||
:deep(.el-table__expand-column) {
|
||||
.cell {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table__expanded-cell) {
|
||||
padding: 20px !important;
|
||||
}
|
||||
:deep(.el-table__expanded-cell) {
|
||||
padding: 20px !important;
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-icon) {
|
||||
height: 23px;
|
||||
line-height: 23px;
|
||||
}
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
:deep(.el-table__expand-icon) {
|
||||
height: 23px;
|
||||
line-height: 23px;
|
||||
}
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
2
frontend/src/env.d.ts
vendored
2
frontend/src/env.d.ts
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
declare module "*.vue" {
|
||||
import type { DefineComponent } from "vue";
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
const component: DefineComponent<Record<string, never>, Record<string, never>, unknown>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@ import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import ElementPlus from "element-plus";
|
||||
import "element-plus/dist/index.css";
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router/index";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
app.component(key, component);
|
||||
}
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
|
||||
@@ -23,20 +23,26 @@ const lastResource = (
|
||||
) as StorageListObject;
|
||||
|
||||
// 定义云盘驱动配置类型
|
||||
interface CloudDriveConfig {
|
||||
interface CloudDriveConfig<
|
||||
T extends Record<string, string>,
|
||||
P extends Save115FileParams | SaveQuarkFileParams,
|
||||
> {
|
||||
name: string;
|
||||
type: string;
|
||||
regex: RegExp;
|
||||
api: {
|
||||
getShareInfo: (parsedCode: any) => Promise<ShareInfoResponse>;
|
||||
saveFile: (params: Record<string, any>) => Promise<any>;
|
||||
getShareInfo: (parsedCode: T) => Promise<ShareInfoResponse>;
|
||||
saveFile: (params: P) => Promise<{ code: number; message?: string }>;
|
||||
};
|
||||
parseShareCode: (match: RegExpMatchArray) => Record<string, string>;
|
||||
getSaveParams: (shareInfo: ShareInfoResponse, folderId: string) => Record<string, any>;
|
||||
parseShareCode: (match: RegExpMatchArray) => T;
|
||||
getSaveParams: (shareInfo: ShareInfoResponse, folderId: string) => P;
|
||||
}
|
||||
|
||||
// 云盘类型配置
|
||||
export const CLOUD_DRIVES: CloudDriveConfig[] = [
|
||||
export const CLOUD_DRIVES: [
|
||||
CloudDriveConfig<{ shareCode: string; receiveCode: string }, Save115FileParams>,
|
||||
CloudDriveConfig<{ pwdId: string }, SaveQuarkFileParams>,
|
||||
] = [
|
||||
{
|
||||
name: "115网盘",
|
||||
type: "pan115",
|
||||
@@ -44,15 +50,17 @@ export const CLOUD_DRIVES: CloudDriveConfig[] = [
|
||||
api: {
|
||||
getShareInfo: (parsedCode: { shareCode: string; receiveCode: string }) =>
|
||||
cloud115Api.getShareInfo(parsedCode.shareCode, parsedCode.receiveCode),
|
||||
saveFile: async (params) => await cloud115Api.saveFile(params as Save115FileParams),
|
||||
saveFile: async (params: Save115FileParams) => {
|
||||
return await cloud115Api.saveFile(params as Save115FileParams);
|
||||
},
|
||||
},
|
||||
parseShareCode: (match) => ({
|
||||
parseShareCode: (match: RegExpMatchArray) => ({
|
||||
shareCode: match[1],
|
||||
receiveCode: match[2] || "",
|
||||
}),
|
||||
getSaveParams: (shareInfo, folderId) => ({
|
||||
shareCode: shareInfo.shareCode,
|
||||
receiveCode: shareInfo.receiveCode,
|
||||
getSaveParams: (shareInfo: ShareInfoResponse, folderId: string) => ({
|
||||
shareCode: shareInfo.shareCode || "",
|
||||
receiveCode: shareInfo.receiveCode || "",
|
||||
fileId: shareInfo.list[0].fileId,
|
||||
folderId,
|
||||
}),
|
||||
@@ -63,12 +71,16 @@ export const CLOUD_DRIVES: CloudDriveConfig[] = [
|
||||
regex: /pan\.quark\.cn\/s\/([a-zA-Z0-9]+)/,
|
||||
api: {
|
||||
getShareInfo: (parsedCode: { pwdId: string }) => quarkApi.getShareInfo(parsedCode.pwdId),
|
||||
saveFile: async (params) => await quarkApi.saveFile(params as SaveQuarkFileParams),
|
||||
saveFile: async (params: SaveQuarkFileParams) => {
|
||||
return await quarkApi.saveFile(params as SaveQuarkFileParams);
|
||||
},
|
||||
},
|
||||
parseShareCode: (match) => ({ pwdId: match[1] }),
|
||||
getSaveParams: (shareInfo, folderId) => ({
|
||||
fid_list: shareInfo.list.map((item) => item.fileId || ""),
|
||||
fid_token_list: shareInfo.list.map((item) => item.fileIdToken || ""),
|
||||
parseShareCode: (match: RegExpMatchArray) => ({ pwdId: match[1] }),
|
||||
getSaveParams: (shareInfo: ShareInfoResponse, folderId: string) => ({
|
||||
fid_list: shareInfo.list.map((item: { fileId?: string }) => item.fileId || ""),
|
||||
fid_token_list: shareInfo.list.map(
|
||||
(item: { fileIdToken?: string }) => item.fileIdToken || ""
|
||||
),
|
||||
to_pdir_fid: folderId,
|
||||
pwd_id: shareInfo.pwdId || "",
|
||||
stoken: shareInfo.stoken || "",
|
||||
@@ -156,7 +168,9 @@ export const useResourceStore = defineStore("resource", {
|
||||
async saveResourceToDrive(
|
||||
resource: ResourceItem,
|
||||
folderId: string,
|
||||
drive: CloudDriveConfig
|
||||
drive:
|
||||
| CloudDriveConfig<{ shareCode: string; receiveCode: string }, Save115FileParams>
|
||||
| CloudDriveConfig<{ pwdId: string }, SaveQuarkFileParams>
|
||||
): Promise<void> {
|
||||
const link = resource.cloudLinks.find((link) => drive.regex.test(link));
|
||||
if (!link) return;
|
||||
@@ -166,27 +180,50 @@ export const useResourceStore = defineStore("resource", {
|
||||
|
||||
const parsedCode = drive.parseShareCode(match);
|
||||
|
||||
let shareInfo = await drive.api.getShareInfo(parsedCode);
|
||||
if (shareInfo) {
|
||||
if (Array.isArray(shareInfo)) {
|
||||
shareInfo = {
|
||||
list: shareInfo,
|
||||
...parsedCode,
|
||||
};
|
||||
} else {
|
||||
shareInfo = {
|
||||
...shareInfo,
|
||||
...parsedCode,
|
||||
};
|
||||
if (this.is115Drive(drive)) {
|
||||
let shareInfo = await drive.api.getShareInfo(
|
||||
parsedCode as { shareCode: string; receiveCode: string }
|
||||
);
|
||||
if (shareInfo) {
|
||||
if (Array.isArray(shareInfo)) {
|
||||
shareInfo = {
|
||||
list: shareInfo,
|
||||
...parsedCode,
|
||||
};
|
||||
} else {
|
||||
shareInfo = {
|
||||
...shareInfo,
|
||||
...parsedCode,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
const params = drive.getSaveParams(shareInfo, folderId);
|
||||
const result = await drive.api.saveFile(params);
|
||||
const params = drive.getSaveParams(shareInfo, folderId);
|
||||
const result = await drive.api.saveFile(params);
|
||||
|
||||
if (result.code === 0) {
|
||||
ElMessage.success(`${drive.name} 转存成功`);
|
||||
if (result.code === 0) {
|
||||
ElMessage.success(`${drive.name} 转存成功`);
|
||||
} else {
|
||||
ElMessage.error(result.message);
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(result.message);
|
||||
let shareInfo = this.is115Drive(drive)
|
||||
? await drive.api.getShareInfo(parsedCode as { shareCode: string; receiveCode: string })
|
||||
: await drive.api.getShareInfo(parsedCode as { pwdId: string });
|
||||
if (shareInfo) {
|
||||
if (Array.isArray(shareInfo)) {
|
||||
shareInfo = {
|
||||
list: shareInfo,
|
||||
};
|
||||
}
|
||||
}
|
||||
const params = drive.getSaveParams(shareInfo, folderId);
|
||||
const result = await drive.api.saveFile(params);
|
||||
|
||||
if (result.code === 0) {
|
||||
ElMessage.success(`${drive.name} 转存成功`);
|
||||
} else {
|
||||
ElMessage.error(result.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -202,7 +239,12 @@ export const useResourceStore = defineStore("resource", {
|
||||
if (!match) throw new Error("链接解析失败");
|
||||
|
||||
const parsedCode = matchedDrive.parseShareCode(match);
|
||||
let shareInfo = await matchedDrive.api.getShareInfo(parsedCode);
|
||||
let shareInfo = this.is115Drive(matchedDrive)
|
||||
? await matchedDrive.api.getShareInfo(
|
||||
parsedCode as { shareCode: string; receiveCode: string }
|
||||
)
|
||||
: await matchedDrive.api.getShareInfo(parsedCode as { pwdId: string });
|
||||
|
||||
if (Array.isArray(shareInfo)) {
|
||||
shareInfo = {
|
||||
list: shareInfo,
|
||||
@@ -246,5 +288,13 @@ export const useResourceStore = defineStore("resource", {
|
||||
console.error(message, error);
|
||||
ElMessage.error(error instanceof Error ? error.message : message);
|
||||
},
|
||||
|
||||
is115Drive(
|
||||
drive:
|
||||
| CloudDriveConfig<{ shareCode: string; receiveCode: string }, Save115FileParams>
|
||||
| CloudDriveConfig<{ pwdId: string }, SaveQuarkFileParams>
|
||||
): drive is CloudDriveConfig<{ shareCode: string; receiveCode: string }, Save115FileParams> {
|
||||
return drive.type === "pan115";
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
:root {
|
||||
--theme-color: #3e3e3e;
|
||||
--theme-theme: #133ab3;
|
||||
--theme-background: #fafafa;
|
||||
--theme-other_background: #ffffff;
|
||||
--theme-color: #3e3e3e;
|
||||
--theme-theme: #133ab3;
|
||||
--theme-background: #fafafa;
|
||||
--theme-other_background: #ffffff;
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface SaveFileParams {
|
||||
folderId: string;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
export interface ApiResponse<T = unknown> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
error?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import axios, { AxiosResponse, AxiosRequestConfig } from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { RequestResult } from "../types/response";
|
||||
|
||||
@@ -49,13 +49,17 @@ axiosInstance.interceptors.response.use(
|
||||
);
|
||||
|
||||
const request = {
|
||||
get: <T>(
|
||||
url: string,
|
||||
config?: Record<string, any>
|
||||
): Promise<RequestResult<T>> => {
|
||||
get: <T>(url: string, config?: AxiosRequestConfig): Promise<RequestResult<T>> => {
|
||||
return axiosInstance.get(url, { ...config });
|
||||
},
|
||||
post: axiosInstance.post,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
post: <T, D = any>(
|
||||
url: string,
|
||||
data: D,
|
||||
config?: AxiosRequestConfig
|
||||
): Promise<RequestResult<T>> => {
|
||||
return axiosInstance.post(url, data, { ...config });
|
||||
},
|
||||
put: axiosInstance.put,
|
||||
delete: axiosInstance.delete,
|
||||
};
|
||||
|
||||
@@ -30,120 +30,118 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useDoubanStore } from "@/stores/douban";
|
||||
interface CurrentParams {
|
||||
type: string;
|
||||
tag?: string;
|
||||
}
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
import { computed, watch } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useDoubanStore } from "@/stores/douban";
|
||||
interface CurrentParams {
|
||||
type: string;
|
||||
tag?: string;
|
||||
}
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const routeParams = computed(
|
||||
(): CurrentParams => ({ ...route.query }) as unknown as CurrentParams
|
||||
);
|
||||
const doubanStore = useDoubanStore();
|
||||
if (routeParams.value) {
|
||||
const routeParams = computed((): CurrentParams => ({ ...route.query }) as unknown as CurrentParams);
|
||||
const doubanStore = useDoubanStore();
|
||||
if (routeParams.value) {
|
||||
doubanStore.setCurrentParams(routeParams.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => routeParams.value,
|
||||
() => {
|
||||
console.log(routeParams.value);
|
||||
doubanStore.setCurrentParams(routeParams.value);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => routeParams.value,
|
||||
() => {
|
||||
console.log(routeParams.value);
|
||||
doubanStore.setCurrentParams(routeParams.value);
|
||||
}
|
||||
);
|
||||
|
||||
const searchMovie = (title: string) => {
|
||||
router.push({ path: "/", query: { keyword: title } });
|
||||
};
|
||||
const searchMovie = (title: string) => {
|
||||
router.push({ path: "/", query: { keyword: title } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.movie-wall {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 200px);
|
||||
grid-row-gap: 15px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.movie-wall {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 200px);
|
||||
grid-row-gap: 15px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.movie-item {
|
||||
width: 200px; /* 设置固定宽度 */
|
||||
overflow: hidden; /* 确保内容不会超出卡片 */
|
||||
text-align: center;
|
||||
background-color: #f9f9f9; /* 可选:设置背景颜色 */
|
||||
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12); /* 可选:设置阴影效果 */
|
||||
border-radius: 15px; /* 设置图片圆角 */
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0px;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.movie-item {
|
||||
width: 200px; /* 设置固定宽度 */
|
||||
overflow: hidden; /* 确保内容不会超出卡片 */
|
||||
text-align: center;
|
||||
background-color: #f9f9f9; /* 可选:设置背景颜色 */
|
||||
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12); /* 可选:设置阴影效果 */
|
||||
border-radius: 15px; /* 设置图片圆角 */
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0px;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.movie-poster-img {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
object-fit: cover; /* 确保图片使用cover模式 */
|
||||
border-radius: 15px; /* 设置图片圆角 */
|
||||
overflow: hidden;
|
||||
}
|
||||
.movie-info {
|
||||
/* margin-top: 8px; */
|
||||
.movie-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
.movie-poster {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 15px;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
.movie-poster-img {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
object-fit: cover; /* 确保图片使用cover模式 */
|
||||
border-radius: 15px; /* 设置图片圆角 */
|
||||
overflow: hidden;
|
||||
}
|
||||
.movie-info {
|
||||
/* margin-top: 8px; */
|
||||
.movie-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
.movie-poster {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 15px;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.movie-poster-hover {
|
||||
opacity: 0; /* 默认情况下隐藏 */
|
||||
transition: opacity 0.3s ease; /* 添加过渡效果 */
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* height: 100%; */
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.movie-poster-hover {
|
||||
opacity: 0; /* 默认情况下隐藏 */
|
||||
transition: opacity 0.3s ease; /* 添加过渡效果 */
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* height: 100%; */
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.movie-poster:hover .movie-poster-hover {
|
||||
opacity: 1; /* 鼠标移入时显示 */
|
||||
}
|
||||
.movie-poster:hover .movie-poster-hover {
|
||||
opacity: 1; /* 鼠标移入时显示 */
|
||||
}
|
||||
|
||||
.movie-rate {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: rgba(88, 83, 250, 0.8);
|
||||
color: white;
|
||||
padding: 0px 8px;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.movie-search {
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.movie-rate {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: rgba(88, 83, 250, 0.8);
|
||||
color: white;
|
||||
padding: 0px 8px;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.movie-search {
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="home" v-loading="resourcStore.loading" element-loading-background="rgba(0,0,0,0.6)">
|
||||
<div v-loading="resourcStore.loading" class="home" element-loading-background="rgba(0,0,0,0.6)">
|
||||
<el-container>
|
||||
<el-aside width="200px"><aside-menu /></el-aside>
|
||||
<el-container class="home-main">
|
||||
@@ -32,62 +32,62 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { useStore } from "@/stores/index";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
import { onUnmounted } from "vue";
|
||||
import AsideMenu from "@/components/AsideMenu.vue";
|
||||
import SearchBar from "@/components/SearchBar.vue";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { useStore } from "@/stores/index";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
import { onUnmounted } from "vue";
|
||||
import AsideMenu from "@/components/AsideMenu.vue";
|
||||
import SearchBar from "@/components/SearchBar.vue";
|
||||
|
||||
const resourcStore = useResourceStore();
|
||||
const store = useStore();
|
||||
const settingStore = useUserSettingStore();
|
||||
settingStore.getSettings();
|
||||
const handleScroll = () => {
|
||||
const scrollTop = window.scrollY;
|
||||
if (scrollTop > 50) {
|
||||
store.scrollTop && store.setScrollTop(false);
|
||||
} else {
|
||||
!store.scrollTop && store.setScrollTop(true);
|
||||
}
|
||||
};
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
});
|
||||
const resourcStore = useResourceStore();
|
||||
const store = useStore();
|
||||
const settingStore = useUserSettingStore();
|
||||
settingStore.getSettings();
|
||||
const handleScroll = () => {
|
||||
const scrollTop = window.scrollY;
|
||||
if (scrollTop > 50) {
|
||||
store.scrollTop && store.setScrollTop(false);
|
||||
} else {
|
||||
!store.scrollTop && store.setScrollTop(true);
|
||||
}
|
||||
};
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.home {
|
||||
// padding: 20px;
|
||||
min-width: 1000px;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.home-header {
|
||||
height: auto;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
// padding: 0;
|
||||
background-color: rgba(231, 235, 239, 0.7) !important;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border-radius: 0 0 5px 5px;
|
||||
// background-color: var(--theme-other_background);
|
||||
// box-shadow: 0 4px 10px rgba(225, 225, 225, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
.home-main {
|
||||
width: 1000px;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.home-main-main {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.home-aside {
|
||||
width: 300px;
|
||||
}
|
||||
.home {
|
||||
// padding: 20px;
|
||||
min-width: 1000px;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.home-header {
|
||||
height: auto;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
// padding: 0;
|
||||
background-color: rgba(231, 235, 239, 0.7) !important;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border-radius: 0 0 5px 5px;
|
||||
// background-color: var(--theme-other_background);
|
||||
// box-shadow: 0 4px 10px rgba(225, 225, 225, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
.home-main {
|
||||
width: 1000px;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.home-main-main {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.home-aside {
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
<!-- 登录表单 -->
|
||||
<el-form
|
||||
v-if="activeTab === 'login'"
|
||||
ref="loginFormRef"
|
||||
:model="loginForm"
|
||||
:rules="loginRules"
|
||||
ref="loginFormRef"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item prop="username" class="form-item">
|
||||
@@ -46,9 +46,9 @@
|
||||
<!-- 注册表单 -->
|
||||
<el-form
|
||||
v-if="activeTab === 'register'"
|
||||
ref="registerFormRef"
|
||||
:model="registerForm"
|
||||
:rules="registerRules"
|
||||
ref="registerFormRef"
|
||||
label-position="top"
|
||||
><el-form-item prop="username" class="form-item">
|
||||
<el-input v-model="registerForm.username" placeholder="用户名" class="form-input" />
|
||||
@@ -80,180 +80,181 @@
|
||||
</template>
|
||||
|
||||
<script setup type="ts">
|
||||
import { ref } from "vue";
|
||||
import { userApi } from "@/api/user";
|
||||
import router from "@/router";
|
||||
import { ref } from "vue";
|
||||
import { userApi } from "@/api/user";
|
||||
import router from "@/router";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const activeTab = ref("login"); // 默认显示登录表单
|
||||
const activeTab = ref("login"); // 默认显示登录表单
|
||||
|
||||
const loginForm = ref({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
const registerForm = ref({
|
||||
username: "",
|
||||
password: "",
|
||||
registerCode: "",
|
||||
});
|
||||
const loginForm = ref({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
const registerForm = ref({
|
||||
username: "",
|
||||
password: "",
|
||||
registerCode: "",
|
||||
});
|
||||
|
||||
const password2 = ref("");
|
||||
const password2 = ref("");
|
||||
|
||||
const loginRules = {
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
};
|
||||
const loginRules = {
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
};
|
||||
|
||||
const registerRules = {
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
registerCode: [{ required: true, message: "请输入注册码", trigger: "blur" }],
|
||||
};
|
||||
const registerRules = {
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
registerCode: [{ required: true, message: "请输入注册码", trigger: "blur" }],
|
||||
};
|
||||
|
||||
const loginFormRef = ref(null);
|
||||
const registerFormRef = ref(null);
|
||||
const loginFormRef = ref(null);
|
||||
const registerFormRef = ref(null);
|
||||
|
||||
|
||||
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
const res = await userApi.login(loginForm.value);
|
||||
if (res.code === 0) {
|
||||
const { token } = res.data;
|
||||
localStorage.setItem("token", token);
|
||||
// 路由跳转首页
|
||||
router.push("/");
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error("登录失败", error);
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
const res = await userApi.login(loginForm.value);
|
||||
if (res.code === 0) {
|
||||
const { token } = res.data;
|
||||
localStorage.setItem("token", token);
|
||||
// 路由跳转首页
|
||||
router.push("/");
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
};
|
||||
const loginFormRefValidate = () => {
|
||||
loginFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
handleLogin();
|
||||
} else {
|
||||
ElMessage.error("登录表单验证失败");
|
||||
} catch (error) {
|
||||
ElMessage.error("登录失败", error);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
const loginFormRefValidate = () => {
|
||||
loginFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
handleLogin();
|
||||
} else {
|
||||
ElMessage.error("登录表单验证失败");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleRegister = async () => {
|
||||
registerFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if(password2.value !== registerForm.value.password){
|
||||
return ElMessage.error("两次输入的密码不一致");
|
||||
}
|
||||
try {
|
||||
const res = await userApi.register(registerForm.value);
|
||||
if (res.code === 0) {
|
||||
ElMessage.success("注册成功");
|
||||
loginForm.value.username = registerForm.value.username
|
||||
loginForm.value.password = registerForm.value.password
|
||||
handleLogin()
|
||||
} else {
|
||||
ElMessage.error(res.message || "注册失败");
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message || "注册失败");
|
||||
}
|
||||
} else {
|
||||
console.error("注册表单验证失败");
|
||||
const handleRegister = async () => {
|
||||
registerFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if(password2.value !== registerForm.value.password){
|
||||
return ElMessage.error("两次输入的密码不一致");
|
||||
}
|
||||
});
|
||||
};
|
||||
try {
|
||||
const res = await userApi.register(registerForm.value);
|
||||
if (res.code === 0) {
|
||||
ElMessage.success("注册成功");
|
||||
loginForm.value.username = registerForm.value.username
|
||||
loginForm.value.password = registerForm.value.password
|
||||
handleLogin()
|
||||
} else {
|
||||
ElMessage.error(res.message || "注册失败");
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message || "注册失败");
|
||||
}
|
||||
} else {
|
||||
console.error("注册表单验证失败");
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.login-register {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.login-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-bg.jpg");
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
-webkit-filter: blur(3px);
|
||||
-moz-filter: blur(3px);
|
||||
-o-filter: blur(3px);
|
||||
-ms-filter: blur(3px);
|
||||
filter: blur(3px);
|
||||
z-index: 0;
|
||||
}
|
||||
.card {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
width: 480px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0px 20px 60px rgba(123, 61, 224, 0.1);
|
||||
}
|
||||
.login-register {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.login-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-bg.jpg");
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
-webkit-filter: blur(3px);
|
||||
-moz-filter: blur(3px);
|
||||
-o-filter: blur(3px);
|
||||
-ms-filter: blur(3px);
|
||||
filter: blur(3px);
|
||||
z-index: 0;
|
||||
}
|
||||
.card {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
width: 480px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0px 20px 60px rgba(123, 61, 224, 0.1);
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
.tab-button {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-input {
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.form-item {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-input {
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
color: #6366f1;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
.forgot-password {
|
||||
color: #6366f1;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-submit {
|
||||
margin-bottom: 10px;
|
||||
background-color: #6366f1;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
}
|
||||
.form-submit {
|
||||
margin-bottom: 10px;
|
||||
background-color: #6366f1;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.google-login {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.google-login {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.agreement {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.user-agreement {
|
||||
color: #6366f1;
|
||||
text-decoration: none;
|
||||
}
|
||||
.user-agreement {
|
||||
color: #6366f1;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
</div>
|
||||
<div class="header_right">
|
||||
<el-icon
|
||||
class="type_icon"
|
||||
v-if="userStore.displayStyle === 'card'"
|
||||
class="type_icon"
|
||||
@click="setDisplayStyle('table')"
|
||||
><Menu
|
||||
/></el-icon>
|
||||
@@ -20,19 +20,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<ResourceTable
|
||||
@loadMore="handleLoadMore"
|
||||
@searchMovieforTag="searchMovieforTag"
|
||||
@save="handleSave"
|
||||
v-if="userStore.displayStyle === 'table'"
|
||||
@load-more="handleLoadMore"
|
||||
@search-moviefor-tag="searchMovieforTag"
|
||||
@save="handleSave"
|
||||
></ResourceTable>
|
||||
<ResourceCard
|
||||
@loadMore="handleLoadMore"
|
||||
@searchMovieforTag="searchMovieforTag"
|
||||
@save="handleSave"
|
||||
v-else
|
||||
@load-more="handleLoadMore"
|
||||
@search-moviefor-tag="searchMovieforTag"
|
||||
@save="handleSave"
|
||||
></ResourceCard>
|
||||
<el-empty v-if="resourceStore.resources.length === 0" :image-size="200" />
|
||||
<el-dialog v-model="folderDialogVisible" title="选择保存目录" v-if="currentResource">
|
||||
<el-dialog v-if="currentResource" v-model="folderDialogVisible" title="选择保存目录">
|
||||
<template #header="{ titleId }">
|
||||
<div class="my-header">
|
||||
<div :id="titleId">
|
||||
@@ -49,9 +49,9 @@
|
||||
</template>
|
||||
<folder-select
|
||||
v-if="folderDialogVisible"
|
||||
:cloud-type="currentResource.cloudType"
|
||||
@select="handleFolderSelect"
|
||||
@close="folderDialogVisible = false"
|
||||
:cloudType="currentResource.cloudType"
|
||||
/>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="folderDialogVisible = false">取消</el-button>
|
||||
@@ -62,125 +62,125 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
import FolderSelect from "@/components/Home/FolderSelect.vue";
|
||||
import ResourceTable from "@/components/Home/ResourceTable.vue";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
import ResourceCard from "@/components/Home/ResourceCard.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
const router = useRouter();
|
||||
import { ref } from "vue";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
import FolderSelect from "@/components/Home/FolderSelect.vue";
|
||||
import ResourceTable from "@/components/Home/ResourceTable.vue";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
import ResourceCard from "@/components/Home/ResourceCard.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
const router = useRouter();
|
||||
|
||||
const resourceStore = useResourceStore();
|
||||
const userStore = useUserSettingStore();
|
||||
const folderDialogVisible = ref(false);
|
||||
const currentResource = ref<ResourceItem | null>(null);
|
||||
const currentFolderId = ref<string | null>(null);
|
||||
const resourceStore = useResourceStore();
|
||||
const userStore = useUserSettingStore();
|
||||
const folderDialogVisible = ref(false);
|
||||
const currentResource = ref<ResourceItem | null>(null);
|
||||
const currentFolderId = ref<string | null>(null);
|
||||
|
||||
const refreshResources = async () => {
|
||||
resourceStore.searchResources("", false);
|
||||
};
|
||||
const refreshResources = async () => {
|
||||
resourceStore.searchResources("", false);
|
||||
};
|
||||
|
||||
const handleSave = (resource: ResourceItem) => {
|
||||
currentResource.value = resource;
|
||||
folderDialogVisible.value = true;
|
||||
};
|
||||
const handleSave = (resource: ResourceItem) => {
|
||||
currentResource.value = resource;
|
||||
folderDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleFolderSelect = async (folderId: string) => {
|
||||
if (!currentResource.value) return;
|
||||
currentFolderId.value = folderId;
|
||||
};
|
||||
const handleFolderSelect = async (folderId: string) => {
|
||||
if (!currentResource.value) return;
|
||||
currentFolderId.value = folderId;
|
||||
};
|
||||
|
||||
const handleSaveBtnClick = async () => {
|
||||
if (!currentResource.value || !currentFolderId.value) return;
|
||||
folderDialogVisible.value = false;
|
||||
await resourceStore.saveResource(currentResource.value, currentFolderId.value);
|
||||
};
|
||||
const setDisplayStyle = (style: string) => {
|
||||
console.log(userStore);
|
||||
userStore.setDisplayStyle(style as "card" | "table");
|
||||
};
|
||||
// 添加加载更多处理函数
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
resourceStore.searchResources("", true, channelId);
|
||||
};
|
||||
const handleSaveBtnClick = async () => {
|
||||
if (!currentResource.value || !currentFolderId.value) return;
|
||||
folderDialogVisible.value = false;
|
||||
await resourceStore.saveResource(currentResource.value, currentFolderId.value);
|
||||
};
|
||||
const setDisplayStyle = (style: string) => {
|
||||
console.log(userStore);
|
||||
userStore.setDisplayStyle(style as "card" | "table");
|
||||
};
|
||||
// 添加加载更多处理函数
|
||||
const handleLoadMore = (channelId: string) => {
|
||||
resourceStore.searchResources("", true, channelId);
|
||||
};
|
||||
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
console.log("iiii");
|
||||
router.push({ path: "/", query: { keyword: tag } });
|
||||
};
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
console.log("iiii");
|
||||
router.push({ path: "/", query: { keyword: tag } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resource-list {
|
||||
/* margin-top: 20px; */
|
||||
position: relative;
|
||||
}
|
||||
.resource-list__header {
|
||||
height: 48px;
|
||||
background-color: var(--theme-other_background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 15px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.header_right {
|
||||
cursor: pointer;
|
||||
}
|
||||
.type_icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
size: 48px;
|
||||
}
|
||||
.refresh_btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
.item-count {
|
||||
color: #909399;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.resource-list {
|
||||
/* margin-top: 20px; */
|
||||
position: relative;
|
||||
}
|
||||
.resource-list__header {
|
||||
height: 48px;
|
||||
background-color: var(--theme-other_background);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 15px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.header_right {
|
||||
cursor: pointer;
|
||||
}
|
||||
.type_icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
size: 48px;
|
||||
}
|
||||
.refresh_btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
.item-count {
|
||||
color: #909399;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-column) {
|
||||
.cell {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
:deep(.el-table__expanded-cell) {
|
||||
padding: 20px !important;
|
||||
}
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-icon) {
|
||||
height: 23px;
|
||||
line-height: 23px;
|
||||
}
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
.item-count {
|
||||
color: #909399;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-column) {
|
||||
.cell {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table__expanded-cell) {
|
||||
padding: 20px !important;
|
||||
}
|
||||
|
||||
:deep(.el-table__expand-icon) {
|
||||
height: 23px;
|
||||
line-height: 23px;
|
||||
}
|
||||
.load-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 16px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
<template>
|
||||
<div class="settings">
|
||||
<el-card class="setting-card" v-if="settingStore.globalSetting">
|
||||
<el-card v-if="settingStore.globalSetting" class="setting-card">
|
||||
<h2>网络配置</h2>
|
||||
<div class="section">
|
||||
<div class="form-group">
|
||||
<label for="proxyDomain">代理域名:</label>
|
||||
<el-input
|
||||
id="proxyDomain"
|
||||
v-model="settingStore.globalSetting.httpProxyHost"
|
||||
class="form-input"
|
||||
type="text"
|
||||
id="proxyDomain"
|
||||
placeholder="127.0.0.1"
|
||||
v-model="settingStore.globalSetting.httpProxyHost"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="proxyPort">代理端口:</label>
|
||||
<el-input
|
||||
id="proxyPort"
|
||||
v-model="settingStore.globalSetting.httpProxyPort"
|
||||
class="form-input"
|
||||
type="text"
|
||||
id="proxyPort"
|
||||
placeholder="7890"
|
||||
v-model="settingStore.globalSetting.httpProxyPort"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="AdminUserCode">管理员注册码:</label>
|
||||
<el-input-number
|
||||
id="AdminUserCode"
|
||||
v-model="settingStore.globalSetting.AdminUserCode"
|
||||
class="form-input"
|
||||
type="text"
|
||||
id="AdminUserCode"
|
||||
:controls="false"
|
||||
:precision="0"
|
||||
placeholder="设置管理员注册码"
|
||||
v-model="settingStore.globalSetting.AdminUserCode"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="CommonUserCode">普通用户注册码:</label>
|
||||
<el-input-number
|
||||
id="CommonUserCode"
|
||||
v-model="settingStore.globalSetting.CommonUserCode"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:precision="0"
|
||||
:controls="false"
|
||||
id="CommonUserCode"
|
||||
placeholder="设置普通用户注册码"
|
||||
v-model="settingStore.globalSetting.CommonUserCode"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,19 +61,19 @@
|
||||
<div class="form-group">
|
||||
<label for="cookie115">115网盘Cookie:</label>
|
||||
<el-input
|
||||
class="form-input"
|
||||
type="text"
|
||||
id="cookie115"
|
||||
v-model="settingStore.userSettings.cloud115Cookie"
|
||||
class="form-input"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cookieQuark">夸克网盘Cookie:</label>
|
||||
<el-input
|
||||
class="form-input"
|
||||
type="text"
|
||||
id="cookieQuark"
|
||||
v-model="settingStore.userSettings.quarkCookie"
|
||||
class="form-input"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,65 +98,65 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
const settingStore = useUserSettingStore();
|
||||
settingStore.getSettings();
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
const settingStore = useUserSettingStore();
|
||||
settingStore.getSettings();
|
||||
|
||||
const saveSettings = () => {
|
||||
settingStore.saveSettings();
|
||||
// Add your save logic here
|
||||
};
|
||||
const saveSettings = () => {
|
||||
settingStore.saveSettings();
|
||||
// Add your save logic here
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.settings {
|
||||
padding: 20px;
|
||||
}
|
||||
.setting-card {
|
||||
margin-bottom: 20px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.settings {
|
||||
padding: 20px;
|
||||
}
|
||||
.setting-card {
|
||||
margin-bottom: 20px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.section {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 10px;
|
||||
width: 48%;
|
||||
}
|
||||
.form-input {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
text-align: left;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 10px;
|
||||
width: 48%;
|
||||
}
|
||||
.form-input {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user