[CLAUDE] PE: V2-aware Inbox/List + 2 dropdown filter quy trình + trạng thái
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m12s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m12s
User báo: "Phiếu chưa thấy lên trong danh sách duyệt — chắc do chưa ăn vào flow. Tách thành 2 cái dropdown là list quy trình duyệt và list trạng thái. Debug trước, phân quyền rút gọn lại sau." BE — V2-aware permission + filter (Application/PurchaseEvaluations/ PurchaseEvaluationFeatures.cs): - ListPurchaseEvaluationsQuery +ApprovalWorkflowId? Guid? param + IDOR loose: phiếu pin V2 → mọi authenticated user thấy được (UAT) - GetMyPurchaseEvaluationInbox V2-aware: ResolveV2InboxIdsAsync helper precompute Set<Guid> phiếu Phase=ChoDuyet pin V2 + actor ∈ Cấp hiện tại approvers (CurrentWorkflowStepIndex + CurrentApprovalLevelOrder match Step.Order + Level.Order). Inbox where = eligiblePhases.Contains || v2InboxIds.Contains. eligiblePhases admin +ChoDuyet. - GetById Detail loose: V2 pin → cho non-Drafter xem (skip eligiblePhases check). API Controller: - PurchaseEvaluationsController.List +approvalWorkflowId query param FE — 2 dropdown filter (cả 2 app mirror): - PurchaseEvaluationsListPage: +URL param `awId` filter quy trình - useQuery `approval-workflows-v2-filter` load list V2 active+history theo applicableType=typeFilter (chỉ enabled khi có type) - Render Select riêng "Tất cả quy trình duyệt" (chỉ show !pendingMe vì Inbox dùng API endpoint khác) + Select "Tất cả trạng thái" giữ - Display option: "QT-DN-V2-001 v01 — Tên quy trình" Verify: BE build 0 error · 2 FE builds OK. Test luồng eoffice: 1. Drafter trình phiếu V2 → Phase=ChoDuyet 2. Login NV X (approver Cấp 1) vào "Duyệt NCC > Duyệt" (?pendingMe=1) → phiếu hiện trong list 3. Login NV Y (không phải approver) → list rỗng (đúng spec) 4. Vào "Duyệt NCC > Danh sách" (không pendingMe) → 2 dropdown: - Quy trình duyệt: filter theo workflow specific - Trạng thái: filter theo Phase
This commit is contained in:
@ -33,10 +33,25 @@ export function PurchaseEvaluationsListPage() {
|
||||
const pendingMe = sp.get('pendingMe') === '1'
|
||||
const search = sp.get('q') ?? ''
|
||||
const phase = sp.get('phase') ?? ''
|
||||
const approvalWorkflowId = sp.get('awId') ?? '' // Mig 23 — filter quy trình
|
||||
const selectedId = sp.get('id')
|
||||
|
||||
// Mig 23 — list quy trình duyệt V2 cho dropdown filter (filter theo type screen)
|
||||
const approvalWorkflows = useQuery({
|
||||
queryKey: ['approval-workflows-v2-filter', typeFilter],
|
||||
queryFn: async () => {
|
||||
if (!typeFilter) return []
|
||||
const res = await api.get<{ types: { applicableType: number; history: { id: string; code: string; version: number; name: string; isActive: boolean }[] }[] }>(
|
||||
'/approval-workflows-v2',
|
||||
{ params: { applicableType: typeFilter } },
|
||||
)
|
||||
return res.data.types.find(t => t.applicableType === typeFilter)?.history ?? []
|
||||
},
|
||||
enabled: !!typeFilter,
|
||||
})
|
||||
|
||||
const list = useQuery({
|
||||
queryKey: ['pe-list', { typeFilter, pendingMe, search, phase }],
|
||||
queryKey: ['pe-list', { typeFilter, pendingMe, search, phase, approvalWorkflowId }],
|
||||
queryFn: async () => {
|
||||
if (pendingMe) {
|
||||
const res = await api.get<PeListItem[]>('/purchase-evaluations/inbox', {
|
||||
@ -50,6 +65,7 @@ export function PurchaseEvaluationsListPage() {
|
||||
search: search || undefined,
|
||||
type: typeFilter ?? undefined,
|
||||
phase: phase || undefined,
|
||||
approvalWorkflowId: approvalWorkflowId || undefined,
|
||||
},
|
||||
})
|
||||
return res.data
|
||||
@ -119,6 +135,17 @@ export function PurchaseEvaluationsListPage() {
|
||||
className="pl-8"
|
||||
/>
|
||||
</div>
|
||||
{/* Mig 23 — 2 dropdown tách: Quy trình duyệt + Trạng thái */}
|
||||
{!pendingMe && (
|
||||
<Select value={approvalWorkflowId} onChange={e => setParam('awId', e.target.value)}>
|
||||
<option value="">Tất cả quy trình duyệt</option>
|
||||
{approvalWorkflows.data?.map(w => (
|
||||
<option key={w.id} value={w.id}>
|
||||
{w.code} v{String(w.version).padStart(2, '0')} — {w.name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
<Select value={phase} onChange={e => setParam('phase', e.target.value)}>
|
||||
<option value="">Tất cả trạng thái</option>
|
||||
{Object.values(PeDisplayStatus).map(s => {
|
||||
|
||||
Reference in New Issue
Block a user