feat(platform-admin): align frontend with backend contracts

This commit is contained in:
david
2026-07-28 14:26:09 +08:00
parent bc8138f978
commit 4cc17c9efb
6 changed files with 438 additions and 68 deletions

View File

@@ -40,6 +40,13 @@ export function buildResourcePayload(
payload[field.key] = number;
break;
}
case 'money': {
const amount = Number(value);
if (!Number.isFinite(amount))
throw new Error(`${field.label}必须是有效金额`);
payload[field.key] = Math.round(amount * 100);
break;
}
case 'boolean':
payload[field.key] = value === true || value === 'true';
break;

View File

@@ -1,4 +1,9 @@
export type ResourceMode = 'writable' | 'readonly' | 'append_only' | 'managed';
export type ResourceMode =
| 'writable'
| 'readonly'
| 'append_only'
| 'editable'
| 'managed';
export type ResourcePageKind = 'list' | 'tree';
export type ResourceFieldType =
| 'text'
@@ -6,6 +11,7 @@ export type ResourceFieldType =
| 'identity'
| 'identity-list'
| 'number'
| 'money'
| 'boolean'
| 'date'
| 'datetime'
@@ -38,6 +44,10 @@ export type ResourceUiDefinition = {
pageKind: ResourcePageKind;
fields: ResourceField[];
detailActions?: DetailAction[];
canCreate: boolean;
canEdit: boolean;
canChangeStatus: boolean;
canArchive: boolean;
};
const fieldLabels: Record<string, string> = {
@@ -87,8 +97,8 @@ const fieldLabels: Record<string, string> = {
alipay_name: '支付宝账户名',
wxpay_id: '微信账号',
wxpay_name: '微信账户名',
balance: '余额(',
withdrawal_balance: '可提现余额(',
balance: '余额(',
withdrawal_balance: '可提现余额(',
card_no_last4: '银行卡末四位',
bank_name: '银行名称',
card_owner: '持卡人',
@@ -98,16 +108,16 @@ const fieldLabels: Record<string, string> = {
payment_type: '支付业务类型',
pay_channel: '支付渠道',
pay_type: '支付类型',
amount: '金额(',
fee: '手续费(',
amount: '金额(',
fee: '手续费(',
args: '支付参数',
callback_msg: '回调信息',
record_no: '流水号',
request_no: '请求流水号',
direction: '收支方向',
trade_type: '交易类型',
balance_after: '变动后余额(',
withdrawal_balance_after: '变动后可提现余额(',
balance_after: '变动后余额(',
withdrawal_balance_after: '变动后可提现余额(',
refund_no: '退款单号',
cash_no: '提现单号',
channel: '渠道',
@@ -119,19 +129,19 @@ const fieldLabels: Record<string, string> = {
title: '标题',
terms: '合同条款',
file_uri: '附件地址',
default_delivery_fee: '默认配送费(',
default_delivery_fee: '默认配送费(',
signed_at: '签署时间',
effective_at: '生效时间',
unit_price: '单价(',
unit_price: '单价(',
unbound_at: '解绑时间',
revision_no: '修订号',
creator_type: '创建方类型',
creator_identity: '创建方标识',
contact_name: '联系人',
contact_phone: '联系电话',
discount_amount: '优惠金额(',
total_amount: '总金额(',
delivery_fee: '配送费(',
discount_amount: '优惠金额(',
total_amount: '总金额(',
delivery_fee: '配送费(',
assigned_at: '分配时间',
from_status: '原状态',
to_status: '新状态',
@@ -141,7 +151,7 @@ const fieldLabels: Record<string, string> = {
confirmed_at: '确认时间',
sort_no: '排序',
product_code: '商品编码',
price_amount: '售价(',
price_amount: '售价(',
stock_quantity: '库存',
value: '属性值',
image_uri: '图片地址',
@@ -149,7 +159,7 @@ const fieldLabels: Record<string, string> = {
quantity: '数量',
selected: '是否选中',
product_snapshot: '商品快照',
sale_amount: '成交金额(',
sale_amount: '成交金额(',
score: '评分',
paid_at: '支付时间',
settlement_no: '结算单号',
@@ -157,7 +167,7 @@ const fieldLabels: Record<string, string> = {
period_start: '结算开始时间',
period_end: '结算结束时间',
bill_date: '账单日期',
difference_amount: '差异金额(',
difference_amount: '差异金额(',
content_type: '内容类型',
body: '正文',
version_no: '版本号',
@@ -175,11 +185,14 @@ const fieldLabels: Record<string, string> = {
};
const numbers = new Set([
'sort_no', 'unit_price', 'amount', 'fee', 'balance', 'withdrawal_balance',
'sort_no', 'stock_quantity', 'quantity', 'score', 'version_no',
'attempt_no',
]);
const money = new Set([
'unit_price', 'amount', 'fee', 'balance', 'withdrawal_balance',
'balance_after', 'withdrawal_balance_after', 'default_delivery_fee',
'discount_amount', 'total_amount', 'delivery_fee', 'price_amount',
'stock_quantity', 'quantity', 'sale_amount', 'score', 'version_no',
'difference_amount', 'attempt_no',
'sale_amount', 'difference_amount',
]);
const booleans = new Set(['is_default', 'is_enabled', 'is_cover', 'selected', 'withdrawable']);
const dates = new Set(['bill_date']);
@@ -196,6 +209,8 @@ const textareas = new Set([
function f(key: string, options: Partial<ResourceField> = {}): ResourceField {
const type: ResourceFieldType = key.endsWith('_identity')
? 'identity'
: money.has(key)
? 'money'
: numbers.has(key)
? 'number'
: booleans.has(key)
@@ -223,7 +238,19 @@ function define(
fields: ResourceField[],
pageKind: ResourcePageKind = 'list',
detailActions?: DetailAction[],
capabilities: Partial<
Pick<
ResourceUiDefinition,
'canCreate' | 'canEdit' | 'canChangeStatus' | 'canArchive'
>
> = {},
): ResourceUiDefinition {
const defaults = {
canCreate: mode === 'writable' || mode === 'editable' || mode === 'append_only',
canEdit: mode === 'writable' || mode === 'editable',
canChangeStatus: mode === 'writable' || mode === 'editable',
canArchive: mode === 'writable',
};
return {
key: name.replace(/_/g, '-'),
name,
@@ -232,6 +259,8 @@ function define(
mode,
pageKind,
fields,
...defaults,
...capabilities,
...(detailActions ? { detailActions } : {}),
};
}
@@ -249,24 +278,24 @@ export const resources: ResourceUiDefinition[] = [
define('user_address', '用户地址', 'writable', [relation('user_account_identity', '/user_account', true), f('address', { required: true }), f('longitude'), f('latitude'), f('is_default')]),
define('user_service_relation', '用户服务关系', 'writable', [relation('user_account_identity', '/user_account', true), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('staff_account_identity', '/staff_account')]),
define('product_type', '产品类型', 'writable', [f('code', { required: true }), f('name', { required: true })]),
define('product_warehouse', '库房', 'writable', [f('code', { required: true }), f('name', { required: true }), f('address'), f('manager'), f('phone'), f('is_enabled')]),
define('product_info', '产品信息', 'managed', [f('code', { required: true }), f('name', { required: true }), relation('product_type_identity', '/product_type', true), f('params', { required: true }), relation('warehouse_identity', '/product_warehouse'), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_account_identity', '/user_account'), f('produced_at', { required: true }), f('is_enabled')], 'list', [
define('product_type', '产品类型', 'editable', [f('code', { required: true }), f('name', { required: true })]),
define('product_warehouse', '库房', 'editable', [f('code', { required: true }), f('name', { required: true }), f('address'), f('manager'), f('phone'), f('is_enabled')]),
define('product_info', '产品信息', 'editable', [f('code', { required: true }), f('name', { required: true }), relation('product_type_identity', '/product_type', true), f('params', { required: true }), relation('warehouse_identity', '/product_warehouse'), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_account_identity', '/user_account'), f('produced_at', { required: true }), f('is_enabled')], 'list', [
{ name: '修改启用状态', resource: '/product_info/:identity/status', method: 'PATCH', fields: [f('status', { required: true, type: 'select', options: [{ label: '启用', value: 'enabled' }, { label: '停用', value: 'disabled' }] })] },
]),
define('product_repair', '产品检修记录', 'writable', [relation('product_info_identity', '/product_info', true), f('repair_no', { required: true }), f('repair_type', { required: true }), f('started_at', { required: true }), f('completed_at'), f('result'), f('target_status'), f('content'), f('operator'), f('remark')]),
define('product_repair', '产品检修记录', 'editable', [relation('product_info_identity', '/product_info', true), f('repair_no', { required: true }), f('repair_type', { required: true }), f('started_at', { required: true }), f('completed_at'), f('result'), f('target_status'), f('content'), f('operator'), f('remark')]),
define('product_owner', '产品归属记录', 'append_only', [relation('product_info_identity', '/product_info', true), relation('warehouse_identity', '/product_warehouse'), relation('gas_basic_identity', '/gas_basic'), relation('delivery_basic_identity', '/delivery_basic'), relation('user_account_identity', '/user_account'), f('action', { required: true }), f('occurred_at', { required: true }), f('reason'), f('remark')]),
define('gasorder_contract', '配送合同', 'managed', [f('contract_no', { required: true }), relation('user_account_identity', '/user_account', true), relation('gas_basic_identity', '/gas_basic', true), relation('delivery_basic_identity', '/delivery_basic'), f('title', { required: true }), f('terms'), f('file_uri'), f('default_delivery_fee'), f('signed_at', { required: true }), f('effective_at', { required: true }), f('expired_at')], 'list', [
{ name: '启用合同', resource: '/gasorder_contract/:identity/activate', fields: reason },
{ name: '续签合同', resource: '/gasorder_contract/:identity/renew', fields: [f('effective_at', { required: true }), f('expired_at'), ...reason] },
{ name: '终止合同', resource: '/gasorder_contract/:identity/terminate', danger: true, fields: reason },
]),
], { canCreate: true, canEdit: true }),
define('gasorder_contract_product', '合同气瓶', 'append_only', [relation('gasorder_contract_identity', '/gasorder_contract', true), relation('product_info_identity', '/product_info', true), f('unit_price')], 'list', [
{ name: '解绑气瓶', resource: '/gasorder_contract_product/:identity/unbind', danger: true, fields: reason },
]),
define('gasorder_contract_revision', '合同修订记录', 'readonly', []),
define('gasorder_basic', '气体配送订单', 'managed', [f('request_no', { required: true }), relation('gasorder_contract_identity', '/gasorder_contract', true), f('creator_type', { required: true, type: 'select', options: [{ label: '用户', value: 'user' }, { label: '工作人员', value: 'staff' }, { label: '配送站', value: 'delivery' }, { label: '气站', value: 'gas' }] }), f('creator_identity', { required: true }), relation('user_address_identity', '/user_address', true), f('gasorder_contract_product_identities', { required: true, type: 'identity-list', relation: '/gasorder_contract_product' }), f('contact_name', { required: true }), f('contact_phone', { required: true }), f('discount_amount'), f('remark')], 'list', [
define('gasorder_basic', '气体配送订单', 'append_only', [f('request_no', { required: true }), relation('gasorder_contract_identity', '/gasorder_contract', true), f('creator_type', { required: true, type: 'select', options: [{ label: '用户', value: 'user' }, { label: '工作人员', value: 'staff' }, { label: '配送站', value: 'delivery' }, { label: '气站', value: 'gas' }] }), f('creator_identity', { required: true }), relation('user_address_identity', '/user_address', true), f('gasorder_contract_product_identities', { required: true, type: 'identity-list', relation: '/gasorder_contract_product' }), f('contact_name', { required: true }), f('contact_phone', { required: true }), f('discount_amount'), f('remark')], 'list', [
{ name: '分配订单', resource: '/gasorder_basic/:identity/assign', fields: [relation('delivery_basic_identity', '/delivery_basic', true), relation('staff_account_identity', '/staff_account', true), ...reason] },
{ name: '开始罐装', resource: '/gasorder_basic/:identity/filling', fields: reason },
{ name: '待配送', resource: '/gasorder_basic/:identity/ready', fields: reason },
@@ -291,7 +320,7 @@ export const resources: ResourceUiDefinition[] = [
define('ec_order_item', '商城订单明细', 'writable', [relation('ec_order_identity', '/ec_order', true), relation('ec_product_identity', '/ec_product', true), f('product_snapshot', { required: true }), f('quantity', { required: true }), f('sale_amount', { required: true })]),
define('ec_review', '商品评价', 'writable', [relation('ec_order_identity', '/ec_order', true), relation('ec_product_identity', '/ec_product', true), relation('user_account_identity', '/user_account', true), f('score', { required: true }), f('content', { required: true })]),
define('wallet_basic', '钱包', 'managed', [f('owner_type'), f('owner_identity'), f('alipay_id'), f('alipay_name'), f('wxpay_id'), f('wxpay_name'), f('balance'), f('withdrawal_balance')], 'list', [
define('wallet_basic', '钱包', 'readonly', [f('owner_type'), f('owner_identity'), f('alipay_id'), f('alipay_name'), f('wxpay_id'), f('wxpay_name'), f('balance'), f('withdrawal_balance')], 'list', [
{ name: '后台充值', resource: '/wallet_basic/:identity/recharge', fields: [f('request_no', { required: true }), f('amount', { required: true }), f('withdrawable'), ...reason, f('remark')] },
{ name: '修改钱包状态', resource: '/wallet_basic/:identity/status', method: 'PATCH', fields: [f('status', { required: true, type: 'select', options: [{ label: '启用', value: 'enabled' }, { label: '停用', value: 'disabled' }, { label: '冻结', value: 'frozen' }] })] },
]),
@@ -299,7 +328,7 @@ export const resources: ResourceUiDefinition[] = [
define('wallet_payment', '钱包支付记录', 'readonly', []),
define('wallet_record', '钱包流水', 'readonly', []),
define('wallet_refund', '退款记录', 'readonly', []),
define('wallet_apply_cash', '提现申请', 'managed', [], 'list', [
define('wallet_apply_cash', '提现申请', 'readonly', [], 'list', [
{ name: '审核通过', resource: '/wallet_apply_cash/:identity/approve', fields: reason },
{ name: '审核驳回', resource: '/wallet_apply_cash/:identity/reject', danger: true, fields: reason },
]),