| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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"; |
| | | } |
| | | |
| | | /** è§£æå®ä¾ 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ï¼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; |
| | | } |
| | | |
| | | 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 ?? ""}`; |
| | | } |