add auto download
This commit is contained in:
@ -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"
|
||||||
|
|||||||
@ -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
3
src/assets/style.less
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.t-alert {
|
||||||
|
padding: .5rem !important;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
18
src/router/index.ts
Normal 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;
|
||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user