liding
2026-06-05 fdd776214d77a657f65fb1555637b03b95e82643
src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js
@@ -165,11 +165,49 @@
function pickApplicantQuery(searchForm = {}) {
  const kw = (searchForm.applicantKeyword || "").trim();
  if (!kw) return {};
  if (/[\u4e00-\u9fa5]/.test(kw)) return { applicantName: kw };
  return { applicantCode: kw };
  // 占位「姓名或编号」:姓名走 applicantName;编号另传 applicantCode
  const out = { applicantName: kw };
  if (!/[\u4e00-\u9fa5]/.test(kw)) {
    out.applicantCode = kw;
  }
  return out;
}
/** 组装 listPage 查询参数(page + finReimbursementDto) */
/** 是否存在列表筛选条件(仅申请人) */
export function hasActiveReimbursementSearch(searchForm = {}) {
  return Boolean((searchForm?.applicantKeyword || "").trim());
}
/** 服务端未生效时,按申请人做前端兜底筛选 */
export function filterReimbursementRowsBySearch(rows, searchForm = {}) {
  const list = Array.isArray(rows) ? rows : [];
  const kw = (searchForm?.applicantKeyword || "").trim().toLowerCase();
  if (!kw) return list;
  return list.filter((row) => {
    const parts = [
      row.applicantName,
      row.employeeName,
      row.applicantNo,
      row.applicantCode,
      row.employeeNo,
    ]
      .filter((v) => v != null && v !== "")
      .map((v) => String(v).toLowerCase());
    return parts.some((p) => p.includes(kw));
  });
}
/** 扁平化为 Spring GET 可绑定的 query(finReimbursementDto.xxx,勿用方括号) */
function appendDotNotationQuery(target, prefix, fields) {
  if (!fields || typeof fields !== "object") return;
  for (const [key, value] of Object.entries(fields)) {
    if (value == null || value === "") continue;
    target[`${prefix}.${key}`] = value;
  }
}
/** 组装 listPage 查询参数(扁平 page.* / finReimbursementDto.*,与 detail 接口一致) */
export function buildFinReimbursementListParams({
  page,
  searchForm,
@@ -182,40 +220,15 @@
    ...(extraDto && typeof extraDto === "object" ? extraDto : {}),
  };
  if (searchForm?.billStatus) {
    dto.billStatus = searchForm.billStatus;
  }
  const range =
    searchForm?.createTimeRange ??
    searchForm?.applyDateRange ??
    (searchForm?.applyTimeFrom || searchForm?.applyTimeTo
      ? [searchForm.applyTimeFrom, searchForm.applyTimeTo]
      : null);
  if (Array.isArray(range) && range[0]) {
    dto.createTimeStart = range[0];
  }
  if (Array.isArray(range) && range[1]) {
    dto.createTimeEnd = range[1];
  }
  if (reimbursementType === FIN_REIMBURSEMENT_TYPE.TRAVEL) {
    if (searchForm?.travelStartFrom) {
      dto.startTimeStart = searchForm.travelStartFrom;
    }
    if (searchForm?.travelEndTo) {
      dto.endTimeEnd = searchForm.travelEndTo;
    }
  }
  return {
    page: {
      current: page.current,
      size: page.size,
    },
    finReimbursementDto: dto,
  const params = {
    current: page.current,
    size: page.size,
    "page.current": page.current,
    "page.size": page.size,
    ...dto,
  };
  appendDotNotationQuery(params, "finReimbursementDto", dto);
  return params;
}
function pickTravelField(obj, keys) {
@@ -329,7 +342,7 @@
    createTime: formatReimbursementDateTime(row.createTime),
    expenseDetails: details.map((d) => ({
      ...d,
      expenseSubject: d.expenseCategory,
      expenseSubject: resolveExpenseSubjectValue(d.expenseCategory ?? d.expenseSubject),
    })),
    travel:
      row.travel && typeof row.travel === "object" && Object.keys(row.travel).length
@@ -375,7 +388,7 @@
    createTime: formatReimbursementDateTime(row.createTime),
    expenseDetails: details.map((d) => ({
      ...d,
      expenseSubject: d.expenseCategory,
      expenseSubject: resolveExpenseSubjectValue(d.expenseCategory ?? d.expenseSubject),
    })),
    details,
    nodes: apiNodes,
@@ -400,6 +413,15 @@
  return hit?.label || subject || "";
}
/** 接口返回的 expenseCategory 可能是中文 label,反转为前端 value;已经是 value 则原样返回 */
function resolveExpenseSubjectValue(val) {
  if (!val) return "";
  const byValue = EXPENSE_SUBJECT_OPTIONS.find((x) => x.value === val);
  if (byValue) return val;
  const byLabel = EXPENSE_SUBJECT_OPTIONS.find((x) => x.label === val);
  return byLabel?.value || val;
}
function expenseCategoryToType(category) {
  const hit = EXPENSE_CATEGORY_OPTIONS.find((x) => x.value === category);
  return hit?.label || category || "";