预览文件统一修改

This commit is contained in:
2026-10-13 12:04:41 +08:00
parent 3d765d2243
commit 0b4f8f3404
9 changed files with 692 additions and 686 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ import { getColorWithOpacity, tagTextColor, tagBgColor, tagBorderColor, download
import { AiError, aiTypeJudge } from "@/service/api/ai";
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
import { rejectApi,agreeApi } from '@/service/api/myTasks';
const themeStore = useThemeStore();
+35 -31
View File
@@ -9,7 +9,7 @@ import { uploadFileApi, deleteFileApi, fileListApi } from "@/service/api/file";
import { systemConfigApi, peopleListApi, templateListApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
import { myTasksCloseMaterialApi } from '@/service/api/myTasks';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
@@ -170,7 +170,7 @@ const chooseFiles = () => {
const ids = new Set(checkedFiles.value);
const result = fileList.value.filter((item:any) => ids.has(item.id));
// 合并文件列表
let files = list.value[currentRowIndex.value]?.attachments.concat(result);
const files = list.value[currentRowIndex.value]?.attachments.concat(result);
// 按id去重
const uniqueList = [
...new Map(files.map((item:any) => [item.id, item])).values(),
@@ -349,7 +349,7 @@ const togglePicker = (s: any) => {
// 添加审批步骤人员
const addMember = (s: any, v: string | null) => {
if (v && !s.members.some((m:any) => m.user_name === v)){
let info = findUserInTree(memberList.value, v);
const info = findUserInTree(memberList.value, v);
s.members.push({ user_id: Number(v), user_name: info?.user_name || '', org_id: info?.org_id || '', org_name: info?.org_name || '', specialty: "", is_sign: 0 });
pick.value = null;
pickerStepId.value = null;
@@ -397,7 +397,7 @@ onMounted(async () => {
</script>
<template>
<NSpace vertical :size="16">
<NSpace vertical :size="16">
<!-- 资料关闭详情-->
<NSpin :show="loading" size="small">
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
@@ -434,13 +434,13 @@ onMounted(async () => {
class="text-11px flex items-center gap-2 border py-0.5 px-1.5 rounded-md text-[#17407F] border-[#ACC6E5] bg-[#EAF0F9]"
>
<Icon icon="akar-icons:file" class="size-12px" />
{{file.file_name}}
{{ file.file_name }}
<NButton text type="primary" class="text-11px" @click="preview(file)">预览</NButton>
<NButton text type="primary" class="text-11px" @click="downloadFile(file,'train')">下载</NButton>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="removeFileReal('3', Number(fileIndex))"
>
<template #trigger>
@@ -456,8 +456,8 @@ onMounted(async () => {
下载培训签到表
</NButton>
<NUpload
class="w-auto"
:key="trainFiles.length?'train_'+trainFiles.length+1:'train'"
class="w-auto"
accept="image/*,.pdf,.docx,.xlsx,.pptx"
:default-upload="false"
:show-file-list="false"
@@ -481,13 +481,13 @@ onMounted(async () => {
class="text-11px flex items-center gap-2 border py-0.5 px-1.5 rounded-md text-[#17407F] border-[#ACC6E5] bg-[#EAF0F9]"
>
<Icon icon="akar-icons:file" class="size-12px" />
{{file.file_name}}
{{ file.file_name }}
<NButton text type="primary" class="text-11px" @click="preview(file)">预览</NButton>
<NButton text type="primary" class="text-11px" @click="downloadFile(file,'pssr')">下载</NButton>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="removeFileReal('4', Number(fileIndex))"
>
<template #trigger>
@@ -503,8 +503,8 @@ onMounted(async () => {
下载PSSR检查表
</NButton>
<NUpload
class="w-auto"
:key="pssrFiles.length?'pssr_'+pssrFiles.length+1:'pssr'"
class="w-auto"
accept="image/*,.pdf,.docx,.xlsx,.pptx"
:default-upload="false"
:show-file-list="false"
@@ -551,13 +551,13 @@ onMounted(async () => {
class="text-11px flex items-center gap-2 border py-0.5 px-1.5 rounded-md text-[#17407F] border-[#ACC6E5] bg-[#EAF0F9]"
>
<Icon icon="akar-icons:file" class="size-12px" />
{{file.file_name}}
{{ file.file_name }}
<NButton text type="primary" class="text-11px" @click="preview(file)">预览</NButton>
<NButton text type="primary" class="text-11px" @click="downloadFile(file,'accept')">下载</NButton>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="removeFileReal('5', Number(fileIndex))"
>
<template #trigger>
@@ -573,8 +573,8 @@ onMounted(async () => {
下载验收表
</NButton>
<NUpload
class="w-auto"
:key="acceptFiles.length?'accept_'+acceptFiles.length+1:'accept'"
class="w-auto"
accept="image/*,.pdf,.docx,.xlsx,.pptx"
:default-upload="false"
:show-file-list="false"
@@ -622,7 +622,7 @@ onMounted(async () => {
<tbody>
<tr v-for="(item, index) in list" :key="index">
<td>
<p>{{item.doc_name}}</p>
<p>{{ item.doc_name }}</p>
<div v-if="item.attachments.length" class="flex flex-wrap gap-2">
<div
v-for="(file, fileIndex) in item.attachments"
@@ -630,13 +630,13 @@ onMounted(async () => {
class="text-11px flex items-center gap-2 border py-0.5 px-1.5 rounded-md text-[#17407F] border-[#ACC6E5] bg-[#EAF0F9]"
>
<Icon icon="akar-icons:file" class="size-12px" />
{{file.file_name}}
{{ file.file_name }}
<NButton text type="primary" class="text-11px" @click="preview(file)">预览</NButton>
<NButton text type="primary" class="text-11px" @click="downloadFile(file,'close')">下载</NButton>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="removeFileReal(item.doc_name, Number(fileIndex), Number(index))"
>
<template #trigger>
@@ -657,8 +657,8 @@ onMounted(async () => {
<div v-if="item.status === 1" class="flex justify-center gap-2">
<NButton size="small" class="text-xs" @click="openFileList(Number(index))">从变更附件选择</NButton>
<NUpload
class="w-auto"
:key="item.id"
class="w-auto"
accept="image/*,.pdf,.docx,.xlsx,.pptx"
:default-upload="false"
:show-file-list="false"
@@ -697,12 +697,12 @@ onMounted(async () => {
<p class="text-xs leading-relaxed text-slate-400">审批链:{{ approvalFlowText }}。专业会签人由申请表「涉及专业」勾选自动增减,可在此调整人选;重要变更自动追加安全审查与分管领导终批。</p>
<div v-for="(s, idx) in flowList" :key="s.id" class="rounded-lg border border-slate-100 bg-slate-50/40 p-3">
<div class="flex flex-wrap items-center gap-2">
<NTag type="info" size="small">{{Number(idx)+1}}</NTag>
<p class="text-sm">{{s.name}}</p>
<NTag type="info" size="small">{{ Number(idx)+1 }}</NTag>
<p class="text-sm">{{ s.name }}</p>
<NCheckbox :checked="s.countersign" size="small" @update:checked="(v) => setStepCountersign(s, v)">
<span class="text-xs text-slate-500">专业会签步骤</span>
</NCheckbox>
<NButton ghost type="primary" size="tiny" @click="togglePicker(s)" title="添加预设人员" class="ml-auto">
<NButton ghost type="primary" size="tiny" title="添加预设人员" class="ml-auto" @click="togglePicker(s)">
<Icon icon="ic:round-plus" class="size-16px" />
</NButton>
</div>
@@ -714,11 +714,13 @@ onMounted(async () => {
<span class="shrink-0 truncate text-xs font-medium text-slate-700">{{ m.user_name }}</span>
<template v-if="s.countersign">
<span class="text-xs text-slate-400"><span class="text-red-500">*</span>专业:</span>
<NSelect :value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
<NSelect
:value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
:options="SPECIALTIES"
@update:value="(v) => selectSpecialty(Number(idx), Number(mIdx), v)"
/>
<NCheckbox :checked="m.is_sign" size="small"
<NCheckbox
:checked="m.is_sign" size="small"
:checked-value="1"
:unchecked-value="0"
@update:checked="(v) => selectSign(Number(idx), Number(mIdx), v)"
@@ -726,16 +728,18 @@ onMounted(async () => {
<span class="text-xs text-slate-500">必须参与会签</span>
</NCheckbox>
</template>
<NButton text type="error" @click="delMember(s, m.user_id)" title="删除该人员">
<NButton text type="error" title="删除该人员" @click="delMember(s, m.user_id)">
<Icon icon="iconamoon:trash" class="size-16px" />
</NButton>
</div>
<p v-if="s.countersign && s.members.length" class="text-[11px] leading-5 text-slate-400">
必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)
</p>
<NCascader v-if="pickerStepId === s.id" :value="pick" :options="memberList"
<NCascader
v-if="pickerStepId === s.id" :value="pick" :options="memberList"
placeholder="请选择人员" size="small" check-strategy="child" :show-path="false" expand-trigger="click"
class="w-56" :on-update:value="(v) => addMember(s, v)" />
class="w-56" :on-update:value="(v) => addMember(s, v)"
/>
<span v-if="s.members.length === 0" class="text-xs leading-7 text-slate-300">未预设</span>
</div>
@@ -795,13 +799,13 @@ onMounted(async () => {
<span>上传时间:{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
</div>
</template>
</NModal>
</NCard>
</NSpin>
</NSpace>
</NSpace>
</template>
<style scoped lang="scss">
+1 -1
View File
@@ -9,7 +9,7 @@ import { AiError, aiTypeJudge } from "@/service/api/ai";
import { systemConfigApi, peopleListApi, templateListApi } from '@/service/api/system';
import { getChangeDetailApi, urgeApi } from '@/service/api/change';
import { myTasksDisposalSubmitApi, myTasksAddItemApi } from '@/service/api/myTasks';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
+1 -1
View File
@@ -8,7 +8,7 @@ import { tagTextColor, tagBgColor, tagBorderColor, downloadFileFun } from '@/uti
import { AiError, aiTypeJudge } from "@/service/api/ai";
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi, urgeApi } from '@/service/api/change';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
+1 -1
View File
@@ -3,7 +3,7 @@ import { ref, onMounted, h } from 'vue';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { NButton, NTag, NDropdown, useDialog } from 'naive-ui';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
import { downloadFileFun } from '@/utils/common';
import {
docTreeListApi,
+1 -1
View File
@@ -3,7 +3,7 @@ import { ref, onMounted, h } from 'vue';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { formatTimestamp, getTimeRangeStamp, downloadFileFun } from "@/utils/common";
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
import { systemConfigApi } from '@/service/api/system';
import { orgListApi } from '@/service/api/user';
import { docArchiveTreeListApi, docArchiveDetailsApi } from "@/service/api/doc";
+1 -1
View File
@@ -6,7 +6,7 @@ import { useRouterPush } from '@/hooks/common/router';
import { getColorWithOpacity, tagTextColor, tagBgColor, tagBorderColor, downloadFileFun } from '@/utils/common';
import { systemConfigApi } from "@/service/api/system";
import { homeSafeApi } from "@/service/api/statistics";
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
@@ -8,7 +8,7 @@ import { localStg } from '@/utils/storage';
import { AiError, aiTypeJudge, aiLevelScore, aiApplication } from "@/service/api/ai";
import { uploadFileApi, deleteFileApi } from "@/service/api/file";
import Footer from './footer.vue'
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
const themeStore = useThemeStore();
@@ -232,7 +232,7 @@ const filterMembersBySpecialties = (steps: any, specialties: string[]) => {
}
// 更新当前模板步骤
const updateCurrentTemplate = () => {
let template = props.templateList.find((item: any) =>
const template = props.templateList.find((item: any) =>
item.level === form.value?.change_level &&
item.category === form.value?.change_type &&
item.duration === form.value?.duration_type
@@ -266,7 +266,7 @@ const typeAi = ref<{ type: string; confidence: number; conclusion: string; hit_r
const typeAiLoading = ref<boolean>(false);
// 打开变更类型抽屉
const openTypeSheet = async () => {
let form = props.formInfo;
const form = props.formInfo;
if (!form?.description) {
return window.$message?.warning("缺少变更描述,请先在 [变更预识别] 里面输入变更描述");
}
@@ -296,7 +296,7 @@ const levelAiBasis = ref<string[]>([]);
const levelAiLoading = ref<boolean>(false);
// 打开等级判定表抽屉
const openLevelSheet = async () => {
let form = props.formInfo;
const form = props.formInfo;
if (!form?.description && props.isAiOpen) {
return window.$message?.warning("缺少变更描述,请先在 [变更预识别] 里面输入变更描述");
}
@@ -305,7 +305,7 @@ const openLevelSheet = async () => {
};
// 使用AI 评分
const useAiLevel = async () => {
let form = props.formInfo;
const form = props.formInfo;
if (levelAiLoading.value) return;
levelAiLoading.value = true;
try {
@@ -447,7 +447,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
</script>
<template>
<div class="p-4">
<div class="p-4">
<div class="space-y-4 scroll">
<!-- 申请部门 / 申请人 -->
<div class="grid gap-4 grid-cols-2">
@@ -482,7 +482,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<!-- 预期效果 -->
<div class="flex gap-3">
<div class="w-24 shrink-0 pt-2 text-sm font-medium text-slate-600 text-right">预期效果</div>
<NInput type="textarea" v-model:value="form.effect" rows="2" placeholder="" />
<NInput v-model:value="form.effect" type="textarea" rows="2" placeholder="" />
</div>
<!-- 主要变更内容 -->
<div class="flex gap-3">
@@ -494,8 +494,8 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<NPopconfirm
v-if="form.main_changes.length > 1"
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="form.main_changes.splice(i, 1)"
>
<template #trigger>
@@ -521,8 +521,8 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<NPopconfirm
v-if="form.related_changes.length > 1"
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="form.related_changes.splice(i, 1)"
>
<template #trigger>
@@ -546,7 +546,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<div class="flex flex-1 items-center gap-4 rounded-lg bg-slate-50 px-3 py-2">
<NRadioGroup v-model:value="form.change_type">
<div class="flex gap-x-2">
<NRadio v-for="t in props.typeList" :key="t.value" :value="t.value">{{t.label}}</NRadio>
<NRadio v-for="t in props.typeList" :key="t.value" :value="t.value">{{ t.label }}</NRadio>
</div>
</NRadioGroup>
<NButton v-if="props.isAiOpen" text type="primary" class="ml-auto text-xs hover:underline" @click="openTypeSheet">
@@ -561,7 +561,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<div class="flex flex-1 items-center gap-4 rounded-lg bg-slate-50 px-3 py-2">
<NRadioGroup v-model:value="form.change_level" disabled>
<div class="flex gap-x-2">
<NRadio v-for="t in props.levelList" :key="t.value" :value="t.value">{{t.label}}</NRadio>
<NRadio v-for="t in props.levelList" :key="t.value" :value="t.value">{{ t.label }}</NRadio>
</div>
</NRadioGroup>
<NButton text type="primary" class="ml-auto text-xs hover:underline" @click="openLevelSheet">
@@ -588,14 +588,15 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<div class="flex gap-3">
<div class="w-24 shrink-0 pt-2 text-sm font-medium text-slate-600 text-right">风险分析</div>
<div class="flex flex-1 flex-wrap items-center gap-2 rounded-lg bg-slate-50 px-3 py-2">
<NButton size="small" round v-for="t in RISK_TOOLS_FORM" :key="t.key" @click="toggleTool(t)" title="点击选用 / 取消;AI 辅助分析在各工具插件内使用"
class="text-sm"
<NButton
v-for="t in RISK_TOOLS_FORM" :key="t.key" size="small" round title="点击选用 / 取消;AI 辅助分析在各工具插件内使用" class="text-sm"
:ghost="form.risk_tools?.includes(t.key) ? false : true"
:type="form.risk_tools?.includes(t.key) ? 'primary' : 'default'"
@click="toggleTool(t)"
>
{{ t.label }}
</NButton>
<NButton type="primary" ghost dashed size="small" round @click="recommendTools" class="text-xs">
<NButton type="primary" ghost dashed size="small" round class="text-xs" @click="recommendTools">
按等级重新推荐
</NButton>
</div>
@@ -623,7 +624,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<div class="w-24 shrink-0 pt-2 text-sm font-medium text-slate-600 text-right">所需材料</div>
<div class="flex-1 space-y-2">
<div class="text-[11px] text-slate-400">施工所需材料(生成变更申请表时系统自动生成,支持手动修改)</div>
<NInput type="textarea" v-model:value="form.materials" rows="4" placeholder="点击「生成变更申请单」后由系统按变更内容自动生成,也可直接填写" />
<NInput v-model:value="form.materials" type="textarea" rows="4" placeholder="点击「生成变更申请单」后由系统按变更内容自动生成,也可直接填写" />
</div>
</div>
<!-- 资料上传 -->
@@ -631,9 +632,9 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<div class="w-24 shrink-0 pt-2 text-sm font-medium text-slate-600 text-right">资料上传</div>
<div class="flex flex-1 flex-wrap items-center gap-2 rounded-lg border border-dashed p-3">
<div
class="relative"
:style="{'--theme-color':themeStore.themeColor}"
v-for="(f,index) in uploadFile" :key="f.id"
v-for="(f,index) in uploadFile"
:key="f.id"
class="relative" :style="{'--theme-color':themeStore.themeColor}"
>
<div
class="text-xs cursor-pointer flex items-center border py-1.5 px-2 rounded-md hover:border-[var(--theme-color)] hover:text-[var(--theme-color)]"
@@ -644,8 +645,8 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
</div>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
:positive-button-props="{ size: 'tiny' }"
:negative-button-props="{ size: 'tiny' }"
@positive-click="removeFile(index)"
>
<template #trigger>
@@ -691,30 +692,30 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
</div>
<div v-if="signers && signers.length" class="mt-1.5 flex flex-wrap items-center gap-1.5 text-xs text-slate-500">
<Icon icon="lucide:users" class="size-12px" />已联动专业会签:
<NTag size="small" type="info" v-for="(p, d) in signers" :key="d">{{ p?.member?.specialty }} · {{ p?.member?.user_name }}{{p?.stepName ? ` (${p.stepName})` : ''}}</NTag>
<NTag v-for="(p, d) in signers" :key="d" size="small" type="info">{{ p?.member?.specialty }} · {{ p?.member?.user_name }}{{ p?.stepName ? ` (${p.stepName})` : '' }}</NTag>
</div>
</div>
</div>
</div>
</div>
<Footer
</div>
<Footer
ref="footerRef"
:type="props.type"
:currentId="props.currentId"
:current-id="props.currentId"
:title="props.title"
:isAiOpen="props.isAiOpen"
:currentForm="form"
:is-ai-open="props.isAiOpen"
:current-form="form"
:confirmed="props.confirmed"
:members="props.members"
:steps="currentSteps"
@save="saveDraft"
@submit="submitConfirm"
@confirmTab="confirmTab"
@confirm-tab="confirmTab"
@regenerate="onRegenerate"
@update:steps="updateSteps"
/>
<!-- 侧边抽屉:AI 类型判定 / 等级判定表 -->
<NDrawer :show="sheet !== ''" @update:show="(v) => !v && (sheet = '')" placement="right" :width="sheet === 'level' ? '45rem' : '28rem'" :auto-focus="false">
/>
<!-- 侧边抽屉:AI 类型判定 / 等级判定表 -->
<NDrawer :show="sheet !== ''" placement="right" :width="sheet === 'level' ? '45rem' : '28rem'" :auto-focus="false" @update:show="(v) => !v && (sheet = '')">
<NDrawerContent>
<template #header>
<div v-if="sheet === 'type'" class="text-base font-semibold text-slate-800">AI 变更类型判定说明</div>
@@ -813,17 +814,17 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
</template>
</div>
</NDrawerContent>
</NDrawer>
</NDrawer>
<!-- 附件在线预览弹窗 -->
<NModal
<!-- 附件在线预览弹窗 -->
<NModal
:show="previewFile !== null"
preset="card"
:auto-focus="false"
:style="{ width: '80%', height: 'auto' }"
:segmented="{ content: true, footer: true }"
@update:show="(v) => !v && (previewFile = null)"
>
>
<template #header>
<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 }}
@@ -836,7 +837,7 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<span>上传时间:{{ previewFile?.created_at }}</span>
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
</div>
<previewComponent v-if="previewFile" :previewFile="previewFile" />
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
</div>
</template>
<template #footer>
@@ -847,8 +848,9 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
<NButton size="small" type="primary" @click="previewFile = null">关闭</NButton>
</div>
</template>
</NModal>
</NModal>
</template>
<style scoped lang="scss">
:deep(.n-radio) {
display: flex;
+1 -1
View File
@@ -5,7 +5,7 @@ import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router';
import { formatTimestamp, getTimeRangeStamp, downloadFileFun } from '@/utils/common';
import previewComponent from '@/components/previewFile/index.vue'
import PreviewComponent from '@/components/previewFile/index.vue'
import { pssrListApi } from '@/service/api/pssr';
const themeStore = useThemeStore();