下载文件名称统一修改
This commit is contained in:
+140
-137
@@ -236,7 +236,7 @@ const handleSelectKeys = (keys: string[],option:any) => {
|
||||
|
||||
// 下载
|
||||
const downloadFile = (file:any) => {
|
||||
downloadFileFun(file.file_url, file.file_name);
|
||||
downloadFileFun(file?.file_url, file?.file_name || file?.doc_name);
|
||||
}
|
||||
|
||||
// 预览
|
||||
@@ -354,164 +354,167 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NSpace vertical :size="16">
|
||||
<NSpin :show="loading" size="small">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive class="pb-[12px] border-b">
|
||||
<NGi span="24 s:24 m:24">
|
||||
<div class="h-100% flex items-center gap-2">
|
||||
<Icon icon="mage:book" class="size-20px" :style="{ color: themeStore.themeColor }" />
|
||||
<p class="text-base font-semibold">变更归档(一次变更一个归档包 · 关闭即自动归档 · 只读锁定)</p>
|
||||
<NSpace vertical :size="16">
|
||||
<NSpin :show="loading" size="small">
|
||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive class="pb-[12px] border-b">
|
||||
<NGi span="24 s:24 m:24">
|
||||
<div class="h-100% flex items-center gap-2">
|
||||
<Icon icon="mage:book" class="size-20px" :style="{ color: themeStore.themeColor }" />
|
||||
<p class="text-base font-semibold">变更归档(一次变更一个归档包 · 关闭即自动归档 · 只读锁定)</p>
|
||||
</div>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<div class="flex items-center gap-2 mt-3">
|
||||
<NInput v-model:value="formInfo.change_no" type="text" class="w-full text-xs" clearable placeholder="按变更单号精确查找,或按名称关键词检索(如 MOC-2026-R01-0039)" @clear="formInfo.change_no = ''; getList()">
|
||||
<template #suffix>
|
||||
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" @click="getList" />
|
||||
</template>
|
||||
</NInput>
|
||||
<NButton class="text-sm" @click="reset">
|
||||
<Icon icon="system-uicons:reset" class="size-14px" />重置
|
||||
</NButton>
|
||||
</div>
|
||||
<!-- 筛选:时间 / 组织 / 专业 -->
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-1.5 mt-3">
|
||||
<NTreeSelect
|
||||
class="!w-200px"
|
||||
:value="formInfo.org_id"
|
||||
:options="orgTree"
|
||||
size="small"
|
||||
default-expand-all
|
||||
label-field="label"
|
||||
key-field="id"
|
||||
:render-switcher-icon="renderSwitcherIcon"
|
||||
placeholder="请选择组织层级"
|
||||
@update:value="orgChange"
|
||||
/>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<span class="text-[11px] text-slate-400">时间</span>
|
||||
<NButton v-for="time in timeOptions" :key="time.value" size="tiny" round class="text-xs" :type="formInfo.time === time.value ? 'primary' : 'default'" @click="timeChange(time.value)">{{ time.label }}</NButton>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<span class="text-[11px] text-slate-400">类型</span>
|
||||
<NButton v-for="type in typeList" :key="type.value" size="tiny" round class="text-xs" :type="formInfo.type === type.value ? 'primary' : 'default'" @click="typeChange(type.value)">{{ type.label }}</NButton>
|
||||
</div>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
<div class="flex items-center gap-2 mt-3">
|
||||
<NInput v-model:value="formInfo.change_no" type="text" class="w-full text-xs" clearable placeholder="按变更单号精确查找,或按名称关键词检索(如 MOC-2026-R01-0039)" @clear="formInfo.change_no = ''; getList()">
|
||||
<template #suffix>
|
||||
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" @click="getList" />
|
||||
</template>
|
||||
</NInput>
|
||||
<NButton class="text-sm" @click="reset">
|
||||
<Icon icon="system-uicons:reset" class="size-14px" />重置
|
||||
</NButton>
|
||||
</div>
|
||||
<!-- 筛选:时间 / 组织 / 专业 -->
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-1.5 mt-3">
|
||||
<NTreeSelect
|
||||
class="!w-200px"
|
||||
:value="formInfo.org_id"
|
||||
:options="orgTree"
|
||||
size="small"
|
||||
default-expand-all
|
||||
label-field="label"
|
||||
key-field="id"
|
||||
:render-switcher-icon="renderSwitcherIcon"
|
||||
placeholder="请选择组织层级"
|
||||
@update:value="orgChange"
|
||||
/>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<span class="text-[11px] text-slate-400">时间</span>
|
||||
<NButton v-for="time in timeOptions" :key="time.value" size="tiny" round class="text-xs" :type="formInfo.time === time.value ? 'primary' : 'default'" @click="timeChange(time.value)">{{ time.label }}</NButton>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<span class="text-[11px] text-slate-400">类型</span>
|
||||
<NButton v-for="type in typeList" :key="type.value" size="tiny" round class="text-xs" :type="formInfo.type === type.value ? 'primary' : 'default'" @click="typeChange(type.value)">{{ type.label }}</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3 mt-3">
|
||||
<!-- 左侧 -->
|
||||
<div class="w-300px border rounded-md p-2">
|
||||
<div class="scroll-left">
|
||||
<NTree
|
||||
class="h-100% flex flex-col"
|
||||
block-line
|
||||
:data="treeList"
|
||||
label-field="label"
|
||||
key-field="key"
|
||||
:expanded-keys="expandedKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:render-switcher-icon="renderSwitcherIcon"
|
||||
selectable
|
||||
:cancelable="false"
|
||||
:on-update:expanded-keys="handleExpandKeys"
|
||||
:on-update:selected-keys="handleSelectKeys"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="h-100% flex items-center justify-center">
|
||||
<NEmpty description="暂无数据" class="text-xs"></NEmpty>
|
||||
<div class="flex gap-3 mt-3">
|
||||
<!-- 左侧 -->
|
||||
<div class="w-300px border rounded-md p-2">
|
||||
<div class="scroll-left">
|
||||
<NTree
|
||||
class="h-100% flex flex-col"
|
||||
block-line
|
||||
:data="treeList"
|
||||
label-field="label"
|
||||
key-field="key"
|
||||
:expanded-keys="expandedKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:render-switcher-icon="renderSwitcherIcon"
|
||||
selectable
|
||||
:cancelable="false"
|
||||
:on-update:expanded-keys="handleExpandKeys"
|
||||
:on-update:selected-keys="handleSelectKeys"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="h-100% flex items-center justify-center">
|
||||
<NEmpty description="暂无数据" class="text-xs"></NEmpty>
|
||||
</div>
|
||||
</template>
|
||||
</NTree>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右:归档包详情 -->
|
||||
<div class="min-w-0 flex-1">
|
||||
<NSpin :show="rightLoading" size="small">
|
||||
<template v-if="rightDetails">
|
||||
<div class="rounded-md border col-span-2">
|
||||
<div class="border-b p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-sm font-semibold">{{ rightDetails.change_no }}</span>
|
||||
</div>
|
||||
<div class="mt-1 text-xs text-slate-600">{{ rightDetails.title }}</div>
|
||||
<div class="mt-2 flex flex-wrap justify-between gap-x-4 gap-y-1 text-[11px] text-slate-500">
|
||||
<span>归档路径:{{ currentPath.join('/') }}</span>
|
||||
<span>关闭时间:{{ rightDetails?.close_time?.slice(0,10) }}</span>
|
||||
<span>共 {{ extractFiles(rightDetails.folders)?.total }} 个文件 · {{ extractFiles(rightDetails.folders)?.formattedSize }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divide-y scroll-right">
|
||||
<div v-for="f in rightDetails?.folders" :key="f.step_no">
|
||||
<button
|
||||
class="flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium hover:bg-slate-50 bg-transparent"
|
||||
@click="openFolders[f.step_no] = !openFolders[f.step_no]"
|
||||
>
|
||||
<Icon icon="formkit:right" class="size-14px text-slate-400 transition-transform" :class="openFolders[f.step_no] ? 'rotate-90' : ''" />
|
||||
<Icon v-if="openFolders[f.step_no]" icon="quill:folder-open" class="size-16px" :style="{color:themeStore.themeColor}" />
|
||||
<Icon v-else icon="material-symbols:folder-outline" class="size-16px text-slate-400" />
|
||||
<span v-if="f.step_no===1">1-申请与审批</span>
|
||||
<span v-else-if="f.step_no===2">2-风险分析</span>
|
||||
<span v-else-if="f.step_no===3">3-培训与考核</span>
|
||||
<span v-else-if="f.step_no===4">4-PSSR检查</span>
|
||||
<span v-else-if="f.step_no===5">5-验收记录</span>
|
||||
<span v-else>6-关闭资料</span>
|
||||
<span class="ml-auto text-[11px] font-normal text-slate-400">{{ f.files.length }} 个文件</span>
|
||||
</button>
|
||||
<template v-if="openFolders[f.step_no]">
|
||||
<div v-for="file in f.files" :key="file.name" class="flex items-center gap-2 py-1.5 pl-10 pr-3 text-xs hover:bg-slate-50">
|
||||
<Icon icon="akar-icons:file" class="size-14px text-slate-400" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ file.file_name }}</span>
|
||||
<span class="text-[11px] text-slate-400">{{ formatSize(file.file_size) }}</span>
|
||||
<NButton text type="primary" title="预览" @click="preview(file)">
|
||||
<Icon icon="lucide:eye" class="size-14px" />
|
||||
</NButton>
|
||||
<NButton text type="primary" title="下载" @click="downloadFile(file)">
|
||||
<Icon icon="material-symbols:download" class="size-16px" />
|
||||
</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NTree>
|
||||
<div v-else class="h-100% rounded-md border scroll-empty">
|
||||
<div class="h-100% flex items-center justify-center">
|
||||
<NEmpty description="暂无归档包详情数据" class="text-xs"></NEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</NSpin>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右:归档包详情 -->
|
||||
<div class="min-w-0 flex-1">
|
||||
<NSpin :show="rightLoading" size="small">
|
||||
<template v-if="rightDetails">
|
||||
<div class="rounded-md border col-span-2">
|
||||
<div class="border-b p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-sm font-semibold">{{ rightDetails.change_no }}</span>
|
||||
</div>
|
||||
<div class="mt-1 text-xs text-slate-600">{{ rightDetails.title }}</div>
|
||||
<div class="mt-2 flex flex-wrap justify-between gap-x-4 gap-y-1 text-[11px] text-slate-500">
|
||||
<span>归档路径:{{ currentPath.join('/') }}</span>
|
||||
<span>关闭时间:{{ rightDetails?.close_time?.slice(0,10) }}</span>
|
||||
<span>共 {{ extractFiles(rightDetails.folders)?.total }} 个文件 · {{ extractFiles(rightDetails.folders)?.formattedSize }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divide-y scroll-right">
|
||||
<div v-for="f in rightDetails?.folders" :key="f.step_no">
|
||||
<button @click="openFolders[f.step_no] = !openFolders[f.step_no]"
|
||||
class="flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium hover:bg-slate-50 bg-transparent">
|
||||
<Icon icon="formkit:right" class="size-14px text-slate-400 transition-transform" :class="openFolders[f.step_no] ? 'rotate-90' : ''" />
|
||||
<Icon icon="quill:folder-open" v-if="openFolders[f.step_no]" class="size-16px" :style="{color:themeStore.themeColor}" />
|
||||
<Icon v-else icon="material-symbols:folder-outline" class="size-16px text-slate-400" />
|
||||
<span v-if="f.step_no===1">1-申请与审批</span>
|
||||
<span v-else-if="f.step_no===2">2-风险分析</span>
|
||||
<span v-else-if="f.step_no===3">3-培训与考核</span>
|
||||
<span v-else-if="f.step_no===4">4-PSSR检查</span>
|
||||
<span v-else-if="f.step_no===5">5-验收记录</span>
|
||||
<span v-else>6-关闭资料</span>
|
||||
<span class="ml-auto text-[11px] font-normal text-slate-400">{{ f.files.length }} 个文件</span>
|
||||
</button>
|
||||
<template v-if="openFolders[f.step_no]">
|
||||
<div v-for="file in f.files" :key="file.name" class="flex items-center gap-2 py-1.5 pl-10 pr-3 text-xs hover:bg-slate-50">
|
||||
<Icon icon="akar-icons:file" class="size-14px text-slate-400" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ file.file_name }}</span>
|
||||
<span class="text-[11px] text-slate-400">{{ formatSize(file.file_size) }}</span>
|
||||
<NButton text type="primary" title="预览" @click="preview(file)">
|
||||
<Icon icon="lucide:eye" class="size-14px" />
|
||||
</NButton>
|
||||
<NButton text type="primary" title="下载" @click="downloadFile(file)">
|
||||
<Icon icon="material-symbols:download" class="size-16px" />
|
||||
</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="h-100% rounded-md border scroll-empty">
|
||||
<div class="h-100% flex items-center justify-center">
|
||||
<NEmpty description="暂无归档包详情数据" class="text-xs"></NEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</NSpin>
|
||||
</div>
|
||||
</div>
|
||||
</NCard>
|
||||
<!-- 附件在线预览弹窗 -->
|
||||
<NModal
|
||||
</NCard>
|
||||
<!-- 附件在线预览弹窗 -->
|
||||
<NModal
|
||||
v-model:show="previewModal"
|
||||
preset="card"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '80%', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: true }"
|
||||
>
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2 text-base font-semibold text-slate-800">
|
||||
<div class="flex items-center gap-2 text-base font-semibold text-slate-800">
|
||||
<Icon icon="akar-icons:file" class="size-18px" /> {{ previewFile?.file_name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="space-y-3">
|
||||
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
|
||||
<span>上传人:{{ previewFile?.uploader_name }}</span>
|
||||
<span>上传时间:{{ previewFile?.created_at?.slice(0, 16) }}</span>
|
||||
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||
</div>
|
||||
<previewComponent v-if="previewFile" :previewFile="previewFile" />
|
||||
<div class="space-y-3">
|
||||
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
|
||||
<span>上传人:{{ previewFile?.uploader_name }}</span>
|
||||
<span>上传时间:{{ previewFile?.created_at?.slice(0, 16) }}</span>
|
||||
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||
</div>
|
||||
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
</NSpin>
|
||||
</NSpace>
|
||||
</NModal>
|
||||
</NSpin>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.scroll-left {
|
||||
height: calc(100vh - 303px);
|
||||
|
||||
Reference in New Issue
Block a user