mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-11 07:38:45 +08:00
Merge remote-tracking branch 'origin/dev'
This commit is contained in:
@@ -69,8 +69,9 @@ export const config: Config = {
|
||||
aliyun: /https?:\/\/\w+\.(?:alipan|aliyundrive)\.com\/[^\s<>"]+/g,
|
||||
// pan115有两个域名 115.com 和 anxia.com 和 115cdn.com
|
||||
pan115: /https?:\/\/(?:115|anxia|115cdn)\.com\/s\/[^\s<>"]+/g,
|
||||
pan123: /https?:\/\/www\.123pan\.com\/s\/[^\s<>"]+/g,
|
||||
// 修改为匹配所有以123开头的域名
|
||||
pan123: /https?:\/\/(?:www\.)?123[^\/\s<>"]+\.com\/s\/[^\s<>"]+/g,
|
||||
quark: /https?:\/\/pan\.quark\.cn\/[^\s<>"]+/g,
|
||||
yidong: /https?:\/\/yun\.139\.com\/[^\s<>"]+/g,
|
||||
yidong: /https?:\/\/caiyun\.139\.com\/[^\s<>"]+/g,
|
||||
},
|
||||
};
|
||||
|
||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cloud-disk-web",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cloud-disk-web",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.7",
|
||||
"element-plus": "^2.6.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cloud-saver-web",
|
||||
"private": true,
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
<div class="detail-cover">
|
||||
<el-image
|
||||
class="cover-image"
|
||||
:src="`/tele-images/?url=${encodeURIComponent(currentResource.image as string)}`"
|
||||
:src="
|
||||
userStore.imagesSource === 'proxy'
|
||||
? `/tele-images/?url=${encodeURIComponent(currentResource.image as string)}`
|
||||
: currentResource.image
|
||||
"
|
||||
fit="cover"
|
||||
/>
|
||||
<el-tag
|
||||
@@ -56,14 +60,25 @@
|
||||
</el-dialog>
|
||||
|
||||
<div v-for="group in store.resources" :key="group.id" class="resource-group">
|
||||
<div class="group-header">
|
||||
<div class="group-header" @click="group.displayList = !group.displayList">
|
||||
<el-link
|
||||
class="group-title"
|
||||
:href="`https://t.me/s/${group.id}`"
|
||||
target="_blank"
|
||||
:underline="false"
|
||||
@click.stop
|
||||
>
|
||||
<el-image :src="group.channelInfo.channelLogo" class="channel-logo" fit="cover" lazy />
|
||||
<el-image
|
||||
:src="
|
||||
userStore.imagesSource === 'proxy'
|
||||
? `/tele-images/?url=${encodeURIComponent(group.channelInfo.channelLogo)}`
|
||||
: group.channelInfo.channelLogo
|
||||
"
|
||||
class="channel-logo"
|
||||
scroll-container="#pc-resources-content"
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<span>{{ group.channelInfo.name }}</span>
|
||||
<span class="item-count">({{ group.list.length }})</span>
|
||||
</el-link>
|
||||
@@ -88,10 +103,14 @@
|
||||
<div class="card-wrapper">
|
||||
<div class="card-cover">
|
||||
<el-image
|
||||
loading="lazy"
|
||||
class="cover-image"
|
||||
:src="`/tele-images/?url=${encodeURIComponent(resource.image as string)}`"
|
||||
:src="
|
||||
userStore.imagesSource === 'proxy'
|
||||
? `/tele-images/?url=${encodeURIComponent(resource.image as string)}`
|
||||
: resource.image
|
||||
"
|
||||
fit="cover"
|
||||
lazy
|
||||
:alt="resource.title"
|
||||
@click="showResourceDetail(resource)"
|
||||
/>
|
||||
@@ -160,8 +179,11 @@ import { useResourceStore } from "@/stores/resource";
|
||||
import { ref } from "vue";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
import { ArrowDown, Plus } from "@element-plus/icons-vue";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
|
||||
const userStore = useUserSettingStore();
|
||||
const store = useResourceStore();
|
||||
|
||||
const showDetail = ref(false);
|
||||
const currentResource = ref<ResourceItem | null>(null);
|
||||
|
||||
@@ -216,6 +238,15 @@ const handleLoadMore = (channelId: string) => {
|
||||
justify-content: space-between;
|
||||
padding: 12px 20px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: var(--theme-card-bg);
|
||||
backdrop-filter: var(--theme-blur);
|
||||
-webkit-backdrop-filter: var(--theme-blur);
|
||||
z-index: 10;
|
||||
border-radius: var(--theme-radius) var(--theme-radius) 0 0;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
.group-title {
|
||||
@include flex-center;
|
||||
@@ -230,6 +261,7 @@ const handleLoadMore = (channelId: string) => {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--theme-shadow-sm);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.item-count {
|
||||
|
||||
@@ -15,10 +15,18 @@
|
||||
<el-image
|
||||
v-if="row.image"
|
||||
class="table-item-image"
|
||||
:src="`/tele-images/?url=${encodeURIComponent(row.image as string)}`"
|
||||
:src="
|
||||
userStore.imagesSource === 'proxy'
|
||||
? `/tele-images/?url=${encodeURIComponent(row.image as string)}`
|
||||
: row.image
|
||||
"
|
||||
hide-on-click-modal
|
||||
:preview-src-list="[
|
||||
`${location.origin}/tele-images/?url=${encodeURIComponent(row.image as string)}`,
|
||||
`${location.origin}${
|
||||
userStore.imagesSource === 'proxy'
|
||||
? '/tele-images/?url=' + encodeURIComponent(row.image as string)
|
||||
: row.image
|
||||
}`,
|
||||
]"
|
||||
:zoom-rate="1.2"
|
||||
:max-scale="7"
|
||||
@@ -84,7 +92,16 @@
|
||||
<el-table-column label="来源" prop="channel">
|
||||
<template #default="{ row }">
|
||||
<div class="group-header">
|
||||
<el-image :src="row.channelInfo.channelLogo" class="channel-logo" fit="cover" lazy />
|
||||
<el-image
|
||||
:src="
|
||||
userStore.imagesSource === 'proxy'
|
||||
? `/tele-images/?url=${encodeURIComponent(row.channelInfo.channelLogo as string)}`
|
||||
: row.channelInfo.channelLogo
|
||||
"
|
||||
class="channel-logo"
|
||||
fit="cover"
|
||||
lazy
|
||||
/>
|
||||
<span>{{ row.channelInfo.name }}</span>
|
||||
<span class="item-count">({{ row.list.length }})</span>
|
||||
</div>
|
||||
@@ -97,6 +114,8 @@
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
import type { Resource, TagColor } from "@/types";
|
||||
import { computed } from "vue";
|
||||
import { useUserSettingStore } from "@/stores/userSetting";
|
||||
const userStore = useUserSettingStore();
|
||||
|
||||
const store = useResourceStore();
|
||||
|
||||
|
||||
@@ -83,10 +83,16 @@ watch(
|
||||
keyword.value = newKeyword;
|
||||
handleSearch();
|
||||
} else {
|
||||
keyword.value = "";
|
||||
keyword.value = resourcStore.keyword;
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => resourcStore.keyword,
|
||||
(newKeyword) => {
|
||||
keyword.value = newKeyword;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
<!-- 描述 - 添加展开收起功能 -->
|
||||
<div
|
||||
class="info__desc"
|
||||
:class="{ 'is-expanded': expandedItems[item.id] }"
|
||||
@click="toggleExpand(item.id)"
|
||||
:class="{
|
||||
'is-expanded': expandedItems[(item.messageId || '') + (item.channelId || '')],
|
||||
}"
|
||||
@click="toggleExpand((item.messageId || '') + (item.channelId || ''))"
|
||||
v-html="item.content"
|
||||
/>
|
||||
|
||||
|
||||
@@ -100,12 +100,12 @@ export const useResourceStore = defineStore("resource", {
|
||||
pan115: "danger",
|
||||
quark: "success",
|
||||
},
|
||||
keyword: "",
|
||||
resources: lastResource.list,
|
||||
lastUpdateTime: lastResource.lastUpdateTime || "",
|
||||
shareInfo: {} as ShareInfoResponse,
|
||||
resourceSelect: [] as ShareInfo[],
|
||||
loading: false,
|
||||
lastKeyWord: "",
|
||||
backupPlan: false,
|
||||
loadTree: false,
|
||||
}),
|
||||
@@ -123,36 +123,45 @@ export const useResourceStore = defineStore("resource", {
|
||||
if (isLoadMore) {
|
||||
const list = this.resources.find((x) => x.id === channelId)?.list || [];
|
||||
lastMessageId = list[list.length - 1].messageId || "";
|
||||
if (list[list.length - 1].isLastMessage) {
|
||||
ElMessage.warning("没有更多了~");
|
||||
return;
|
||||
}
|
||||
if (!lastMessageId) {
|
||||
ElMessage.error("当次搜索源不支持加载更多");
|
||||
return;
|
||||
}
|
||||
keyword = this.lastKeyWord;
|
||||
keyword = this.keyword;
|
||||
}
|
||||
let { data = [] } = await resourceApi.search(keyword || "", channelId, lastMessageId);
|
||||
this.keyword = keyword || "";
|
||||
data = data.filter((item) => item.list.length > 0);
|
||||
this.lastKeyWord = keyword || "";
|
||||
if (isLoadMore) {
|
||||
const findedIndex = this.resources.findIndex((item) => item.id === data[0]?.id);
|
||||
if (findedIndex !== -1) {
|
||||
this.resources[findedIndex].list.push(...data[0].list);
|
||||
}
|
||||
if (data.length === 0) {
|
||||
const list = this.resources.find((item) => item.id === channelId)?.list;
|
||||
list && list[list.length - 1] && (list[list.length - 1]!.isLastMessage = true);
|
||||
ElMessage.warning("没有更多了~");
|
||||
}
|
||||
} else {
|
||||
this.resources = data.map((item) => ({ ...item, displayList: true }));
|
||||
this.resources = data.map((item, index) => ({ ...item, displayList: index === 0 }));
|
||||
if (!keyword) {
|
||||
// 获取当前时间字符串 用于存储到本地
|
||||
this.lastUpdateTime = new Date().toLocaleString();
|
||||
localStorage.setItem(
|
||||
"last_resource_list",
|
||||
JSON.stringify({ list: this.resources, lastUpdateTime: this.lastUpdateTime })
|
||||
);
|
||||
}
|
||||
if (this.resources.length === 0) {
|
||||
ElMessage.warning("未搜索到相关资源");
|
||||
}
|
||||
}
|
||||
// 获取当前时间字符串 用于存储到本地
|
||||
this.lastUpdateTime = new Date().toLocaleString();
|
||||
localStorage.setItem(
|
||||
"last_resource_list",
|
||||
JSON.stringify({ list: this.resources, lastUpdateTime: this.lastUpdateTime })
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this.handleError("搜索失败,请重试", null);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
|
||||
@@ -14,7 +14,8 @@ export const useUserSettingStore = defineStore("user", {
|
||||
cloud115Cookie: "",
|
||||
quarkCookie: "",
|
||||
},
|
||||
displayStyle: "card",
|
||||
displayStyle: (localStorage.getItem("display_style") as "table" | "card") || "card",
|
||||
imagesSource: (localStorage.getItem("images_source") as "proxy" | "local") || "proxy",
|
||||
}),
|
||||
|
||||
actions: {
|
||||
@@ -41,7 +42,14 @@ export const useUserSettingStore = defineStore("user", {
|
||||
|
||||
setDisplayStyle(style: "table" | "card") {
|
||||
this.displayStyle = style;
|
||||
ElMessage.success(`切换成功,当前为${style}模式`);
|
||||
localStorage.setItem("display_style", style);
|
||||
ElMessage.success(`切换成功,当前为${style === "table" ? "列表" : "卡片"}模式`);
|
||||
},
|
||||
|
||||
setImagesSource(source: "proxy" | "local") {
|
||||
this.imagesSource = source;
|
||||
localStorage.setItem("images_source", source);
|
||||
ElMessage.success(`切换成功,图片模式当前为${source === "proxy" ? "代理" : "直连"}模式`);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface ResourceItem {
|
||||
pubDate: string;
|
||||
cloudType: string;
|
||||
messageId?: string;
|
||||
isLastMessage?: boolean;
|
||||
}
|
||||
|
||||
export interface Resource {
|
||||
|
||||
@@ -15,4 +15,5 @@ export interface UserSettingStore {
|
||||
globalSetting: GlobalSettingAttributes | null;
|
||||
userSettings: UserSettingAttributes;
|
||||
displayStyle: "table" | "card";
|
||||
imagesSource: "proxy" | "local";
|
||||
}
|
||||
|
||||
@@ -13,6 +13,25 @@
|
||||
</div>
|
||||
|
||||
<div class="header__right">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="
|
||||
userStore.imagesSource === 'local' ? '图片切换到代理模式' : '图片切换到直连模式'
|
||||
"
|
||||
placement="bottom"
|
||||
>
|
||||
<el-button
|
||||
type="text"
|
||||
class="view-toggle"
|
||||
@click="
|
||||
userStore.setImagesSource(userStore.imagesSource === 'proxy' ? 'local' : 'proxy')
|
||||
"
|
||||
>
|
||||
<el-icon>
|
||||
<component :is="userStore.imagesSource === 'proxy' ? 'Guide' : 'Location'" />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="userStore.displayStyle === 'card' ? '切换到列表视图' : '切换到卡片视图'"
|
||||
@@ -32,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 资源列表 -->
|
||||
<div ref="contentRef" class="pc-resources__content">
|
||||
<div id="pc-resources-content" ref="contentRef" class="pc-resources__content">
|
||||
<component
|
||||
:is="userStore.displayStyle === 'table' ? ResourceTable : ResourceCard"
|
||||
v-if="resourceStore.resources.length > 0"
|
||||
@@ -142,7 +161,7 @@ import ResourceSelect from "@/components/Home/ResourceSelect.vue";
|
||||
import ResourceTable from "@/components/Home/ResourceTable.vue";
|
||||
import { formattedFileSize } from "@/utils/index";
|
||||
import type { ResourceItem, TagColor } from "@/types";
|
||||
|
||||
import { onMounted, onBeforeUnmount } from "vue";
|
||||
import ResourceCard from "@/components/Home/ResourceCard.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
@@ -212,8 +231,20 @@ const handleLoadMore = (channelId: string) => {
|
||||
};
|
||||
|
||||
const searchMovieforTag = (tag: string) => {
|
||||
router.push({ path: "/", query: { keyword: tag } });
|
||||
router.push({ path: "/resource", query: { keyword: tag } });
|
||||
};
|
||||
// 页面进入 设置缓存的数据源
|
||||
onMounted(() => {
|
||||
const lastResourceList = localStorage.getItem("last_resource_list");
|
||||
if (lastResourceList) {
|
||||
resourceStore.resources = JSON.parse(lastResourceList).list;
|
||||
}
|
||||
});
|
||||
|
||||
// 页面销毁 清除搜索词
|
||||
onBeforeUnmount(() => {
|
||||
resourceStore.keyword = "";
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -81,10 +81,16 @@ watch(
|
||||
searchForm.value.keyword = keyword;
|
||||
handleSearch();
|
||||
} else {
|
||||
searchForm.value.keyword = "";
|
||||
searchForm.value.keyword = resourceStore.keyword;
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => resourceStore.keyword,
|
||||
(newKeyword) => {
|
||||
searchForm.value.keyword = newKeyword;
|
||||
}
|
||||
);
|
||||
|
||||
// 方法定义
|
||||
const handleSearch = async () => {
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted, onUnmounted, computed } from "vue";
|
||||
import { ref, watch, onMounted, onUnmounted, computed, onBeforeUnmount } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { showToast } from "vant";
|
||||
import { useResourceStore } from "@/stores/resource";
|
||||
@@ -223,14 +223,14 @@ const searchMovieforTag = (tag: string) => {
|
||||
// 使用节流包装加载更多函数
|
||||
const throttledLoadMore = throttle((channelId: string) => {
|
||||
resourceStore.searchResources("", true, channelId);
|
||||
}, 200);
|
||||
}, 2000);
|
||||
|
||||
// 滚动加载
|
||||
const doScroll = () => {
|
||||
const appElement = document.querySelector("#app") as HTMLElement;
|
||||
if (appElement) {
|
||||
const { scrollHeight, scrollTop, clientHeight } = appElement;
|
||||
if (scrollHeight - (clientHeight + scrollTop) <= 200) {
|
||||
if (scrollHeight - (clientHeight + scrollTop) <= 1) {
|
||||
throttledLoadMore(currentTab.value);
|
||||
}
|
||||
}
|
||||
@@ -258,6 +258,18 @@ watch(currentTab, () => {
|
||||
appElement.scrollTo(0, 0);
|
||||
}
|
||||
});
|
||||
// 页面进入 设置缓存的数据源
|
||||
onMounted(() => {
|
||||
const lastResourceList = localStorage.getItem("last_resource_list");
|
||||
if (lastResourceList) {
|
||||
resourceStore.resources = JSON.parse(lastResourceList).list;
|
||||
}
|
||||
});
|
||||
|
||||
// 页面销毁 清除搜索词
|
||||
onBeforeUnmount(() => {
|
||||
resourceStore.keyword = "";
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -60,7 +60,7 @@
|
||||
},
|
||||
"frontend": {
|
||||
"name": "cloud-saver-web",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.7",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cloud-saver",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"frontend",
|
||||
|
||||
Reference in New Issue
Block a user