发布候选:整合桌面端界面与发布稳定化里程碑
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
This commit is contained in:
@@ -121,7 +121,10 @@
|
||||
{{ TEXT.common.labels.preview }}
|
||||
</el-button>
|
||||
<el-button link type="primary" size="small" @click="downloadVersion(row)" v-if="canReadDocument">
|
||||
{{ TEXT.modules.fileVersionManagement.actions.download }}
|
||||
另存为
|
||||
</el-button>
|
||||
<el-button link type="primary" size="small" @click="openVersion(row)" v-if="canReadDocument">
|
||||
打开
|
||||
</el-button>
|
||||
<el-button v-if="canDeleteDocument" link type="danger" size="small" @click="confirmDeleteVersion(row)">
|
||||
{{ TEXT.common.actions.delete }}
|
||||
@@ -261,8 +264,13 @@
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
|
||||
上传文件
|
||||
</div>
|
||||
<div class="upload-zone" :class="{ 'has-file': uploadFile }" @click="triggerFileInput">
|
||||
<input type="file" ref="fileInputRef" @change="onFileChange" class="file-input-hidden" accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.png,.jpg" />
|
||||
<div
|
||||
class="upload-zone"
|
||||
:class="{ 'has-file': uploadFile }"
|
||||
@click="triggerFileInput"
|
||||
@dragover.prevent
|
||||
@drop.prevent="handleUploadDrop"
|
||||
>
|
||||
<template v-if="!uploadFile">
|
||||
<div class="upload-zone-icon">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
|
||||
@@ -342,7 +350,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, watch } from "vue";
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { ElMessage, ElMessageBox, FormInstance, FormRules } from "element-plus";
|
||||
import { Edit, Upload, Share } from "@element-plus/icons-vue";
|
||||
@@ -370,6 +378,8 @@ import { useRoleTemplateMeta } from "../../composables/useRoleTemplateMeta";
|
||||
import { usePermission } from "../../utils/permission";
|
||||
import StateError from "../../components/StateError.vue";
|
||||
import StateLoading from "../../components/StateLoading.vue";
|
||||
import { openFile, pickFiles, saveFile } from "../../runtime";
|
||||
import { onDesktopRefreshCurrentView } from "../../composables/useDesktopRefresh";
|
||||
|
||||
const route = useRoute();
|
||||
const auth = useAuthStore();
|
||||
@@ -377,6 +387,7 @@ const study = useStudyStore();
|
||||
const { roleLabel, loadRoleTemplates } = useRoleTemplateMeta();
|
||||
const { can } = usePermission();
|
||||
const documentId = computed(() => route.params.id as string);
|
||||
let desktopRefreshCleanup: (() => void) | undefined;
|
||||
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref("");
|
||||
@@ -494,7 +505,6 @@ const editorDirtyGuard = useDrawerDirtyGuard(() => editorForm);
|
||||
const uploadVisible = ref(false);
|
||||
const uploading = ref(false);
|
||||
const uploadFormRef = ref<FormInstance>();
|
||||
const fileInputRef = ref<HTMLInputElement | null>(null);
|
||||
const uploadForm = reactive({
|
||||
version_no: "",
|
||||
version_date: "",
|
||||
@@ -513,8 +523,19 @@ const uploadDirtyGuard = useDrawerDirtyGuard(() => ({
|
||||
: null,
|
||||
}));
|
||||
|
||||
const triggerFileInput = () => { fileInputRef.value?.click(); };
|
||||
const removeFile = () => { uploadFile.value = null; if (fileInputRef.value) fileInputRef.value.value = ""; };
|
||||
const triggerFileInput = async () => {
|
||||
const [file] = await pickFiles({
|
||||
multiple: false,
|
||||
accept: ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "png", "jpg", "jpeg"],
|
||||
title: "选择文档版本",
|
||||
});
|
||||
if (file) uploadFile.value = file;
|
||||
};
|
||||
const handleUploadDrop = (event: DragEvent) => {
|
||||
const [file] = Array.from(event.dataTransfer?.files || []);
|
||||
if (file) uploadFile.value = file;
|
||||
};
|
||||
const removeFile = () => { uploadFile.value = null; };
|
||||
|
||||
const distributeVisible = ref(false);
|
||||
const distributing = ref(false);
|
||||
@@ -706,11 +727,6 @@ const openUpload = () => {
|
||||
uploadVisible.value = true;
|
||||
};
|
||||
|
||||
const onFileChange = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files[0]) uploadFile.value = target.files[0];
|
||||
};
|
||||
|
||||
const submitUpload = async () => {
|
||||
if (!canUpdateDocument.value) { ElMessage.warning("权限不足"); return; }
|
||||
if (!uploadFormRef.value) return;
|
||||
@@ -797,13 +813,25 @@ const downloadVersion = async (version: DocumentVersion) => {
|
||||
const contentType = response.headers?.["content-type"] || "application/octet-stream";
|
||||
const filename = getFilename(response.headers?.["content-disposition"]) || `document-${version.version_no || version.id}.bin`;
|
||||
const blob = new Blob([response.data], { type: contentType });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a"); link.href = url; link.download = filename;
|
||||
document.body.appendChild(link); link.click(); link.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
await saveFile({ suggestedName: filename, mimeType: contentType, data: blob });
|
||||
} catch (e: any) { ElMessage.error(e?.response?.data?.message || TEXT.common.messages.downloadFailed); }
|
||||
};
|
||||
|
||||
const openVersion = async (version: DocumentVersion) => {
|
||||
try {
|
||||
const response = await downloadDocumentVersion(version.id);
|
||||
const contentType = response.headers?.["content-type"] || "application/octet-stream";
|
||||
const filename = getFilename(response.headers?.["content-disposition"]) || `document-${version.version_no || version.id}.bin`;
|
||||
await openFile({
|
||||
suggestedName: filename,
|
||||
mimeType: contentType,
|
||||
data: new Blob([response.data], { type: contentType }),
|
||||
});
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || TEXT.common.messages.downloadFailed);
|
||||
}
|
||||
};
|
||||
|
||||
const confirmDeleteVersion = async (version: DocumentVersion) => {
|
||||
if (!version?.id) return;
|
||||
if (!canDeleteDocument.value) { ElMessage.warning("权限不足"); return; }
|
||||
@@ -871,9 +899,14 @@ watch(previewVisible, (visible) => {
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
desktopRefreshCleanup = onDesktopRefreshCurrentView(loadDetail);
|
||||
await loadRoleTemplates();
|
||||
await loadDetail();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
desktopRefreshCleanup?.();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user