| | |
| | | </span> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="申请人编号">{{ row.applicantNo || "—" }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请人名称">{{ row.applicantName || "—" }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请人名称">{{ applicantNameDisplay }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请摘要">{{ row.summary || "—" }}</el-descriptions-item> |
| | | <el-descriptions-item v-if="row.rejectReason" label="驳回原因" :span="2"> |
| | | <span class="reject-text">{{ row.rejectReason }}</span> |
| | |
| | | readonly |
| | | /> |
| | | </div> |
| | | |
| | | <div class="detail-block"> |
| | | <div class="detail-block-title">附件</div> |
| | | <template v-if="attachmentFiles.length"> |
| | | <el-tag v-for="(f, i) in attachmentFiles" :key="i" class="file-tag" type="info" @click="openFile(f)"> |
| | | {{ f.name || f.originalFilename }} |
| | | </el-tag> |
| | | </template> |
| | | <el-empty v-else description="暂无附件" :image-size="48" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed } from "vue"; |
| | | import { computed, onMounted, watch } from "vue"; |
| | | import { formatDisplayTime } from "../../approve-template/approveTemplateConstants.js"; |
| | | import { useSelectOptionSources } from "../../approve-template/useSelectOptionSources.js"; |
| | | import { |
| | | approvalTypeLabel, |
| | | approvalTypeStyle, |
| | | approvalStatusLabel, |
| | | approvalStatusTagType, |
| | | resolveInstanceFormFields, |
| | | formatFieldDisplayValue, |
| | | } from "../approveListConstants.js"; |
| | | import FormPayloadFields from "./FormPayloadFields.vue"; |
| | | |
| | |
| | | row: { type: Object, default: () => ({}) }, |
| | | }); |
| | | |
| | | const { ensureForFields, getDisplayLabel } = useSelectOptionSources(); |
| | | |
| | | const formResolved = computed(() => resolveInstanceFormFields(props.row)); |
| | | |
| | | const applicantField = computed(() => { |
| | | const fields = formResolved.value.fields || []; |
| | | return ( |
| | | fields.find((f) => String(f?.label || "").includes("申请人")) || |
| | | fields.find((f) => f?.type === "select" && f?.optionSource === "user") || |
| | | null |
| | | ); |
| | | }); |
| | | |
| | | const applicantNameDisplay = computed(() => { |
| | | if (!applicantField.value) return props.row?.applicantName || "—"; |
| | | const val = formResolved.value.formPayload?.[applicantField.value.key]; |
| | | if (val == null || val === "") return props.row?.applicantName || "—"; |
| | | if (applicantField.value.optionSource && applicantField.value.optionSource !== "static") { |
| | | const label = getDisplayLabel(applicantField.value, val); |
| | | if (label && label !== "—") return label; |
| | | } |
| | | const formatted = formatFieldDisplayValue(applicantField.value, val); |
| | | if (formatted && formatted !== "—") return formatted; |
| | | return props.row?.applicantName || "—"; |
| | | }); |
| | | |
| | | async function loadOptionCaches() { |
| | | await ensureForFields(formResolved.value.fields || []); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | loadOptionCaches(); |
| | | }); |
| | | |
| | | watch( |
| | | () => formResolved.value.fields, |
| | | () => { |
| | | loadOptionCaches(); |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | |
| | | const attachmentFiles = computed(() => { |
| | | const list = |
| | | props.row?.storageBlobVOList || |
| | | props.row?.storageBlobDTOs || |
| | | props.row?.storageBlobDTOS || |
| | | props.row?.storageBlobVOS || |
| | | props.row?.attachmentList || |
| | | []; |
| | | return Array.isArray(list) ? list : []; |
| | | }); |
| | | |
| | | function openFile(f) { |
| | | const url = f?.url || f?.previewURL || f?.downloadURL; |
| | | if (url) window.open(url, "_blank"); |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | |
| | | .reject-text { |
| | | color: var(--el-color-danger); |
| | | } |
| | | .file-tag { |
| | | margin: 0 8px 8px 0; |
| | | cursor: pointer; |
| | | } |
| | | </style> |