fix: 补齐签名导入待审通知并展示通道组成本
This commit is contained in:
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { CheckCircle2, Info, Pencil, Plus, RadioTower, Trash2 } from 'lucide-react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { adminApi, type AdminChannel, type ChannelGroup } from '@/api/adminApi';
|
||||
import { formatRateAmount, MONEY_UNITS_PER_YUAN } from '@/utils/currency';
|
||||
import { Breadcrumb, Button, Input, Modal, Select, Table, Tag, type TableColumn } from '@/components/ui';
|
||||
|
||||
type Carrier = 'mobile' | 'unicom' | 'telecom';
|
||||
@@ -227,6 +228,15 @@ export function AdminChannelGroupFormPage() {
|
||||
width: '280px',
|
||||
render: (route) => channelById.get(route.channelId)?.name ?? '未命名通道',
|
||||
},
|
||||
{
|
||||
key: 'cost',
|
||||
title: '成本价格(元/条)',
|
||||
width: '180px',
|
||||
render: (route) => {
|
||||
const price = channelById.get(route.channelId)?.unitPrice;
|
||||
return price == null ? '—' : formatRateAmount(price / MONEY_UNITS_PER_YUAN);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: '通道状态',
|
||||
@@ -253,6 +263,15 @@ export function AdminChannelGroupFormPage() {
|
||||
width: '280px',
|
||||
render: (route) => channelById.get(route.channelId)?.name ?? '未命名通道',
|
||||
},
|
||||
{
|
||||
key: 'cost',
|
||||
title: '成本价格(元/条)',
|
||||
width: '180px',
|
||||
render: (route) => {
|
||||
const price = channelById.get(route.channelId)?.unitPrice;
|
||||
return price == null ? '—' : formatRateAmount(price / MONEY_UNITS_PER_YUAN);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: '通道状态',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter, Link } from 'react-router-dom';
|
||||
import { expect, it, vi } from 'vitest';
|
||||
import { AdminSignatureAuditPage } from './AdminSignatureAuditPage';
|
||||
|
||||
vi.mock('@/api/adminApi', () => ({ adminApi: { listEnterpriseSignatures: vi.fn().mockResolvedValue([]) } }));
|
||||
vi.mock('./ReportImportAuditPanel', () => ({ ReportImportAuditPanel: () => <div>导入审核面板内容</div> }));
|
||||
|
||||
it('opens import reviews when the notification changes query parameters on the current audit page', async () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/admin/signatures']}>
|
||||
<Link to="/admin/signatures?tab=import">签名导入待审入口</Link>
|
||||
<AdminSignatureAuditPage />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
expect(screen.queryByText('导入审核面板内容')).not.toBeInTheDocument();
|
||||
await user.click(screen.getByRole('link', { name: '签名导入待审入口' }));
|
||||
expect(await screen.findByText('导入审核面板内容')).toBeVisible();
|
||||
});
|
||||
@@ -161,7 +161,7 @@ function SignatureDetail({ item, onClose }: { item: ClientSmsSignature; onClose:
|
||||
export function AdminSignatureAuditPage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const requestedImportBatchId = searchParams.get('batchId') ?? undefined;
|
||||
const [activeTab, setActiveTab] = useState(searchParams.get('tab') === 'import' ? 'import' : 'single');
|
||||
const activeTab = searchParams.get('tab') === 'import' ? 'import' : 'single';
|
||||
const [items, setItems] = useState<ClientSmsSignature[]>([]);
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [status, setStatus] = useState('pending');
|
||||
@@ -269,7 +269,6 @@ export function AdminSignatureAuditPage() {
|
||||
{error ? <p className="form-error">{error}</p> : null}
|
||||
<Tabs
|
||||
onChange={(value) => {
|
||||
setActiveTab(value);
|
||||
setSearchParams(value === 'import' ? { tab: 'import' } : {});
|
||||
}}
|
||||
value={activeTab}
|
||||
|
||||
@@ -104,6 +104,7 @@ export function ReportImportAuditPanel({
|
||||
setError('');
|
||||
try {
|
||||
await adminApi.reviewReportImportItems(detail.id, { decision, itemIds, reason: reason.trim() || undefined });
|
||||
window.dispatchEvent(new Event('cmpp-audit-count-refresh'));
|
||||
setSelected(new Set());
|
||||
setReason('');
|
||||
setRejectOpen(false);
|
||||
|
||||
@@ -118,6 +118,8 @@ describe('ReportMaterialImportModal mapping profile action', () => {
|
||||
});
|
||||
const user = userEvent.setup();
|
||||
const onCompleted = vi.fn();
|
||||
const refresh = vi.fn();
|
||||
window.addEventListener('cmpp-audit-count-refresh', refresh);
|
||||
render(<ReportMaterialImportModal onClose={vi.fn()} onCompleted={onCompleted} />);
|
||||
await waitFor(() => expect(adminApi.listTenantOptions).toHaveBeenCalledTimes(1));
|
||||
await user.click(screen.getByText('所属企业').closest('label')!.querySelector('button')!);
|
||||
@@ -146,5 +148,7 @@ describe('ReportMaterialImportModal mapping profile action', () => {
|
||||
),
|
||||
);
|
||||
expect(onCompleted).toHaveBeenCalledWith(expect.objectContaining({ id: 'analysis-1', status: 'pending_review' }));
|
||||
expect(refresh).toHaveBeenCalledTimes(1);
|
||||
window.removeEventListener('cmpp-audit-count-refresh', refresh);
|
||||
}, 10_000);
|
||||
});
|
||||
|
||||
@@ -270,6 +270,7 @@ export function ReportMaterialImportModal({
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
window.dispatchEvent(new Event('cmpp-audit-count-refresh'));
|
||||
onCompleted(result);
|
||||
onClose();
|
||||
} catch (failure) {
|
||||
|
||||
Reference in New Issue
Block a user