|
@@ -9,14 +9,20 @@
|
|
|
<span class="file-name">{{ document?.fileName || '未命名文档' }}</span>
|
|
<span class="file-name">{{ document?.fileName || '未命名文档' }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="header-actions">
|
|
<div class="header-actions">
|
|
|
|
|
+ <el-tooltip content="查看文档的历史版本" placement="bottom">
|
|
|
|
|
+ <el-button size="small" @click="handleViewVersions" :loading="loadingVersions">
|
|
|
|
|
+ <el-icon><Clock /></el-icon>
|
|
|
|
|
+ 查看历史版本
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-tooltip>
|
|
|
|
|
+ <el-tooltip content="清空文档中的所有批注" placement="bottom">
|
|
|
|
|
+ <el-button size="small" @click="handleCleanComments" :loading="cleaningComments">
|
|
|
|
|
+ <el-icon><Delete /></el-icon>
|
|
|
|
|
+ 清空批注
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-tooltip>
|
|
|
<el-tooltip content="点击复制签名图片到剪贴板" placement="bottom">
|
|
<el-tooltip content="点击复制签名图片到剪贴板" placement="bottom">
|
|
|
- <el-button
|
|
|
|
|
- type="primary"
|
|
|
|
|
- size="small"
|
|
|
|
|
- @click="handleCopyAvatar"
|
|
|
|
|
- class="copy-avatar-btn"
|
|
|
|
|
- :loading="copyingAvatar"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <el-button type="primary" size="small" @click="handleCopyAvatar" class="copy-avatar-btn" :loading="copyingAvatar">
|
|
|
<el-icon><Picture /></el-icon>
|
|
<el-icon><Picture /></el-icon>
|
|
|
复制签名
|
|
复制签名
|
|
|
</el-button>
|
|
</el-button>
|
|
@@ -25,9 +31,9 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div class="preview-container">
|
|
<div class="preview-container">
|
|
|
<!-- WPS 编辑器容器 -->
|
|
<!-- WPS 编辑器容器 -->
|
|
|
- <div
|
|
|
|
|
- v-if="document?.ossId"
|
|
|
|
|
- ref="wpsContainerRef"
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="document?.ossId"
|
|
|
|
|
+ ref="wpsContainerRef"
|
|
|
class="wps-container"
|
|
class="wps-container"
|
|
|
@dragenter="handleDragEnter"
|
|
@dragenter="handleDragEnter"
|
|
|
@dragleave="handleDragLeave"
|
|
@dragleave="handleDragLeave"
|
|
@@ -41,7 +47,7 @@
|
|
|
<p>松开鼠标插入图片</p>
|
|
<p>松开鼠标插入图片</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<!-- 降级方案:iframe 预览 -->
|
|
<!-- 降级方案:iframe 预览 -->
|
|
|
<iframe v-if="wpsError && document?.url" :src="document.url" class="document-iframe" frameborder="0"></iframe>
|
|
<iframe v-if="wpsError && document?.url" :src="document.url" class="document-iframe" frameborder="0"></iframe>
|
|
|
</div>
|
|
</div>
|
|
@@ -56,7 +62,7 @@
|
|
|
<div v-if="wpsError && !document?.url" class="error-state">
|
|
<div v-if="wpsError && !document?.url" class="error-state">
|
|
|
<el-result icon="error" title="加载失败" :sub-title="wpsError">
|
|
<el-result icon="error" title="加载失败" :sub-title="wpsError">
|
|
|
<template #extra>
|
|
<template #extra>
|
|
|
- <el-button type="primary" @click="initWpsEditor">重新加载</el-button>
|
|
|
|
|
|
|
+ <el-button type="primary" @click="() => initWpsEditor(false)">重新加载</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-result>
|
|
</el-result>
|
|
|
</div>
|
|
</div>
|
|
@@ -148,6 +154,26 @@
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 历史版本对话框 -->
|
|
|
|
|
+ <el-dialog v-model="showVersionDialog" title="历史版本" width="800px" append-to-body destroy-on-close>
|
|
|
|
|
+ <el-table :data="versionList" v-loading="loadingVersions" stripe>
|
|
|
|
|
+ <el-table-column prop="version" label="版本号" width="150" align="center" />
|
|
|
|
|
+ <el-table-column prop="createTime" label="创建时间" min-width="180" align="center" />
|
|
|
|
|
+ <el-table-column prop="updateTime" label="更新时间" min-width="180" align="center" />
|
|
|
|
|
+ <el-table-column label="操作" width="120" align="center" fixed="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-button type="primary" size="small" @click="handleSelectVersion(row.version)">
|
|
|
|
|
+ 选择
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="showVersionDialog = false">关闭</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
@@ -155,9 +181,9 @@ import { ref, reactive, watch, nextTick, onBeforeUnmount } from 'vue';
|
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
import type { FormInstance } from 'element-plus';
|
|
import type { FormInstance } from 'element-plus';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
-import { Document, Edit, InfoFilled, CircleCheck, CircleClose, Close, Check, Loading, Upload, Picture } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
+import { Document, Edit, InfoFilled, CircleCheck, CircleClose, Close, Check, Loading, Upload, Picture, Delete, Clock } from '@element-plus/icons-vue';
|
|
|
import { useUserStore } from '@/store/modules/user';
|
|
import { useUserStore } from '@/store/modules/user';
|
|
|
-import { getSignature, downloadSignature, updateDocumentVersion } from '@/api/system/signature';
|
|
|
|
|
|
|
+import { cleanDocumentComments, getFileVersionList, getFinalFile, initWpsDocument, cancelWpsDocument, type FileVersion } from '@/api/wps/save';
|
|
|
|
|
|
|
|
interface Document {
|
|
interface Document {
|
|
|
id: number | string;
|
|
id: number | string;
|
|
@@ -171,18 +197,18 @@ interface AuditData {
|
|
|
documentId: number | string;
|
|
documentId: number | string;
|
|
|
result: number;
|
|
result: number;
|
|
|
rejectReason?: string;
|
|
rejectReason?: string;
|
|
|
|
|
+ ossId?: number | string; // 最终的 ossId
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
interface Props {
|
|
interface Props {
|
|
|
modelValue: boolean;
|
|
modelValue: boolean;
|
|
|
document?: Document | null;
|
|
document?: Document | null;
|
|
|
title?: string;
|
|
title?: string;
|
|
|
- auditApi: (data: AuditData) => Promise<any>;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
interface Emits {
|
|
interface Emits {
|
|
|
(e: 'update:modelValue', value: boolean): void;
|
|
(e: 'update:modelValue', value: boolean): void;
|
|
|
- (e: 'success'): void;
|
|
|
|
|
|
|
+ (e: 'submit', data: AuditData): void; // 提交审核数据
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const props = defineProps<Props>();
|
|
const props = defineProps<Props>();
|
|
@@ -201,11 +227,16 @@ const wpsLoading = ref(false);
|
|
|
const wpsError = ref('');
|
|
const wpsError = ref('');
|
|
|
const isDragging = ref(false);
|
|
const isDragging = ref(false);
|
|
|
const copyingAvatar = ref(false);
|
|
const copyingAvatar = ref(false);
|
|
|
|
|
+const cleaningComments = ref(false);
|
|
|
|
|
+const currentVersion = ref(1); // 当前文档版本号
|
|
|
|
|
+const showVersionDialog = ref(false); // 显示历史版本对话框
|
|
|
|
|
+const versionList = ref<FileVersion[]>([]); // 历史版本列表
|
|
|
|
|
+const loadingVersions = ref(false); // 加载历史版本中
|
|
|
let wpsInstance: any = null;
|
|
let wpsInstance: any = null;
|
|
|
let dragCounter = 0; // 用于跟踪拖拽进入/离开次数
|
|
let dragCounter = 0; // 用于跟踪拖拽进入/离开次数
|
|
|
|
|
|
|
|
// WPS 配置
|
|
// WPS 配置
|
|
|
-const WPS_APP_ID = 'SX20251229FLIAPD';
|
|
|
|
|
|
|
+const WPS_APP_ID = 'SX20260105YMMIXV';
|
|
|
|
|
|
|
|
// 审核表单数据
|
|
// 审核表单数据
|
|
|
const auditForm = ref({
|
|
const auditForm = ref({
|
|
@@ -243,7 +274,8 @@ const getFileType = (fileName: string) => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 初始化 WPS 编辑器
|
|
// 初始化 WPS 编辑器
|
|
|
-const initWpsEditor = async () => {
|
|
|
|
|
|
|
+// shouldCallInitApi: 是否需要调用后端初始化接口(只在 dialog 首次打开时为 true)
|
|
|
|
|
+const initWpsEditor = async (shouldCallInitApi = false) => {
|
|
|
if (!wpsContainerRef.value || !props.document?.ossId) {
|
|
if (!wpsContainerRef.value || !props.document?.ossId) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -262,15 +294,44 @@ const initWpsEditor = async () => {
|
|
|
const WebOfficeSDK = (window as any).WebOfficeSDK;
|
|
const WebOfficeSDK = (window as any).WebOfficeSDK;
|
|
|
|
|
|
|
|
// 获取文件类型
|
|
// 获取文件类型
|
|
|
- const officeType = getFileType(props.document.fileName || '');
|
|
|
|
|
|
|
+ const officeType = getFileType(props.document.fileName || '', props.document.url);
|
|
|
|
|
+
|
|
|
|
|
+ // 只在 dialog 首次打开时调用后端接口初始化文档
|
|
|
|
|
+ if (shouldCallInitApi) {
|
|
|
|
|
+ console.log('[WPS] 调用后端初始化接口,ossId:', props.document.ossId);
|
|
|
|
|
+ try {
|
|
|
|
|
+ const initRes = await initWpsDocument(props.document.ossId);
|
|
|
|
|
+ const backendVersion = initRes.data; // data 直接是版本号
|
|
|
|
|
+ currentVersion.value = backendVersion;
|
|
|
|
|
+ console.log('[WPS] 后端返回版本号:', backendVersion);
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ console.error('[WPS] 调用后端初始化接口失败:', err);
|
|
|
|
|
+ wpsLoading.value = false;
|
|
|
|
|
+ wpsError.value = '初始化文档失败';
|
|
|
|
|
+
|
|
|
|
|
+ // 显示错误提示
|
|
|
|
|
+ ElMessage.error('初始化文档失败: ' + (err.message || '未知错误'));
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭对话框
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ dialogVisible.value = false;
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
+
|
|
|
|
|
+ return; // 终止初始化流程
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log('[WPS] 使用当前版本号重新初始化编辑器,版本:', currentVersion.value);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 使用原始文档 ID(不添加时间戳)
|
|
|
|
|
- const fileId = `${props.document.id}`;
|
|
|
|
|
|
|
+ // 使用 ossId + 当前版本号组成 fileId
|
|
|
|
|
+ const fileId = `${props.document.ossId}_${currentVersion.value}`;
|
|
|
|
|
|
|
|
console.log('[WPS] 初始化配置:', {
|
|
console.log('[WPS] 初始化配置:', {
|
|
|
appId: WPS_APP_ID,
|
|
appId: WPS_APP_ID,
|
|
|
officeType: officeType,
|
|
officeType: officeType,
|
|
|
fileId: fileId,
|
|
fileId: fileId,
|
|
|
|
|
+ ossId: props.document.ossId,
|
|
|
|
|
+ version: currentVersion.value,
|
|
|
fileName: props.document.fileName,
|
|
fileName: props.document.fileName,
|
|
|
fileUrl: props.document.url
|
|
fileUrl: props.document.url
|
|
|
});
|
|
});
|
|
@@ -283,7 +344,9 @@ const initWpsEditor = async () => {
|
|
|
fileId: fileId,
|
|
fileId: fileId,
|
|
|
|
|
|
|
|
// 可选参数
|
|
// 可选参数
|
|
|
- mount: wpsContainerRef.value
|
|
|
|
|
|
|
+ mount: wpsContainerRef.value,
|
|
|
|
|
+ // 指定当前用户ID为编辑者ID
|
|
|
|
|
+ userId: String(userStore.userId)
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 初始化 WPS 编辑器
|
|
// 初始化 WPS 编辑器
|
|
@@ -356,50 +419,50 @@ const handleDragOver = (e: DragEvent) => {
|
|
|
const handleDrop = async (e: DragEvent) => {
|
|
const handleDrop = async (e: DragEvent) => {
|
|
|
e.preventDefault();
|
|
e.preventDefault();
|
|
|
e.stopPropagation();
|
|
e.stopPropagation();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
isDragging.value = false;
|
|
isDragging.value = false;
|
|
|
dragCounter = 0;
|
|
dragCounter = 0;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!wpsInstance) {
|
|
if (!wpsInstance) {
|
|
|
ElMessage.warning('WPS 编辑器未初始化');
|
|
ElMessage.warning('WPS 编辑器未初始化');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 处理图片拖放
|
|
// 处理图片拖放
|
|
|
const files = e.dataTransfer?.files;
|
|
const files = e.dataTransfer?.files;
|
|
|
if (!files || files.length === 0) {
|
|
if (!files || files.length === 0) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 只处理第一个文件
|
|
// 只处理第一个文件
|
|
|
const file = files[0];
|
|
const file = files[0];
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 检查是否是图片
|
|
// 检查是否是图片
|
|
|
if (!file.type.startsWith('image/')) {
|
|
if (!file.type.startsWith('image/')) {
|
|
|
ElMessage.warning('只支持插入图片文件');
|
|
ElMessage.warning('只支持插入图片文件');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
console.log('[WPS] 开始插入图片:', file.name);
|
|
console.log('[WPS] 开始插入图片:', file.name);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 读取图片为 base64
|
|
// 读取图片为 base64
|
|
|
const reader = new FileReader();
|
|
const reader = new FileReader();
|
|
|
reader.onload = async (event) => {
|
|
reader.onload = async (event) => {
|
|
|
const base64 = event.target?.result as string;
|
|
const base64 = event.target?.result as string;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
// 获取 WPS Application 对象
|
|
// 获取 WPS Application 对象
|
|
|
const app = await wpsInstance.Application;
|
|
const app = await wpsInstance.Application;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!app) {
|
|
if (!app) {
|
|
|
ElMessage.error('无法获取 WPS Application 对象');
|
|
ElMessage.error('无法获取 WPS Application 对象');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 根据文件类型插入图片
|
|
// 根据文件类型插入图片
|
|
|
const officeType = getFileType(props.document?.fileName || '');
|
|
const officeType = getFileType(props.document?.fileName || '');
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (officeType === 'w') {
|
|
if (officeType === 'w') {
|
|
|
// Word 文档:插入图片到光标位置
|
|
// Word 文档:插入图片到光标位置
|
|
|
const selection = await app.ActiveDocument.Application.Selection;
|
|
const selection = await app.ActiveDocument.Application.Selection;
|
|
@@ -421,20 +484,19 @@ const handleDrop = async (e: DragEvent) => {
|
|
|
} else {
|
|
} else {
|
|
|
ElMessage.warning('当前文档类型不支持插入图片');
|
|
ElMessage.warning('当前文档类型不支持插入图片');
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
console.log('[WPS] 图片插入成功');
|
|
console.log('[WPS] 图片插入成功');
|
|
|
} catch (err: any) {
|
|
} catch (err: any) {
|
|
|
console.error('[WPS] 插入图片失败:', err);
|
|
console.error('[WPS] 插入图片失败:', err);
|
|
|
ElMessage.error('插入图片失败: ' + err.message);
|
|
ElMessage.error('插入图片失败: ' + err.message);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
reader.onerror = () => {
|
|
reader.onerror = () => {
|
|
|
ElMessage.error('读取图片文件失败');
|
|
ElMessage.error('读取图片文件失败');
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
reader.readAsDataURL(file);
|
|
reader.readAsDataURL(file);
|
|
|
-
|
|
|
|
|
} catch (err: any) {
|
|
} catch (err: any) {
|
|
|
console.error('[WPS] 处理拖放失败:', err);
|
|
console.error('[WPS] 处理拖放失败:', err);
|
|
|
ElMessage.error('处理拖放失败');
|
|
ElMessage.error('处理拖放失败');
|
|
@@ -444,123 +506,278 @@ const handleDrop = async (e: DragEvent) => {
|
|
|
// 复制头像到剪贴板
|
|
// 复制头像到剪贴板
|
|
|
const handleCopyAvatar = async () => {
|
|
const handleCopyAvatar = async () => {
|
|
|
try {
|
|
try {
|
|
|
|
|
+ // 先让用户选择审核结果
|
|
|
|
|
+ let reviewResult: string;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm(
|
|
|
|
|
+ t('document.document.copySignature.selectResultMessage'),
|
|
|
|
|
+ t('document.document.copySignature.selectResult'),
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: t('document.document.copySignature.pass'),
|
|
|
|
|
+ cancelButtonText: t('document.document.copySignature.reject'),
|
|
|
|
|
+ distinguishCancelAndClose: true,
|
|
|
|
|
+ closeOnClickModal: false,
|
|
|
|
|
+ closeOnPressEscape: false,
|
|
|
|
|
+ type: 'info'
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ // 点击确认按钮 = 通过
|
|
|
|
|
+ reviewResult = 'pass';
|
|
|
|
|
+ } catch (action) {
|
|
|
|
|
+ if (action === 'cancel') {
|
|
|
|
|
+ // 点击取消按钮 = 驳回
|
|
|
|
|
+ reviewResult = 'reject';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 点击关闭或按 ESC = 取消操作
|
|
|
|
|
+ console.log('[签名] 用户取消选择');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
copyingAvatar.value = true;
|
|
copyingAvatar.value = true;
|
|
|
- console.log('[签名] 开始获取签名信息');
|
|
|
|
|
|
|
+ console.log('[签名] 开始生成审核信息图片,审核结果:', reviewResult);
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前用户昵称
|
|
|
|
|
+ const reviewerName = userStore.nickname || userStore.name || t('document.document.copySignature.unknown');
|
|
|
|
|
|
|
|
- // 1. 调用获取签名接口
|
|
|
|
|
- const signatureRes = await getSignature();
|
|
|
|
|
- const ossId = signatureRes.data.id;
|
|
|
|
|
|
|
+ // 获取当前时间
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ const year = now.getFullYear();
|
|
|
|
|
+ const month = now.getMonth() + 1;
|
|
|
|
|
+ const day = now.getDate();
|
|
|
|
|
+ const hour = now.getHours();
|
|
|
|
|
+ const minute = now.getMinutes();
|
|
|
|
|
+ const reviewTime = t('document.document.copySignature.timeFormat', { year, month, day, hour, minute });
|
|
|
|
|
|
|
|
- if (!ossId) {
|
|
|
|
|
- ElMessage.warning('未找到签名图片');
|
|
|
|
|
|
|
+ // 审核结果文本
|
|
|
|
|
+ const resultText = reviewResult === 'pass'
|
|
|
|
|
+ ? t('document.document.copySignature.passText')
|
|
|
|
|
+ : t('document.document.copySignature.rejectText');
|
|
|
|
|
+
|
|
|
|
|
+ // 根据审核结果确定颜色
|
|
|
|
|
+ const color = reviewResult === 'pass' ? '#00aa00' : '#ff0000';
|
|
|
|
|
+
|
|
|
|
|
+ console.log('[签名] 审核结果:', reviewResult, '颜色:', color, '结果文本:', resultText);
|
|
|
|
|
+
|
|
|
|
|
+ // 创建 canvas
|
|
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
|
|
+
|
|
|
|
|
+ if (!ctx) {
|
|
|
|
|
+ ElMessage.error(t('document.document.copySignature.canvasNotSupported'));
|
|
|
|
|
+ copyingAvatar.value = false;
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 设置 canvas 尺寸
|
|
|
|
|
+ const width = 300;
|
|
|
|
|
+ const height = 100;
|
|
|
|
|
+ canvas.width = width;
|
|
|
|
|
+ canvas.height = height;
|
|
|
|
|
+
|
|
|
|
|
+ // 不填充背景,保持透明
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制边框(5px 粗,根据审核结果变色)
|
|
|
|
|
+ ctx.strokeStyle = color;
|
|
|
|
|
+ ctx.lineWidth = 5;
|
|
|
|
|
+ ctx.strokeRect(2.5, 2.5, width - 5, height - 5);
|
|
|
|
|
+
|
|
|
|
|
+ // 设置字体样式(根据审核结果变色)
|
|
|
|
|
+ ctx.fillStyle = color;
|
|
|
|
|
+ ctx.textBaseline = 'middle';
|
|
|
|
|
+
|
|
|
|
|
+ // 第一行:审核人(左边)和审核结果(右边)
|
|
|
|
|
+ ctx.font = 'bold 18px Arial, "Microsoft YaHei", sans-serif';
|
|
|
|
|
+ const reviewerText = t('document.document.copySignature.reviewer', { name: reviewerName });
|
|
|
|
|
+ ctx.fillText(reviewerText, 20, height / 3);
|
|
|
|
|
|
|
|
- console.log('[签名] 签名 OSS ID:', ossId);
|
|
|
|
|
-
|
|
|
|
|
- // 2. 下载签名图片
|
|
|
|
|
- console.log('[签名] 开始下载签名图片');
|
|
|
|
|
- const blob = await downloadSignature(ossId);
|
|
|
|
|
|
|
+ // 审核结果靠右显示
|
|
|
|
|
+ const resultWidth = ctx.measureText(resultText).width;
|
|
|
|
|
+ ctx.fillText(resultText, width - resultWidth - 20, height / 3);
|
|
|
|
|
+
|
|
|
|
|
+ // 第二行:审核时间(居左对齐,加粗)
|
|
|
|
|
+ ctx.font = 'bold 16px Arial, "Microsoft YaHei", sans-serif';
|
|
|
|
|
+ const line2 = t('document.document.copySignature.reviewTime', { time: reviewTime });
|
|
|
|
|
+ ctx.fillText(line2, 20, height * 2 / 3);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('[签名] Canvas 绘制完成');
|
|
|
|
|
+
|
|
|
|
|
+ // 将 canvas 转换为 Blob
|
|
|
|
|
+ canvas.toBlob(async (blob) => {
|
|
|
|
|
+ if (!blob) {
|
|
|
|
|
+ ElMessage.error(t('document.document.copySignature.generateFailed'));
|
|
|
|
|
+ copyingAvatar.value = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log('[签名] 图片生成成功,大小:', blob.size);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 复制到剪贴板
|
|
|
|
|
+ await navigator.clipboard.write([
|
|
|
|
|
+ new ClipboardItem({
|
|
|
|
|
+ 'image/png': blob
|
|
|
|
|
+ })
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ ElMessage({
|
|
|
|
|
+ type: 'success',
|
|
|
|
|
+ message: t('document.document.copySignature.copySuccess'),
|
|
|
|
|
+ duration: 3000
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 显示使用提示
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ ElMessage({
|
|
|
|
|
+ type: 'info',
|
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
|
+ message: t('document.document.copySignature.usageHint'),
|
|
|
|
|
+ duration: 6000,
|
|
|
|
|
+ showClose: true
|
|
|
|
|
+ });
|
|
|
|
|
+ }, 500);
|
|
|
|
|
+
|
|
|
|
|
+ console.log('[签名] 复制成功');
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ console.error('[签名] 复制失败:', err);
|
|
|
|
|
+
|
|
|
|
|
+ // 根据错误类型显示不同提示
|
|
|
|
|
+ if (err.message?.includes('clipboard') || err.message?.includes('Clipboard')) {
|
|
|
|
|
+ ElMessage({
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
|
+ message: t('document.document.copySignature.browserNotSupported'),
|
|
|
|
|
+ duration: 6000,
|
|
|
|
|
+ showClose: true
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage({
|
|
|
|
|
+ type: 'error',
|
|
|
|
|
+ message: t('document.document.copySignature.copyFailed', { error: err.message || t('document.document.copySignature.unknownError') }),
|
|
|
|
|
+ duration: 5000
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ copyingAvatar.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 'image/png');
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ console.error('[签名] 生成图片失败:', err);
|
|
|
|
|
+ ElMessage.error(t('document.document.copySignature.generateFailed') + ': ' + (err.message || t('document.document.copySignature.unknownError')));
|
|
|
|
|
+ copyingAvatar.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 清空批注
|
|
|
|
|
+const handleCleanComments = async () => {
|
|
|
|
|
+ if (!props.document?.id || !props.document?.ossId) {
|
|
|
|
|
+ ElMessage.warning('文档信息不完整');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm(
|
|
|
|
|
+ '确定要清空文档中的所有批注吗?此操作不可恢复。',
|
|
|
|
|
+ '清空批注',
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ cleaningComments.value = true;
|
|
|
|
|
+ console.log('[清空批注] 开始清空文档批注,文档ID:', props.document.id, 'ossId:', props.document.ossId, '当前版本:', currentVersion.value);
|
|
|
|
|
+
|
|
|
|
|
+ await cleanDocumentComments(props.document.ossId);
|
|
|
|
|
+
|
|
|
|
|
+ ElMessage.success('批注已清空');
|
|
|
|
|
+ console.log('[清空批注] 批注清空成功');
|
|
|
|
|
+
|
|
|
|
|
+ // 版本号递增
|
|
|
|
|
+ currentVersion.value += 1;
|
|
|
|
|
+ console.log('[清空批注] 版本号递增至:', currentVersion.value);
|
|
|
|
|
+
|
|
|
|
|
+ // 销毁当前 WPS 编辑器
|
|
|
|
|
+ destroyWpsEditor();
|
|
|
|
|
|
|
|
- console.log('[签名] 图片下载成功,大小:', blob.size, '原始类型:', blob.type);
|
|
|
|
|
|
|
+ // 等待 DOM 更新
|
|
|
|
|
+ await nextTick();
|
|
|
|
|
|
|
|
- // 3. 检测图片真实类型并转换 Blob
|
|
|
|
|
- let imageBlob = blob;
|
|
|
|
|
- let mimeType = blob.type;
|
|
|
|
|
|
|
+ // 使用新版本号重新初始化 WPS 编辑器(不调用后端初始化接口)
|
|
|
|
|
+ await initWpsEditor(false);
|
|
|
|
|
|
|
|
- // 如果是 application/octet-stream,需要检测真实的图片类型
|
|
|
|
|
- if (mimeType === 'application/octet-stream' || !mimeType.startsWith('image/')) {
|
|
|
|
|
- console.log('[签名] 检测到非图片 MIME 类型,尝试转换');
|
|
|
|
|
-
|
|
|
|
|
- // 通过读取文件头来判断图片类型
|
|
|
|
|
- const arrayBuffer = await blob.arrayBuffer();
|
|
|
|
|
- const uint8Array = new Uint8Array(arrayBuffer);
|
|
|
|
|
-
|
|
|
|
|
- // 检测文件头
|
|
|
|
|
- if (uint8Array[0] === 0xFF && uint8Array[1] === 0xD8 && uint8Array[2] === 0xFF) {
|
|
|
|
|
- mimeType = 'image/jpeg';
|
|
|
|
|
- } else if (uint8Array[0] === 0x89 && uint8Array[1] === 0x50 && uint8Array[2] === 0x4E && uint8Array[3] === 0x47) {
|
|
|
|
|
- mimeType = 'image/png';
|
|
|
|
|
- } else if (uint8Array[0] === 0x47 && uint8Array[1] === 0x49 && uint8Array[2] === 0x46) {
|
|
|
|
|
- mimeType = 'image/gif';
|
|
|
|
|
- } else if (uint8Array[0] === 0x42 && uint8Array[1] === 0x4D) {
|
|
|
|
|
- mimeType = 'image/bmp';
|
|
|
|
|
- } else if (uint8Array[0] === 0x52 && uint8Array[1] === 0x49 && uint8Array[2] === 0x46 && uint8Array[3] === 0x46) {
|
|
|
|
|
- mimeType = 'image/webp';
|
|
|
|
|
- } else {
|
|
|
|
|
- // 默认使用 PNG
|
|
|
|
|
- mimeType = 'image/png';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- console.log('[签名] 检测到的图片类型:', mimeType);
|
|
|
|
|
-
|
|
|
|
|
- // 创建新的 Blob,使用正确的 MIME 类型
|
|
|
|
|
- imageBlob = new Blob([arrayBuffer], { type: mimeType });
|
|
|
|
|
|
|
+ console.log('[清空批注] WPS 编辑器已使用新版本重新初始化,fileId:', `${props.document.ossId}_${currentVersion.value}`);
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ if (err === 'cancel') {
|
|
|
|
|
+ console.log('[清空批注] 用户取消操作');
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ console.error('[清空批注] 清空失败:', err);
|
|
|
|
|
+ ElMessage.error('清空批注失败: ' + (err.message || '未知错误'));
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ cleaningComments.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 查看历史版本
|
|
|
|
|
+const handleViewVersions = async () => {
|
|
|
|
|
+ if (!props.document?.ossId) {
|
|
|
|
|
+ ElMessage.warning('文档信息不完整');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ loadingVersions.value = true;
|
|
|
|
|
+ showVersionDialog.value = true;
|
|
|
|
|
|
|
|
- console.log('[签名] 最终 MIME 类型:', imageBlob.type);
|
|
|
|
|
|
|
+ console.log('[历史版本] 获取历史版本列表,ossId:', props.document.ossId);
|
|
|
|
|
|
|
|
- // 4. 复制到剪贴板
|
|
|
|
|
- await navigator.clipboard.write([
|
|
|
|
|
- new ClipboardItem({
|
|
|
|
|
- [imageBlob.type]: imageBlob
|
|
|
|
|
- })
|
|
|
|
|
- ]);
|
|
|
|
|
|
|
+ const res = await getFileVersionList(props.document.ossId);
|
|
|
|
|
+ versionList.value = res.data || [];
|
|
|
|
|
|
|
|
- ElMessage({
|
|
|
|
|
- type: 'success',
|
|
|
|
|
- message: '签名图片已复制到剪贴板',
|
|
|
|
|
- duration: 3000
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ console.log('[历史版本] 获取成功,版本数量:', versionList.value.length);
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ console.error('[历史版本] 获取失败:', err);
|
|
|
|
|
+ ElMessage.error('获取历史版本失败: ' + (err.message || '未知错误'));
|
|
|
|
|
+ showVersionDialog.value = false;
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loadingVersions.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 选择历史版本
|
|
|
|
|
+const handleSelectVersion = async (version: number) => {
|
|
|
|
|
+ if (!props.document?.ossId) {
|
|
|
|
|
+ ElMessage.warning('文档信息不完整');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ console.log('[历史版本] 选择版本:', version, 'ossId:', props.document.ossId);
|
|
|
|
|
|
|
|
- // 显示使用提示
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- ElMessage({
|
|
|
|
|
- type: 'info',
|
|
|
|
|
- dangerouslyUseHTMLString: true,
|
|
|
|
|
- message: `
|
|
|
|
|
- <div style="text-align: left;">
|
|
|
|
|
- <p style="margin: 0 0 8px 0; font-weight: bold;">请按以下步骤操作:</p>
|
|
|
|
|
- <p style="margin: 0 0 4px 0;">• <strong>PDF</strong>:使用批注工具 → 选择图片 → 粘贴</p>
|
|
|
|
|
- <p style="margin: 0 0 4px 0;">• <strong>Word/Excel/PPT</strong>:在文档中按 Ctrl+V 粘贴</p>
|
|
|
|
|
- <p style="margin: 0;">• 或者直接拖拽外部图片到文档中</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- `,
|
|
|
|
|
- duration: 6000,
|
|
|
|
|
- showClose: true
|
|
|
|
|
- });
|
|
|
|
|
- }, 500);
|
|
|
|
|
|
|
+ // 更新当前版本号
|
|
|
|
|
+ currentVersion.value = version;
|
|
|
|
|
|
|
|
- console.log('[签名] 复制成功');
|
|
|
|
|
- } catch (err: any) {
|
|
|
|
|
- console.error('[签名] 复制失败:', err);
|
|
|
|
|
|
|
+ // 关闭历史版本对话框
|
|
|
|
|
+ showVersionDialog.value = false;
|
|
|
|
|
|
|
|
- // 根据错误类型显示不同提示
|
|
|
|
|
- if (err.message?.includes('clipboard') || err.message?.includes('Clipboard')) {
|
|
|
|
|
- ElMessage({
|
|
|
|
|
- type: 'warning',
|
|
|
|
|
- dangerouslyUseHTMLString: true,
|
|
|
|
|
- message: `
|
|
|
|
|
- <div style="text-align: left;">
|
|
|
|
|
- <p style="margin: 0 0 4px 0;">浏览器不支持复制图片,请尝试以下方法:</p>
|
|
|
|
|
- <p style="margin: 0 0 4px 0;">1. 使用 Chrome 或 Edge 浏览器</p>
|
|
|
|
|
- <p style="margin: 0;">2. 或者使用 WPS 的插入图片功能</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- `,
|
|
|
|
|
- duration: 6000,
|
|
|
|
|
- showClose: true
|
|
|
|
|
- });
|
|
|
|
|
- } else if (err.response?.status === 404) {
|
|
|
|
|
- ElMessage.warning('未找到签名图片,请先设置签名');
|
|
|
|
|
- } else {
|
|
|
|
|
- ElMessage({
|
|
|
|
|
- type: 'error',
|
|
|
|
|
- message: '获取签名失败: ' + (err.message || '未知错误'),
|
|
|
|
|
- duration: 5000
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- } finally {
|
|
|
|
|
- copyingAvatar.value = false;
|
|
|
|
|
|
|
+ // 销毁当前 WPS 编辑器
|
|
|
|
|
+ destroyWpsEditor();
|
|
|
|
|
+
|
|
|
|
|
+ // 等待 DOM 更新
|
|
|
|
|
+ await nextTick();
|
|
|
|
|
+
|
|
|
|
|
+ // 使用选择的版本号重新初始化 WPS 编辑器(不调用后端初始化接口)
|
|
|
|
|
+ await initWpsEditor(false);
|
|
|
|
|
+
|
|
|
|
|
+ ElMessage.success(`已切换到版本 ${version}`);
|
|
|
|
|
+ console.log('[历史版本] WPS 编辑器已切换到版本:', version, 'fileId:', `${props.document.ossId}_${version}`);
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ console.error('[历史版本] 切换版本失败:', err);
|
|
|
|
|
+ ElMessage.error('切换版本失败: ' + (err.message || '未知错误'));
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -570,6 +787,9 @@ watch(
|
|
|
(val) => {
|
|
(val) => {
|
|
|
dialogVisible.value = val;
|
|
dialogVisible.value = val;
|
|
|
if (val && props.document) {
|
|
if (val && props.document) {
|
|
|
|
|
+ // 重置版本号为 1
|
|
|
|
|
+ currentVersion.value = 1;
|
|
|
|
|
+
|
|
|
auditForm.value = {
|
|
auditForm.value = {
|
|
|
id: props.document.id,
|
|
id: props.document.id,
|
|
|
result: '3',
|
|
result: '3',
|
|
@@ -577,9 +797,10 @@ watch(
|
|
|
};
|
|
};
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
auditFormRef.value?.clearValidate();
|
|
auditFormRef.value?.clearValidate();
|
|
|
- // 自动初始化 WPS 编辑器
|
|
|
|
|
|
|
+ // 自动初始化 WPS 编辑器,使用版本号 1(调用后端初始化接口)
|
|
|
if (props.document?.ossId) {
|
|
if (props.document?.ossId) {
|
|
|
- initWpsEditor();
|
|
|
|
|
|
|
+ console.log('[WPS] 对话框打开,初始化编辑器,版本号:', currentVersion.value);
|
|
|
|
|
+ initWpsEditor(true);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
@@ -587,14 +808,28 @@ watch(
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
// 监听dialogVisible变化
|
|
// 监听dialogVisible变化
|
|
|
-watch(dialogVisible, (val) => {
|
|
|
|
|
|
|
+watch(dialogVisible, async (val) => {
|
|
|
emit('update:modelValue', val);
|
|
emit('update:modelValue', val);
|
|
|
if (!val) {
|
|
if (!val) {
|
|
|
|
|
+ // 对话框关闭时,调用取消接口
|
|
|
|
|
+ if (props.document?.ossId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ console.log('[WPS] 对话框关闭,调用取消接口,ossId:', props.document.ossId);
|
|
|
|
|
+ await cancelWpsDocument(props.document.ossId);
|
|
|
|
|
+ console.log('[WPS] 取消接口调用成功');
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error('[WPS] 取消接口调用失败:', err);
|
|
|
|
|
+ // 取消接口失败不影响关闭流程
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
auditForm.value = {
|
|
auditForm.value = {
|
|
|
id: 0,
|
|
id: 0,
|
|
|
result: '3',
|
|
result: '3',
|
|
|
reason: ''
|
|
reason: ''
|
|
|
};
|
|
};
|
|
|
|
|
+ // 关闭对话框时重置版本号
|
|
|
|
|
+ currentVersion.value = 1;
|
|
|
destroyWpsEditor();
|
|
destroyWpsEditor();
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -616,34 +851,49 @@ const submitForm = () => {
|
|
|
try {
|
|
try {
|
|
|
savedFileInfo = await saveWpsDocument();
|
|
savedFileInfo = await saveWpsDocument();
|
|
|
if (savedFileInfo) {
|
|
if (savedFileInfo) {
|
|
|
- console.log('文档保存成功:', savedFileInfo);
|
|
|
|
|
|
|
+ console.log('[审核提交] 文档保存成功:', savedFileInfo);
|
|
|
ElMessage.success('文档已保存');
|
|
ElMessage.success('文档已保存');
|
|
|
}
|
|
}
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- console.error('保存文档失败:', err);
|
|
|
|
|
|
|
+ console.error('[审核提交] 保存文档失败:', err);
|
|
|
ElMessage.warning('文档保存失败,将继续提交审核');
|
|
ElMessage.warning('文档保存失败,将继续提交审核');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 获取当前 fileId
|
|
|
|
|
+ const currentFileId = `${props.document?.ossId}_${currentVersion.value}`;
|
|
|
|
|
+ console.log('[审核提交] 当前 fileId:', currentFileId);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用接口获取最终文档信息
|
|
|
|
|
+ let finalOssId = props.document?.ossId;
|
|
|
|
|
+ try {
|
|
|
|
|
+ console.log('[审核提交] 获取最终文档信息...');
|
|
|
|
|
+ const finalFileRes = await getFinalFile(currentFileId);
|
|
|
|
|
+ finalOssId = finalFileRes.data.ossId;
|
|
|
|
|
+ console.log('[审核提交] 获取到最终 ossId:', finalOssId);
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error('[审核提交] 获取最终文档信息失败:', err);
|
|
|
|
|
+ ElMessage.warning('获取最终文档信息失败,将使用原始 ossId');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 构建审核数据
|
|
// 构建审核数据
|
|
|
- const auditData: any = {
|
|
|
|
|
|
|
+ const auditData: AuditData = {
|
|
|
documentId: auditForm.value.id,
|
|
documentId: auditForm.value.id,
|
|
|
result: parseInt(auditForm.value.result),
|
|
result: parseInt(auditForm.value.result),
|
|
|
- rejectReason: auditForm.value.reason
|
|
|
|
|
|
|
+ rejectReason: auditForm.value.reason,
|
|
|
|
|
+ ossId: finalOssId // 使用最终的 ossId
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // 添加保存的文件信息
|
|
|
|
|
- if (savedFileInfo) {
|
|
|
|
|
- auditData.fileInfo = savedFileInfo;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await props.auditApi(auditData);
|
|
|
|
|
- ElMessage.success(t('document.document.message.auditSuccess'));
|
|
|
|
|
|
|
+ console.log('[审核提交] 提交审核数据到父组件:', auditData);
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭对话框
|
|
|
dialogVisible.value = false;
|
|
dialogVisible.value = false;
|
|
|
- emit('success');
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 通过 emit 将审核数据传递给父组件
|
|
|
|
|
+ emit('submit', auditData);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error(t('document.document.message.auditFailed'), error);
|
|
|
|
|
- ElMessage.error(t('document.document.message.auditFailed'));
|
|
|
|
|
|
|
+ console.error('[审核提交] 处理失败:', error);
|
|
|
|
|
+ ElMessage.error('处理失败: ' + (error as any).message || '未知错误');
|
|
|
} finally {
|
|
} finally {
|
|
|
loading.value = false;
|
|
loading.value = false;
|
|
|
}
|
|
}
|
|
@@ -728,11 +978,11 @@ onBeforeUnmount(() => {
|
|
|
white-space: nowrap;
|
|
white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.header-actions {
|
|
.header-actions {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
gap: 8px;
|
|
gap: 8px;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.copy-avatar-btn {
|
|
.copy-avatar-btn {
|
|
|
.el-icon {
|
|
.el-icon {
|
|
|
margin-right: 4px;
|
|
margin-right: 4px;
|
|
@@ -760,7 +1010,7 @@ onBeforeUnmount(() => {
|
|
|
height: 100%;
|
|
height: 100%;
|
|
|
border: none;
|
|
border: none;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.drag-overlay {
|
|
.drag-overlay {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
top: 0;
|
|
top: 0;
|
|
@@ -774,16 +1024,16 @@ onBeforeUnmount(() => {
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
z-index: 9999;
|
|
z-index: 9999;
|
|
|
pointer-events: none;
|
|
pointer-events: none;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.drag-hint {
|
|
.drag-hint {
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
.drag-icon {
|
|
.drag-icon {
|
|
|
font-size: 64px;
|
|
font-size: 64px;
|
|
|
color: #409eff;
|
|
color: #409eff;
|
|
|
margin-bottom: 16px;
|
|
margin-bottom: 16px;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
p {
|
|
p {
|
|
|
font-size: 18px;
|
|
font-size: 18px;
|
|
|
font-weight: 500;
|
|
font-weight: 500;
|