yyb
9 天以前 552ec6b7d8ccc56c379da195fc6c9c74312b1070
OA部分查询条件变更
已修改6个文件
473 ■■■■ 文件已修改
src/pages/oa/_components/ApprovalInstanceListPage.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_components/FinReimbursementListPage.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_utils/approvalModuleListSearch.js 333 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_utils/approvalModuleRegistry.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_utils/approveListUtils.js 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_utils/finReimbursementMappers.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/oa/_components/ApprovalInstanceListPage.vue
@@ -128,6 +128,7 @@
    filterRowsByModuleBusinessType,
    formatDateRangeLabel,
    getModuleSearchMeta,
    hasActiveModuleSearch,
  } from "../_utils/approvalModuleListSearch.js";
  import {
    buildInstanceListParams,
@@ -235,14 +236,22 @@
      const res = await listApprovalInstancePage(buildListRequestParams());
      const { records, total } = unwrapInstancePage(res);
      const listFields = moduleConfig.value?.listFields || [];
      const mapped = records.map(row => mapInstanceListRow(row, listFields));
      let mapped = records.map(row => mapInstanceListRow(row, listFields));
      if (hasActiveModuleSearch(props.moduleKey, searchForm)) {
        mapped = filterRowsByModuleSearch(props.moduleKey, mapped, searchForm);
      }
      if (page.current === 1) {
        list.value = mapped;
      } else {
        list.value = [...list.value, ...mapped];
      }
      page.total = total;
      const dropped = records.length - mapped.length;
      page.total = hasActiveModuleSearch(props.moduleKey, searchForm)
        ? list.value.length
        : dropped > 0
          ? Math.max(0, Number(total) - dropped)
          : Number(total);
      if (list.value.length >= total || records.length < page.size) {
        pageStatus.value = "nomore";
src/pages/oa/_components/FinReimbursementListPage.vue
@@ -118,7 +118,6 @@
  import { getApprovalModuleConfig } from "../_utils/approvalModuleRegistry.js";
  import {
    createModuleSearchForm,
    filterRowsByModuleSearch,
    formatDateRangeLabel,
    getModuleSearchMeta,
  } from "../_utils/approvalModuleListSearch.js";
@@ -132,7 +131,9 @@
    deleteFinReimbursement,
    getReimbursementTypeByModuleKey,
    enrichReimbursementListRowsWithApprovalFlow,
    filterReimbursementRowsBySearch,
    filterRowsByReimbursementType,
    hasActiveReimbursementSearch,
    mapFinReimbursementFromApi,
    resolveReimbursementDeleteId,
    unwrapFinReimbursementPage,
@@ -170,7 +171,7 @@
  }
  const displayList = computed(() =>
    filterRowsByModuleSearch(props.moduleKey, list.value, searchForm)
    filterReimbursementRowsBySearch(list.value, searchForm)
  );
  const hasActiveFilter = computed(() => Boolean(filterSummary.value));
@@ -242,6 +243,9 @@
        mapped,
        reimbursementType.value
      );
      if (hasActiveReimbursementSearch(searchForm)) {
        mapped = filterReimbursementRowsBySearch(mapped, searchForm);
      }
      if (page.current === 1) {
        list.value = mapped;
@@ -249,8 +253,12 @@
        list.value = [...list.value, ...mapped];
      }
      const dropped = records.length - filtered.length;
      page.total =
      let nextTotal =
        dropped > 0 ? Math.max(0, Number(total) - dropped) : Number(total);
      if (hasActiveReimbursementSearch(searchForm)) {
        nextTotal = list.value.length;
      }
      page.total = nextTotal;
      if (list.value.length >= total || records.length < page.size) {
        pageStatus.value = "nomore";
src/pages/oa/_utils/approvalModuleListSearch.js
@@ -178,61 +178,135 @@
  return hit?.value ?? hit?.defaultValue ?? "";
}
function pickDateRange(searchForm) {
  const range =
    searchForm?.createTimeRange ??
    searchForm?.applyDateRange ??
    searchForm?.transferDateRange;
  if (!Array.isArray(range) || !range[0]) return {};
  const out = { createTimeStart: range[0] };
  if (range[1]) out.createTimeEnd = range[1];
/** 扁平化为 Spring GET 可绑定的 query(approvalInstanceDto.xxx,勿用方括号) */
export 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;
  }
}
function pickApplicantFromSearchForm(searchForm = {}) {
  const out = {};
  const sf = searchForm || {};
  const name = (sf.applicantName || "").trim();
  const kw = (sf.applicantKeyword || "").trim();
  const id = sf.applicantId;
  if (name) out.applicantName = name;
  if (kw) {
    out.applicantName = kw;
    if (/^\d+$/.test(kw)) out.applicantId = Number(kw);
  }
  if (id != null && id !== "") {
    out.applicantId = typeof id === "number" ? id : Number(id) || id;
  }
  return out;
}
/** 各模块默认查询表单(与 Web searchForm 字段一致) */
export function createModuleSearchForm(moduleKey) {
  switch (moduleKey) {
    case APPROVAL_MODULE_KEYS.REGULAR:
      return { applicantName: "", applyDateRange: null };
    case APPROVAL_MODULE_KEYS.TRANSFER:
      return { applicantId: "", transferDateRange: null };
    case APPROVAL_MODULE_KEYS.WORK_HANDOVER:
      return { applicantId: "", handoverStatus: "", handoverType: "" };
    case APPROVAL_MODULE_KEYS.LEAVE:
      return { applicantKeyword: "", leaveType: "" };
    case APPROVAL_MODULE_KEYS.OVERTIME:
      return { applicantKeyword: "", overtimeType: "" };
    case APPROVAL_MODULE_KEYS.TRAVEL_REIMBURSE:
    case APPROVAL_MODULE_KEYS.COST_REIMBURSE:
    case APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS:
      return { applicantKeyword: "" };
    default:
      return {};
  }
function pickInstanceNoFromSearchForm(searchForm = {}) {
  const no = (searchForm?.instanceNo || "").trim();
  return no ? { instanceNo: no } : {};
}
/** 服务端 listPage DTO 片段(与 Web buildExtraListParams + buildApprovalInstanceListParams 一致) */
export function buildModuleListDto(moduleKey, searchForm = {}) {
  const sf = searchForm || {};
  const dto = { ...pickDateRange(sf) };
/** 支持审批单号查询的审批申请模块 */
export const INSTANCE_NO_SEARCH_MODULE_KEYS = new Set([
  APPROVAL_MODULE_KEYS.REGULAR,
  APPROVAL_MODULE_KEYS.TRANSFER,
  APPROVAL_MODULE_KEYS.WORK_HANDOVER,
  APPROVAL_MODULE_KEYS.LEAVE,
  APPROVAL_MODULE_KEYS.OVERTIME,
]);
  switch (moduleKey) {
    case APPROVAL_MODULE_KEYS.REGULAR: {
      const name = (sf.applicantName || "").trim();
      if (name) dto.applicantName = name;
      break;
    }
    case APPROVAL_MODULE_KEYS.TRANSFER:
      break;
    case APPROVAL_MODULE_KEYS.WORK_HANDOVER:
      break;
    case APPROVAL_MODULE_KEYS.LEAVE:
    case APPROVAL_MODULE_KEYS.OVERTIME:
      break;
    default:
      break;
  }
const INSTANCE_NO_SEARCH_FIELD = {
  key: "instanceNo",
  type: "input",
  label: "审批单号",
  placeholder: "请输入审批单号",
};
/** 组装 approvalInstanceDto 查询片段(申请人 + 审批单号) */
export function buildApprovalInstanceSearchDto(searchForm = {}, extraParams = {}) {
  const dto = {
    ...(extraParams && typeof extraParams === "object" ? extraParams : {}),
  };
  Object.assign(dto, pickApplicantFromSearchForm(searchForm));
  Object.assign(dto, pickInstanceNoFromSearchForm(searchForm));
  delete dto.createTime;
  delete dto.createTimeStart;
  delete dto.createTimeEnd;
  return dto;
}
function pickDateRange(searchForm) {
  return buildApprovalInstanceSearchDto(searchForm);
}
/** 各模块默认查询表单(与 Web searchForm 字段一致) */
const APPLICANT_ONLY_MODULE_KEYS = new Set([
  APPROVAL_MODULE_KEYS.REGULAR,
  APPROVAL_MODULE_KEYS.TRANSFER,
  APPROVAL_MODULE_KEYS.WORK_HANDOVER,
  APPROVAL_MODULE_KEYS.LEAVE,
  APPROVAL_MODULE_KEYS.OVERTIME,
  APPROVAL_MODULE_KEYS.TRAVEL_REIMBURSE,
  APPROVAL_MODULE_KEYS.COST_REIMBURSE,
]);
function withInstanceNoSearch(moduleKey, base) {
  if (INSTANCE_NO_SEARCH_MODULE_KEYS.has(moduleKey)) {
    return { instanceNo: "", ...base };
  }
  return base;
}
function applicantOnlySearchForm(moduleKey) {
  if (moduleKey === APPROVAL_MODULE_KEYS.REGULAR) {
    return withInstanceNoSearch(moduleKey, { applicantName: "" });
  }
  if (
    moduleKey === APPROVAL_MODULE_KEYS.TRANSFER ||
    moduleKey === APPROVAL_MODULE_KEYS.WORK_HANDOVER
  ) {
    return withInstanceNoSearch(moduleKey, { applicantId: "" });
  }
  if (APPLICANT_ONLY_MODULE_KEYS.has(moduleKey)) {
    return withInstanceNoSearch(moduleKey, { applicantKeyword: "" });
  }
  return {};
}
export function createModuleSearchForm(moduleKey) {
  if (APPLICANT_ONLY_MODULE_KEYS.has(moduleKey)) {
    return applicantOnlySearchForm(moduleKey);
  }
  if (moduleKey === APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS) {
    return { applicantKeyword: "" };
  }
  return {};
}
/** 服务端 listPage DTO 片段(与 Web buildApprovalInstanceListParams 一致) */
export function buildModuleListDto(moduleKey, searchForm = {}) {
  return buildApprovalInstanceSearchDto(searchForm);
}
function matchInstanceNo(row, instanceNo) {
  const kw = (instanceNo || "").trim().toLowerCase();
  if (!kw) return true;
  const parts = [row?.instanceNo, row?.bizId]
    .filter(v => v != null && v !== "")
    .map(v => String(v).toLowerCase());
  return parts.some(p => p.includes(kw));
}
export function hasActiveModuleSearch(moduleKey, searchForm = {}) {
  const sf = searchForm || {};
  if ((sf.instanceNo || "").trim()) return true;
  if ((sf.applicantKeyword || "").trim()) return true;
  if ((sf.applicantName || "").trim()) return true;
  return sf.applicantId != null && sf.applicantId !== "";
}
function matchApplicantKeyword(row, keyword) {
@@ -298,131 +372,66 @@
  });
}
/** 前端筛选(Web 未下发接口的字段与 Web 行为一致) */
/** 按申请人、审批单号做前端兜底筛选 */
export function filterRowsByModuleSearch(moduleKey, rows, searchForm = {}) {
  const sf = searchForm || {};
  const list = Array.isArray(rows) ? rows : [];
  if (!hasActiveModuleSearch(moduleKey, sf)) return list;
  switch (moduleKey) {
    case APPROVAL_MODULE_KEYS.TRANSFER:
      return list.filter(
        row =>
          matchApplicantId(row, sf.applicantId) &&
          matchApplicantKeyword(row, sf.applicantKeyword)
      );
    case APPROVAL_MODULE_KEYS.WORK_HANDOVER:
      return list.filter(
        row =>
          matchApplicantId(row, sf.applicantId) &&
          matchSelectValue(row, ["handoverStatus", "交接状态"], sf.handoverStatus) &&
          matchSelectValue(row, ["handoverType", "交接类型"], sf.handoverType)
      );
    case APPROVAL_MODULE_KEYS.LEAVE:
      return list.filter(
        row =>
          matchApplicantKeyword(row, sf.applicantKeyword) &&
          matchSelectValue(row, ["leaveType", "请假类型"], sf.leaveType)
      );
    case APPROVAL_MODULE_KEYS.OVERTIME:
      return list.filter(
        row =>
          matchApplicantKeyword(row, sf.applicantKeyword) &&
          matchSelectValue(row, ["overtimeType", "加班类型"], sf.overtimeType)
      );
    case APPROVAL_MODULE_KEYS.TRAVEL_REIMBURSE:
    case APPROVAL_MODULE_KEYS.COST_REIMBURSE:
    case APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS:
      return list.filter(row => matchApplicantKeyword(row, sf.applicantKeyword));
    default:
      return list;
  }
  return list.filter(
    row =>
      matchInstanceNo(row, sf.instanceNo) &&
      matchApplicantId(row, sf.applicantId) &&
      matchApplicantKeyword(row, sf.applicantKeyword || sf.applicantName)
  );
}
function prependInstanceNoField(fields, moduleKey) {
  if (!INSTANCE_NO_SEARCH_MODULE_KEYS.has(moduleKey)) return fields;
  return [INSTANCE_NO_SEARCH_FIELD, ...fields];
}
/** 模块筛选 UI 配置 */
export function getModuleSearchMeta(moduleKey) {
  switch (moduleKey) {
    case APPROVAL_MODULE_KEYS.REGULAR:
      return {
        fields: [
  if (moduleKey === APPROVAL_MODULE_KEYS.REGULAR) {
    return {
      fields: prependInstanceNoField(
        [
          { key: "applicantName", type: "input", label: "申请人", placeholder: "请输入申请人" },
          { key: "applyDateRange", type: "daterange", label: "申请日期" },
        ],
      };
    case APPROVAL_MODULE_KEYS.TRANSFER:
      return {
        fields: [
          { key: "applicantId", type: "user", label: "申请人", placeholder: "请选择申请人" },
          { key: "transferDateRange", type: "daterange", label: "转岗时间" },
        ],
      };
    case APPROVAL_MODULE_KEYS.WORK_HANDOVER:
      return {
        fields: [
          { key: "applicantId", type: "user", label: "申请人", placeholder: "请选择申请人" },
          {
            key: "handoverStatus",
            type: "select",
            label: "交接状态",
            options: HANDOVER_STATUS_OPTIONS,
          },
          {
            key: "handoverType",
            type: "select",
            label: "交接类型",
            options: HANDOVER_TYPE_OPTIONS,
          },
        ],
      };
    case APPROVAL_MODULE_KEYS.LEAVE:
      return {
        fields: [
          {
            key: "applicantKeyword",
            type: "input",
            label: "申请人",
            placeholder: "姓名或编号",
          },
          {
            key: "leaveType",
            type: "select",
            label: "请假类型",
            options: LEAVE_TYPE_OPTIONS,
          },
        ],
      };
    case APPROVAL_MODULE_KEYS.OVERTIME:
      return {
        fields: [
          {
            key: "applicantKeyword",
            type: "input",
            label: "申请人",
            placeholder: "姓名或编号",
          },
          {
            key: "overtimeType",
            type: "select",
            label: "加班类型",
            options: OVERTIME_TYPE_OPTIONS,
          },
        ],
      };
    case APPROVAL_MODULE_KEYS.TRAVEL_REIMBURSE:
    case APPROVAL_MODULE_KEYS.COST_REIMBURSE:
    case APPROVAL_MODULE_KEYS.ENTERPRISE_NEWS:
      return {
        fields: [
          {
            key: "applicantKeyword",
            type: "input",
            label: "申请人",
            placeholder: "姓名或编号",
          },
        ],
      };
    default:
      return { fields: [] };
        moduleKey
      ),
    };
  }
  if (
    moduleKey === APPROVAL_MODULE_KEYS.TRANSFER ||
    moduleKey === APPROVAL_MODULE_KEYS.WORK_HANDOVER
  ) {
    return {
      fields: prependInstanceNoField(
        [
          { key: "applicantId", type: "user", label: "申请人", placeholder: "请选择申请人" },
        ],
        moduleKey
      ),
    };
  }
  if (APPLICANT_ONLY_MODULE_KEYS.has(moduleKey)) {
    return {
      fields: prependInstanceNoField(
        [
          {
            key: "applicantKeyword",
            type: "input",
            label: "申请人",
            placeholder: "姓名或编号",
          },
        ],
        moduleKey
      ),
    };
  }
  return { fields: [] };
}
export function resetModuleSearchForm(moduleKey, target) {
src/pages/oa/_utils/approvalModuleRegistry.js
@@ -30,6 +30,7 @@
    businessType: APPROVAL_BUSINESS_TYPE[APPROVAL_MODULE_KEYS.REGULAR],
    typeLabels: ["转正", "转正申请"],
    listFields: [
      { label: "审批单号", prop: "instanceNo" },
      { label: "入职日期", prop: "entryDate" },
      { label: "转正日期", prop: "regularDate" },
    ],
@@ -40,6 +41,7 @@
    businessType: APPROVAL_BUSINESS_TYPE[APPROVAL_MODULE_KEYS.TRANSFER],
    typeLabels: ["调岗", "调动", "调岗申请", "调动申请"],
    listFields: [
      { label: "审批单号", prop: "instanceNo" },
      { label: "原岗位", prop: "fromPost" },
      { label: "目标岗位", prop: "toPost" },
    ],
@@ -50,6 +52,7 @@
    businessType: APPROVAL_BUSINESS_TYPE[APPROVAL_MODULE_KEYS.WORK_HANDOVER],
    typeLabels: ["工作交接", "交接", "工作交接审批"],
    listFields: [
      { label: "审批单号", prop: "instanceNo" },
      { label: "交接人", prop: "handoverTo" },
      { label: "交接事项", prop: "handoverItems" },
    ],
@@ -60,6 +63,7 @@
    businessType: APPROVAL_BUSINESS_TYPE[APPROVAL_MODULE_KEYS.LEAVE],
    typeLabels: ["请假", "请假申请", "请假审批"],
    listFields: [
      { label: "审批单号", prop: "instanceNo" },
      { label: "请假类型", prop: "leaveType" },
      { label: "开始时间", prop: "startTime" },
      { label: "结束时间", prop: "endTime" },
@@ -71,6 +75,7 @@
    businessType: APPROVAL_BUSINESS_TYPE[APPROVAL_MODULE_KEYS.OVERTIME],
    typeLabels: ["加班", "加班申请", "加班审批"],
    listFields: [
      { label: "审批单号", prop: "instanceNo" },
      { label: "加班日期", prop: "overtimeDate" },
      { label: "时长(小时)", prop: "hours" },
    ],
src/pages/oa/_utils/approveListUtils.js
@@ -6,6 +6,8 @@
  mergeFormConfigForEdit,
} from "./approvalFormField.js";
import {
  appendDotNotationQuery,
  buildApprovalInstanceSearchDto,
  formatKnownSelectLabel,
  resolveInstanceFormPayload,
  resolveListFieldRawValue,
@@ -272,8 +274,7 @@
}
/**
 * 与 Web buildApprovalInstanceListParams 一致:扁平 query(current/size/businessType/...)
 * 审批列表不传 businessType 即查全部
 * 与 Web buildApprovalInstanceListParams 一致
 */
export function buildInstanceListParams({
  page,
@@ -281,37 +282,20 @@
  extraDto = {},
  searchForm,
}) {
  const extra = { ...(extraDto && typeof extraDto === "object" ? extraDto : {}) };
  if (extra.createTime != null && extra.createTimeStart == null) {
    extra.createTimeStart = extra.createTime;
  const dto = buildApprovalInstanceSearchDto(searchForm, extraDto);
  const bizType = businessType ?? searchForm?.businessType;
  if (bizType != null && bizType !== "") {
    dto.businessType = bizType;
  }
  delete extra.createTime;
  const params = {
    current: page.current,
    size: page.size,
    ...extra,
    "page.current": page.current,
    "page.size": page.size,
    ...dto,
  };
  const bizType = businessType ?? searchForm?.businessType;
  if (bizType != null && bizType !== "") {
    params.businessType = bizType;
  }
  if (searchForm?.status) {
    params.status = searchForm.status;
  }
  const range =
    searchForm?.createTimeRange ??
    searchForm?.applyDateRange ??
    searchForm?.transferDateRange;
  if (Array.isArray(range) && range[0] && params.createTimeStart == null) {
    params.createTimeStart = range[0];
  }
  if (Array.isArray(range) && range[1] && params.createTimeEnd == null) {
    params.createTimeEnd = range[1];
  }
  appendDotNotationQuery(params, "approvalInstanceDto", dto);
  return params;
}
src/pages/oa/_utils/finReimbursementMappers.js
@@ -159,8 +159,43 @@
function pickApplicantQuery(searchForm = {}) {
  const kw = (searchForm.applicantKeyword || "").trim();
  if (!kw) return {};
  if (/[\u4e00-\u9fa5]/.test(kw)) return { applicantName: kw };
  return { applicantCode: kw };
  const out = { applicantName: kw };
  if (!/[\u4e00-\u9fa5]/.test(kw)) {
    out.applicantCode = kw;
  }
  return out;
}
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;
  }
}
export function buildFinReimbursementListParams({
@@ -175,30 +210,15 @@
    ...(extraDto && typeof extraDto === "object" ? extraDto : {}),
  };
  const range = searchForm?.createTimeRange ?? searchForm?.applyDateRange;
  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) {