fix: complete first version issue remediation

This commit is contained in:
hectorzhao
2026-07-11 10:14:37 +08:00
parent 709ac97764
commit 208a6c23f8
73 changed files with 1549 additions and 245 deletions
+35 -22
View File
@@ -1,7 +1,8 @@
import { useEffect, useMemo, useState } from 'react';
import { Plus, Search } from 'lucide-react';
import { Breadcrumb, Button, DateRangeInput, Input, Modal, Pagination, Select, Textarea, Tag, type DateRangeValue } from '@/components/ui';
import { adminApi, type RechargeOrder, type TenantAccount, type TenantOption } from '@/api/adminApi';
import { adminApi, type RechargeOrder, type TenantOption } from '@/api/adminApi';
import { formatDateTime } from '@/utils/dateTime';
type ManualRechargeForm = {
tenantId: string;
@@ -36,7 +37,6 @@ function RemarkCell({ value }: { value?: string }) {
export function AdminRechargeRecordsPage() {
const [records, setRecords] = useState<RechargeOrder[]>([]);
const [accounts, setAccounts] = useState<TenantAccount[]>([]);
const [tenants, setTenants] = useState<TenantOption[]>([]);
const [enterpriseKeyword, setEnterpriseKeyword] = useState('');
const [dateRange, setDateRange] = useState<DateRangeValue>({});
@@ -45,19 +45,19 @@ export function AdminRechargeRecordsPage() {
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [manualError, setManualError] = useState('');
const [submitting, setSubmitting] = useState(false);
async function loadData() {
setLoading(true);
setError('');
try {
const [nextTenants, nextRecords, nextAccounts] = await Promise.all([
const [nextTenants, nextRecords] = await Promise.all([
adminApi.listTenants(),
adminApi.listManualRecharges(),
adminApi.listAccounts(),
]);
setTenants(nextTenants);
setRecords(nextRecords);
setAccounts(nextAccounts);
setForm((current) => ({ ...current, tenantId: current.tenantId || nextTenants[0]?.id || '' }));
} catch (err) {
setError(err instanceof Error ? err.message : '充值记录加载失败');
@@ -98,23 +98,33 @@ export function AdminRechargeRecordsPage() {
function updateForm<K extends keyof ManualRechargeForm>(key: K, value: ManualRechargeForm[K]) {
setForm((current) => ({ ...current, [key]: value }));
setManualError('');
}
async function submitManualRecharge() {
const amount = Number(form.amount);
const smsUnits = Number(form.smsUnits || 0);
if (!form.tenantId || !Number.isFinite(amount) || !Number.isFinite(smsUnits) || (amount === 0 && smsUnits === 0)) {
setManualError('请填写非 0 的充值金额或短信条数;金额支持负数冲正。');
return;
}
await adminApi.createManualRecharge({
tenantId: form.tenantId,
amountCents: Math.round(amount * 100),
smsUnits,
remark: [form.operator, form.remark].filter(Boolean).join(' / '),
});
await loadData();
setManualOpen(false);
setForm({ tenantId: tenants[0]?.id ?? '', amount: '', smsUnits: '0', operator: '运营', remark: '' });
setSubmitting(true);
setManualError('');
try {
await adminApi.createManualRecharge({
tenantId: form.tenantId,
amountCents: Math.round(amount * 100),
smsUnits,
remark: [form.operator, form.remark].filter(Boolean).join(' / '),
});
await loadData();
setManualOpen(false);
setForm({ tenantId: tenants[0]?.id ?? '', amount: '', smsUnits: '0', operator: '运营', remark: '' });
} catch (failure) {
setManualError(failure instanceof Error ? failure.message : '人工充值失败');
} finally {
setSubmitting(false);
}
}
return (
@@ -158,14 +168,13 @@ export function AdminRechargeRecordsPage() {
) : filteredRows.length === 0 ? (
<tr><td className="ui-table__empty" colSpan={7}></td></tr>
) : visibleRows.map((record) => {
const account = accounts.find((item) => item.tenantId === record.tenantId);
const tenantName = record.tenant?.name ?? tenants.find((tenant) => tenant.id === record.tenantId)?.name ?? record.tenantId;
return (
<tr key={record.id}>
<td><strong>{tenantName}</strong></td>
<td>{new Date(record.paidAt ?? record.createdAt).toLocaleString('zh-CN')}</td>
<td>{formatAmount(record.amountCents / 100)}</td>
<td>{formatAmount((account?.balanceCents ?? 0) / 100)}</td>
<td>{formatDateTime(record.paidAt ?? record.createdAt)}</td>
<td>¥{formatAmount(record.amountCents / 100)}</td>
<td>{record.balanceAfterCents === null || record.balanceAfterCents === undefined ? '-' : `¥${formatAmount(record.balanceAfterCents / 100)}`}</td>
<td><Tag tone="warning"></Tag></td>
<td>{record.operatorId || '运营'}</td>
<td><RemarkCell value={record.remark ?? undefined} /></td>
@@ -181,6 +190,8 @@ export function AdminRechargeRecordsPage() {
onNext={() => setPage((value) => Math.min(totalPages, value + 1))}
onPrevious={() => setPage((value) => Math.max(1, value - 1))}
page={currentPage}
totalPages={totalPages}
onPageChange={setPage}
previousDisabled={currentPage <= 1}
total={filteredRows.length}
/>
@@ -190,8 +201,8 @@ export function AdminRechargeRecordsPage() {
<Modal
footer={(
<>
<Button onClick={() => setManualOpen(false)} variant="ghost"></Button>
<Button onClick={submitManualRecharge}></Button>
<Button disabled={submitting} onClick={() => setManualOpen(false)} variant="ghost"></Button>
<Button disabled={submitting} onClick={() => { void submitManualRecharge(); }}>{submitting ? '充值中...' : '确认充值'}</Button>
</>
)}
onClose={() => setManualOpen(false)}
@@ -204,13 +215,15 @@ export function AdminRechargeRecordsPage() {
label="企业名称"
onChange={(event) => updateForm('tenantId', event.target.value)}
options={tenants.map((tenant) => ({ label: tenant.name, value: tenant.id }))}
required
value={form.tenantId}
/>
<Input label="充值金额" onChange={(event) => updateForm('amount', event.target.value)} prefix="¥" type="number" value={form.amount} />
<Input label="充值金额" onChange={(event) => updateForm('amount', event.target.value)} prefix="¥" required type="number" value={form.amount} />
<Input label="短信条数" onChange={(event) => updateForm('smsUnits', event.target.value)} type="number" value={form.smsUnits} />
<Input label="操作人" onChange={(event) => updateForm('operator', event.target.value)} value={form.operator} />
<Input label="操作人" onChange={(event) => updateForm('operator', event.target.value)} required value={form.operator} />
<Textarea className="admin-system-modal-form__wide" label="充值备注" onChange={(event) => updateForm('remark', event.target.value)} rows={4} value={form.remark} />
</div>
{manualError ? <p className="form-error">{manualError}</p> : null}
</Modal>
) : null}
</section>