| | |
| | | |
| | | <el-form-item label="模板名称" prop="templateName"> |
| | | |
| | | <el-input v-model="form.templateName" placeholder="如:项目立项审批" maxlength="50" show-word-limit /> |
| | | <el-input |
| | | v-model="form.templateName" |
| | | placeholder="如:项目立项审批" |
| | | maxlength="50" |
| | | show-word-limit |
| | | :disabled="isEditingBuiltin" |
| | | /> |
| | | |
| | | </el-form-item> |
| | | |
| | |
| | | |
| | | <el-form-item label="模板类型" prop="businessType"> |
| | | |
| | | <el-select v-model="form.businessType" placeholder="请选择" style="width: 100%"> |
| | | <el-select |
| | | v-model="form.businessType" |
| | | placeholder="请选择" |
| | | style="width: 100%" |
| | | :disabled="isEditingBuiltin" |
| | | > |
| | | |
| | | <el-option |
| | | |
| | |
| | | |
| | | <el-form-item label="填报配置"> |
| | | |
| | | <FormConfigEditor v-model="form.formConfigData" /> |
| | | <FormConfigEditor |
| | | v-model="form.formConfigData" |
| | | :exclude-template-id="form.id" |
| | | :disable-import="isEditingBuiltin" |
| | | :locked-field-uids="isEditingBuiltin ? form.lockedFormFieldUids : []" |
| | | /> |
| | | |
| | | <p class="flow-tip">配置提交审批时需填写的表单项,保存后写入 formConfig(JSON)。</p> |
| | | |
| | |
| | | 按顺序流转:可为每个节点添加多名审批人;会签需全部通过,或签任一人通过即可进入下一节点。 |
| | | |
| | | </p> |
| | | |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="附件"> |
| | | |
| | | <div class="upload-block"> |
| | | |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" :limit="10" button-text="点击选择文件" /> |
| | | |
| | | </div> |
| | | |
| | | <p class="flow-tip">可上传模板说明文档、制度文件等(选填)。</p> |
| | | |
| | | </el-form-item> |
| | | |
| | |
| | | |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="选项来源" width="100"> |
| | | |
| | | <template #default="{ row }"> |
| | | |
| | | {{ row.type === 'select' ? selectOptionSourceLabel(row.optionSource) : '—' }} |
| | | |
| | | </template> |
| | | |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="必填" width="70" align="center"> |
| | | |
| | | <template #default="{ row }">{{ row.required !== false ? "是" : "否" }}</template> |
| | |
| | | |
| | | <el-empty v-else description="暂无流程节点" :image-size="60" /> |
| | | |
| | | <el-divider content-position="left">附件({{ detailAttachments.length }} 个)</el-divider> |
| | | |
| | | <template v-if="detailAttachments.length"> |
| | | |
| | | <div class="detail-attachment-list"> |
| | | <div |
| | | v-for="(f, i) in detailAttachments" |
| | | :key="i" |
| | | class="detail-attachment-item" |
| | | @click="openAttachmentFile(f)" |
| | | > |
| | | <el-icon class="attachment-icon"><Document /></el-icon> |
| | | <span class="attachment-name">{{ attachmentDisplayName(f) }}</span> |
| | | <el-icon class="attachment-download"><Download /></el-icon> |
| | | </div> |
| | | </div> |
| | | |
| | | </template> |
| | | |
| | | <el-empty v-else description="暂无附件" :image-size="48" /> |
| | | |
| | | </div> |
| | | |
| | | <template #footer> |
| | |
| | | |
| | | <script setup> |
| | | |
| | | import { ArrowRight, Plus, RefreshRight } from "@element-plus/icons-vue"; |
| | | import { ArrowRight, Document, Download, Plus, RefreshRight } from "@element-plus/icons-vue"; |
| | | |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | |
| | | |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | |
| | | import FormConfigEditor from "./components/FormConfigEditor.vue"; |
| | | |
| | | import TemplateFlowEditor from "./components/TemplateFlowEditor.vue"; |
| | | |
| | | import { formatDisplayTime } from "./approveTemplateConstants.js"; |
| | | import { formatDisplayTime, mapAttachmentsFromApi } from "./approveTemplateConstants.js"; |
| | | |
| | | import { formatDefaultValueDisplay, formFieldTypeLabel, parseFormConfigToData } from "./formConfigUtils.js"; |
| | | import { selectOptionSourceLabel } from "./selectOptionSource.js"; |
| | | |
| | | import { useApproveTemplate } from "./useApproveTemplate.js"; |
| | | |
| | |
| | | |
| | | formRules, |
| | | |
| | | isEditingBuiltin, |
| | | |
| | | detailDialog, |
| | | |
| | | detailRow, |
| | |
| | | |
| | | ); |
| | | |
| | | |
| | | |
| | | const detailAttachments = computed(() => mapAttachmentsFromApi(detailRow.value)); |
| | | |
| | | |
| | | |
| | | function attachmentDisplayName(file) { |
| | | |
| | | if (!file) return "未命名"; |
| | | |
| | | return file.name || file.originalFilename || file.fileName || "未命名"; |
| | | |
| | | } |
| | | |
| | | function openAttachmentFile(file) { |
| | | const url = file?.url || file?.previewURL || file?.downloadURL || file?.previewUrl || ""; |
| | | if (url) { |
| | | window.open(url, "_blank"); |
| | | } else { |
| | | ElMessage.warning("无法打开该附件"); |
| | | } |
| | | } |
| | | |
| | | |
| | | function unwrapArray(payload) { |
| | |
| | | |
| | | } |
| | | |
| | | .upload-block { |
| | | |
| | | width: 100%; |
| | | |
| | | } |
| | | |
| | | .detail-attachment-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .detail-attachment-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | padding: 8px 12px; |
| | | background: var(--el-fill-color-light); |
| | | border-radius: 6px; |
| | | cursor: pointer; |
| | | transition: background 0.2s; |
| | | } |
| | | |
| | | .detail-attachment-item:hover { |
| | | background: var(--el-fill-color); |
| | | } |
| | | |
| | | .attachment-icon { |
| | | font-size: 16px; |
| | | color: var(--el-text-color-regular); |
| | | } |
| | | |
| | | .attachment-name { |
| | | font-size: 14px; |
| | | color: var(--el-text-color-primary); |
| | | } |
| | | |
| | | .attachment-download { |
| | | font-size: 14px; |
| | | color: var(--el-text-color-secondary); |
| | | } |
| | | |
| | | .text-muted { |
| | | |
| | | font-size: 12px; |