import dayjs from "dayjs";
|
import {
|
APPROVAL_MODULE_KEYS,
|
APPROVAL_MODULE_REGISTRY,
|
getModuleMatchingBusinessTypes,
|
} from "./approvalModuleRegistry.js";
|
import { matchBusinessTypeValue } from "./approvalTemplateType.js";
|
import { parseDatetimerangeValue } from "./approvalFormField.js";
|
|
/** 人员下拉字段识别(与 Web SELECT_OPTION_SOURCE.USER 等价) */
|
export function isUserSelectField(field) {
|
const src = String(field?.optionSource ?? "").toLowerCase();
|
return (
|
src === "user" ||
|
src === "personnel" ||
|
src === "userlist" ||
|
(field?.type === "select" && String(field?.label || "").includes("申请人"))
|
);
|
}
|
|
export function findApplicantTemplateField(fields = []) {
|
return (
|
fields.find(f => String(f?.label || "").includes("申请人")) ||
|
fields.find(f => isUserSelectField(f)) ||
|
null
|
);
|
}
|
|
/* ---------- 请假 ---------- */
|
|
export function isLeaveBalanceField(field) {
|
const label = String(field?.label || "");
|
return label.includes("假期余额") || field?.key === "leaveBalanceDays";
|
}
|
|
export function isLeaveDurationField(field) {
|
const label = String(field?.label || "");
|
return label.includes("请假时长") || field?.key === "leaveDurationDays";
|
}
|
|
export function displayLeaveTemplateFields(fields = []) {
|
return (fields || []).filter(
|
f => !isLeaveBalanceField(f) && !isLeaveDurationField(f)
|
);
|
}
|
|
export function findLeaveTimeTemplateField(fields = []) {
|
return (
|
fields.find(
|
f => f?.type === "datetimerange" && String(f?.label || "").includes("请假时间")
|
) ||
|
fields.find(f => f?.type === "datetimerange" && f?.key === "dateRange") ||
|
fields.find(f => f?.type === "datetimerange") ||
|
null
|
);
|
}
|
|
export function resolveTimeRangeFromPayload(payload, timeField) {
|
if (!timeField?.key) return { start: "", end: "" };
|
const val = payload?.[timeField.key];
|
if (Array.isArray(val) && val.length >= 2) {
|
return { start: val[0] || "", end: val[1] || "" };
|
}
|
return parseDatetimerangeValue(val);
|
}
|
|
export function computeLeaveDays(startStr, endStr) {
|
if (!startStr || !endStr) return null;
|
const t0 = dayjs(startStr);
|
const t1 = dayjs(endStr);
|
if (!t0.isValid() || !t1.isValid() || !t1.isAfter(t0)) return null;
|
const days = t1.diff(t0, "millisecond") / (24 * 60 * 60 * 1000);
|
return Math.round(days * 100) / 100;
|
}
|
|
export function computeLeaveDurationDisplay(fields, formPayload) {
|
const timeField = findLeaveTimeTemplateField(fields);
|
const { start, end } = resolveTimeRangeFromPayload(formPayload, timeField);
|
const d = computeLeaveDays(start, end);
|
return d == null ? "" : String(d);
|
}
|
|
export function validateLeaveBeforeSubmit(fields, formPayload) {
|
const timeField = findLeaveTimeTemplateField(fields);
|
const { start, end } = resolveTimeRangeFromPayload(formPayload, timeField);
|
if (computeLeaveDays(start, end) == null) {
|
return "请检查模板中的请假时间,结束时间须晚于开始时间";
|
}
|
return "";
|
}
|
|
/* ---------- 加班 ---------- */
|
|
export function isOvertimeDurationField(field) {
|
const label = String(field?.label || "");
|
return label.includes("加班时长") || field?.key === "overtimeHours";
|
}
|
|
export function displayOvertimeTemplateFields(fields = []) {
|
return (fields || []).filter(f => !isOvertimeDurationField(f));
|
}
|
|
export function findOvertimeTimeTemplateField(fields = []) {
|
return (
|
fields.find(
|
f => f?.type === "datetimerange" && String(f?.label || "").includes("加班时间")
|
) ||
|
fields.find(f => f?.type === "datetimerange") ||
|
null
|
);
|
}
|
|
export function computeOvertimeHours(startStr, endStr) {
|
if (!startStr || !endStr) return null;
|
const t0 = dayjs(startStr);
|
const t1 = dayjs(endStr);
|
if (!t0.isValid() || !t1.isValid() || !t1.isAfter(t0)) return null;
|
return Math.round((t1.diff(t0, "millisecond") / 3600000) * 100) / 100;
|
}
|
|
export function computeOvertimeHoursDisplay(fields, formPayload) {
|
const field = findOvertimeTimeTemplateField(fields);
|
const { start, end } = resolveTimeRangeFromPayload(formPayload, field);
|
const h = computeOvertimeHours(start, end);
|
return h == null ? "" : String(h);
|
}
|
|
export function validateOvertimeBeforeSubmit(fields, formPayload) {
|
const field = findOvertimeTimeTemplateField(fields);
|
const { start, end } = resolveTimeRangeFromPayload(formPayload, field);
|
if (computeOvertimeHours(start, end) == null) {
|
return "请检查模板中的加班时间,结束时间须晚于开始时间";
|
}
|
return "";
|
}
|
|
/* ---------- 调岗 ---------- */
|
|
export function isOriginalPostField(field) {
|
const label = String(field?.label || "");
|
return (
|
label.includes("原岗位") ||
|
field?.key === "originalPost" ||
|
field?.key === "originalPostName" ||
|
field?.key === "originalPostId"
|
);
|
}
|
|
export function displayTransferTemplateFields(fields = []) {
|
return (fields || []).filter(f => !isOriginalPostField(f));
|
}
|
|
export function unwrapUserArray(payload) {
|
if (Array.isArray(payload)) return payload;
|
if (payload?.data && Array.isArray(payload.data)) return payload.data;
|
if (payload?.rows && Array.isArray(payload.rows)) return payload.rows;
|
return [];
|
}
|
|
export function isActiveUser(u) {
|
if (u?.delFlag === "2" || u?.delFlag === 2) return false;
|
if (u?.status == null) return true;
|
return String(u.status) === "0";
|
}
|
|
export function firstPostId(user) {
|
if (!user) return undefined;
|
if (Array.isArray(user.postIds) && user.postIds.length) return user.postIds[0];
|
if (user.postId != null && user.postId !== "") return user.postId;
|
return undefined;
|
}
|
|
export function buildPostIdToNameMap(postRows = []) {
|
const m = {};
|
for (const p of postRows) {
|
const id = p.postId ?? p.value ?? p.id;
|
if (id != null && id !== "") {
|
m[String(id)] = p.postName ?? p.label ?? p.name ?? "";
|
}
|
}
|
return m;
|
}
|
|
export function resolveOriginalPostName(user, postIdToName = {}) {
|
if (!user) return "";
|
const nameStr = (user.postName ?? user.postname ?? "").toString().trim();
|
if (nameStr) return nameStr;
|
if (Array.isArray(user.posts) && user.posts.length) {
|
return (user.posts[0].postName ?? "").toString() || "未命名岗位";
|
}
|
const pid = firstPostId(user);
|
if (pid != null && pid !== "") {
|
const n = postIdToName[String(pid)] || "";
|
return n || "当前岗位(未在岗位字典中)";
|
}
|
return "未分配岗位";
|
}
|
|
export function userById(users, id) {
|
if (id == null || id === "") return undefined;
|
return (users || []).find(u => String(u.userId ?? u.id) === String(id));
|
}
|
|
/** 按 moduleKey 过滤模板填报项 */
|
export function displayTemplateFieldsByModule(moduleKey, fields = []) {
|
if (moduleKey === APPROVAL_MODULE_KEYS.LEAVE) {
|
return displayLeaveTemplateFields(fields);
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.OVERTIME) {
|
return displayOvertimeTemplateFields(fields);
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.TRANSFER) {
|
return displayTransferTemplateFields(fields);
|
}
|
return fields || [];
|
}
|
|
/** 保存前将业务扩展字段写入 formValues */
|
export function syncModuleExtrasToFormValues(moduleKey, formValues, extras, fields) {
|
if (!moduleKey || !formValues) return;
|
if (moduleKey === APPROVAL_MODULE_KEYS.LEAVE) {
|
if (extras.leaveBalanceDays != null && extras.leaveBalanceDays !== "") {
|
formValues.leaveBalanceDays = extras.leaveBalanceDays;
|
}
|
const days = computeLeaveDurationDisplay(fields, formValues);
|
if (days) formValues.leaveDurationDays = days;
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.OVERTIME) {
|
const hours = computeOvertimeHoursDisplay(fields, formValues);
|
if (hours) formValues.overtimeHours = hours;
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.TRANSFER && extras.originalPostName) {
|
formValues.originalPostName = extras.originalPostName;
|
formValues.originalPost = extras.originalPostName;
|
}
|
}
|
|
/** 业务扩展校验 */
|
export function validateModuleExtras(moduleKey, fields, formPayload, extras) {
|
if (moduleKey === APPROVAL_MODULE_KEYS.LEAVE) {
|
if (
|
extras.leaveBalanceDays == null ||
|
extras.leaveBalanceDays === "" ||
|
Number.isNaN(Number(extras.leaveBalanceDays))
|
) {
|
return "请填写假期余额";
|
}
|
const msg = validateLeaveBeforeSubmit(fields, formPayload);
|
if (msg) return msg;
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.OVERTIME) {
|
const msg = validateOvertimeBeforeSubmit(fields, formPayload);
|
if (msg) return msg;
|
}
|
return "";
|
}
|
|
/** 从实例 businessType 推断 moduleKey(编辑入口未带 moduleKey 时) */
|
export function inferModuleKeyFromRow(row, typeOptions = []) {
|
const bt = row?.businessType;
|
if (bt == null || bt === "") return "";
|
for (const key of Object.values(APPROVAL_MODULE_KEYS)) {
|
const types = getModuleMatchingBusinessTypes(key, typeOptions);
|
if (types.some(t => matchBusinessTypeValue(t, bt))) return key;
|
const cfg = APPROVAL_MODULE_REGISTRY[key];
|
if (cfg && matchBusinessTypeValue(cfg.approvalType, bt)) return key;
|
}
|
return "";
|
}
|
|
/** 编辑回显:从实例行恢复扩展字段 */
|
export function loadModuleExtrasFromRow(moduleKey, row, formPayload) {
|
const extras = {
|
leaveBalanceDays: undefined,
|
originalPostName: "",
|
};
|
if (!moduleKey || !row) return extras;
|
|
const payload = formPayload || {};
|
if (moduleKey === APPROVAL_MODULE_KEYS.LEAVE) {
|
const v = payload.leaveBalanceDays ?? row.leaveBalanceDays;
|
extras.leaveBalanceDays =
|
v != null && v !== "" ? Number(v) : undefined;
|
}
|
if (moduleKey === APPROVAL_MODULE_KEYS.TRANSFER) {
|
extras.originalPostName =
|
payload.originalPostName ||
|
payload.originalPost ||
|
row.originalPostName ||
|
"";
|
}
|
return extras;
|
}
|