|
|
@@ -280,6 +280,48 @@
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
+
|
|
|
+ <!-- 第六行:上传附件 -->
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="上传附件">
|
|
|
+ <!-- 文件上传组件 -->
|
|
|
+ <FileUpload
|
|
|
+ v-if="!isApprovalMode"
|
|
|
+ ref="fileUploadRef"
|
|
|
+ :device-id="deviceId"
|
|
|
+ :show-folder-button="false"
|
|
|
+ @upload-success="handleUploadSuccess"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 已上传附件列表显示 -->
|
|
|
+ <div v-if="formData.attachments && formData.attachments.length > 0" class="attachment-list">
|
|
|
+ <div
|
|
|
+ v-for="(attachment, index) in formData.attachments"
|
|
|
+ :key="attachment.id || index"
|
|
|
+ class="attachment-item"
|
|
|
+ >
|
|
|
+ <span class="attachment-name">{{ attachment.filename }}</span>
|
|
|
+ <el-button
|
|
|
+ v-if="!isApprovalMode"
|
|
|
+ type="danger"
|
|
|
+ link
|
|
|
+ size="small"
|
|
|
+ @click="removeAttachment(index)"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 审批模式下只显示附件列表 -->
|
|
|
+ <div v-else-if="isApprovalMode && (!formData.attachments || formData.attachments.length === 0)" class="no-attachment">
|
|
|
+ 无附件
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
</el-form>
|
|
|
</ContentWrap>
|
|
|
|
|
|
@@ -339,7 +381,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, computed, onMounted } from 'vue'
|
|
|
+import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
|
|
|
import { useI18n } from '@/hooks/web/useI18n'
|
|
|
import { useMessage } from '@/hooks/web/useMessage'
|
|
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
|
@@ -350,6 +392,7 @@ import { IotDailyReportAttrsApi } from '@/api/pms/iotdailyreportattrs'
|
|
|
import * as DeptApi from '@/api/system/dept'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import dayjs from 'dayjs'
|
|
|
+import FileUpload from "@/components/UploadFile/src/FileUpload.vue";
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
const message = useMessage()
|
|
|
@@ -385,6 +428,9 @@ const approvalFormRules = reactive({
|
|
|
]
|
|
|
})
|
|
|
|
|
|
+// 添加文件上传组件的引用
|
|
|
+const fileUploadRef = ref()
|
|
|
+
|
|
|
// 表单数据
|
|
|
const formData = ref({
|
|
|
id: undefined,
|
|
|
@@ -410,9 +456,105 @@ const formData = ref({
|
|
|
externalRental: '', // 外租设备
|
|
|
|
|
|
// 添加动态字段对象
|
|
|
- dynamicFields: {} as Record<string, any>
|
|
|
+ dynamicFields: {} as Record<string, any>,
|
|
|
+ // 附件列表
|
|
|
+ attachments: [] as any[]
|
|
|
})
|
|
|
|
|
|
+// 添加上传成功处理函数
|
|
|
+const handleUploadSuccess = (result: any) => {
|
|
|
+ console.log('上传成功:', result)
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 检查响应是否成功
|
|
|
+ if (!result.response) {
|
|
|
+ message.error('上传响应数据异常')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (result.response.code !== 0) {
|
|
|
+ message.error(result.response.msg || '文件上传失败')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const responseData = result.response.data
|
|
|
+
|
|
|
+ if (!responseData) {
|
|
|
+ message.error('上传数据为空')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理返回的文件列表
|
|
|
+ if (responseData.files && Array.isArray(responseData.files) && responseData.files.length > 0) {
|
|
|
+ responseData.files.forEach((file: any) => {
|
|
|
+ if (!file.filePath) {
|
|
|
+ console.warn('文件缺少 filePath:', file)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据后端返回的数据结构构建附件对象
|
|
|
+ const attachment = {
|
|
|
+ id: undefined,
|
|
|
+ category: 'daily_report',
|
|
|
+ bizId: formData.value.id,
|
|
|
+ type: 'attachment',
|
|
|
+ filename: file.name || '未知文件',
|
|
|
+ fileType: getFileType(file.name),
|
|
|
+ filePath: file.filePath, // 关键修改:使用正确的 filePath
|
|
|
+ fileSize: formatFileSize(file.size || 0),
|
|
|
+ remark: ''
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加到附件列表
|
|
|
+ if (!formData.value.attachments) {
|
|
|
+ formData.value.attachments = []
|
|
|
+ }
|
|
|
+ formData.value.attachments.push(attachment)
|
|
|
+ })
|
|
|
+
|
|
|
+ message.success(`成功上传 ${responseData.files.length} 个文件`)
|
|
|
+ } else {
|
|
|
+ console.warn('上传成功但没有返回文件信息')
|
|
|
+ message.warning('上传成功但未获取到文件信息')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('处理上传结果时发生错误:', error)
|
|
|
+ message.error('处理上传结果失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 删除附件
|
|
|
+const removeAttachment = (index: number) => {
|
|
|
+ if (formData.value.attachments && formData.value.attachments.length > index) {
|
|
|
+ formData.value.attachments.splice(index, 1)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取文件类型辅助函数
|
|
|
+const getFileType = (filename: string) => {
|
|
|
+ const ext = filename.split('.').pop()?.toLowerCase()
|
|
|
+ if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext || '')) {
|
|
|
+ return 'image'
|
|
|
+ } else if (['pdf'].includes(ext || '')) {
|
|
|
+ return 'pdf'
|
|
|
+ } else if (['doc', 'docx'].includes(ext || '')) {
|
|
|
+ return 'word'
|
|
|
+ } else if (['xls', 'xlsx'].includes(ext || '')) {
|
|
|
+ return 'excel'
|
|
|
+ } else {
|
|
|
+ return 'other'
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 格式化文件大小辅助函数
|
|
|
+const formatFileSize = (bytes: number) => {
|
|
|
+ if (bytes === 0) return '0 Bytes'
|
|
|
+ const k = 1024
|
|
|
+ const sizes = ['Bytes', 'KB', 'MB', 'GB']
|
|
|
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
|
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
|
|
+}
|
|
|
+
|
|
|
// 表单验证规则
|
|
|
const formRules = reactive({
|
|
|
timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
|
|
|
@@ -702,7 +844,9 @@ const initFormData = (reportData: any) => {
|
|
|
startTime: reportData.startTime || undefined,
|
|
|
endTime: reportData.endTime || undefined,
|
|
|
companyId: reportData.companyId || '',
|
|
|
- dynamicFields: {} // 确保有初始值
|
|
|
+ dynamicFields: {}, // 确保有初始值
|
|
|
+ // 初始化附件数据
|
|
|
+ attachments: reportData.attachments || []
|
|
|
}
|
|
|
queryParams.deptId = reportData.companyId
|
|
|
// 设置时间范围选择器
|
|
|
@@ -988,4 +1132,37 @@ const handleApprove = async (action: 'pass' | 'reject') => {
|
|
|
font-weight: bold;
|
|
|
color: #606266;
|
|
|
}
|
|
|
+
|
|
|
+/* 附件列表样式 */
|
|
|
+.attachment-list {
|
|
|
+ margin-top: 10px;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #fafafa;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 8px 12px;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-name {
|
|
|
+ flex: 1;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.no-attachment {
|
|
|
+ color: #909399;
|
|
|
+ font-style: italic;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
</style>
|