update: docs

This commit is contained in:
2026-03-13 14:48:32 +08:00
parent e0a40ceff0
commit b7e973e2b6
31 changed files with 2183 additions and 196 deletions

View File

@@ -14,6 +14,7 @@ import {
Divider,
Descriptions,
Checkbox,
Alert,
message,
Result,
} from 'antd';
@@ -21,7 +22,6 @@ import {
FileTextOutlined,
FileExcelOutlined,
FilePdfOutlined,
FileWordOutlined,
DownloadOutlined,
PrinterOutlined,
HistoryOutlined,
@@ -36,8 +36,7 @@ type ContentKeys =
| 'include_flow_chart'
| 'include_timeline'
| 'include_reasons'
| 'include_inquiry'
| 'include_screenshots';
| 'include_inquiry';
const contentOptions: Array<{ key: ContentKeys; label: string; defaultOn: boolean }> = [
{ key: 'include_summary', label: '被骗金额汇总表', defaultOn: true },
@@ -46,7 +45,6 @@ const contentOptions: Array<{ key: ContentKeys; label: string; defaultOn: boolea
{ key: 'include_timeline', label: '交易时间轴', defaultOn: true },
{ key: 'include_reasons', label: '认定理由与排除说明', defaultOn: true },
{ key: 'include_inquiry', label: '笔录辅助问询建议', defaultOn: false },
{ key: 'include_screenshots', label: '原始截图附件', defaultOn: false },
];
const STORAGE_PREFIX = 'report-content-';
@@ -80,7 +78,7 @@ const Reports: React.FC = () => {
const { id = '1' } = useParams();
const qc = useQueryClient();
const [generated, setGenerated] = useState(false);
const [selectedFormats, setSelectedFormats] = useState<Array<'excel' | 'pdf' | 'word'>>([
const [selectedFormats, setSelectedFormats] = useState<Array<'excel' | 'pdf'>>([
'excel',
'pdf',
]);
@@ -114,7 +112,7 @@ const Reports: React.FC = () => {
);
const genMutation = useMutation({
mutationFn: async (reportTypes: Array<'excel' | 'pdf' | 'word'>) => {
mutationFn: async (reportTypes: Array<'excel' | 'pdf'>) => {
const result = await Promise.all(
reportTypes.map((reportType) =>
generateReport(id, { report_type: reportType, ...contentSel }),
@@ -150,7 +148,6 @@ const Reports: React.FC = () => {
const map: Record<string, { icon: React.ReactNode; label: string; color: string }> = {
pdf: { icon: <FilePdfOutlined />, label: 'PDF', color: 'red' },
excel: { icon: <FileExcelOutlined />, label: 'Excel', color: 'green' },
word: { icon: <FileWordOutlined />, label: 'Word', color: 'blue' },
};
const cfg = map[t] || map.pdf;
return <Tag icon={cfg.icon} color={cfg.color}>{cfg.label}</Tag>;
@@ -322,35 +319,17 @@ const Reports: React.FC = () => {
</Checkbox>
</div>
</Card>
<Card
hoverable
style={{ width: 140, textAlign: 'center' }}
styles={{ body: { padding: 16 } }}
>
<FileWordOutlined style={{ fontSize: 32, color: '#1677ff' }} />
<div style={{ marginTop: 8 }}>
<Typography.Text>Word </Typography.Text>
</div>
<div>
<Checkbox
checked={selectedFormats.includes('word')}
onChange={(e) => {
setSelectedFormats((prev) =>
e.target.checked
? Array.from(new Set([...prev, 'word']))
: prev.filter((x) => x !== 'word'),
);
}}
>
</Checkbox>
</div>
</Card>
</Space>
</div>
<Typography.Text strong></Typography.Text>
<div style={{ margin: '12px 0 24px' }}>
<Alert
type="info"
showIcon
style={{ marginBottom: 12 }}
message="PDF 报告不包含原始截图附件,仅保留证据索引。"
/>
<Space direction="vertical">
{contentOptions.map((opt) => (
<Checkbox
@@ -406,15 +385,6 @@ const Reports: React.FC = () => {
>
PDF
</Button>,
<Button
key="word"
icon={<DownloadOutlined />}
href={latestReportByType.word ? getReportDownloadUrl(latestReportByType.word.id) : undefined}
target="_blank"
disabled={!latestReportByType.word}
>
Word
</Button>,
<Button
key="print"
icon={<PrinterOutlined />}

View File

@@ -440,7 +440,11 @@ const Review: React.FC = () => {
onClick={() => {
setReviewModal(r);
setEditableTx({ ...r.transaction });
setReviewAction(getAiSuggestedAction(r, allAssessments));
setReviewAction(
r.reviewStatus === 'pending'
? getAiSuggestedAction(r, allAssessments)
: (r.reviewStatus as ReviewAction),
);
setReviewNote('');
}}
>
@@ -788,34 +792,32 @@ const Review: React.FC = () => {
</Card>
)}
{reviewModal.reviewStatus === 'pending' && (
<>
<Divider />
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text strong></Typography.Text>
<Typography.Text type="secondary">
AI {aiSuggestionLabel[getAiSuggestedAction(reviewModal, allAssessments)]}
</Typography.Text>
<Select
value={reviewAction}
onChange={setReviewAction}
style={{ width: '100%' }}
options={[
{ label: '确认 - 该笔计入被骗金额', value: 'confirmed' },
{ label: '排除 - 该笔不计入被骗金额', value: 'rejected' },
{ label: '需补充 - 需进一步调查确认', value: 'needs_info' },
]}
/>
<Typography.Text strong></Typography.Text>
<Input.TextArea
rows={3}
value={reviewNote}
onChange={(e) => setReviewNote(e.target.value)}
placeholder="请输入复核意见或备注..."
/>
</Space>
</>
)}
<Divider />
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text strong></Typography.Text>
<Typography.Text type="secondary">
{reviewModal.reviewStatus === 'pending'
? `已默认选中 AI 建议:${aiSuggestionLabel[getAiSuggestedAction(reviewModal, allAssessments)]}`
: '当前可修改复核状态并重新提交。'}
</Typography.Text>
<Select
value={reviewAction}
onChange={setReviewAction}
style={{ width: '100%' }}
options={[
{ label: '确认 - 该笔计入被骗金额', value: 'confirmed' },
{ label: '排除 - 该笔不计入被骗金额', value: 'rejected' },
{ label: '需补充 - 需进一步调查确认', value: 'needs_info' },
]}
/>
<Typography.Text strong></Typography.Text>
<Input.TextArea
rows={3}
value={reviewNote}
onChange={(e) => setReviewNote(e.target.value)}
placeholder="请输入复核意见或备注..."
/>
</Space>
{reviewModal.reviewStatus !== 'pending' && reviewModal.reviewedBy && (
<Descriptions column={2} size="small" style={{ marginTop: 16 }}>
@@ -839,24 +841,22 @@ const Review: React.FC = () => {
>
</Button>
{reviewModal.reviewStatus === 'pending' && (
<Button
type="primary"
loading={reviewMutation.isPending}
onClick={() => {
reviewMutation.mutate({
assessmentId: reviewModal.id,
body: {
review_status: reviewAction,
review_note: reviewNote,
reviewed_by: 'demo_user',
},
});
}}
>
</Button>
)}
<Button
type="primary"
loading={reviewMutation.isPending}
onClick={() => {
reviewMutation.mutate({
assessmentId: reviewModal.id,
body: {
review_status: reviewAction,
review_note: reviewNote,
reviewed_by: 'demo_user',
},
});
}}
>
</Button>
</div>
</>
)}

View File

@@ -509,6 +509,23 @@ const Transactions: React.FC = () => {
)}
</Space>
</Descriptions.Item>
<Descriptions.Item label="标记修改">
<Select
style={{ width: '100%' }}
value={getEffectiveMark(detail)}
options={[
{ label: '重复', value: 'duplicate' },
{ label: '中转', value: 'transit' },
{ label: '有效', value: 'valid' },
]}
onChange={(val) =>
setMarkOverrides((prev) => ({
...prev,
[detail.id]: val as 'duplicate' | 'transit' | 'valid',
}))
}
/>
</Descriptions.Item>
</Descriptions>
</Col>
</Row>

View File

@@ -250,7 +250,6 @@ export async function generateReport(
include_timeline?: boolean;
include_reasons?: boolean;
include_inquiry?: boolean;
include_screenshots?: boolean;
},
): Promise<ExportReport> {
if (!(await isBackendUp())) return mockReports[0];

View File

@@ -93,7 +93,7 @@ export interface FundFlowEdge {
export interface ExportReport {
id: string;
caseId: string;
reportType: 'pdf' | 'excel' | 'word';
reportType: 'pdf' | 'excel';
filePath: string;
createdAt: string;
version: number;