This commit is contained in:
2026-06-12 18:02:57 +08:00
parent 2ba0e6d766
commit 9e98c9c981
+174 -170
View File
@@ -80,191 +80,195 @@ const AdminPaymentConfig: React.FC = () => {
};
return (
<div style={{ maxWidth: 720 }}>
{/* 通用设置 */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: 'rgba(99,102,241,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: '#6366f1',
}}><ClockCircleOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}></Typography.Text>
<div style={{ maxWidth: '100%' }}>
{/* 上边一排:通用设置 + 模拟支付模式 */}
<div style={{ display: 'flex', gap: 24, flexWrap: 'wrap', marginBottom: 24 }}>
{/* 通用设置:订单超时时间 */}
<div style={{ flex: '1 1 400px', minWidth: 400 }}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 40, height: 40, borderRadius: 10,
background: 'rgba(99,102,241,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 20, color: '#6366f1',
}}><ClockCircleOutlined /></div>
<div>
<Typography.Text strong style={{ fontSize: 14 }}></Typography.Text>
</div>
</div>
<Form form={form} layout="inline">
<Form.Item name="order_timeout" style={{ margin: 0 }}>
<InputNumber
min={30}
max={86400}
placeholder="180"
style={{ width: 140 }}
size="middle"
addonAfter="秒"
/>
</Form.Item>
</Form>
</div>
</div>
</Card>
</div>
<Form form={form} layout="vertical">
<Form.Item
name="order_timeout"
label={<span style={{ fontWeight: 500 }}></span>}
extra="订单创建后超过此时间未支付将自动取消(秒)"
>
<InputNumber
min={30}
max={86400}
placeholder="180"
style={{ width: '100%' }}
size="large"
/>
</Form.Item>
</Form>
</Card>
{/* Mock Mode Toggle */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16, background: mockMode ? '#fff7e6' : '#fafbff' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: mockMode ? 'rgba(245,158,11,0.15)' : 'rgba(99,102,241,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: mockMode ? '#f59e0b' : '#6366f1',
}}><DollarOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{mockMode ? '⚠️ 开启后所有充值会直接成功(仅用于测试)' : '关闭 - 使用真实支付渠道'}
</Typography.Text>
{/* 模拟支付模式 */}
<div style={{ flex: '1 1 400px', minWidth: 400 }}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', background: mockMode ? '#fff7e6' : '#fafbff' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 40, height: 40, borderRadius: 10,
background: mockMode ? 'rgba(245,158,11,0.15)' : 'rgba(99,102,241,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 20, color: mockMode ? '#f59e0b' : '#6366f1',
}}><DollarOutlined /></div>
<div>
<Typography.Text strong style={{ fontSize: 14 }}></Typography.Text>
</div>
</div>
<Switch checked={mockMode} onChange={setMockMode} checkedChildren="已开启" unCheckedChildren="已关闭" />
</div>
</div>
<Switch checked={mockMode} onChange={setMockMode} checkedChildren="已开启" unCheckedChildren="已关闭" />
</Card>
</div>
</Card>
</div>
{/* WeChat Pay */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: 'rgba(7,193,96,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: '#07c160',
}}><WechatOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}></Typography.Text>
{/* 下边一排:微信支付 + 支付宝 */}
<div style={{ display: 'flex', gap: 24, flexWrap: 'wrap' }}>
{/* 微信支付 */}
<div style={{ flex: '1 1 400px', minWidth: 400 }}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: 'rgba(7,193,96,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: '#07c160',
}}><WechatOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}></Typography.Text>
</div>
</div>
<Switch checked={wechatEnabled} onChange={setWechatEnabled} checkedChildren="已启用" unCheckedChildren="未启用" />
</div>
</div>
<Switch checked={wechatEnabled} onChange={setWechatEnabled} checkedChildren="已启用" unCheckedChildren="未启用" />
</div>
<Form form={form} layout="vertical">
<Form.Item name="wechat_appid" label="AppID">
<Input placeholder="微信支付 AppID" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_mch_id" label="商户号 (MchID)">
<Input placeholder="微信支付商户号" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item
name="wechat_private_key"
label="商户私钥"
extra={`
⚠️ 重要:请填写 apiclient_key.pem 的内容,不是 apiclient_cert.pem
内容应该以 -----BEGIN PRIVATE KEY----- 或 -----BEGIN RSA PRIVATE KEY----- 开头
`}
>
<Input.TextArea
rows={6}
placeholder="
<Form form={form} layout="vertical">
<Form.Item name="wechat_appid" label="AppID">
<Input placeholder="微信支付 AppID" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_mch_id" label="商户号 (MchID)">
<Input placeholder="微信支付商户号" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item
name="wechat_private_key"
label="商户私钥"
extra={`
⚠️ 重要:请填写 apiclient_key.pem 的内容,不是 apiclient_cert.pem
内容应该以 -----BEGIN PRIVATE KEY----- 或 -----BEGIN RSA PRIVATE KEY----- 开头
`}
>
<Input.TextArea
rows={4}
placeholder="
-----BEGIN PRIVATE KEY-----
...这里是私钥内容...
-----END PRIVATE KEY-----
"
disabled={!wechatEnabled}
/>
</Form.Item>
<Form.Item
name="wechat_cert_serial_no"
label="商户证书序列号"
extra="从 apiclient_cert.pem 中提取的证书序列号,或者在微信商户平台获取"
>
<Input placeholder="商户证书序列号" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_api_v3_key" label="API v3 密钥">
<Input.Password placeholder="API v3 密钥" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_notify_url" label="回调地址" extra="用户支付成功后,微信会主动通知此地址,服务器收到通知后给用户加积分">
<Input placeholder="https://yourdomain.com/api/payments/wechat/callback" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item
name="wechat_public_key"
label="微信平台公钥"
extra="(可选)微信支付平台公钥,用于验证回调签名"
>
<Input.TextArea
rows={4}
placeholder="微信支付平台公钥内容"
disabled={!wechatEnabled}
/>
</Form.Item>
<Form.Item
name="wechat_public_key_id"
label="微信平台公钥ID"
extra="(可选)对应平台公钥ID"
>
<Input placeholder="平台公钥ID" size="large" disabled={!wechatEnabled} />
</Form.Item>
</Form>
</Card>
{/* Alipay */}
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5', marginBottom: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: 'rgba(0,122,255,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: '#007aff',
}}><AlipayCircleOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}></Typography.Text>
</div>
</div>
<Switch checked={alipayEnabled} onChange={setAlipayEnabled} checkedChildren="已启用" unCheckedChildren="未启用" />
"
disabled={!wechatEnabled}
/>
</Form.Item>
<Form.Item
name="wechat_cert_serial_no"
label="商户证书序列号"
extra="从 apiclient_cert.pem 中提取的证书序列号"
>
<Input placeholder="商户证书序列号" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_api_v3_key" label="API v3 密钥">
<Input.Password placeholder="API v3 密钥" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item name="wechat_notify_url" label="回调地址">
<Input placeholder="https://yourdomain.com/api/payments/wechat/callback" size="large" disabled={!wechatEnabled} />
</Form.Item>
<Form.Item
name="wechat_public_key"
label="微信平台公钥(可选)"
>
<Input.TextArea
rows={3}
placeholder="微信支付平台公钥内容"
disabled={!wechatEnabled}
/>
</Form.Item>
<Form.Item
name="wechat_public_key_id"
label="微信平台公钥ID(可选)"
>
<Input placeholder="平台公钥ID" size="large" disabled={!wechatEnabled} />
</Form.Item>
</Form>
</Card>
</div>
<Form form={form} layout="vertical">
<Form.Item name="alipay_app_id" label="AppID">
<Input placeholder="支付宝应用AppID" size="large" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item
name="alipay_private_key"
label="应用私钥"
extra="支付宝应用私钥(PKCS8格式),不需要添加头部和尾部标记,直接粘贴私钥内容"
>
<Input.TextArea rows={4} placeholder="
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item
name="alipay_public_key"
label="支付宝公钥"
extra="从支付宝开放平台获取的支付宝公钥,不需要添加头部和尾部标记"
>
<Input.TextArea rows={4} placeholder="
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item name="alipay_gateway" label="网关地址" extra="正式环境: https://openapi.alipay.com/gateway.do 沙箱环境: https://openapi-sandbox.dl.alipaydev.com/gateway.do">
<Input placeholder="https://openapi.alipay.com/gateway.do" size="large" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item name="alipay_notify_url" label="回调地址" extra="用户支付成功后,支付宝会主动通知此地址,服务器收到通知后给用户加积分">
<Input placeholder="https://yourdomain.com/api/payments/alipay/callback" size="large" disabled={!alipayEnabled} />
</Form.Item>
</Form>
</Card>
{/* 支付宝 */}
<div style={{ flex: '1 1 400px', minWidth: 400 }}>
<Card bordered={false} style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{
width: 44, height: 44, borderRadius: 10,
background: 'rgba(0,122,255,0.08)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontSize: 22, color: '#007aff',
}}><AlipayCircleOutlined /></div>
<div>
<Typography.Title level={5} style={{ margin: 0 }}></Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}></Typography.Text>
</div>
</div>
<Switch checked={alipayEnabled} onChange={setAlipayEnabled} checkedChildren="已启用" unCheckedChildren="未启用" />
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Form form={form} layout="vertical">
<Form.Item name="alipay_app_id" label="AppID">
<Input placeholder="支付宝应用AppID" size="large" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item
name="alipay_private_key"
label="应用私钥"
extra="支付宝应用私钥(PKCS8格式),不需要添加头部和尾部标记"
>
<Input.TextArea rows={4} placeholder="
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item
name="alipay_public_key"
label="支付宝公钥"
extra="从支付宝开放平台获取的支付宝公钥"
>
<Input.TextArea rows={4} placeholder="
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item name="alipay_gateway" label="网关地址">
<Input placeholder="https://openapi.alipay.com/gateway.do" size="large" disabled={!alipayEnabled} />
</Form.Item>
<Form.Item name="alipay_notify_url" label="回调地址">
<Input placeholder="https://yourdomain.com/api/payments/alipay/callback" size="large" disabled={!alipayEnabled} />
</Form.Item>
</Form>
</Card>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 24 }}>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSave} loading={saving}
size="large" style={{ borderRadius: 8, minWidth: 140 }}>
size="large" style={{ borderRadius: 8, minWidth: 160, height: 44, fontSize: 15 }}>
</Button>
</div>