Files
platforms/frontend/platform_admin/src/api/resource-staff-relation.ts
czl231 6bcde94388 功能:完善用户服务关系展示与组织联动
统一平台、气站和配送点后台的服务关系业务名称展示。
新增气站、配送点、服务人员三级联动及暂未分配语义。
后端补充组织归属、人员角色和启用状态的严格校验。
补充前后端测试、项目文档、操作日志及本机日志忽略规则。
2026-08-12 00:37:58 +08:00

138 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 功能:定义工作人员关联字段的显式过滤、角色展示与资质来源校验策略。
* 版本v1.0.0
*/
export const staffRoleCodes = ['installer', 'delivery', 'operations'] as const;
export type StaffRoleCode = (typeof staffRoleCodes)[number];
export type StaffRelationPolicy = {
roles: readonly StaffRoleCode[] | 'context';
enabledOnly?: boolean;
workStatus?: 'on_duty' | 'off_duty';
lockPrefilled?: boolean;
showIdentityCopy?: boolean;
organizationScoped?: boolean;
};
export type StaffRelationContext = {
staffType?: string;
};
type StaffRelationField = {
relation?: string;
staffRelation?: StaffRelationPolicy;
};
type StaffOwner = {
identity?: unknown;
role_code?: unknown;
status?: unknown;
};
const roleLabels: Record<StaffRoleCode, string> = {
installer: '安装人员',
delivery: '配送人员',
operations: '运维人员',
};
/** 将外部字符串收敛为工作人员闭集角色。 */
export function normalizeStaffRole(value: unknown): StaffRoleCode | '' {
const role = String(value ?? '').trim();
return staffRoleCodes.includes(role as StaffRoleCode)
? (role as StaffRoleCode)
: '';
}
/** 返回工作人员角色的中文名称。 */
export function staffRoleLabel(value: unknown) {
const role = normalizeStaffRole(value);
return role ? roleLabels[role] : '未知角色';
}
/**
* 为工作人员关联字段构造服务端过滤条件;缺少显式策略时立即失败,
* 防止业务字段再次继承隐含的配送人员默认值。
*/
export function staffRelationFilters(
field: StaffRelationField,
context: StaffRelationContext = {},
) {
if (field.relation !== '/staff_account') return {};
if (!field.staffRelation) {
throw new Error('工作人员关联字段缺少显式过滤策略');
}
const roles =
field.staffRelation.roles === 'context'
? [normalizeStaffRole(context.staffType)].filter(
(role): role is StaffRoleCode => Boolean(role),
)
: [...field.staffRelation.roles];
if (!roles.length) throw new Error('工作人员关联字段缺少有效角色上下文');
const filters: Record<string, string> =
roles.length === 1
? { role_code: roles[0] }
: { role_codes: roles.join(',') };
if (field.staffRelation.enabledOnly) filters.status = '1';
if (field.staffRelation.workStatus) {
filters.work_status = field.staffRelation.workStatus;
}
return filters;
}
/** 从站内返回地址中推断工作人员菜单角色,仅用作显式参数缺失时的回退。 */
export function staffRoleFromReturnPath(returnTo: string) {
let current = returnTo;
for (let depth = 0; depth < 3 && current; depth += 1) {
const url = new URL(current, 'http://codex.local');
const queryRole = normalizeStaffRole(url.searchParams.get('staff_type'));
if (queryRole) return queryRole;
const pathRole = [
['/staff/installers', 'installer'],
['/staff/delivery', 'delivery'],
['/staff/operations', 'operations'],
].find(([path]) => url.pathname.startsWith(path))?.[1];
if (pathRole) return pathRole as StaffRoleCode;
current = url.searchParams.get('return_to') ?? '';
}
return '';
}
/** 解析资质页面角色来源,并拒绝显式参数与返回路径互相冲突。 */
export function resolveCredentialStaffRole(
explicitRole: unknown,
returnTo: string,
) {
const explicit = normalizeStaffRole(explicitRole);
const inferred = staffRoleFromReturnPath(returnTo);
if (explicit && inferred && explicit !== inferred) {
return { role: '' as const, error: '工作人员角色与来源菜单不一致' };
}
const role = explicit || inferred;
return role
? { role, error: '' }
: {
role: '' as const,
error: '缺少工作人员角色来源,请从工作人员页面进入',
};
}
/** 校验资质所有者与经服务端查询得到的真实人员记录是否一致。 */
export function credentialOwnerValidationMessage(
ownerIdentity: string,
expectedRole: StaffRoleCode,
owner: StaffOwner | undefined,
) {
if (!ownerIdentity) return '缺少工作人员唯一标识,请从工作人员页面进入';
if (!owner) return '工作人员不存在、已归档或无权访问';
if (String(owner.identity ?? '') !== ownerIdentity) {
return '工作人员唯一标识与查询结果不一致';
}
if (normalizeStaffRole(owner.role_code) !== expectedRole) {
return '工作人员角色已变化,请从当前角色菜单重新进入';
}
if (Number(owner.status) === 3) return '已归档工作人员不能新增资质';
return '';
}