From 0333d66e4b397c161c6a44ce1e2a121c2cc41082 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 28 五月 2026 09:20:20 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' into dev_天津_中兴实强
---
src/pages/oa/_utils/approvalModuleListSearch.js | 456 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 456 insertions(+), 0 deletions(-)
diff --git a/src/pages/oa/_utils/approvalModuleListSearch.js b/src/pages/oa/_utils/approvalModuleListSearch.js
new file mode 100644
index 0000000..a98409a
--- /dev/null
+++ b/src/pages/oa/_utils/approvalModuleListSearch.js
@@ -0,0 +1,456 @@
+import {
+ APPROVAL_MODULE_KEYS,
+ APPROVAL_MODULE_REGISTRY,
+ getApprovalModuleConfig,
+ getModuleMatchingBusinessTypes,
+} from "./approvalModuleRegistry.js";
+import {
+ parseApprovalFormConfig,
+ parseDatetimerangeValue,
+} from "./approvalFormField.js";
+import { matchBusinessTypeValue } from "./approvalTemplateType.js";
+
+/** 涓� Web leave-apply LEAVE_TYPE_OPTIONS 涓�鑷� */
+export const LEAVE_TYPE_OPTIONS = [
+ { label: "骞村亣", value: "annual" },
+ { label: "鐥呭亣", value: "sick" },
+ { label: "浜嬪亣", value: "personal" },
+ { label: "濠氬亣", value: "marriage" },
+ { label: "浜у亣", value: "maternity" },
+ { label: "鍝轰钩鍋�", value: "nursing" },
+ { label: "鎱板攣鍋�", value: "condolence" },
+ { label: "璋冧紤", value: "compensatory" },
+];
+
+/** 涓� Web overtime-apply OVERTIME_TYPE_OPTIONS 涓�鑷� */
+export const OVERTIME_TYPE_OPTIONS = [
+ { label: "宸ヤ綔鏃ュ姞鐝�", value: "weekday" },
+ { label: "浼戞伅鏃ュ姞鐝�", value: "weekend" },
+ { label: "娉曞畾鑺傚亣鏃ュ姞鐝�", value: "holiday" },
+];
+
+export const HANDOVER_STATUS_OPTIONS = [
+ { label: "杩涜涓�", value: "in_progress" },
+ { label: "宸插畬鎴�", value: "completed" },
+ { label: "宸查��鍥�", value: "returned" },
+];
+
+export const HANDOVER_TYPE_OPTIONS = [
+ { label: "绂昏亴浜ゆ帴", value: "resignation" },
+ { label: "璋冨矖浜ゆ帴", value: "transfer" },
+];
+
+function buildFormPayloadFromFields(fields = []) {
+ const payload = {};
+ for (const f of fields) {
+ if (!f?.key) continue;
+ const val = f.value ?? f.defaultValue;
+ if (val !== undefined && val !== null && val !== "") {
+ payload[f.key] = val;
+ }
+ }
+ return payload;
+}
+
+function guessFieldTypeFromValue(val) {
+ if (Array.isArray(val)) return "datetimerange";
+ if (typeof val === "number") return "number";
+ return "text";
+}
+
+/** 瑙f瀽瀹炰緥 formConfig / formPayload锛堜笌 Web resolveInstanceFormFields 瀵归綈锛� */
+export function resolveInstanceFormPayload(row) {
+ const cfg = parseApprovalFormConfig(row?.formConfig);
+ let fields = (row?.formFieldDefs?.length ? row.formFieldDefs : cfg.fields) || [];
+ const formPayload = {
+ ...(fields.length ? buildFormPayloadFromFields(fields) : {}),
+ ...cfg.formPayload,
+ ...(row?.formPayload || {}),
+ };
+ if (!fields.length && Object.keys(formPayload).length) {
+ fields = Object.keys(formPayload)
+ .filter(k => k && k !== "summary")
+ .map(k => ({
+ key: k,
+ label: k,
+ type: guessFieldTypeFromValue(formPayload[k]),
+ required: false,
+ options: [],
+ }));
+ }
+ fields = fields.map(field => ({
+ ...field,
+ value:
+ formPayload[field.key] ?? field.value ?? field.defaultValue ?? "",
+ }));
+ return { fields, formPayload };
+}
+
+/** 宸茬煡涓嬫媺瀛楁 value 鈫� 灞曠ず鏂囨锛堟ā鏉挎湭甯� options 鏃跺厹搴曪級 */
+export function formatKnownSelectLabel(prop, val) {
+ if (val === undefined || val === null || val === "") return "";
+ const maps = {
+ leaveType: LEAVE_TYPE_OPTIONS,
+ overtimeType: OVERTIME_TYPE_OPTIONS,
+ handoverStatus: HANDOVER_STATUS_OPTIONS,
+ handoverType: HANDOVER_TYPE_OPTIONS,
+ };
+ const options = maps[prop];
+ if (!options) return "";
+ const hit = options.find(o => String(o.value) === String(val));
+ return hit?.label || "";
+}
+
+export function getRowPayloadValue(row, keys) {
+ const keyList = Array.isArray(keys) ? keys : [keys];
+ const { formPayload } = resolveInstanceFormPayload(row);
+ for (const k of keyList) {
+ if (row?.[k] != null && row[k] !== "") return row[k];
+ if (formPayload[k] != null && formPayload[k] !== "") return formPayload[k];
+ }
+ return "";
+}
+
+const DATETIME_RANGE_KEYS = [
+ "dateRange",
+ "leaveTime",
+ "overtimeTime",
+ "timeRange",
+];
+
+function pickDatetimerangeRaw(formPayload, fields = []) {
+ for (const key of DATETIME_RANGE_KEYS) {
+ const v = formPayload?.[key];
+ if (v != null && v !== "") return v;
+ const field = (fields || []).find(f => f?.key === key);
+ const fv = field?.value ?? field?.defaultValue;
+ if (fv != null && fv !== "") return fv;
+ }
+ const rangeField = (fields || []).find(
+ f => String(f?.type || "").toLowerCase() === "datetimerange"
+ );
+ if (rangeField?.key) {
+ const v =
+ formPayload?.[rangeField.key] ?? rangeField.value ?? rangeField.defaultValue;
+ if (v != null && v !== "") return v;
+ }
+ return null;
+}
+
+function splitRangeValue(val) {
+ if (val === undefined || val === null || val === "") {
+ return { start: "", end: "" };
+ }
+ if (Array.isArray(val)) {
+ return { start: val[0] || "", end: val[1] || "" };
+ }
+ return parseDatetimerangeValue(val);
+}
+
+/**
+ * 鍒楄〃鍒� prop 涓� formPayload 瀵归綈锛堣鍋� startTime/endTime 鏉ヨ嚜 dateRange锛�
+ */
+export function resolveListFieldRawValue(prop, row, fields = [], formPayload = {}) {
+ const payload = formPayload || {};
+ const direct = payload[prop] ?? row?.[prop];
+
+ if (prop === "startTime" || prop === "endTime") {
+ if (direct != null && direct !== "") return direct;
+ const altStart =
+ payload.start ?? payload.startDate ?? payload.beginTime ?? row?.startTime;
+ const altEnd =
+ payload.end ?? payload.endDate ?? payload.finishTime ?? row?.endTime;
+ if (prop === "startTime" && altStart) return altStart;
+ if (prop === "endTime" && altEnd) return altEnd;
+ const { start, end } = splitRangeValue(pickDatetimerangeRaw(payload, fields));
+ return prop === "startTime" ? start : end;
+ }
+
+ if (prop === "overtimeDate") {
+ const d = payload.overtimeDate ?? payload.date ?? direct;
+ if (d != null && d !== "") return Array.isArray(d) ? d[0] || "" : d;
+ const { start } = splitRangeValue(pickDatetimerangeRaw(payload, fields));
+ return start || "";
+ }
+
+ if (direct != null && direct !== "") return direct;
+ const hit = (fields || []).find(f => f?.key === prop);
+ return hit?.value ?? hit?.defaultValue ?? "";
+}
+
+/** 鎵佸钩鍖栦负 Spring GET 鍙粦瀹氱殑 query锛坅pprovalInstanceDto.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;
+}
+
+function pickInstanceNoFromSearchForm(searchForm = {}) {
+ const no = (searchForm?.instanceNo || "").trim();
+ return no ? { instanceNo: no } : {};
+}
+
+/** 鏀寔瀹℃壒鍗曞彿鏌ヨ鐨勫鎵圭敵璇锋ā鍧� */
+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,
+]);
+
+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) {
+ const kw = (keyword || "").trim().toLowerCase();
+ if (!kw) return true;
+ const parts = [
+ row?.applicantName,
+ row?.applicantNo,
+ row?.applicantId,
+ getRowPayloadValue(row, ["applicant", "applicantName", "applicantId"]),
+ ]
+ .filter(v => v != null && v !== "")
+ .map(v => String(v).toLowerCase());
+ return parts.some(p => p.includes(kw));
+}
+
+function matchSelectValue(row, keys, expected) {
+ if (!expected) return true;
+ const raw = getRowPayloadValue(row, keys);
+ return String(raw) === String(expected);
+}
+
+function matchApplicantId(row, applicantId) {
+ if (!applicantId) return true;
+ const id = String(applicantId);
+ if (row?.applicantId != null && String(row.applicantId) === id) return true;
+ const payloadApplicant = getRowPayloadValue(row, [
+ "applicant",
+ "applicantId",
+ "applicantUserId",
+ ]);
+ return String(payloadApplicant) === id;
+}
+
+/** 鎸夋ā鍧� businessType / 鏍囬褰掑睘杩囨护锛堟湇鍔$鏈敓鏁堟椂鐨勫厹搴曪級 */
+export function filterRowsByModuleBusinessType(moduleKey, rows, typeOptions = []) {
+ const cfg = getApprovalModuleConfig(moduleKey);
+ if (!cfg) return rows;
+
+ const types = getModuleMatchingBusinessTypes(moduleKey, typeOptions);
+ const myLabels = [cfg.label, ...(cfg.typeLabels || [])].filter(Boolean);
+
+ return (rows || []).filter(row => {
+ if (types.length && row?.businessType != null && row.businessType !== "") {
+ if (types.some(t => matchBusinessTypeValue(row.businessType, t))) {
+ return true;
+ }
+ }
+
+ const title = String(row?.title || row?.templateName || "").trim();
+ if (title) {
+ if (myLabels.some(l => title === l || title.includes(l))) return true;
+ for (const [key, other] of Object.entries(APPROVAL_MODULE_REGISTRY)) {
+ if (key === moduleKey) continue;
+ const otherLabels = [other.label, ...(other.typeLabels || [])].filter(Boolean);
+ if (otherLabels.some(l => title === l || (l.length > 2 && title.includes(l)))) {
+ return false;
+ }
+ }
+ }
+
+ return types.length === 0;
+ });
+}
+
+/** 鎸夌敵璇蜂汉銆佸鎵瑰崟鍙峰仛鍓嶇鍏滃簳绛涢�� */
+export function filterRowsByModuleSearch(moduleKey, rows, searchForm = {}) {
+ const sf = searchForm || {};
+ const list = Array.isArray(rows) ? rows : [];
+ if (!hasActiveModuleSearch(moduleKey, sf)) 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) {
+ if (moduleKey === APPROVAL_MODULE_KEYS.REGULAR) {
+ return {
+ fields: prependInstanceNoField(
+ [
+ { key: "applicantName", type: "input", label: "鐢宠浜�", placeholder: "璇疯緭鍏ョ敵璇蜂汉" },
+ ],
+ 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) {
+ const defaults = createModuleSearchForm(moduleKey);
+ Object.keys(target).forEach(k => {
+ if (!(k in defaults)) delete target[k];
+ });
+ Object.assign(target, defaults);
+}
+
+export function formatDateRangeLabel(range) {
+ if (!Array.isArray(range) || !range[0]) return "";
+ if (range[1]) return `${range[0]} 鑷� ${range[1]}`;
+ return range[0];
+}
+
+export function userSelectLabel(u) {
+ const nick = u?.nickName || "";
+ const name = u?.userName || "";
+ if (nick && name && nick !== name) return `${nick}锛�${name}锛塦;
+ return nick || name || `鐢ㄦ埛${u?.userId ?? u?.id ?? ""}`;
+}
--
Gitblit v1.9.3