feat: restore credit limits and harden SMS sending
This commit is contained in:
@@ -69,6 +69,7 @@ export function AdminCustomerDetailPage() {
|
||||
<div className="surface mini-status-card"><Server size={22} /><div><span>企业编码</span><strong>{tenant?.code ?? '-'}</strong><small>{tenant?.status ?? '-'}</small></div></div>
|
||||
<div className="surface mini-status-card"><MessageSquare size={22} /><div><span>计费方式</span><strong>按量计费</strong><small>仅从现金余额扣费</small></div></div>
|
||||
<div className="surface mini-status-card"><FileText size={22} /><div><span>现金余额</span><strong>¥{formatCents(account?.balanceCents)}</strong><small>真实账户余额</small></div></div>
|
||||
<div className="surface mini-status-card"><FileText size={22} /><div><span>授信额度</span><strong>¥{formatCents(account?.creditCents)}</strong><small>可配置为正数、负数或 0</small></div></div>
|
||||
</div>
|
||||
|
||||
<div className="surface section-stack">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Breadcrumb, Button, FileActions, Input, Select, Textarea } from '@/comp
|
||||
type EnterpriseForm = {
|
||||
name: string;
|
||||
creditCode: string;
|
||||
creditLimit: string;
|
||||
province: string;
|
||||
city: string;
|
||||
address: string;
|
||||
@@ -44,6 +45,7 @@ const cityOptionsByProvince: Record<string, Array<{ label: string; value: string
|
||||
const emptyForm: EnterpriseForm = {
|
||||
name: '',
|
||||
creditCode: '',
|
||||
creditLimit: '0',
|
||||
province: '',
|
||||
city: '',
|
||||
address: '',
|
||||
@@ -56,11 +58,12 @@ const emptyForm: EnterpriseForm = {
|
||||
photoContentType: '',
|
||||
};
|
||||
|
||||
function formFromTenant(tenant: TenantOption): EnterpriseForm {
|
||||
function formFromTenant(tenant: TenantOption, creditCents = 0): EnterpriseForm {
|
||||
const profile = tenant.enterpriseProfile;
|
||||
return {
|
||||
name: tenant.name,
|
||||
creditCode: profile?.creditCode ?? '',
|
||||
creditLimit: String(creditCents / 100),
|
||||
province: profile?.province ?? '',
|
||||
city: profile?.city ?? '',
|
||||
address: profile?.address ?? '',
|
||||
@@ -89,9 +92,9 @@ export function AdminCustomerFormPage() {
|
||||
setForm(emptyForm);
|
||||
return;
|
||||
}
|
||||
adminApi.getTenant(enterpriseId)
|
||||
.then((tenant) => {
|
||||
setForm(formFromTenant(tenant));
|
||||
Promise.all([adminApi.getTenant(enterpriseId), adminApi.listAccounts()])
|
||||
.then(([tenant, accounts]) => {
|
||||
setForm(formFromTenant(tenant, accounts.find((account) => account.tenantId === enterpriseId)?.creditCents ?? 0));
|
||||
setError('');
|
||||
})
|
||||
.catch((failure: Error) => setError(failure.message || '企业信息加载失败'));
|
||||
@@ -117,21 +120,30 @@ export function AdminCustomerFormPage() {
|
||||
if (!form.creditCode.trim()) nextErrors.creditCode = '请填写统一社会信用代码';
|
||||
if (!form.contactName.trim()) nextErrors.contactName = '请填写联系人姓名';
|
||||
if (!form.contactPhone.trim()) nextErrors.contactPhone = '请填写手机号';
|
||||
const creditLimit = Number(form.creditLimit);
|
||||
if (!Number.isFinite(creditLimit)) nextErrors.creditLimit = '请填写有效的授信额度';
|
||||
setErrors(nextErrors);
|
||||
return Object.keys(nextErrors).length === 0;
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
async function submitForm() {
|
||||
if (!validateForm()) return;
|
||||
setSaving(true);
|
||||
const { photoContentType, photoFileName, ...payload } = form;
|
||||
const request = isEdit && enterpriseId
|
||||
? adminApi.updateTenant(enterpriseId, payload)
|
||||
: adminApi.createTenant(payload);
|
||||
request
|
||||
.then(() => navigate('/admin/customers'))
|
||||
.catch((failure: Error) => setError(failure.message || '企业保存失败'))
|
||||
.finally(() => setSaving(false));
|
||||
const { creditLimit, photoContentType, photoFileName, ...payload } = form;
|
||||
try {
|
||||
const tenant = isEdit && enterpriseId
|
||||
? await adminApi.updateTenant(enterpriseId, payload)
|
||||
: await adminApi.createTenant(payload);
|
||||
await adminApi.updateCreditLimit(tenant.id, {
|
||||
creditCents: Math.round(Number(creditLimit) * 100),
|
||||
remark: isEdit ? '企业编辑页调整授信额度' : '创建企业初始化授信额度',
|
||||
});
|
||||
navigate('/admin/customers');
|
||||
} catch (failure) {
|
||||
setError(failure instanceof Error ? failure.message : '企业保存失败');
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
function uploadEnterprisePhoto(file: File | undefined) {
|
||||
@@ -204,6 +216,18 @@ export function AdminCustomerFormPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-grid form-grid--two">
|
||||
<Input
|
||||
error={errors.creditLimit}
|
||||
hint="可填写正数、负数或 0;短信发送时判断余额与授信额度之和是否大于 0。"
|
||||
label="授信额度(元)"
|
||||
onChange={(event) => updateForm('creditLimit', event.target.value)}
|
||||
required
|
||||
type="number"
|
||||
value={form.creditLimit}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-grid form-grid--two">
|
||||
<Select label="省/直辖市" onChange={(event) => updateForm('province', event.target.value)} options={provinceOptions} value={form.province} />
|
||||
<Select label="市/区" onChange={(event) => updateForm('city', event.target.value)} options={cityOptions} value={form.city} />
|
||||
|
||||
@@ -86,6 +86,7 @@ export function AdminCustomersPage({ basePath = '/admin/customers' }: AdminCusto
|
||||
);
|
||||
},
|
||||
},
|
||||
{ key: 'creditLimit', title: '授信额度', width: '150px', align: 'right', render: (record) => `¥${formatCents(record.account?.creditCents ?? 0)}` },
|
||||
{ key: 'todaySpend', title: '今日消费', width: '150px', align: 'right', render: (record) => `¥${formatCents(record.todaySpendCents)}` },
|
||||
{ key: 'todayRefund', title: '今日返还', width: '150px', align: 'right', render: (record) => `¥${formatCents(record.todayRefundCents)}` },
|
||||
{ key: 'status', title: '企业状态', width: '130px', render: (record) => <Tag tone={record.status === 'active' ? 'success' : 'warning'}>{record.status === 'active' ? '正常' : '已禁用'}</Tag> },
|
||||
|
||||
@@ -69,7 +69,7 @@ export function AdminHome() {
|
||||
const todaySpend = Math.abs(dashboard?.recentRecharges
|
||||
.filter((item) => item.tenantId === account.tenantId)
|
||||
.reduce((sum, item) => sum + item.amountCents, 0) ?? 0) / 100;
|
||||
const availableBalance = account.balanceCents / 100;
|
||||
const availableBalance = (account.balanceCents + account.creditCents) / 100;
|
||||
return {
|
||||
id: account.tenantId,
|
||||
enterprise: account.tenant?.name ?? account.tenantId,
|
||||
|
||||
Reference in New Issue
Block a user