feat: wire admin workflows to real APIs
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Check, FileSearch, Search, X } from 'lucide-react';
|
||||
import { Breadcrumb, Button, Input, Select, Table, Tag, type TableColumn } from '@/components/ui';
|
||||
import { adminApi, type EnterpriseCertification } from '@/api/adminApi';
|
||||
import { Breadcrumb, Button, Input, Modal, Select, Table, Tag, type TableColumn } from '@/components/ui';
|
||||
|
||||
type EnterpriseAuditStatus = 'pending' | 'approved' | 'rejected';
|
||||
|
||||
@@ -8,9 +9,18 @@ type EnterpriseAuditRecord = {
|
||||
id: string;
|
||||
companyName: string;
|
||||
creditCode: string;
|
||||
legalPerson: string;
|
||||
registeredAddress: string;
|
||||
businessLicense: string;
|
||||
bankAccountName: string;
|
||||
bankName: string;
|
||||
bankAccountNo: string;
|
||||
verificationAmount: string;
|
||||
contactName: string;
|
||||
contactPhone: string;
|
||||
contactEmail: string;
|
||||
submittedAt: string;
|
||||
reviewRemark: string;
|
||||
status: EnterpriseAuditStatus;
|
||||
};
|
||||
|
||||
@@ -34,16 +44,45 @@ const statusToneMap: Record<EnterpriseAuditStatus, 'warning' | 'success' | 'dang
|
||||
};
|
||||
|
||||
const initialEnterpriseAudits: EnterpriseAuditRecord[] = [
|
||||
{ id: 'ENT-20260319-001', companyName: '北京星云科技有限公司', creditCode: '91110000X12345678A', contactName: '张伟', contactPhone: '13800138000', submittedAt: '2026-03-19 10:23:45', status: 'pending' },
|
||||
{ id: 'ENT-20260319-002', companyName: '上海蓝海科技有限公司', creditCode: '91310000X87654321B', contactName: '李娜', contactPhone: '13900139000', submittedAt: '2026-03-18 15:45:12', status: 'pending' },
|
||||
{ id: 'ENT-20260318-001', companyName: '广州飞跃文化传媒有限公司', creditCode: '91440100X11223344C', contactName: '王强', contactPhone: '13700137000', submittedAt: '2026-03-17 09:12:30', status: 'approved' },
|
||||
{ id: 'ENT-20260317-001', companyName: '深圳前海贸易有限公司', creditCode: '91440300X55667788D', contactName: '陈杰', contactPhone: '13600136000', submittedAt: '2026-03-16 11:30:22', status: 'rejected' },
|
||||
{ id: 'ENT-20260319-001', companyName: '北京星云科技有限公司', creditCode: '91110000X12345678A', legalPerson: '赵明', registeredAddress: '北京市朝阳区望京东路 88 号', businessLicense: 'business-license-20260319-001.pdf', bankAccountName: '北京星云科技有限公司', bankName: '招商银行北京望京支行', bankAccountNo: '6214 **** **** 1028', verificationAmount: '0.23 元', contactName: '张伟', contactPhone: '13800138000', contactEmail: 'zhangwei@nebula.example.com', submittedAt: '2026-03-19 10:23:45', reviewRemark: '待核验营业执照与对公打款流水。', status: 'pending' },
|
||||
{ id: 'ENT-20260319-002', companyName: '上海蓝海科技有限公司', creditCode: '91310000X87654321B', legalPerson: '周海', registeredAddress: '上海市浦东新区张江路 66 号', businessLicense: 'business-license-20260319-002.pdf', bankAccountName: '上海蓝海科技有限公司', bankName: '建设银行上海张江支行', bankAccountNo: '6227 **** **** 3319', verificationAmount: '0.18 元', contactName: '李娜', contactPhone: '13900139000', contactEmail: 'lina@blueocean.example.com', submittedAt: '2026-03-18 15:45:12', reviewRemark: '联系人授权书已上传,等待人工复核。', status: 'pending' },
|
||||
{ id: 'ENT-20260318-001', companyName: '广州飞跃文化传媒有限公司', creditCode: '91440100X11223344C', legalPerson: '黄杰', registeredAddress: '广州市天河区体育西路 118 号', businessLicense: 'business-license-20260318-001.pdf', bankAccountName: '广州飞跃文化传媒有限公司', bankName: '工商银行广州天河支行', bankAccountNo: '6202 **** **** 7750', verificationAmount: '0.31 元', contactName: '王强', contactPhone: '13700137000', contactEmail: 'wangqiang@feiyue.example.com', submittedAt: '2026-03-17 09:12:30', reviewRemark: '资料一致,对公验证通过。', status: 'approved' },
|
||||
{ id: 'ENT-20260317-001', companyName: '深圳前海贸易有限公司', creditCode: '91440300X55667788D', legalPerson: '林越', registeredAddress: '深圳市前海深港合作区梦海大道 1 号', businessLicense: 'business-license-20260317-001.pdf', bankAccountName: '深圳前海贸易有限公司', bankName: '中国银行深圳前海支行', bankAccountNo: '6216 **** **** 8901', verificationAmount: '0.12 元', contactName: '陈杰', contactPhone: '13600136000', contactEmail: 'chenjie@qianhai.example.com', submittedAt: '2026-03-16 11:30:22', reviewRemark: '营业执照主体与对公账户户名不一致,请重新提交。', status: 'rejected' },
|
||||
];
|
||||
|
||||
function mapCertification(record: EnterpriseCertification): EnterpriseAuditRecord {
|
||||
const materials = record.materials ?? {};
|
||||
return {
|
||||
id: record.id,
|
||||
companyName: record.companyName,
|
||||
creditCode: record.licenseNo ?? '',
|
||||
legalPerson: String(materials.legalPerson ?? ''),
|
||||
registeredAddress: String(materials.registeredAddress ?? ''),
|
||||
businessLicense: String(materials.businessLicense ?? ''),
|
||||
bankAccountName: String(materials.bankAccountName ?? record.companyName),
|
||||
bankName: String(materials.bankName ?? ''),
|
||||
bankAccountNo: String(materials.bankAccountNo ?? ''),
|
||||
verificationAmount: String(materials.verificationAmount ?? ''),
|
||||
contactName: record.contactName ?? '',
|
||||
contactPhone: record.contactPhone ?? '',
|
||||
contactEmail: String(materials.contactEmail ?? ''),
|
||||
submittedAt: new Date(record.submittedAt).toLocaleString('zh-CN', { hour12: false }),
|
||||
reviewRemark: record.rejectReason ?? String(materials.reviewRemark ?? ''),
|
||||
status: record.status as EnterpriseAuditStatus,
|
||||
};
|
||||
}
|
||||
|
||||
export function AdminEnterpriseAuditPage() {
|
||||
const [keyword, setKeyword] = useState('');
|
||||
const [status, setStatus] = useState('all');
|
||||
const [records, setRecords] = useState(initialEnterpriseAudits);
|
||||
const [detailRecord, setDetailRecord] = useState<EnterpriseAuditRecord | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
adminApi.listEnterpriseCertifications({ keyword, status })
|
||||
.then((items) => setRecords(items.map(mapCertification)))
|
||||
.catch(() => undefined);
|
||||
}, [keyword, status]);
|
||||
|
||||
const filteredRecords = useMemo(
|
||||
() => records.filter((record) => {
|
||||
@@ -54,8 +93,13 @@ export function AdminEnterpriseAuditPage() {
|
||||
[keyword, records, status],
|
||||
);
|
||||
|
||||
function updateStatus(id: string, nextStatus: EnterpriseAuditStatus) {
|
||||
setRecords((items) => items.map((item) => (item.id === id ? { ...item, status: nextStatus } : item)));
|
||||
async function updateStatus(id: string, nextStatus: EnterpriseAuditStatus) {
|
||||
const updated = nextStatus === 'approved'
|
||||
? await adminApi.approveEnterpriseCertification(id)
|
||||
: await adminApi.rejectEnterpriseCertification(id);
|
||||
const mapped = mapCertification(updated);
|
||||
setRecords((items) => items.map((item) => (item.id === id ? mapped : item)));
|
||||
setDetailRecord((current) => (current?.id === id ? mapped : current));
|
||||
}
|
||||
|
||||
const columns: Array<TableColumn<EnterpriseAuditRecord>> = [
|
||||
@@ -78,11 +122,11 @@ export function AdminEnterpriseAuditPage() {
|
||||
<div className="audit-actions">
|
||||
{record.status === 'pending' ? (
|
||||
<>
|
||||
<button className="audit-link audit-link--success" onClick={() => updateStatus(record.id, 'approved')} type="button">通过</button>
|
||||
<button className="audit-link audit-link--danger" onClick={() => updateStatus(record.id, 'rejected')} type="button">拒绝</button>
|
||||
<button className="audit-link audit-link--success" onClick={() => void updateStatus(record.id, 'approved')} type="button">通过</button>
|
||||
<button className="audit-link audit-link--danger" onClick={() => void updateStatus(record.id, 'rejected')} type="button">拒绝</button>
|
||||
</>
|
||||
) : null}
|
||||
<button className="audit-link" type="button">详情</button>
|
||||
<button className="audit-link" onClick={() => setDetailRecord(record)} type="button">详情</button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
@@ -110,6 +154,53 @@ export function AdminEnterpriseAuditPage() {
|
||||
<Button disabled icon={<X size={15} />} size="sm" variant="ghost">下一页</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{detailRecord ? (
|
||||
<Modal
|
||||
footer={(
|
||||
<>
|
||||
<Button onClick={() => setDetailRecord(null)} variant="ghost">关闭</Button>
|
||||
{detailRecord.status === 'pending' ? (
|
||||
<>
|
||||
<Button onClick={() => void updateStatus(detailRecord.id, 'rejected')} variant="danger">驳回认证</Button>
|
||||
<Button onClick={() => void updateStatus(detailRecord.id, 'approved')}>审核通过</Button>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
onClose={() => setDetailRecord(null)}
|
||||
open
|
||||
size="xl"
|
||||
title={<div className="template-modal-title"><h2>企业认证详情</h2><p>{detailRecord.id}</p></div>}
|
||||
>
|
||||
<div className="enterprise-audit-detail">
|
||||
<section>
|
||||
<h3>主体资料</h3>
|
||||
<div><span>企业名称</span><strong>{detailRecord.companyName}</strong></div>
|
||||
<div><span>统一社会信用代码</span><strong>{detailRecord.creditCode}</strong></div>
|
||||
<div><span>法定代表人</span><strong>{detailRecord.legalPerson}</strong></div>
|
||||
<div><span>注册地址</span><strong>{detailRecord.registeredAddress}</strong></div>
|
||||
<div><span>营业执照附件</span><strong>{detailRecord.businessLicense}</strong></div>
|
||||
</section>
|
||||
<section>
|
||||
<h3>对公验证</h3>
|
||||
<div><span>账户户名</span><strong>{detailRecord.bankAccountName}</strong></div>
|
||||
<div><span>开户银行</span><strong>{detailRecord.bankName}</strong></div>
|
||||
<div><span>银行账号</span><strong>{detailRecord.bankAccountNo}</strong></div>
|
||||
<div><span>验证金额</span><strong>{detailRecord.verificationAmount}</strong></div>
|
||||
</section>
|
||||
<section>
|
||||
<h3>联系人与审核</h3>
|
||||
<div><span>联系人</span><strong>{detailRecord.contactName}</strong></div>
|
||||
<div><span>联系电话</span><strong>{detailRecord.contactPhone}</strong></div>
|
||||
<div><span>联系邮箱</span><strong>{detailRecord.contactEmail}</strong></div>
|
||||
<div><span>提交时间</span><strong>{detailRecord.submittedAt}</strong></div>
|
||||
<div><span>当前状态</span><strong>{statusTextMap[detailRecord.status]}</strong></div>
|
||||
<div className="enterprise-audit-detail__remark"><span>审核备注</span><strong>{detailRecord.reviewRemark}</strong></div>
|
||||
</section>
|
||||
</div>
|
||||
</Modal>
|
||||
) : null}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user