add auto download

This commit is contained in:
Timi
2025-12-20 09:58:50 +08:00
parent 35e34088b8
commit db9630f1dd
9 changed files with 154 additions and 8 deletions

View File

@ -12,6 +12,7 @@
"vue": "^3.5.24", "vue": "^3.5.24",
"less": "^4.3.0", "less": "^4.3.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"vue-router": "^4.5.0",
"timi-web": "link:..\\timi-web", "timi-web": "link:..\\timi-web",
"timi-tdesign-pc": "link:..\\timi-tdesign-pc", "timi-tdesign-pc": "link:..\\timi-tdesign-pc",
"tdesign-vue-next": "1.17.7" "tdesign-vue-next": "1.17.7"

View File

@ -1,6 +1,6 @@
<template> <template>
<root-layout class="root diselect" author="夜雨" icp="粤ICP备2025368555号-1" domain="imyeyu.com" text> <root-layout class="root diselect" author="夜雨" icp="粤ICP备2025368555号-1" domain="imyeyu.com" text>
<home /> <router-view />
<t-back-top class="to-top" size="small"> <t-back-top class="to-top" size="small">
<icon name="arrow_1_n" :scale="2" /> <icon name="arrow_1_n" :scale="2" />
</t-back-top> </t-back-top>
@ -8,7 +8,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import Home from "@/views/Home.vue";
import { RootLayout } from "../../timi-tdesign-pc"; import { RootLayout } from "../../timi-tdesign-pc";
import { Icon } from "../../timi-web"; import { Icon } from "../../timi-web";
</script> </script>

3
src/assets/style.less Normal file
View File

@ -0,0 +1,3 @@
.t-alert {
padding: .5rem !important;
}

View File

