|
|
@@ -227,6 +227,7 @@
|
|
|
border
|
|
|
:data="repairOrderList"
|
|
|
@selection-change="handleSelectionChange"
|
|
|
+ @row-dblclick="handleDetail"
|
|
|
style="width: 100%"
|
|
|
:scroll-x="true"
|
|
|
class="scroll-table"
|
|
|
@@ -429,7 +430,7 @@
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 添加或修改报修工单对话框 -->
|
|
|
- <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
|
|
+ <el-dialog :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
|
|
|
<el-form ref="repairOrderFormRef" :model="form" :rules="rules" label-width="120px">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
@@ -529,7 +530,7 @@
|
|
|
:action="uploadAction"
|
|
|
:headers="uploadHeaders"
|
|
|
:data="uploadData"
|
|
|
- :auto-upload="false"
|
|
|
+ :auto-upload="true"
|
|
|
:before-upload="handleBeforeUpload"
|
|
|
:on-success="handleUploadSuccess"
|
|
|
:on-error="handleUploadError"
|
|
|
@@ -545,7 +546,8 @@
|
|
|
<template #tip>
|
|
|
<div class="el-upload__tip">
|
|
|
支持图片、视频、PDF、Word文档等格式,单个文件大小不超过10MB,最多上传15个文件。
|
|
|
- <span class="el-upload__tip" v-if="!form.id" style="color: #ff0000">(新增时文件将在保存工单后上传)</span>
|
|
|
+ <span class="el-upload__tip" v-if="!form.id" style="color: #ff0000">(新增时文件会立即上传,保存工单后自动关联)</span>
|
|
|
+ <span class="el-upload__tip" v-else style="color: #ff0000">(编辑时文件会立即上传并关联到当前工单)</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -569,9 +571,26 @@
|
|
|
/>
|
|
|
<div v-else class="upload-file-placeholder">
|
|
|
<el-icon><Document /></el-icon>
|
|
|
- <span class="file-ext">{{ file.name }}</span>
|
|
|
+ <span class="file-ext">{{ getFileExt(file.name) }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 文件名称 -->
|
|
|
+ <div class="upload-file-name" :title="file.name">
|
|
|
+ {{ file.name }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 操作按钮区域 (与预览界面样式一致) -->
|
|
|
+ <div class="upload-file-card-actions" v-if="file.status && file.status !== 'ready'">
|
|
|
+ <el-button-group size="small">
|
|
|
+ <el-button type="success" @click.stop="handleDownloadAttachment(file)" title="下载" :disabled="file.status !== 'success'">
|
|
|
+ <el-icon><Download /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ <el-button type="danger" @click.stop="handleRemoveAttachmentConfirm(file)" title="删除">
|
|
|
+ <el-icon><Delete /></el-icon>
|
|
|
+ </el-button>
|
|
|
+ </el-button-group>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-upload>
|
|
|
@@ -876,6 +895,8 @@
|
|
|
<p><strong>报修标题:</strong>{{ currentOrder?.title }}</p>
|
|
|
<p><strong>报修地点:</strong>{{ currentOrder?.repairLocation }}</p>
|
|
|
<p><strong>维修类型:</strong>{{ getCategoryNameById(currentOrder?.categoryId) }}</p>
|
|
|
+ <p><strong>问题描述:</strong>{{ currentOrder?.description }}</p>
|
|
|
+ <p><strong>备注信息:</strong>{{ currentOrder?.remark }}</p>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="分派维修员" prop="assigneeId">
|
|
|
@@ -928,7 +949,7 @@
|
|
|
<div class="progress-card">
|
|
|
<div class="progress-header">
|
|
|
<div class="progress-type-status">
|
|
|
- <el-tag :type="getProgressTypeTag(progress.progressType) as any" size="small">
|
|
|
+ <el-tag :type="getProgressTypeTag(progress.progressType)" size="small">
|
|
|
{{ getProgressTypeText(progress.progressType) }}
|
|
|
</el-tag>
|
|
|
<span class="progress-status">{{ progress.progressStatus }}</span>
|
|
|
@@ -997,14 +1018,14 @@
|
|
|
<!-- 进度更新对话框 -->
|
|
|
<el-dialog title="进度更新" v-model="updateProgressDialog.visible" width="600px" append-to-body>
|
|
|
<el-form ref="progressFormRef" :model="progressForm" :rules="progressRules" label-width="120px">
|
|
|
- <el-form-item label="工单编号" prop="orderId">
|
|
|
- <el-input v-model="progressForm.orderId" placeholder="请输入工单编号" />
|
|
|
+ <el-form-item label="工单编号" prop="orderNo">
|
|
|
+ <el-input v-model="progressForm.orderNo" placeholder="请输入工单编号" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="进度类型" prop="progressType">
|
|
|
+ <!-- <el-form-item label="进度类型" prop="progressType">
|
|
|
<el-select v-model="progressForm.progressType" placeholder="请选择进度类型" style="width: 100%">
|
|
|
<el-option v-for="type in progressTypeOptions" :key="type.value" :label="type.label" :value="type.value" />
|
|
|
</el-select>
|
|
|
- </el-form-item>
|
|
|
+ </el-form-item> -->
|
|
|
<el-form-item label="进度状态" prop="progressStatus">
|
|
|
<el-input v-model="progressForm.progressStatus" placeholder="请输入进度状态" />
|
|
|
</el-form-item>
|
|
|
@@ -1041,17 +1062,17 @@
|
|
|
<!-- 完成工单对话框 -->
|
|
|
<el-dialog title="完成工单" v-model="completeDialog.visible" width="600px" append-to-body>
|
|
|
<el-form ref="completeFormRef" :model="completeForm" :rules="completeRules" label-width="120px">
|
|
|
- <el-form-item label="工单编号" prop="orderId">
|
|
|
- <el-input v-model="completeForm.orderId" placeholder="请输入工单编号" />
|
|
|
+ <el-form-item label="工单编号" prop="orderNo">
|
|
|
+ <el-input v-model="completeForm.orderNo" placeholder="请输入工单编号" readonly disabled />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="维修结果" prop="repairResult">
|
|
|
<el-input v-model="completeForm.repairResult" placeholder="请输入维修结果" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="使用材料" prop="usedMaterials">
|
|
|
- <el-input v-model="completeForm.usedMaterials" placeholder="请输入使用材料" />
|
|
|
+ <el-input v-model="completeForm.usedMaterials" type="textarea" placeholder="请输入使用材料" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="后续建议" prop="followSuggestions">
|
|
|
- <el-input v-model="completeForm.followSuggestions" placeholder="请输入后续建议" />
|
|
|
+ <el-input v-model="completeForm.followSuggestions" type="textarea" placeholder="请输入后续建议" />
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
@@ -1206,7 +1227,8 @@ import {
|
|
|
getRepairAttachments,
|
|
|
uploadAttachment,
|
|
|
uploadAttachments,
|
|
|
- deleteAttachment
|
|
|
+ deleteAttachment,
|
|
|
+ batchUpdateAttachmentOrderId
|
|
|
} from '@/api/hq/pm/repairOrder';
|
|
|
import { getRepairCategoryOptions, getRepairCategoryTree } from '@/api/hq/pm/repairCategory';
|
|
|
import {
|
|
|
@@ -1224,7 +1246,7 @@ import {
|
|
|
import { useUserStore } from '@/store/modules/user';
|
|
|
import { getInfo } from '@/api/login'; // 添加获取用户详细信息的API
|
|
|
import { getToken } from '@/utils/auth'; // 修复:添加getToken导入
|
|
|
-import { vLoading } from 'element-plus';
|
|
|
+import { vLoading, ElLoading } from 'element-plus';
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
|
@@ -1266,7 +1288,7 @@ const workerOptions = ref<Array<{ value: string | number; label: string; userNam
|
|
|
|
|
|
// 附件相关数据
|
|
|
const attachmentList = ref<any[]>([]);
|
|
|
-const uploadAction = ref('/dev-api/pm/attachment/upload'); // 修复:添加/dev-api前缀
|
|
|
+const uploadAction = ref('/dev-api/hq/pm/attachment/upload'); // 修复:使用正确的API路径
|
|
|
const uploadHeaders = ref({
|
|
|
'Authorization': `Bearer ${getToken() || ''}`,
|
|
|
'clientid': import.meta.env.VITE_APP_CLIENT_ID || 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
|
|
@@ -1276,6 +1298,12 @@ const uploadData = ref<any>({});
|
|
|
// 新增:临时文件存储,用于新增时收集文件
|
|
|
const tempFileList = ref<File[]>([]);
|
|
|
|
|
|
+// 新增:临时附件ID列表,用于新增时收集已上传附件的ID
|
|
|
+const tempAttachmentIds = ref<string[]>([]);
|
|
|
+
|
|
|
+// 待删除的附件ID列表 (保存时统一删除)
|
|
|
+const pendingDeleteAttachmentIds = ref<string[]>([]);
|
|
|
+
|
|
|
// 字典数据
|
|
|
const pm_priority_level = ref([
|
|
|
{ value: '1', label: '非常紧急' },
|
|
|
@@ -1830,24 +1858,53 @@ const submitForm = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-/** 处理待上传的附件 */
|
|
|
+/** 处理待关联的附件 */
|
|
|
const handlePendingAttachments = async (orderId: string | number) => {
|
|
|
- // 处理临时文件列表(新增时的文件)
|
|
|
- if (tempFileList.value.length > 0) {
|
|
|
+ let hasOperations = false;
|
|
|
+ let successMessages: string[] = [];
|
|
|
+ let errorMessages: string[] = [];
|
|
|
+
|
|
|
+ // 处理待删除的附件(编辑模式)
|
|
|
+ if (pendingDeleteAttachmentIds.value.length > 0) {
|
|
|
try {
|
|
|
- console.log('开始上传临时文件,文件数量:', tempFileList.value.length);
|
|
|
- for (const file of tempFileList.value) {
|
|
|
- await uploadAttachment(String(orderId), '1', file, '');
|
|
|
- console.log('成功上传文件:', file.name);
|
|
|
+ console.log('开始删除标记的附件,数量:', pendingDeleteAttachmentIds.value.length);
|
|
|
+
|
|
|
+ // 批量删除附件
|
|
|
+ for (const attachmentId of pendingDeleteAttachmentIds.value) {
|
|
|
+ await deleteAttachment(attachmentId);
|
|
|
}
|
|
|
- proxy?.$modal.msgSuccess(`成功上传 ${tempFileList.value.length} 个附件`);
|
|
|
|
|
|
- // 清空临时文件列表
|
|
|
+ console.log('成功删除附件IDs:', pendingDeleteAttachmentIds.value);
|
|
|
+ successMessages.push(`成功删除 ${pendingDeleteAttachmentIds.value.length} 个附件`);
|
|
|
+
|
|
|
+ // 清空待删除列表
|
|
|
+ pendingDeleteAttachmentIds.value = [];
|
|
|
+ hasOperations = true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('附件删除失败:', error);
|
|
|
+ errorMessages.push('部分附件删除失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理新增模式下已上传的附件(更新order_id)
|
|
|
+ if (tempAttachmentIds.value.length > 0) {
|
|
|
+ try {
|
|
|
+ console.log('开始关联临时附件到工单,附件数量:', tempAttachmentIds.value.length);
|
|
|
+
|
|
|
+ // 调用API批量更新附件的order_id
|
|
|
+ await batchUpdateAttachmentOrderId(tempAttachmentIds.value, String(orderId));
|
|
|
+ console.log('成功关联附件IDs:', tempAttachmentIds.value, '到工单:', orderId);
|
|
|
+
|
|
|
+ successMessages.push(`成功关联 ${tempAttachmentIds.value.length} 个附件到工单`);
|
|
|
+
|
|
|
+ // 清空临时附件ID列表
|
|
|
+ tempAttachmentIds.value = [];
|
|
|
tempFileList.value = [];
|
|
|
attachmentList.value = [];
|
|
|
+ hasOperations = true;
|
|
|
} catch (error) {
|
|
|
- console.error('附件上传失败:', error);
|
|
|
- proxy?.$modal.msgWarning('工单保存成功,但部分附件上传失败');
|
|
|
+ console.error('附件关联失败:', error);
|
|
|
+ errorMessages.push('部分附件关联失败');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1865,13 +1922,21 @@ const handlePendingAttachments = async (orderId: string | number) => {
|
|
|
fileItem.status = 'success';
|
|
|
}
|
|
|
}
|
|
|
- if (tempFileList.value.length === 0) {
|
|
|
- // 只有当没有临时文件时才显示这个提示,避免重复提示
|
|
|
- proxy?.$modal.msgSuccess(`成功上传 ${newFiles.length} 个新附件`);
|
|
|
- }
|
|
|
+ successMessages.push(`成功上传 ${newFiles.length} 个新附件`);
|
|
|
+ hasOperations = true;
|
|
|
} catch (error) {
|
|
|
console.error('新附件上传失败:', error);
|
|
|
- proxy?.$modal.msgWarning('工单保存成功,但部分新附件上传失败');
|
|
|
+ errorMessages.push('部分新附件上传失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示操作结果消息
|
|
|
+ if (hasOperations) {
|
|
|
+ if (successMessages.length > 0) {
|
|
|
+ proxy?.$modal.msgSuccess(successMessages.join(','));
|
|
|
+ }
|
|
|
+ if (errorMessages.length > 0) {
|
|
|
+ proxy?.$modal.msgWarning(`工单保存成功,但${errorMessages.join(',')}`);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
@@ -2227,16 +2292,27 @@ const handleBeforeUpload = (file: File) => {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // 新增时不直接上传,而是收集文件
|
|
|
- if (!form.value.id) {
|
|
|
- return false; // 阻止自动上传
|
|
|
+ // 设置上传参数
|
|
|
+ const uploadParams: any = {
|
|
|
+ uploadStage: '1', // 报修申请阶段
|
|
|
+ description: `${form.value.title || '报修工单'}相关附件` // 添加描述信息
|
|
|
+ };
|
|
|
+
|
|
|
+ // 只有编辑模式时才传递orderId
|
|
|
+ if (form.value.id) {
|
|
|
+ uploadParams.orderId = form.value.id;
|
|
|
}
|
|
|
|
|
|
- // 编辑时设置上传参数
|
|
|
- uploadData.value = {
|
|
|
- orderId: form.value.id,
|
|
|
- uploadStage: '1' // 报修申请阶段
|
|
|
- };
|
|
|
+ uploadData.value = uploadParams;
|
|
|
+
|
|
|
+ console.log('准备上传文件:', {
|
|
|
+ 文件名: file.name,
|
|
|
+ 文件大小: (file.size / 1024 / 1024).toFixed(2) + 'MB',
|
|
|
+ 工单ID: uploadParams.orderId || '待关联',
|
|
|
+ 上传阶段: uploadParams.uploadStage,
|
|
|
+ 描述: uploadParams.description,
|
|
|
+ 模式: form.value.id ? '编辑模式' : '新增模式'
|
|
|
+ });
|
|
|
|
|
|
return true;
|
|
|
};
|
|
|
@@ -2244,11 +2320,41 @@ const handleBeforeUpload = (file: File) => {
|
|
|
/** 上传成功 */
|
|
|
const handleUploadSuccess = (response: any, file: any) => {
|
|
|
console.log('上传成功:', response, file);
|
|
|
- proxy?.$modal.msgSuccess(`文件 ${file.name} 上传成功`);
|
|
|
|
|
|
- // 更新附件列表
|
|
|
if (response.code === 200) {
|
|
|
- // 这里可以刷新附件列表或更新UI
|
|
|
+ proxy?.$modal.msgSuccess(`文件 ${file.name} 上传成功`);
|
|
|
+
|
|
|
+ // 立即记录附件数据
|
|
|
+ const attachmentData = response.data;
|
|
|
+ if (attachmentData && attachmentData.id) {
|
|
|
+ // 如果是新增模式,收集附件ID到临时列表
|
|
|
+ if (!form.value.id) {
|
|
|
+ tempAttachmentIds.value.push(attachmentData.id);
|
|
|
+ console.log('新增模式:已收集附件ID', attachmentData.id, '当前临时附件ID列表:', tempAttachmentIds.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新文件对象的相关信息
|
|
|
+ file.attachmentId = attachmentData.id;
|
|
|
+ file.status = 'success';
|
|
|
+ file.url = attachmentData.filePath;
|
|
|
+
|
|
|
+ // 如果是编辑模式,附件已经自动关联到工单,直接更新UI
|
|
|
+ if (form.value.id) {
|
|
|
+ console.log('编辑模式:附件已关联到工单', form.value.id, '附件ID:', attachmentData.id);
|
|
|
+ // 可以选择刷新附件列表以确保数据同步
|
|
|
+ // loadAttachments(form.value.id);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('附件记录成功:', {
|
|
|
+ 附件ID: attachmentData.id,
|
|
|
+ 文件名: attachmentData.fileName,
|
|
|
+ 文件路径: attachmentData.filePath,
|
|
|
+ 工单ID: form.value.id || '待关联',
|
|
|
+ 模式: form.value.id ? '编辑' : '新增'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ proxy?.$modal.msgError(`文件 ${file.name} 上传失败: ${response.msg || '未知错误'}`);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -2258,25 +2364,108 @@ const handleUploadError = (error: Error, file: any) => {
|
|
|
proxy?.$modal.msgError(`文件 ${file.name} 上传失败`);
|
|
|
};
|
|
|
|
|
|
-/** 移除附件 */
|
|
|
-const handleRemoveAttachment = async (file: any) => {
|
|
|
- // 如果是已上传的文件(编辑模式下的已有附件)
|
|
|
- if (file.response && file.response.data && file.response.data.id) {
|
|
|
- try {
|
|
|
- await deleteAttachment(file.response.data.id);
|
|
|
- proxy?.$modal.msgSuccess('附件删除成功');
|
|
|
+/** 下载附件 */
|
|
|
+const handleDownloadAttachment = async (file: any) => {
|
|
|
+ let downloadUrl = '';
|
|
|
+ let fileName = file.name || 'attachment';
|
|
|
+
|
|
|
+ // 如果文件已经上传成功,使用服务器返回的路径
|
|
|
+ if (file.response && file.response.data && file.response.data.filePath) {
|
|
|
+ downloadUrl = file.response.data.filePath;
|
|
|
+ fileName = file.response.data.fileName || fileName;
|
|
|
+ }
|
|
|
+ // 如果是已有的附件,使用文件的url
|
|
|
+ else if (file.url) {
|
|
|
+ downloadUrl = file.url;
|
|
|
+ }
|
|
|
+ // 如果是本地文件,直接使用raw文件
|
|
|
+ else if (file.raw) {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = URL.createObjectURL(file.raw);
|
|
|
+ link.download = fileName;
|
|
|
+ link.style.display = 'none';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ URL.revokeObjectURL(link.href);
|
|
|
+ console.log('下载本地文件:', fileName);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // 编辑模式下删除附件后,从attachmentList中移除
|
|
|
- const index = attachmentList.value.findIndex((item) => item.uid === file.uid);
|
|
|
- if (index > -1) {
|
|
|
- attachmentList.value.splice(index, 1);
|
|
|
+ if (!downloadUrl) {
|
|
|
+ proxy?.$modal.msgError('无法获取文件下载地址');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对于服务器文件,使用fetch获取内容强制下载
|
|
|
+ try {
|
|
|
+ const loading = ElLoading.service({
|
|
|
+ text: '正在下载文件...',
|
|
|
+ target: document.body
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await fetch(downloadUrl);
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const blob = await response.blob();
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = fileName;
|
|
|
+ link.style.display = 'none';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+ loading?.close();
|
|
|
+ console.log('下载服务器文件成功:', fileName);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载文件失败:', error);
|
|
|
+ proxy?.$modal.msgError('下载文件失败,请稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除附件确认 */
|
|
|
+const handleRemoveAttachmentConfirm = async (file: any) => {
|
|
|
+ await proxy?.$modal.confirm('确定要删除该附件吗?删除操作将在保存时生效。');
|
|
|
+ handleRemoveAttachment(file);
|
|
|
+};
|
|
|
+
|
|
|
+/** 移除附件 (修改为延迟删除) */
|
|
|
+const handleRemoveAttachment = (file: any) => {
|
|
|
+ // 如果是已上传的文件(编辑模式下的已有附件或新增模式下已上传的附件)
|
|
|
+ if (file.response && file.response.data && file.response.data.id) {
|
|
|
+ // 不立即删除数据库记录,而是标记为待删除
|
|
|
+ const attachmentId = file.response.data.id;
|
|
|
+
|
|
|
+ // 如果是新增模式,从临时附件ID列表中移除
|
|
|
+ if (!form.value.id) {
|
|
|
+ const attachmentIndex = tempAttachmentIds.value.indexOf(attachmentId);
|
|
|
+ if (attachmentIndex > -1) {
|
|
|
+ tempAttachmentIds.value.splice(attachmentIndex, 1);
|
|
|
+ console.log('新增模式:已从临时附件ID列表中移除:', attachmentId, '剩余附件数:', tempAttachmentIds.value.length);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 编辑模式:添加到待删除列表
|
|
|
+ if (!pendingDeleteAttachmentIds.value.includes(attachmentId)) {
|
|
|
+ pendingDeleteAttachmentIds.value.push(attachmentId);
|
|
|
+ console.log('编辑模式:已标记附件为待删除:', attachmentId, '待删除列表:', pendingDeleteAttachmentIds.value);
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('删除附件失败:', error);
|
|
|
- proxy?.$modal.msgError('删除附件失败');
|
|
|
}
|
|
|
+
|
|
|
+ // 从attachmentList中移除
|
|
|
+ const index = attachmentList.value.findIndex((item) => item.uid === file.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ attachmentList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ proxy?.$modal.msgSuccess('附件已移除,将在保存时生效');
|
|
|
}
|
|
|
- // 如果是临时文件(新增时添加的文件),从临时列表中删除
|
|
|
+ // 如果是临时文件(新增时添加但未上传的文件),从临时列表中删除
|
|
|
else if (file.raw && !form.value.id) {
|
|
|
const index = tempFileList.value.findIndex((f) => f.name === file.raw.name && f.size === file.raw.size);
|
|
|
if (index > -1) {
|
|
|
@@ -2321,7 +2510,9 @@ const reset = async (autoFillUserInfo: boolean = false) => {
|
|
|
// 清空附件相关数据
|
|
|
attachmentList.value = [];
|
|
|
tempFileList.value = [];
|
|
|
- console.log('已清空附件列表和临时文件列表');
|
|
|
+ tempAttachmentIds.value = [];
|
|
|
+ pendingDeleteAttachmentIds.value = [];
|
|
|
+ console.log('已清空附件列表、临时文件列表、临时附件ID列表和待删除附件列表');
|
|
|
|
|
|
// 如果是新增操作,自动填充当前用户信息
|
|
|
if (autoFillUserInfo) {
|
|
|
@@ -2497,8 +2688,46 @@ const cancelEvaluation = () => {
|
|
|
};
|
|
|
|
|
|
/** 下载附件 */
|
|
|
-const downloadAttachment = (attachment: any) => {
|
|
|
- window.open(attachment.filePath, '_blank');
|
|
|
+const downloadAttachment = async (attachment: any) => {
|
|
|
+ if (!attachment.filePath) {
|
|
|
+ proxy?.$modal.msgError('无法获取文件下载地址');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 显示加载提示
|
|
|
+ const loading = ElLoading.service({
|
|
|
+ text: '正在下载文件...',
|
|
|
+ target: document.body
|
|
|
+ });
|
|
|
+
|
|
|
+ // 通过fetch获取文件内容,强制下载
|
|
|
+ const response = await fetch(attachment.filePath);
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const blob = await response.blob();
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ // 创建下载链接
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = attachment.fileName || '附件';
|
|
|
+ link.style.display = 'none';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+
|
|
|
+ // 释放blob URL
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+
|
|
|
+ loading?.close();
|
|
|
+ console.log('下载附件成功:', attachment.fileName || '附件');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载附件失败:', error);
|
|
|
+ proxy?.$modal.msgError('下载文件失败,请稍后重试');
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
/** 预览附件 */
|
|
|
@@ -2602,8 +2831,8 @@ const getProgressIconColor = (progressType: string) => {
|
|
|
};
|
|
|
|
|
|
/** 获取进度类型标签类型 */
|
|
|
-const getProgressTypeTag = (progressType: string) => {
|
|
|
- const tagMap: Record<string, string> = {
|
|
|
+const getProgressTypeTag = (progressType: string): 'success' | 'warning' | 'info' | 'primary' | 'danger' => {
|
|
|
+ const tagMap: Record<string, 'success' | 'warning' | 'info' | 'primary' | 'danger'> = {
|
|
|
'1': 'primary',
|
|
|
'2': 'success',
|
|
|
'3': 'warning',
|
|
|
@@ -2827,6 +3056,8 @@ const getFileExt = (fileName: string): string => {
|
|
|
|
|
|
/* 工单信息样式 */
|
|
|
.order-info {
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: border-box; // 使内边距计入总宽度,避免超出表单内容区域
|
|
|
background-color: #f8f9fa;
|
|
|
padding: 16px;
|
|
|
border-radius: 8px;
|
|
|
@@ -3505,18 +3736,35 @@ const getFileExt = (fileName: string): string => {
|
|
|
display: flex !important;
|
|
|
}
|
|
|
|
|
|
+/* Element Plus upload 组件样式覆盖 */
|
|
|
+:deep(.el-upload-list--picture-card) {
|
|
|
+ .el-upload-list__item {
|
|
|
+ width: 166px !important;
|
|
|
+ height: auto !important;
|
|
|
+ min-height: 180px !important;
|
|
|
+ margin: 0 8px 8px 0 !important;
|
|
|
+ border-radius: 6px !important;
|
|
|
+ overflow: hidden !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* 卡片整体布局包含文件名 */
|
|
|
.upload-file-card {
|
|
|
width: 100%;
|
|
|
+ height: 100%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
+ min-height: 180px;
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
.upload-file-thumb {
|
|
|
width: 100%;
|
|
|
- aspect-ratio: 1 / 1;
|
|
|
+ height: 120px;
|
|
|
position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ border-radius: 4px 4px 0 0;
|
|
|
}
|
|
|
|
|
|
.upload-file-thumb .el-image,
|
|
|
@@ -3525,13 +3773,61 @@ const getFileExt = (fileName: string): string => {
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
+.upload-file-placeholder {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: #fafafa;
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ font-size: 24px;
|
|
|
+ color: #c0c4cc;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .file-ext {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ text-align: center;
|
|
|
+ word-break: break-all;
|
|
|
+ padding: 0 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.upload-file-name {
|
|
|
width: 100%;
|
|
|
- margin-top: 4px;
|
|
|
+ padding: 8px 4px 4px 4px;
|
|
|
font-size: 12px;
|
|
|
text-align: center;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
+ color: #606266;
|
|
|
+ background-color: #fff;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 上传文件卡片操作按钮样式 (与预览界面保持一致) */
|
|
|
+.upload-file-card-actions {
|
|
|
+ width: 100%;
|
|
|
+ padding: 6px 8px;
|
|
|
+ border-top: 1px solid #f0f0f0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: #fafafa;
|
|
|
+ margin-top: auto;
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .el-button-group {
|
|
|
+ .el-button {
|
|
|
+ padding: 4px 6px;
|
|
|
+ font-size: 12px;
|
|
|
+
|
|
|
+ .el-icon {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|