/** 填报项类型(与审批提交页 field.type 一致) */ export const FORM_FIELD_TYPE_OPTIONS = [ { value: "text", label: "单行文本" }, { value: "textarea", label: "多行文本" }, { value: "number", label: "数字" }, { value: "date", label: "日期" }, { value: "datetimerange", label: "日期时间范围" }, { value: "select", label: "下拉选择" }, ]; /** 常用预设(如费用报销) */ export const FORM_CONFIG_PRESETS = [ { key: "cost_reimburse", label: "费用报销", summaryPlaceholder: "请填写报销事由、金额等", fields: [ { key: "summary", label: "报销说明", type: "textarea", required: true, rows: 3 }, { key: "amount", label: "报销金额(元)", type: "number", required: true, min: 0, precision: 2 }, ], }, { key: "travel_reimburse", label: "差旅报销", summaryPlaceholder: "出差行程与费用说明", fields: [ { key: "summary", label: "差旅说明", type: "textarea", required: true, rows: 3 }, { key: "amount", label: "报销金额(元)", type: "number", required: true, min: 0, precision: 2 }, { key: "tripDays", label: "出差天数", type: "number", required: false, min: 0, precision: 0 }, ], }, { key: "leave", label: "请假申请", summaryPlaceholder: "请填写请假类型与时间", fields: [ { key: "leaveType", label: "请假类型", type: "select", required: true, options: [ { label: "年假", value: "annual" }, { label: "病假", value: "sick" }, { label: "事假", value: "personal" }, { label: "调休", value: "compensatory" }, ], }, { key: "summary", label: "请假事由", type: "textarea", required: true, rows: 2 }, { key: "dateRange", label: "请假时间", type: "datetimerange", required: true }, ], }, ]; function newFieldUid() { return `f_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; } export function createEmptyFormField() { return { _uid: newFieldUid(), key: "", label: "", type: "text", required: true, rows: 3, min: 0, precision: 0, defaultValue: "", options: [{ label: "", value: "" }], }; } /** 解析单项默认值(供提交页 formPayload 初始化) */ export function resolveFieldDefaultValue(field) { const type = field?.type || "text"; const dv = field?.defaultValue; if (dv === undefined || dv === null || dv === "") { if (type === "number") return undefined; if (type === "datetimerange") return []; return ""; } if (type === "number") { const n = Number(dv); return Number.isNaN(n) ? undefined : n; } if (type === "datetimerange") { return Array.isArray(dv) ? [...dv] : []; } return dv; } function hasDefaultValue(field) { const type = field?.type || "text"; const dv = field?.defaultValue; if (dv === undefined || dv === null) return false; if (type === "number") return dv !== "" && !Number.isNaN(Number(dv)); if (type === "datetimerange") return Array.isArray(dv) && dv.length === 2; if (type === "select") return dv !== ""; return String(dv).trim() !== ""; } /** 根据字段定义生成 formPayload 初始值(含默认值) */ export function buildFormPayloadFromFields(fields) { const payload = {}; (fields || []).forEach((f) => { const key = (f.key || "").trim(); if (!key) return; payload[key] = resolveFieldDefaultValue(f); }); return payload; } export function createEmptyFormConfigData() { return { summaryPlaceholder: "", fields: [], }; } function parseFormConfigRaw(formConfig) { if (!formConfig) return {}; if (typeof formConfig === "object") return formConfig; try { return JSON.parse(formConfig); } catch { return {}; } } function normalizeDefaultValueFromApi(f) { const type = f.type || "text"; if (f.defaultValue === undefined || f.defaultValue === null) { if (type === "number") return undefined; if (type === "datetimerange") return []; return ""; } if (type === "datetimerange" && Array.isArray(f.defaultValue)) { return [...f.defaultValue]; } return f.defaultValue; } /** 接口 formConfig → 编辑器数据 */ export function parseFormConfigToData(formConfig) { const raw = parseFormConfigRaw(formConfig); const fields = (raw.fields || raw.formFields || []).map((f) => ({ _uid: newFieldUid(), key: f.key || "", label: f.label || "", type: f.type || "text", required: f.required !== false, rows: f.rows ?? 3, min: f.min ?? 0, precision: f.precision ?? 0, defaultValue: normalizeDefaultValueFromApi(f), options: (f.options || []).length ? f.options.map((o) => ({ label: o.label || "", value: o.value ?? "" })) : [{ label: "", value: "" }], })); return { summaryPlaceholder: raw.summaryPlaceholder || "", fields, }; } /** 编辑器数据 → 提交用 JSON 字符串 */ export function buildFormConfigJson(formConfigData) { const data = formConfigData || createEmptyFormConfigData(); const fields = (data.fields || []).map((f) => { const item = { key: (f.key || "").trim(), label: (f.label || "").trim(), type: f.type || "text", required: f.required !== false, }; if (item.type === "textarea") item.rows = Number(f.rows) || 3; if (item.type === "number") { item.min = f.min ?? 0; item.precision = f.precision ?? 0; } if (item.type === "select") { item.options = (f.options || []) .filter((o) => (o.label || "").trim() || o.value !== "" && o.value != null) .map((o) => ({ label: (o.label || "").trim(), value: o.value })); } if (hasDefaultValue(f)) { item.defaultValue = f.type === "datetimerange" && Array.isArray(f.defaultValue) ? f.defaultValue : f.defaultValue; } return item; }); const payload = { summaryPlaceholder: (data.summaryPlaceholder || "").trim(), fields, }; return JSON.stringify(payload); } export function applyFormConfigPreset(presetKey) { const preset = FORM_CONFIG_PRESETS.find((p) => p.key === presetKey); if (!preset) return createEmptyFormConfigData(); return parseFormConfigToData({ summaryPlaceholder: preset.summaryPlaceholder, fields: preset.fields, }); } export function validateFormConfigData(formConfigData) { const fields = formConfigData?.fields || []; if (!fields.length) { return { ok: true }; } const keys = new Set(); for (let i = 0; i < fields.length; i++) { const f = fields[i]; const key = (f.key || "").trim(); const label = (f.label || "").trim(); if (!key) return { ok: false, message: `请填写第 ${i + 1} 个填报项的字段标识` }; if (!label) return { ok: false, message: `请填写第 ${i + 1} 个填报项的显示名称` }; if (keys.has(key)) return { ok: false, message: `字段标识「${key}」重复,请修改` }; keys.add(key); if (f.type === "select") { const opts = (f.options || []).filter((o) => (o.label || "").trim() && o.value !== "" && o.value != null); if (!opts.length) return { ok: false, message: `请为「${label}」配置至少一个下拉选项` }; } } return { ok: true }; } export function formFieldTypeLabel(type) { return FORM_FIELD_TYPE_OPTIONS.find((x) => x.value === type)?.label || type || "—"; } export function formatDefaultValueDisplay(field) { const dv = field?.defaultValue; if (dv === undefined || dv === null || dv === "") return "—"; if (field?.type === "datetimerange" && Array.isArray(dv)) { return dv.length === 2 ? `${dv[0]} ~ ${dv[1]}` : "—"; } if (field?.type === "select") { const opt = (field.options || []).find((o) => String(o.value) === String(dv)); return opt?.label || String(dv); } return String(dv); } /** 将后端模板行转为提交页模板结构(含 fields 默认值) */ export function buildSubmitTemplateFromRow(row) { const cfg = parseFormConfigToData(row?.formConfig); const fields = (cfg.fields || []).map(({ _uid, ...rest }) => ({ ...rest, key: rest.key, label: rest.label, type: rest.type, required: rest.required, rows: rest.rows, min: rest.min, precision: rest.precision, defaultValue: rest.defaultValue, options: rest.options, })); return { label: row?.templateName || "审批", approvalType: cfg.approvalType || "", summaryPlaceholder: cfg.summaryPlaceholder || "", approvalMode: cfg.approvalMode || "parallel", fields, }; } export function formConfigFieldsSummary(formConfigData) { const fields = formConfigData?.fields || []; if (!fields.length) return "—"; return fields.map((f) => f.label || f.key || "未命名").join("、"); }