OAFLOW1 支持负责人本人报销兜底审批

这个提交包含在:
2026-05-24 21:12:18 +08:00
父节点 d6ae1cff89
当前提交 2e778d3c9f
共修改 23 个文件,包含 1324 行新增和 86 行删除
+3 -1
查看文件
@@ -9,6 +9,7 @@ export type ApprovalRoleCode =
| "administration"
| "hr"
| "admin";
export type ApprovalOwnerSelfFallbackRoleCode = "finance_mgr";
export type ApprovalRule = {
id: string;
@@ -18,6 +19,7 @@ export type ApprovalRule = {
level1Role: ApprovalRoleCode;
level2Role: ApprovalRoleCode | null;
level3Role: ApprovalRoleCode | null;
ownerSelfFallbackRole: ApprovalOwnerSelfFallbackRoleCode | null;
enabled: boolean;
priority: number;
createdAt: string | null;
@@ -46,6 +48,7 @@ export type ApprovalRuleCreatePayload = {
level1Role: ApprovalRoleCode;
level2Role: ApprovalRoleCode | null;
level3Role: ApprovalRoleCode | null;
ownerSelfFallbackRole: ApprovalOwnerSelfFallbackRoleCode | null;
enabled?: boolean;
priority?: number;
};
@@ -65,4 +68,3 @@ export async function patchApprovalRule(approvalRuleId: string, payload: Approva
body: JSON.stringify(payload),
});
}
+50 -2
查看文件
@@ -7,6 +7,7 @@ import {
createApprovalRule,
fetchApprovalRules,
patchApprovalRule,
type ApprovalOwnerSelfFallbackRoleCode,
type ApprovalRoleCode,
type ApprovalRule,
} from "../api/approvalRules";
@@ -27,6 +28,9 @@ const ROLE_OPTIONS: Array<{ code: ApprovalRoleCode; label: string }> = [
{ code: "finance_mgr", label: "finance_mgr" },
{ code: "admin", label: "admin" },
];
const OWNER_SELF_FALLBACK_ROLE_OPTIONS = ROLE_OPTIONS.filter(
(role) => role.code === "finance_mgr",
);
function formatAmount(value: string | null) {
if (!value) return "-";
@@ -44,6 +48,7 @@ export function ApprovalRulesPage() {
const [level1Role, setLevel1Role] = useState<ApprovalRoleCode>("manager");
const [level2Role, setLevel2Role] = useState<ApprovalRoleCode | "">("");
const [level3Role, setLevel3Role] = useState<ApprovalRoleCode | "">("");
const [ownerSelfFallbackRole, setOwnerSelfFallbackRole] = useState<ApprovalOwnerSelfFallbackRoleCode | "">("finance_mgr");
const [enabled, setEnabled] = useState(true);
const [editOpen, setEditOpen] = useState(false);
@@ -65,10 +70,11 @@ export function ApprovalRulesPage() {
level1Role,
level2Role: level2Role ? (level2Role as ApprovalRoleCode) : null,
level3Role: level3Role ? (level3Role as ApprovalRoleCode) : null,
ownerSelfFallbackRole: ownerSelfFallbackRole ? (ownerSelfFallbackRole as ApprovalOwnerSelfFallbackRoleCode) : null,
enabled,
priority: priority.trim() ? Number(priority) : undefined,
};
}, [enabled, level1Role, level2Role, level3Role, maxAmount, minAmount, name, priority]);
}, [enabled, level1Role, level2Role, level3Role, maxAmount, minAmount, name, ownerSelfFallbackRole, priority]);
const createMutation = useMutation({
mutationFn: () => createApprovalRule(createPayload),
@@ -81,6 +87,7 @@ export function ApprovalRulesPage() {
setLevel1Role("manager");
setLevel2Role("");
setLevel3Role("");
setOwnerSelfFallbackRole("finance_mgr");
setEnabled(true);
setError("");
toast.success("规则已创建");
@@ -141,6 +148,7 @@ export function ApprovalRulesPage() {
setLevel1Role(editRule.level1Role);
setLevel2Role(editRule.level2Role ?? "");
setLevel3Role(editRule.level3Role ?? "");
setOwnerSelfFallbackRole(editRule.ownerSelfFallbackRole ?? "");
}, [editOpen, editRule]);
return (
@@ -262,6 +270,25 @@ export function ApprovalRulesPage() {
</select>
</div>
<div className="space-y-1">
<Label htmlFor="ownerSelfFallbackRole">负责人本人兜底角色</Label>
<select
id="ownerSelfFallbackRole"
data-testid="approval-rules-create-owner-self-fallback"
className="select-std"
value={ownerSelfFallbackRole}
onChange={(event) => setOwnerSelfFallbackRole(event.target.value as ApprovalOwnerSelfFallbackRoleCode)}
>
<option value="">无</option>
{OWNER_SELF_FALLBACK_ROLE_OPTIONS.map((role) => (
<option key={role.code} value={role.code}>
{role.label}
</option>
))}
</select>
<p className="text-xs text-zinc-500">推荐 finance_mgr;不使用 admin。</p>
</div>
<div className="flex items-center gap-2 pt-6">
<input
id="ruleEnabled"
@@ -328,7 +355,10 @@ export function ApprovalRulesPage() {
{formatAmount(rule.minAmount)} ~ {rule.maxAmount ? formatAmount(rule.maxAmount) : "∞"}
</TableCell>
<TableCell className="text-sm text-zinc-700">
{[rule.level1Role, rule.level2Role, rule.level3Role].filter(Boolean).join(" -> ") || "-"}
<div>{[rule.level1Role, rule.level2Role, rule.level3Role].filter(Boolean).join(" -> ") || "-"}</div>
<div className="mt-1 text-xs text-zinc-500">
本人兜底:{rule.ownerSelfFallbackRole ?? "无"}
</div>
</TableCell>
<TableCell>{rule.priority}</TableCell>
<TableCell className="text-sm">
@@ -483,6 +513,24 @@ export function ApprovalRulesPage() {
</select>
</div>
<div className="space-y-1">
<Label htmlFor="editRuleOwnerSelfFallback">负责人本人兜底角色</Label>
<select
id="editRuleOwnerSelfFallback"
data-testid="approval-rule-edit-owner-self-fallback"
className="select-std"
value={ownerSelfFallbackRole}
onChange={(event) => setOwnerSelfFallbackRole(event.target.value as ApprovalOwnerSelfFallbackRoleCode)}
>
<option value="">无</option>
{OWNER_SELF_FALLBACK_ROLE_OPTIONS.map((role) => (
<option key={role.code} value={role.code}>
{role.label}
</option>
))}
</select>
</div>
<div className="flex items-center gap-2 pt-6">
<input
id="editRuleEnabled"
-32
查看文件
@@ -2,30 +2,6 @@ import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
const PAGE_CHUNK_PATTERNS = {
"page-travel": ["TravelRequestsPage"],
"page-assets": ["AssetRegistryPage", "InventoryChecksPage"],
"page-procurement": ["PurchaseRequestsPage"],
"page-workflow": ["WorkflowTasksPage", "WorkflowTaskDetailPage"],
"page-system": [
"AuditLogsPage",
"ApprovalRulesPage",
"DelegationsPage",
"DepartmentsPage",
"ErpIntegrationPage",
"FeatureFlagsPage",
"InvoicePoolPage",
"LeaveRequestPage",
"MasterDataPage",
"NotificationChannelsPage",
"NotificationsPage",
"ReimbursementDetailPage",
"ReimbursementsPage",
"UserManagementPage",
],
"page-mobile": ["MobileCapturePage", "MobileAssetScanPage", "MobileApprovalsPage"],
} as const;
function resolveManualChunk(id: string) {
if (id.includes("node_modules")) {
if (["react", "react-dom", "react-router-dom"].some((pkg) => id.includes(`/node_modules/${pkg}/`))) {
@@ -71,14 +47,6 @@ function resolveManualChunk(id: string) {
return "app-domain-shared";
}
for (const [chunkName, pageNames] of Object.entries(PAGE_CHUNK_PATTERNS)) {
for (const pageName of pageNames) {
if (id.includes(`/src/router/lazy/${pageName}.ts`)) {
return chunkName;
}
}
}
return undefined;
}