gaoluyang
2026-05-29 4762afb6cb043a3e539ed7ec8da5bde997bfaf65
src/views/officeProcessAutomation/ApproveManage/approve-template/formConfigUtils.js
@@ -1,9 +1,19 @@
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: "datetime", label: "日期时间" },
  { value: "datetimerange", label: "日期时间范围" },
  { value: "select", label: "下拉选择" },
];
@@ -50,6 +60,56 @@
      { key: "dateRange", label: "请假时间", type: "datetimerange", required: true },
    ],
  },
  {
    key: "vehicle",
    label: "车辆审批",
    summaryPlaceholder: "请填写车辆使用申请信息",
    fields: [
      { key: "vehicleNo", label: "车牌号", type: "select", required: true, optionSource: "vehicle_list", placeholder: "请选择车辆" },
      { key: "driver", label: "驾驶员", type: "text", required: true },
      { key: "purpose", label: "用车事由", type: "textarea", required: true, rows: 2 },
      { key: "useDateRange", label: "车辆使用时间", type: "datetimerange", required: true },
      { key: "destination", label: "目的地", type: "text", required: true },
      { key: "passengers", label: "乘车人数", type: "number", required: false, min: 1, precision: 0 },
      { key: "startMileage", label: "起始公里数", type: "number", required: true, min: 0, precision: 1 },
      { key: "startMileagePhoto", label: "起始公里数照片", type: "image", required: false },
      { key: "estimatedEndMileage", label: "预计结束公里数", type: "number", required: false, min: 0, precision: 1 },
      { key: "remark", label: "备注", type: "textarea", required: false, rows: 2 },
    ],
  },
  {
    key: "vehicle_return",
    label: "车辆还车审批",
    summaryPlaceholder: "请填写车辆还车信息",
    fields: [
      { key: "vehicleNo", label: "车牌号", type: "select", required: true, optionSource: "vehicle_list", placeholder: "请选择车辆" },
      { key: "driver", label: "驾驶员", type: "text", required: true },
      { key: "originalApprovalNo", label: "原审批单号", type: "text", required: true },
      { key: "returnDate", label: "还车日期", type: "date", required: true },
      { key: "endMileage", label: "结束公里数", type: "number", required: true, min: 0, precision: 1 },
      { key: "endMileagePhoto", label: "结束公里数照片", type: "image", required: false },
      { key: "actualMileage", label: "实际行驶公里数", type: "number", required: false, min: 0, precision: 1 },
      { key: "extendDays", label: "延期天数", type: "number", required: false, min: 0, precision: 0 },
      { key: "extendReason", label: "延期原因", type: "textarea", required: false, rows: 2 },
      { key: "vehicleStatus", label: "车辆状态", type: "select", required: true, options: [{ label: "完好", value: "good" }, { label: "轻微损坏", value: "minor_damage" }, { label: "需要维修", value: "need_repair" }] },
      { key: "remark", label: "备注", type: "textarea", required: false, rows: 2 },
    ],
  },
  {
    key: "vehicle_extend",
    label: "车辆延期审批",
    summaryPlaceholder: "车辆到期后申请延期使用",
    fields: [
      { key: "vehicleNo", label: "车牌号", type: "select", required: true, optionSource: "vehicle_list", placeholder: "请选择车辆" },
      { key: "driver", label: "驾驶员", type: "text", required: true },
      { key: "originalApprovalNo", label: "原审批单号", type: "text", required: true },
      { key: "originalEndDate", label: "原到期日期", type: "date", required: true },
      { key: "extendDays", label: "延期天数", type: "number", required: true, min: 1, precision: 0 },
      { key: "newEndDate", label: "新到期日期", type: "date", required: true },
      { key: "extendReason", label: "延期原因", type: "textarea", required: true, rows: 3 },
      { key: "remark", label: "备注", type: "textarea", required: false, rows: 2 },
    ],
  },
];
function newFieldUid() {
@@ -67,6 +127,7 @@
    min: 0,
    precision: 0,
    defaultValue: "",
    optionSource: SELECT_OPTION_SOURCE.STATIC,
    options: [{ label: "", value: "" }],
  };
}
@@ -78,6 +139,7 @@
  if (dv === undefined || dv === null || dv === "") {
    if (type === "number") return undefined;
    if (type === "datetimerange") return [];
    if (type === "datetime") return "";
    return "";
  }
  if (type === "number") {
@@ -96,6 +158,7 @@
  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 === "datetime") return String(dv).trim() !== "";
  if (type === "select") return dv !== "";
  return String(dv).trim() !== "";
}
@@ -133,6 +196,7 @@
  if (f.defaultValue === undefined || f.defaultValue === null) {
    if (type === "number") return undefined;
    if (type === "datetimerange") return [];
    if (type === "datetime") return "";
    return "";
  }
  if (type === "datetimerange" && Array.isArray(f.defaultValue)) {
@@ -154,6 +218,7 @@
    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: "" }],
@@ -180,9 +245,13 @@
      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 }));
      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 =
@@ -223,6 +292,8 @@
    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}」配置至少一个下拉选项` };
    }
@@ -241,13 +312,16 @@
    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 默认值) */
/** 将后端模板行转为提交页模板结构(含 fields 默认值、附件) */
export function buildSubmitTemplateFromRow(row) {
  const cfg = parseFormConfigToData(row?.formConfig);
  const fields = (cfg.fields || []).map(({ _uid, ...rest }) => ({
@@ -260,6 +334,7 @@
    min: rest.min,
    precision: rest.precision,
    defaultValue: rest.defaultValue,
    optionSource: rest.optionSource,
    options: rest.options,
  }));
  return {
@@ -269,6 +344,7 @@
    summaryPlaceholder: cfg.summaryPlaceholder || "",
    approvalMode: cfg.approvalMode || "parallel",
    fields,
    storageBlobDTOs: mapAttachmentsFromApi(row),
  };
}