新增未登录状态下的假资料展示,优化用户卡片界面,允许用户点击登录以打开登录弹窗。同时,更新登录弹窗样式,增加取消按钮,提升用户体验和交互性。

This commit is contained in:
乘风
2026-02-10 10:39:39 +08:00
parent e6fa0b8e0d
commit e295f55fd9
9 changed files with 162 additions and 78 deletions

View File

@@ -50,10 +50,14 @@ Page({
withdrawMchId: '',
withdrawAppId: '',
// 未登录假资料(展示用)
guestNickname: '游客',
guestAvatar: '',
// 登录弹窗
showLoginModal: false,
isLoggingIn: false,
// 修改昵称弹窗
showNicknameModal: false,
editingNickname: ''

View File

@@ -11,16 +11,36 @@
<!-- 导航栏占位 -->
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
<!-- 用户卡片 - 未登录状态 - 只显示登录提示 -->
<view class="user-card card-gradient login-card" wx:if="{{!isLoggedIn}}">
<view class="login-prompt">
<view class="login-icon-large">🔐</view>
<text class="login-title">登录 Soul创业实验</text>
<text class="login-desc">登录后可购买章节、解锁更多内容</text>
<button class="btn-wechat-large" bindtap="handleWechatLogin">
<text class="btn-icon">微</text>
<text>微信快捷登录</text>
</button>
<!-- 用户卡片 - 未登录:假资料界面,名字旁点击登录打开弹窗 -->
<view class="user-card card-gradient" wx:if="{{!isLoggedIn}}">
<view class="user-header-row">
<view class="avatar avatar-placeholder">
<image class="avatar-img" wx:if="{{guestAvatar}}" src="{{guestAvatar}}" mode="aspectFill"/>
<text class="avatar-text" wx:else>{{guestNickname[0] || '游'}}</text>
</view>
<view class="user-info-block">
<view class="user-name-row">
<text class="user-name">{{guestNickname}}</text>
<view class="btn-login-inline" bindtap="showLogin">点击登录</view>
</view>
<view class="user-id-row">
<text class="user-id user-id-guest">登录后查看完整信息</text>
</view>
</view>
</view>
<view class="stats-grid">
<view class="stat-item">
<text class="stat-value brand-color">--</text>
<text class="stat-label">已读章节</text>
</view>
<view class="stat-item">
<text class="stat-value brand-color">--</text>
<text class="stat-label">推荐好友</text>
</view>
<view class="stat-item">
<text class="stat-value gold-color">--</text>
<text class="stat-label">待领收益</text>
</view>
</view>
</view>
@@ -241,9 +261,9 @@
</view>
</view>
<!-- 登录弹窗 - 只保留微信登录 -->
<!-- 登录弹窗:可取消,用户主动选择是否登录 -->
<view class="modal-overlay" wx:if="{{showLoginModal}}" bindtap="closeLoginModal">
<view class="modal-content" catchtap="stopPropagation">
<view class="modal-content login-modal-content" catchtap="stopPropagation">
<view class="modal-close" bindtap="closeLoginModal">✕</view>
<view class="login-icon">🔐</view>
<text class="login-title">登录 Soul创业实验</text>
@@ -257,6 +277,7 @@
<text class="btn-wechat-icon">微</text>
<text>{{isLoggingIn ? '登录中...' : '微信快捷登录'}}</text>
</button>
<view class="login-modal-cancel" bindtap="closeLoginModal">取消</view>
<text class="login-notice">登录即表示同意《用户协议》和《隐私政策》</text>
</view>

View File

@@ -305,67 +305,24 @@
margin-top: 4rpx;
}
/* ===== 登录卡片样式 ===== */
.login-card {
min-height: 400rpx;
display: flex;
align-items: center;
justify-content: center;
/* ===== 登录假资料样式 ===== */
.avatar-placeholder {
cursor: default;
}
.login-prompt {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 40rpx 0;
width: 100%;
.user-id-guest {
color: rgba(255, 255, 255, 0.35) !important;
}
.login-icon-large {
font-size: 80rpx;
margin-bottom: 32rpx;
}
.login-title {
font-size: 36rpx;
.btn-login-inline {
flex-shrink: 0;
margin-left: 16rpx;
padding: 10rpx 24rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
color: #000;
font-size: 24rpx;
font-weight: 600;
color: #ffffff;
margin-bottom: 16rpx;
}
.login-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.5);
margin-bottom: 48rpx;
line-height: 1.6;
}
.btn-wechat-large {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
width: 80%;
padding: 28rpx 0;
background: linear-gradient(135deg, #07C160 0%, #06AD56 100%);
border-radius: 48rpx;
border: none;
color: #ffffff;
font-size: 32rpx;
font-weight: 600;
}
.btn-wechat-large .btn-icon {
width: 48rpx;
height: 48rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 700;
border-radius: 24rpx;
}
.user-name {
@@ -1028,6 +985,15 @@
font-size: 32rpx;
}
/* 登录弹窗内取消按钮 */
.login-modal-cancel {
margin-top: 24rpx;
padding: 24rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
text-align: center;
}
.login-notice {
display: block;
margin-top: 32rpx;

View File

@@ -234,12 +234,13 @@ export function DistributionPage() {
async function handleApproveWithdrawal(id: string) {
if (!confirm('确认审核通过并打款?')) return
try {
const res = await put<{ success?: boolean; error?: string }>('/api/admin/withdrawals', {
id,
action: 'approve',
})
const res = await put<{ success?: boolean; error?: string; message?: string }>(
'/api/admin/withdrawals',
{ id, action: 'approve' },
)
if (!res?.success) {
alert(res?.error || '操作失败')
const detail = res?.message || res?.error || '操作失败'
alert(detail)
return
}
await refreshCurrentTab()

View File

@@ -0,0 +1 @@
exit status 1exit status 1

View File

@@ -173,8 +173,10 @@ func AdminWithdrawalsAction(c *gin.Context) {
result, err := wechat.InitiateTransfer(params)
if err != nil {
// 未初始化转账客户端:仅标记为 success提示线下打款
if err.Error() == "转账客户端未初始化" {
errMsg := err.Error()
fmt.Printf("[AdminWithdrawals] 发起转账失败 id=%s: %s\n", body.ID, errMsg)
// 未初始化或未配置转账:仅标记为已打款并提示线下处理(与 transfer 包返回文案一致)
if errMsg == "支付/转账未初始化,请先调用 wechat.Init" || errMsg == "转账客户端未初始化" {
_ = db.Model(&w).Updates(map[string]interface{}{
"status": "success",
"processed_at": now,
@@ -185,8 +187,8 @@ func AdminWithdrawalsAction(c *gin.Context) {
})
return
}
// 其他打款失败:记失败原因
failMsg := err.Error()
// 其他打款失败(含调用腾讯接口失败):记失败原因
failMsg := errMsg
_ = db.Model(&w).Updates(map[string]interface{}{
"status": "failed",
"fail_reason": failMsg,

BIN
soul-api/tmp/main.exe Normal file

Binary file not shown.

View File

@@ -28,3 +28,33 @@
{"level":"debug","timestamp":"2026-02-09T21:46:31+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 400 Bad Request\r\nContent-Length: 207\r\nCache-Control: no-cache, must-revalidate\r\nConnection: keep-alive\r\nContent-Language: zh-CN\r\nContent-Type: application/json; charset=utf-8\r\nDate: Mon, 09 Feb 2026 13:46:31 GMT\r\nKeep-Alive: timeout=8\r\nRequest-Id: 08B7CAA7CC0610EA0418B3D7BCA80120812028ACD903-268435462\r\nServer: nginx\r\nWechatpay-Nonce: d08926059983e7a83c001572543aa0cc\r\nWechatpay-Serial: 5F2543BF58239A4EB68FA4433DF1438A88B34B16\r\nWechatpay-Signature: DCqVYlZQVZC7VVTr55VqYFA1OxgJ048FAhYFZ2m2rBuMuRxUEF/JlSe3dZjRZUn9ZSUDzROrF5zBMG2phkxa8Qy2O7+hy/mrWd6BVD778TD6TiL2MqwIsj83DoMtV/yFrwlnhDRc4McKnD+NbrWdplVIYnSt1MyKJU1RQEdofGBKlx3p88bn8dgnNwsnokAp7dJBldQapOUCZc5LWJ2ZGEws5uniob6HIeZlQm7a3rgVzBm9VwJEuVpErZE0O5IvXOcZjGg+D1yiEBxLrIquQyjFyajOui4NN6jfCIG+On0YLRuB3IXGS1eOvgJXCZev//VeNq3IXHobIf1F/H65jg==\r\nWechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048\r\nWechatpay-Timestamp: 1770644791\r\nX-Content-Type-Options: nosniff\r\n\r\n{\"code\":\"PARAM_ERROR\",\"detail\":{\"location\":\"body\",\"value\":41},\"message\":\"输入源“/body/batch_remark”映射到值字段“批次备注”字符串规则校验失败字符数 41大于最大值 32\"}"}
{"level":"debug","timestamp":"2026-02-09T21:48:08+08:00","caller":"kernel/baseClient.go:457","content":"POST https://api.mch.weixin.qq.com/v3/transfer/batches request header: { Content-Type:application/jsonAuthorization:WECHATPAY2-SHA256-RSA2048 mchid=\"1318592501\",nonce_str=\"wUX5RqmlbUUTEnuzRiD9FAFTFL9zPXLY\",timestamp=\"1770644888\",serial_no=\"4A1DB62CD5C9BE0B6FC51C30621D6F99686E75C5\",signature=\"w1YBlKTIo07vfIJbf4IvFf88QKaWXdOS9ulWxMzguvxb6bfgKNZQ1xLdOWlesI+b5KdJr9rpLDc2/7r6sZcqauKTH2mxxcW48VwPkNTzGfb7pqKsCcOHu3xpn6XR+lSPe/qEL4vyxwS83HLJhlRk32opXOFPp/g457D/DJn8X1QDnW0jngLug4SG/uu8J4vqZNGODPvsRyXQZZzPkGAJ3cVYuqLAywkaVxgwKjcB4dVz6PWm58EOakxN1wIkDUIIxkddFqkTg1z9zy3NoFagqwyNXDJ0K4VumBWt3yNThPA376RBF04noV0mrTXzRpylHGeKPp7TLTcEeJYmQUiRtg==\"Accept:*/*} request body:"}
{"level":"debug","timestamp":"2026-02-09T21:48:08+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 400 Bad Request\r\nContent-Length: 207\r\nCache-Control: no-cache, must-revalidate\r\nConnection: keep-alive\r\nContent-Language: zh-CN\r\nContent-Type: application/json; charset=utf-8\r\nDate: Mon, 09 Feb 2026 13:48:08 GMT\r\nKeep-Alive: timeout=8\r\nRequest-Id: 0898CBA7CC06108803188AD2BCA80120B00B2890DB05-268435462\r\nServer: nginx\r\nWechatpay-Nonce: 28af031c95ea837f0ffb34c27b76c76d\r\nWechatpay-Serial: 5F2543BF58239A4EB68FA4433DF1438A88B34B16\r\nWechatpay-Signature: KtamVaPOVNlk+XuLtBcSUh9sq6B+QVPnupofCmLD95NF3z+uUsu2ia7tOXG6BR8oEOL6z/YVkJ9LmR8sQ/Kmx9/n3wlrQTYzWhesHUNNK/rkzXgefeYofh4LBZKlaaqjJ3PuCafyueBmrW4V6Vqt1XwSbrbLx4MLrR9t2qFrW0xG43Ru0ymA9hN7c0N/XTE/8V8Jl3BB1jJx24NlJr0T+RWEkzDOn54gzRJaGJTdDJYRQCOVterVYQPfMUxPvfIJbRi2/Fh1NXYESrgsq9gKPyc6S/oPgEBGyQXaY8LQDqQgA2NNrn1vVEOiOzvluF2l8CtCNo/RWwfBKmE0jZcj4A==\r\nWechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048\r\nWechatpay-Timestamp: 1770644888\r\nX-Content-Type-Options: nosniff\r\n\r\n{\"code\":\"PARAM_ERROR\",\"detail\":{\"location\":\"body\",\"value\":41},\"message\":\"输入源“/body/batch_remark”映射到值字段“批次备注”字符串规则校验失败字符数 41大于最大值 32\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsPSSjAJASVV\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsJFCjAJARNK\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsFHNjAJAMOU\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsDCAjAJAQPN\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsMLYjAJAXWJ\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"access_token\":\"100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsUPBjAJALGS\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsPSSjAJASVV&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0f3MqnGa1OW0aL0Go4Ha1nzWzE4MqnGE&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:39 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsJFCjAJARNK&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0e3jJGll2nQW9h4v4nnl2wgWd22jJGla&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsFHNjAJAMOU&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0a3tY3nl29v18h4yGSkl2Mg4Cf4tY3nv&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsDCAjAJAQPN&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0d3U7y1w30Qhw63wgj2w3Z7DZg2U7y1n&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:39+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsMLYjAJAXWJ&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0b3On6Ga1JTJ9L0kS0Ha1Px9241On6Gn&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsUPBjAJALGS&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0c3UwVGa1XeFbL0v8bGa1BKzkp3UwVGg&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_P7g4blBL6WGpiWnpgaOj6g5fofKxJaow-bPXoxC2KpcTQJnGqp1TC4Kam6XU8RJXghMpp0tJkAz9fDxQaP_34XYZq6DHf3lzGH0-j7-YHiSOIuvNAdO7wxX6ovsUPBjAJALGS&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0f3lGpll2gNF9h4B4wnl28WCjd4lGple&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:28:40+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:28:40 GMT\r\n\r\n{\"session_key\":\"CpKNLe0O+AZIOaSznEhU2w==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-10T10:39:28+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:39:28+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Tue, 10 Feb 2026 02:39:28 GMT\r\n\r\n{\"access_token\":\"100_O1K3OEKfS5xdLDj3z6g41UuJ8grNWUghMbn1ZZ8PbY1mh_EqTuJQId9K7ZnEB966BoXPGtxZnB6rk8JXK-4pAvWaCkc0sEr-gKN0s1wVDmuB1zrNACtonCTbPGgVFQgAEAOYJ\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-10T10:39:28+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=100_O1K3OEKfS5xdLDj3z6g41UuJ8grNWUghMbn1ZZ8PbY1mh_EqTuJQId9K7ZnEB966BoXPGtxZnB6rk8JXK-4pAvWaCkc0sEr-gKN0s1wVDmuB1zrNACtonCTbPGgVFQgAEAOYJ&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0b3I5oGa1Ow0aL0FiSFa1VLWfZ2I5oGx&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-10T10:39:28+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Tue, 10 Feb 2026 02:39:28 GMT\r\n\r\n{\"session_key\":\"RtzZJRnbC1pTwaJreA1XRw==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}

View File

@@ -0,0 +1,59 @@
# 商家转账到零钱 - 功能位置与打通条件
## 一、入口在哪个页面(唯一入口)
- 管理端soul-admin【分销】页 → 左侧 Tab 选【提现审核】→ 某条提现右侧点【通过】按钮。
- 即:管理后台 → 提现审核列表 → 点击「通过」= 发起「商家转账到零钱」到腾讯。
没有别的页面会发起转账;小程序端只负责「申请提现」(落库待审核),打款只在管理端点「通过」时触发。
---
## 二、后端调用链(代码位置)
1. 接口PUT /api/admin/withdrawalsbody: { "id": "提现记录id", "action": "approve" }
2. 处理soul-api/internal/handler/admin_withdrawals.go → AdminWithdrawalsActioncase "approve"
3. 调微信wechat.InitiateTransfer(params)
4. 实现soul-api/internal/wechat/transfer.go → InitiateTransfer → paymentApp.TransferBatch.Batch()PowerWeChat 调腾讯「发起转账」API
---
## 三、为什么「没发起到腾讯」常见原因
1. 启动时 wechat.Init 失败
- main.go 里会 log.Fatal服务起不来若能正常访问 /health说明 Init 已成功paymentApp 非空。
2. 商户号未开通「商家转账到零钱」
- 登录 微信支付商户平台 → 产品中心 → 商家转账到零钱,需已开通且生效。
3. 证书/密钥不对
- 转账用 API v3需要APIv3 密钥、商户证书apiclient_cert.pem、商户私钥apiclient_key.pem、证书序列号。
- .env 里 WECHAT_CERT_PATH、WECHAT_KEY_PATH、WECHAT_APIV3_KEY、WECHAT_SERIAL_NO 必须与商户平台一致,且路径在运行目录下可读(或 OSS 等 URL 可访问)。
4. 环境变量未生效
- 若未配置或配错,可能走 config 默认值;部署时务必用实际 .env 覆盖,并重启 soul-api。
---
## 四、必须的 .env 配置(转账相关)
- WECHAT_APPID小程序 AppID与商户号已绑定
- WECHAT_MCH_ID商户号
- WECHAT_APIV3_KEY商户平台 → API 安全 → APIv3 密钥32 位)
- WECHAT_CERT_PATH商户 API 证书pem路径或可访问 URL
- WECHAT_KEY_PATH商户 API 私钥pem路径或可访问 URL
- WECHAT_SERIAL_NO商户 API 证书序列号(商户平台可查)
- WECHAT_TRANSFER_URL转账结果回调地址需 HTTPS、外网可访问https://你的域名/api/payment/wechat/transfer/notify
---
## 五、自检是否打通
1. 管理端点「通过」后:
- 若返回「已发起打款,微信处理中」且列表里该条变为「处理中」→ 说明已调通腾讯,等回调或去商户平台查单。
- 若返回「发起打款失败」且 message 里是「支付/转账未初始化…」→ 未初始化或未配置,检查 .env 与 wechat.Init。
- 若返回「发起打款失败」且 message 里是证书/签名/权限等错误 → 按报错检查商户号开通、证书、APIv3 密钥、序列号。
2. 看 soul-api 启动日志:若 wechat.Init 报错会直接退出;无报错则说明 Payment 初始化成功,问题多在商户开通或单次请求参数。
3. 商户平台:产品中心 → 商家转账到零钱 → 查看是否已开通;可查转账记录/批次号确认是否收到请求。