@ -1,10 +1,23 @@
<template> <template>
<div class="file-download"> <div class="file-download">
<h4>文件下载</h4> <h4>文件下载</h4>
<t-alert v-if="0 < autoDownloadCD" class="alert auto-dl" theme="warning">
<template #message>
<div class="content">
<span v-text="`${autoDownloadCD} 秒后自动开始下载`"></span>
<t-button class="cancel" size="small" theme="default" @click="cancelAutoDownload" variant="outline">取消</t-button>
</div>
</template>
</t-alert>
<t-alert v-if="showDownloadReminder" class="alert reminder" theme="info" close-btn>
<span>如果浏览器没有自动下载请直接点击</span>
<strong class="word-space">下载文件</strong>
<span>按钮</span>
</t-alert>
<div class="input-group"> <div class="input-group">
<t-input <t-input
class="input" class="input"
v-model="downloadFileId" v-model="id"
placeholder="请输入临时文件 ID" placeholder="请输入临时文件 ID"
clearable clearable
@keyup.enter="download" @keyup.enter="download"
@ -23,10 +36,62 @@
import { MessagePlugin } from "tdesign-vue-next"; import { MessagePlugin } from "tdesign-vue-next";
import TempFileAPI from "@/api/TempFileAPI.ts"; import TempFileAPI from "@/api/TempFileAPI.ts";
import { Icon } from "timi-web"; import { Icon } from "timi-web";
import { useRoute, useRouter } from "vue-router";
const downloadFileId = ref(""); const route = useRoute();
const router = useRouter();
const id = ref("");
const autoDownloadCD = ref(-1);
const showDownloadReminder = ref(false);
let autoDownloadTimer: number | undefined = undefined;
// 检查 URL 参数中的 id
onMounted(() => {
const uriId = route.query.id as string;
if (uriId) {
id.value = uriId;
startAutoDownload();
}
});
/** 开始自动下载倒计时 */
function startAutoDownload() {
autoDownloadCD.value = 5;
autoDownloadTimer = window.setInterval(() => {
autoDownloadCD.value--;
if (autoDownloadCD.value <= 0) {
showDownloadReminder.value = true;
clearInterval(autoDownloadTimer);
TempFileAPI.download(id.value.trim());
MessagePlugin.success("开始下载");
router.replace({ query: {} });
}
}, 1000);
}
/** 取消自动下载 */
function cancelAutoDownload() {
clearInterval(autoDownloadTimer);
id.value = "";
autoDownloadCD.value = -1;
MessagePlugin.info("已取消自动下载");
}
// 组件卸载时清理定时器
onUnmounted(() => {
clearInterval(autoDownloadTimer);
});
/** 下载文件 */
function download() { function download() {
const fileId = downloadFileId.value.trim(); if (autoDownloadTimer) {
autoDownloadCD.value = -1;
clearInterval(autoDownloadTimer);
}
if (showDownloadReminder.value) {
showDownloadReminder.value = false;
}
const fileId = id.value.trim();
if (!fileId) { if (!fileId) {
MessagePlugin.warning("请输入文件 ID"); MessagePlugin.warning("请输入文件 ID");
return; return;
@ -40,6 +105,34 @@ function download() {
.file-download { .file-download {
padding: 0 1rem; padding: 0 1rem;
.alert {
margin-bottom: 1rem;
&.auto-dl {
:deep(.t-alert__description) {
flex: 1;
}
.content {
display: flex;
align-items: center;
justify-content: space-between;
.cancel {
margin-left: 1rem;
}
}
}
&.reminder {
:deep(.t-alert__close) {
margin-left: 0;
}
}
}
.input-group { .input-group {
gap: .625rem; gap: .625rem;
display: flex; display: flex;

View File

@ -22,6 +22,7 @@
<div class="expiry gray" v-text="getTimeRemaining(file.expiryTime)"></div> <div class="expiry gray" v-text="getTimeRemaining(file.expiryTime)"></div>
<div class="actions"> <div class="actions">
<t-button size="small" theme="default" variant="outline" @click="copyFileId(file.id)">复制 ID</t-button> <t-button size="small" theme="default" variant="outline" @click="copyFileId(file.id)">复制 ID</t-button>
<t-button size="small" theme="primary" variant="outline" @click="copyDownloadLink(file.id)">复制下载直链</t-button>
<t-button class="download" size="small" theme="primary" @click="download(file.id)">下载</t-button> <t-button class="download" size="small" theme="primary" @click="download(file.id)">下载</t-button>
</div> </div>
</div> </div>
@ -56,6 +57,18 @@ async function copyFileId(fileId: string) {
} }
} }
/** 复制下载直链 */
async function copyDownloadLink(fileId: string) {
try {
const baseUrl = window.location.origin + window.location.pathname;
const downloadUrl = `${baseUrl}?id=${fileId}`;
await navigator.clipboard.writeText(downloadUrl);
await MessagePlugin.success("已复制下载直链到剪贴板");
} catch (error) {
await MessagePlugin.error("复制失败");
}
}
/** 获取剩余时间 */ /** 获取剩余时间 */
function getTimeRemaining(expiryTime: string): string { function getTimeRemaining(expiryTime: string): string {
const now = Time.now(); const now = Time.now();
@ -140,7 +153,7 @@ onMounted(fileHistoryStore.loadHistory);
} }
.actions { .actions {
gap: 1rem; gap: .5rem;
display: flex; display: flex;
.download { .download {
@ -151,4 +164,20 @@ onMounted(fileHistoryStore.loadHistory);
} }
} }
} }
@media (max-width: 960px) {
.file-history-list {
flex-direction: column;
.list .item .bottom {
align-items: flex-start;
flex-direction: column;
.actions {
margin-top: .5rem;
place-self: flex-end;
}
}
}
}
</style> </style>

View File

@ -204,7 +204,7 @@ async function upload(files: File[]) {
.upload-area { .upload-area {
border: .125rem dashed #CBD5E0; border: .125rem dashed #CBD5E0;
padding: 1rem 2.5rem; padding: 1rem;
text-align: center; text-align: center;
transition: all .3s ease; transition: all .3s ease;
background: #F7FAFC; background: #F7FAFC;

View File

@ -5,8 +5,10 @@ import { axios, Network, VDraggable, VPopup } from "timi-web";
import "timi-tdesign-pc/style.css"; import "timi-tdesign-pc/style.css";
import "timi-web/style.css"; import "timi-web/style.css";
import "@/assets/style.less";
import Root from "@/Root.vue"; import Root from "@/Root.vue";
import router from "@/router";
console.log(` console.log(`
______ __ _ _ ______ __ _ _
@ -24,6 +26,7 @@ axios.interceptors.request.use(Network.userTokenInterceptors);
const pinia = createPinia(); const pinia = createPinia();
const app = createApp(Root); const app = createApp(Root);
app.use(pinia); app.use(pinia);
app.use(router);
app.directive("draggable", VDraggable as any); app.directive("draggable", VDraggable as any);
app.directive("popup", VPopup as any); app.directive("popup", VPopup as any);
app.mount("#root"); app.mount("#root");

18
src/router/index.ts Normal file
View File

@ -0,0 +1,18 @@
import { createRouter, createWebHistory } from "vue-router";
import type { RouteRecordRaw } from "vue-router";
import Home from "@/views/Home.vue";
const routes: RouteRecordRaw[] = [
{
path: "/",
name: "Home",
component: Home,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;

View File

@ -74,7 +74,7 @@ onMounted(() => setInterval(fileHistoryStore.cleanExpiredFiles, Time.S));
} }
} }
@media (max-width: 45rem) { @media (max-width: 960px) {
.home .content { .home .content {
flex-direction: column; flex-direction: column;