From bc39d20d8630e5e6ed8ab6a8707fb86ef406f94f Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 04 六月 2026 14:43:48 +0800
Subject: [PATCH] 新增差旅报销后,对应的费用科目不展示
---
src/views/officeProcessAutomation/ApproveManage/approve-template/formConfigUtils.js | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 301 insertions(+), 0 deletions(-)
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-template/formConfigUtils.js b/src/views/officeProcessAutomation/ApproveManage/approve-template/formConfigUtils.js
new file mode 100644
index 0000000..c1f66bd
--- /dev/null
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-template/formConfigUtils.js
@@ -0,0 +1,301 @@
+import { mapAttachmentsFromApi } from "./approveTemplateConstants.js";
+import {
+ isDynamicOptionSource,
+ SELECT_OPTION_SOURCE,
+ selectOptionSourceLabel,
+} from "./selectOptionSource.js";
+
+export { selectOptionSourceLabel };
+
+/** 濉姤椤圭被鍨嬶紙涓庡鎵规彁浜ら〉 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: "",
+ optionSource: SELECT_OPTION_SOURCE.STATIC,
+ options: [{ label: "", value: "" }],
+ };
+}
+
+/** 瑙f瀽鍗曢」榛樿鍊硷紙渚涙彁浜ら〉 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),
+ optionSource: f.optionSource || SELECT_OPTION_SOURCE.STATIC,
+ 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") {
+ const source = f.optionSource || SELECT_OPTION_SOURCE.STATIC;
+ item.optionSource = source;
+ if (!isDynamicOptionSource(source)) {
+ 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 source = f.optionSource || SELECT_OPTION_SOURCE.STATIC;
+ if (isDynamicOptionSource(source)) continue;
+ 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") {
+ if (isDynamicOptionSource(field.optionSource)) {
+ return `${selectOptionSourceLabel(field.optionSource)}锛�${String(dv)}`;
+ }
+ 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,
+ optionSource: rest.optionSource,
+ options: rest.options,
+ }));
+ return {
+ label: row?.templateName || "瀹℃壒",
+ businessType: row?.businessType ?? cfg.approvalType ?? "",
+ approvalType: cfg.approvalType || "",
+ summaryPlaceholder: cfg.summaryPlaceholder || "",
+ approvalMode: cfg.approvalMode || "parallel",
+ fields,
+ storageBlobDTOs: mapAttachmentsFromApi(row),
+ };
+}
+
+export function formConfigFieldsSummary(formConfigData) {
+ const fields = formConfigData?.fields || [];
+ if (!fields.length) return "鈥�";
+ return fields.map((f) => f.label || f.key || "鏈懡鍚�").join("銆�");
+}
--
Gitblit v1.9.3