mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 05:07:27 +00:00
调整 优化代码细节
This commit is contained in:
@@ -36,8 +36,9 @@ func generateCreemSignature(payload string, secret string) string {
|
|||||||
// 验证Creem webhook签名
|
// 验证Creem webhook签名
|
||||||
func verifyCreemSignature(payload string, signature string, secret string) bool {
|
func verifyCreemSignature(payload string, signature string, secret string) bool {
|
||||||
if secret == "" {
|
if secret == "" {
|
||||||
|
log.Printf("Creem webhook secret not set")
|
||||||
if setting.CreemTestMode {
|
if setting.CreemTestMode {
|
||||||
log.Printf("Creem webhook secret未配置,测试模式下跳过签名验证")
|
log.Printf("Skip Creem webhook sign verify in test mode")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -146,8 +147,8 @@ func RequestCreemPay(c *gin.Context) {
|
|||||||
// 读取body内容用于打印,同时保留原始数据供后续使用
|
// 读取body内容用于打印,同时保留原始数据供后续使用
|
||||||
bodyBytes, err := io.ReadAll(c.Request.Body)
|
bodyBytes, err := io.ReadAll(c.Request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("读取请求body失败: %v", err)
|
log.Printf("read creem pay req body err: %v", err)
|
||||||
c.JSON(200, gin.H{"message": "error", "data": "读取请求失败"})
|
c.JSON(200, gin.H{"message": "error", "data": "read query error"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +159,6 @@ func RequestCreemPay(c *gin.Context) {
|
|||||||
c.Request.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
c.Request.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
||||||
|
|
||||||
err = c.ShouldBindJSON(&req)
|
err = c.ShouldBindJSON(&req)
|
||||||
log.Printf(" json body is %+v", req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, gin.H{"message": "error", "data": "参数错误"})
|
c.JSON(200, gin.H{"message": "error", "data": "参数错误"})
|
||||||
return
|
return
|
||||||
@@ -251,7 +251,9 @@ func CreemWebhook(c *gin.Context) {
|
|||||||
|
|
||||||
// 打印关键信息(避免输出完整敏感payload)
|
// 打印关键信息(避免输出完整敏感payload)
|
||||||
log.Printf("Creem Webhook - URI: %s", c.Request.RequestURI)
|
log.Printf("Creem Webhook - URI: %s", c.Request.RequestURI)
|
||||||
if signature == "" && !setting.CreemTestMode {
|
if setting.CreemTestMode {
|
||||||
|
log.Printf("Creem Webhook - Signature: %s , Body: %s", signature, bodyBytes)
|
||||||
|
} else if signature == "" {
|
||||||
log.Printf("Creem Webhook缺少签名头")
|
log.Printf("Creem Webhook缺少签名头")
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
@@ -314,12 +316,11 @@ func handleCheckoutCompleted(c *gin.Context, event *CreemWebhookEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 记录详细的支付信息
|
// 记录详细的支付信息
|
||||||
log.Printf("处理Creem支付完成 - 订单号: %s, Creem订单ID: %s, 支付金额: %d %s, 客户邮箱: %s, 产品: %s",
|
log.Printf("处理Creem支付完成 - 订单号: %s, Creem订单ID: %s, 支付金额: %d %s, 客户邮箱: <redacted>, 产品: %s",
|
||||||
referenceId,
|
referenceId,
|
||||||
event.Object.Order.Id,
|
event.Object.Order.Id,
|
||||||
event.Object.Order.AmountPaid,
|
event.Object.Order.AmountPaid,
|
||||||
event.Object.Order.Currency,
|
event.Object.Order.Currency,
|
||||||
event.Object.Customer.Email,
|
|
||||||
event.Object.Product.Name)
|
event.Object.Product.Name)
|
||||||
|
|
||||||
// 查询本地订单确认存在
|
// 查询本地订单确认存在
|
||||||
@@ -355,8 +356,8 @@ func handleCheckoutCompleted(c *gin.Context, event *CreemWebhookEvent) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Creem充值成功 - 订单号: %s, 充值额度: %d, 支付金额: %.2f, 客户邮箱: %s, 客户姓名: %s",
|
log.Printf("Creem充值成功 - 订单号: %s, 充值额度: %d, 支付金额: %.2f",
|
||||||
referenceId, topUp.Amount, topUp.Money, customerEmail, customerName)
|
referenceId, topUp.Amount, topUp.Money)
|
||||||
c.Status(http.StatusOK)
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,11 +439,11 @@ func genCreemLink(referenceId string, product *CreemProduct, email string, usern
|
|||||||
return "", fmt.Errorf("读取响应失败: %v", err)
|
return "", fmt.Errorf("读取响应失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Creem API响应 - 状态码: %d, 响应体: %s", resp.StatusCode, string(body))
|
log.Printf("Creem API resp - status code: %d, resp: %s", resp.StatusCode, string(body))
|
||||||
|
|
||||||
// 检查响应状态
|
// 检查响应状态
|
||||||
if resp.StatusCode/100 != 2 {
|
if resp.StatusCode/100 != 2 {
|
||||||
return "", fmt.Errorf("Creem API 返回错误状态 %d: %s", resp.StatusCode, string(body))
|
return "", fmt.Errorf("Creem API http status %d ", resp.StatusCode)
|
||||||
}
|
}
|
||||||
// 解析响应
|
// 解析响应
|
||||||
var checkoutResp CreemCheckoutResponse
|
var checkoutResp CreemCheckoutResponse
|
||||||
@@ -452,7 +453,7 @@ func genCreemLink(referenceId string, product *CreemProduct, email string, usern
|
|||||||
}
|
}
|
||||||
|
|
||||||
if checkoutResp.CheckoutUrl == "" {
|
if checkoutResp.CheckoutUrl == "" {
|
||||||
return "", fmt.Errorf("Creem API 未返回支付链接")
|
return "", fmt.Errorf("Creem API resp no checkout url ")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Creem 支付链接创建成功 - 订单号: %s, 支付链接: %s", referenceId, checkoutResp.CheckoutUrl)
|
log.Printf("Creem 支付链接创建成功 - 订单号: %s, 支付链接: %s", referenceId, checkoutResp.CheckoutUrl)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func Recharge(referenceId string, customerId string) (err error) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func RechargeCreem(referenceId string, customerEmail string) (err error) {
|
func RechargeCreem(referenceId string, customerEmail string, customerName string) (err error) {
|
||||||
if referenceId == "" {
|
if referenceId == "" {
|
||||||
return errors.New("未提供支付单号")
|
return errors.New("未提供支付单号")
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,6 @@ func RechargeCreem(referenceId string, customerEmail string) (err error) {
|
|||||||
// 如果用户邮箱为空,则更新为支付时使用的邮箱
|
// 如果用户邮箱为空,则更新为支付时使用的邮箱
|
||||||
if user.Email == "" {
|
if user.Email == "" {
|
||||||
updateFields["email"] = customerEmail
|
updateFields["email"] = customerEmail
|
||||||
// 避免输出敏感信息到stdout
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,12 +50,7 @@ const PaymentSetting = () => {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'CreemProducts':
|
case 'CreemProducts':
|
||||||
try {
|
newInputs[item.key] = item.value || '[]';
|
||||||
newInputs[item.key] = item.value;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('解析CreemProducts出错:', error);
|
|
||||||
newInputs[item.key] = '[]';
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'Price':
|
case 'Price':
|
||||||
case 'MinTopUp':
|
case 'MinTopUp':
|
||||||
|
|||||||
@@ -315,6 +315,11 @@ const TopUp = () => {
|
|||||||
showError(t('请选择产品'));
|
showError(t('请选择产品'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Validate product has required fields
|
||||||
|
if (!selectedCreemProduct.productId) {
|
||||||
|
showError(t('产品配置错误,请联系管理员'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setConfirmLoading(true);
|
setConfirmLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await API.post('/api/user/creem/pay', {
|
const res = await API.post('/api/user/creem/pay', {
|
||||||
@@ -668,14 +673,14 @@ const TopUp = () => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title={t('确定要充值吗')}
|
title={t('确定要充值吗')}
|
||||||
visible={stripeOpen}
|
visible={stripeOpen}
|
||||||
onOk={onlineStripeTopUp}
|
onOk={onlineStripeTopUp}
|
||||||
onCancel={handleStripeCancel}
|
onCancel={handleStripeCancel}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
size='small'
|
size='small'
|
||||||
centered
|
centered
|
||||||
confirmLoading={confirmLoading}
|
confirmLoading={confirmLoading}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
{t('充值数量')}:{stripeTopUpCount}
|
{t('充值数量')}:{stripeTopUpCount}
|
||||||
@@ -1026,85 +1031,85 @@ const TopUp = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{enableStripeTopUp && (
|
{enableStripeTopUp && (
|
||||||
<>
|
<>
|
||||||
{/* 桌面端显示的自定义金额和支付按钮 */}
|
{/* 桌面端显示的自定义金额和支付按钮 */}
|
||||||
<div className='hidden md:block space-y-4'>
|
<div className='hidden md:block space-y-4'>
|
||||||
<Divider style={{ margin: '24px 0' }}>
|
<Divider style={{ margin: '24px 0' }}>
|
||||||
<Text className='text-sm font-medium'>
|
<Text className='text-sm font-medium'>
|
||||||
{t(!enableOnlineTopUp ? '或输入自定义金额' : 'Stripe')}
|
{t(!enableOnlineTopUp ? '或输入自定义金额' : 'Stripe')}
|
||||||
</Text>
|
</Text>
|
||||||
</Divider>
|
</Divider>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className='flex justify-between mb-2'>
|
<div className='flex justify-between mb-2'>
|
||||||
<Text strong>{t('充值数量')}</Text>
|
<Text strong>{t('充值数量')}</Text>
|
||||||
{amountLoading ? (
|
{amountLoading ? (
|
||||||
<Skeleton.Title
|
<Skeleton.Title
|
||||||
style={{ width: '80px', height: '16px' }}
|
style={{ width: '80px', height: '16px' }}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text type='tertiary'>
|
<Text type='tertiary'>
|
||||||
{t('实付金额:') + renderStripeAmount()}
|
{t('实付金额:') + renderStripeAmount()}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<InputNumber
|
|
||||||
disabled={!enableStripeTopUp}
|
|
||||||
placeholder={
|
|
||||||
t('充值数量,最低 ') + renderQuotaWithAmount(stripeMinTopUp)
|
|
||||||
}
|
|
||||||
value={stripeTopUpCount}
|
|
||||||
min={stripeMinTopUp}
|
|
||||||
max={999999999}
|
|
||||||
step={1}
|
|
||||||
precision={0}
|
|
||||||
onChange={async (value) => {
|
|
||||||
if (value && value >= 1) {
|
|
||||||
setStripeTopUpCount(value);
|
|
||||||
setSelectedPreset(null);
|
|
||||||
await getStripeAmount(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={(e) => {
|
|
||||||
const value = parseInt(e.target.value);
|
|
||||||
if (!value || value < 1) {
|
|
||||||
setStripeTopUpCount(1);
|
|
||||||
getStripeAmount(1);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
size='large'
|
|
||||||
className='w-full'
|
|
||||||
formatter={(value) => (value ? `${value}` : '')}
|
|
||||||
parser={(value) =>
|
|
||||||
value ? parseInt(value.replace(/[^\d]/g, '')) : 0
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<InputNumber
|
||||||
|
disabled={!enableStripeTopUp}
|
||||||
|
placeholder={
|
||||||
|
t('充值数量,最低 ') + renderQuotaWithAmount(stripeMinTopUp)
|
||||||
|
}
|
||||||
|
value={stripeTopUpCount}
|
||||||
|
min={stripeMinTopUp}
|
||||||
|
max={999999999}
|
||||||
|
step={1}
|
||||||
|
precision={0}
|
||||||
|
onChange={async (value) => {
|
||||||
|
if (value && value >= 1) {
|
||||||
|
setStripeTopUpCount(value);
|
||||||
|
setSelectedPreset(null);
|
||||||
|
await getStripeAmount(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
const value = parseInt(e.target.value);
|
||||||
|
if (!value || value < 1) {
|
||||||
|
setStripeTopUpCount(1);
|
||||||
|
getStripeAmount(1);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
size='large'
|
||||||
|
className='w-full'
|
||||||
|
formatter={(value) => (value ? `${value}` : '')}
|
||||||
|
parser={(value) =>
|
||||||
|
value ? parseInt(value.replace(/[^\d]/g, '')) : 0
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Text strong className='block mb-3'>
|
<Text strong className='block mb-3'>
|
||||||
{t('选择支付方式')}
|
{t('选择支付方式')}
|
||||||
</Text>
|
</Text>
|
||||||
<div className='grid grid-cols-1 gap-3'>
|
<div className='grid grid-cols-1 gap-3'>
|
||||||
<Button
|
<Button
|
||||||
key='stripe'
|
key='stripe'
|
||||||
type='primary'
|
type='primary'
|
||||||
onClick={() => stripePreTopUp()}
|
onClick={() => stripePreTopUp()}
|
||||||
size='large'
|
size='large'
|
||||||
disabled={!enableStripeTopUp}
|
disabled={!enableStripeTopUp}
|
||||||
loading={paymentLoading && payWay === 'stripe'}
|
loading={paymentLoading && payWay === 'stripe'}
|
||||||
icon={<CreditCard size={16} />}
|
icon={<CreditCard size={16} />}
|
||||||
style={{
|
style={{
|
||||||
height: '40px',
|
height: '40px',
|
||||||
color: '#b161fe',
|
color: '#b161fe',
|
||||||
}}
|
}}
|
||||||
className='transition-all hover:shadow-md w-full'
|
className='transition-all hover:shadow-md w-full'
|
||||||
>
|
>
|
||||||
<span className='ml-1'>Stripe</span>
|
<span className='ml-1'>Stripe</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 移动端 Stripe 充值区域 */}
|
{/* 移动端 Stripe 充值区域 */}
|
||||||
<div className='md:hidden space-y-4'>
|
<div className='md:hidden space-y-4'>
|
||||||
|
|||||||
Reference in New Issue
Block a user