fix: harden channel retry attribution and operations UI

This commit is contained in:
hectorzhao
2026-07-26 21:33:58 +08:00
parent 059b38e8fe
commit 0857de09d8
27 changed files with 888 additions and 117 deletions
+59 -14
View File
@@ -11,10 +11,30 @@ type AdminCustomersPageProps = {
type CustomerRow = TenantManagementRow;
function ConfirmModal({ message, onCancel, onConfirm }: { message: string; onCancel: () => void; onConfirm: () => void }) {
function ConfirmModal({
error,
isSubmitting,
message,
onCancel,
onConfirm,
type,
}: {
error: string;
isSubmitting: boolean;
message: string;
onCancel: () => void;
onConfirm: () => void;
type: 'toggle' | 'delete';
}) {
return (
<Modal footer={<><Button onClick={onCancel} variant="ghost"></Button><Button onClick={onConfirm}></Button></>} onClose={onCancel} open title="操作确认">
<Modal
footer={<><Button disabled={isSubmitting} onClick={onCancel} variant="ghost"></Button><Button disabled={isSubmitting} onClick={onConfirm} variant={type === 'delete' ? 'danger' : 'primary'}>{isSubmitting ? '处理中...' : '确认'}</Button></>}
onClose={() => { if (!isSubmitting) onCancel(); }}
open
title={type === 'delete' ? '删除企业' : '变更企业状态'}
>
<p className="admin-confirm-text">{message}</p>
{error ? <p className="form-error" role="alert">{error}</p> : null}
</Modal>
);
}
@@ -26,6 +46,8 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
const [queryStatus, setQueryStatus] = useState('all');
const [filters, setFilters] = useState({ name: '', status: 'all' });
const [confirmAction, setConfirmAction] = useState<{ type: 'toggle' | 'delete'; record: CustomerRow } | null>(null);
const [confirmError, setConfirmError] = useState('');
const [confirming, setConfirming] = useState(false);
const [rechargeTarget, setRechargeTarget] = useState<CustomerRow | null>(null);
const [error, setError] = useState('');
@@ -82,10 +104,10 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
<div className="table-actions">
<Button icon={<DollarSign size={15} />} onClick={() => openRechargeModal(record)} size="sm" variant="ghost"></Button>
<Button onClick={() => navigate(`${basePath}/${record.id}/edit`)} size="sm" variant="ghost"></Button>
<Button onClick={() => setConfirmAction({ type: 'toggle', record })} size="sm" variant={record.status === 'active' ? 'warning' : 'success'}>
<Button onClick={() => openConfirmAction({ type: 'toggle', record })} size="sm" variant={record.status === 'active' ? 'warning' : 'success'}>
{record.status === 'active' ? '禁用' : '启用'}
</Button>
<Button icon={<Trash2 size={15} />} onClick={() => setConfirmAction({ type: 'delete', record })} size="sm" variant="danger"></Button>
<Button icon={<Trash2 size={15} />} onClick={() => openConfirmAction({ type: 'delete', record })} size="sm" variant="danger"></Button>
</div>
),
},
@@ -95,15 +117,35 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
setRechargeTarget(record);
}
function submitConfirmAction() {
function openConfirmAction(action: { type: 'toggle' | 'delete'; record: CustomerRow }) {
setConfirmError('');
setConfirmAction(action);
}
async function submitConfirmAction() {
if (!confirmAction) return;
const action = confirmAction.type === 'delete'
? adminApi.deleteTenant(confirmAction.record.id)
: adminApi.changeTenantStatus(confirmAction.record.id, confirmAction.record.status === 'active' ? 'disabled' : 'active');
action.then(() => {
setConfirmAction(null);
loadData();
}).catch((failure: Error) => setError(failure.message || '企业状态更新失败'));
setConfirming(true);
setConfirmError('');
try {
if (confirmAction.type === 'delete') {
await adminApi.deleteTenant(confirmAction.record.id);
} else {
await adminApi.changeTenantStatus(confirmAction.record.id, confirmAction.record.status === 'active' ? 'disabled' : 'active');
}
} catch (failure) {
const detail = failure instanceof Error ? failure.message : '企业操作失败';
setConfirmError(`${confirmAction.type === 'delete' ? '删除' : '状态变更'}失败:${detail}`);
setConfirming(false);
return;
}
setConfirmAction(null);
try {
await loadData();
} catch (failure) {
setError(failure instanceof Error ? failure.message : '企业列表刷新失败');
} finally {
setConfirming(false);
}
}
return (
@@ -140,9 +182,12 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
{confirmAction ? (
<ConfirmModal
error={confirmError}
isSubmitting={confirming}
message={confirmAction.type === 'delete' ? `确认删除企业“${confirmAction.record.name}”吗?` : `确认${confirmAction.record.status === 'active' ? '禁用' : '启用'}企业“${confirmAction.record.name}”吗?`}
onCancel={() => setConfirmAction(null)}
onConfirm={submitConfirmAction}
onCancel={() => { setConfirmAction(null); setConfirmError(''); }}
onConfirm={() => void submitConfirmAction()}
type={confirmAction.type}
/>
) : null}
<ManualRechargeDialog