feat: 新增提现文案翻译工具类,统一处理失败与驳回原因
这个提交包含在:
@@ -3,6 +3,7 @@
|
||||
namespace app\admin\controller\fc;
|
||||
|
||||
use app\common\controller\Backend;
|
||||
use app\common\library\WithdrawText;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
@@ -131,6 +132,8 @@ class Withdraw extends Backend
|
||||
'totalWithdrawn' => round($totalWithdrawn, 2),
|
||||
'withdrawable' => round($withdrawable, 2),
|
||||
'rejectReasons' => $rejectReasons,
|
||||
'failReasonText' => WithdrawText::fail($row['fail_reason']),
|
||||
'reasonText' => WithdrawText::reason($row['reason']),
|
||||
]);
|
||||
|
||||
return $this->view->fetch();
|
||||
@@ -293,7 +296,7 @@ class Withdraw extends Backend
|
||||
if ($latest['status'] === 'paid') {
|
||||
$this->success('微信转账已完成,单据已更新为「已成功到账」');
|
||||
} elseif ($latest['status'] === 'failed') {
|
||||
$this->error('微信转账已失败/已撤销:' . ($latest['fail_reason'] ?: '未知原因'));
|
||||
$this->error('微信转账已失败/已撤销:' . (WithdrawText::fail($latest['fail_reason']) ?: '未知原因'));
|
||||
} else {
|
||||
$this->success('已同步微信最新状态:' . $stText . '(微信已受理,需收款人在微信完成确认方可到账)');
|
||||
}
|
||||
|
||||
@@ -186,15 +186,15 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if condition="!empty($row.fail_reason)"}
|
||||
{if condition="!empty($failReasonText)"}
|
||||
<div class="alert alert-danger" style="margin-top:6px;margin-bottom:8px;padding:10px 14px;">
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>打款失败说明:</strong>{$row.fail_reason|htmlentities}
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>打款失败说明:</strong>{$failReasonText|htmlentities}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if condition="!empty($row.reason)"}
|
||||
{if condition="!empty($reasonText)"}
|
||||
<div class="alert alert-warning" style="margin-top:6px;margin-bottom:8px;padding:10px 14px;">
|
||||
<i class="fa fa-info-circle"></i> <strong>拒绝/驳回原因:</strong>{$row.reason|htmlentities}
|
||||
<i class="fa fa-info-circle"></i> <strong>拒绝/驳回原因:</strong>{$reasonText|htmlentities}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\common\library\WithdrawText;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
@@ -105,7 +106,7 @@ class AdminDist extends V1
|
||||
'status' => (string)$row['status'],
|
||||
'channel' => (string)$row['channel'],
|
||||
'transferStatus' => (string)(isset($row['transfer_status']) ? $row['transfer_status'] : ''),
|
||||
'failReason' => (string)(isset($row['fail_reason']) ? $row['fail_reason'] : ''),
|
||||
'failReason' => WithdrawText::fail(isset($row['fail_reason']) ? $row['fail_reason'] : ''),
|
||||
'createdAt' => $this->iso($row['createtime']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\common\library\WithdrawText;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
@@ -366,7 +367,7 @@ class Distribution extends V1
|
||||
'status' => (string)$row['status'],
|
||||
'transferStatus' => (string)(isset($row['transfer_status']) ? $row['transfer_status'] : ''),
|
||||
'packageInfo' => (string)(isset($row['package_info']) ? $row['package_info'] : ''),
|
||||
'failReason' => (string)(isset($row['fail_reason']) ? $row['fail_reason'] : ''),
|
||||
'failReason' => WithdrawText::fail(isset($row['fail_reason']) ? $row['fail_reason'] : ''),
|
||||
'createdAt' => $this->iso($row['createtime']),
|
||||
'transferMchId' => $mchId,
|
||||
'transferAppId' => $appId,
|
||||
@@ -413,12 +414,12 @@ class Distribution extends V1
|
||||
'amount' => round((float)$row['amount'], 2),
|
||||
'channel' => (string)$row['channel'],
|
||||
'status' => (string)$row['status'],
|
||||
'reason' => (string)$row['reason'],
|
||||
'reason' => WithdrawText::reason($row['reason']),
|
||||
'outBillNo' => (string)$row['out_bill_no'],
|
||||
'transferStatus' => (string)$row['transfer_status'],
|
||||
'transferId' => (string)$row['transfer_id'],
|
||||
'packageInfo' => (string)$row['package_info'],
|
||||
'failReason' => (string)$row['fail_reason'],
|
||||
'failReason' => WithdrawText::fail($row['fail_reason']),
|
||||
'createdAt' => $this->iso($row['createtime']),
|
||||
'payTime' => !empty($row['paytime']) ? $this->iso($row['paytime']) : '',
|
||||
'transferTime' => !empty($row['transfer_time']) ? $this->iso($row['transfer_time']) : '',
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
/**
|
||||
* 提现文案翻译
|
||||
*
|
||||
* 微信商家转账会把失败/撤销以「错误码」形式返回(如 MCH_CANCEL、NOT_ENOUGH),
|
||||
* 早期驳回原因也存在数字编码,这些标识对用户不可读。
|
||||
* 此处统一把码值翻译为中文,数据库仍保留原始码值以便排查。
|
||||
*/
|
||||
class WithdrawText
|
||||
{
|
||||
/** 微信转账失败/撤销错误码 → 中文说明 */
|
||||
protected static $failMap = [
|
||||
'NOT_ENOUGH' => '商户转账账户余额不足',
|
||||
'ACCOUNT_ERROR' => '收款账户状态异常',
|
||||
'V2_ACCOUNT_SIMPLE_BAN' => '收款账户被限制收款',
|
||||
'V3_ACCOUNT_NOT_EXIST' => '收款微信账户不存在',
|
||||
'NAME_NOT_MATCH' => '收款人姓名与微信实名不一致',
|
||||
'USER_NAME_NOT_MATCH' => '收款人姓名与微信实名不一致',
|
||||
'REAL_NAME_CHECK_FAIL' => '收款人微信实名核验未通过',
|
||||
'INVALID_OPENID' => '收款人微信标识无效',
|
||||
'OPENID_ERROR' => '收款人微信标识异常',
|
||||
'AMOUNT_EXCEED' => '超出单笔转账限额',
|
||||
'DAILY_LIMIT_EXCEED' => '超出当日转账限额',
|
||||
'MCH_CANCEL' => '商户主动撤销转账',
|
||||
'MCH_REVOKE' => '商户主动撤销转账',
|
||||
'TRANSFER_FAILED' => '微信转账未成功',
|
||||
'FAIL' => '微信转账未成功',
|
||||
'CANCEL' => '转账已撤销',
|
||||
'CANCELLED' => '转账已撤销',
|
||||
'PARAM_ERROR' => '转账参数有误,请联系客服',
|
||||
'SYSTEM_ERROR' => '微信系统繁忙,请稍后重试',
|
||||
'FREQUENCY_LIMITED' => '操作过于频繁,请稍后重试',
|
||||
'RULE_LIMIT' => '触发微信风控限制',
|
||||
'ACCOUNT_FROZEN' => '收款账户已被冻结',
|
||||
'NO_AUTH' => '商户无转账接口权限',
|
||||
'APPID_MCHID_NOT_MATCH' => '小程序与商户号不匹配',
|
||||
'SIGN_ERROR' => '商户签名错误',
|
||||
'IP_NOT_ALLOWED' => '服务器IP未加入微信白名单',
|
||||
'IP_FORBIDDEN' => '服务器IP未加入微信白名单',
|
||||
];
|
||||
|
||||
/** 未识别码值的兜底文案 */
|
||||
const FAIL_FALLBACK = '微信转账未成功,请稍后重试或联系客服';
|
||||
const REASON_FALLBACK = '审核未通过,请联系客服了解详情';
|
||||
|
||||
/**
|
||||
* 转账失败原因翻译
|
||||
*
|
||||
* @param string $raw 数据库原始 fail_reason
|
||||
* @return string 可读中文
|
||||
*/
|
||||
public static function fail($raw)
|
||||
{
|
||||
$text = trim((string)$raw);
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 去掉「微信转账失败:」这类前缀,只留原因本体
|
||||
$text = preg_replace('/^微信转账(失败|撤销)[::]\s*/u', '', $text);
|
||||
$text = trim((string)$text);
|
||||
|
||||
$code = strtoupper($text);
|
||||
if (isset(self::$failMap[$code])) {
|
||||
return self::$failMap[$code];
|
||||
}
|
||||
|
||||
// 纯码值(如 V3_XXX / ERR_123):翻译不出就兜底,不把码抛给用户
|
||||
if (preg_match('/^[A-Z0-9_\-\.\/]{2,60}$/i', $text)) {
|
||||
return self::FAIL_FALLBACK;
|
||||
}
|
||||
|
||||
// 已是中文(微信返回的描述)则直接展示
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回原因翻译
|
||||
*
|
||||
* @param string $raw 数据库原始 reason
|
||||
* @return string 可读中文
|
||||
*/
|
||||
public static function reason($raw)
|
||||
{
|
||||
$text = trim((string)$raw);
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 数字编码或纯码值(早期数据)→ 兜底文案
|
||||
if (preg_match('/^[0-9]+$/', $text) || preg_match('/^[A-Z0-9_\-\.\/]{2,60}$/i', $text)) {
|
||||
return self::REASON_FALLBACK;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,70 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'backend/format'], fu
|
||||
'</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信转账失败/撤销错误码 → 中文说明
|
||||
* 与 application/common/library/WithdrawText.php 保持同一份字典
|
||||
*/
|
||||
var FAIL_TEXT = {
|
||||
NOT_ENOUGH: '商户转账账户余额不足',
|
||||
ACCOUNT_ERROR: '收款账户状态异常',
|
||||
V2_ACCOUNT_SIMPLE_BAN: '收款账户被限制收款',
|
||||
V3_ACCOUNT_NOT_EXIST: '收款微信账户不存在',
|
||||
NAME_NOT_MATCH: '收款人姓名与微信实名不一致',
|
||||
USER_NAME_NOT_MATCH: '收款人姓名与微信实名不一致',
|
||||
REAL_NAME_CHECK_FAIL: '收款人微信实名核验未通过',
|
||||
INVALID_OPENID: '收款人微信标识无效',
|
||||
OPENID_ERROR: '收款人微信标识异常',
|
||||
AMOUNT_EXCEED: '超出单笔转账限额',
|
||||
DAILY_LIMIT_EXCEED: '超出当日转账限额',
|
||||
MCH_CANCEL: '商户主动撤销转账',
|
||||
MCH_REVOKE: '商户主动撤销转账',
|
||||
TRANSFER_FAILED: '微信转账未成功',
|
||||
FAIL: '微信转账未成功',
|
||||
CANCEL: '转账已撤销',
|
||||
CANCELLED: '转账已撤销',
|
||||
PARAM_ERROR: '转账参数有误,请联系客服',
|
||||
SYSTEM_ERROR: '微信系统繁忙,请稍后重试',
|
||||
FREQUENCY_LIMITED: '操作过于频繁,请稍后重试',
|
||||
RULE_LIMIT: '触发微信风控限制',
|
||||
ACCOUNT_FROZEN: '收款账户已被冻结',
|
||||
NO_AUTH: '商户无转账接口权限',
|
||||
APPID_MCHID_NOT_MATCH: '小程序与商户号不匹配',
|
||||
SIGN_ERROR: '商户签名错误',
|
||||
IP_NOT_ALLOWED: '服务器IP未加入微信白名单',
|
||||
IP_FORBIDDEN: '服务器IP未加入微信白名单'
|
||||
};
|
||||
var FAIL_FALLBACK = '微信转账未成功,请稍后重试或联系客服';
|
||||
var REASON_FALLBACK = '审核未通过,请联系客服了解详情';
|
||||
|
||||
/**
|
||||
* 失败原因码值转中文
|
||||
*
|
||||
* @param {string} raw 数据库原始 fail_reason
|
||||
* @return {string} 可读中文
|
||||
*/
|
||||
function failText(raw) {
|
||||
var text = $.trim(raw || '');
|
||||
if (!text) return '';
|
||||
text = $.trim(text.replace(/^微信转账(失败|撤销)[::]\s*/, ''));
|
||||
if (FAIL_TEXT[text.toUpperCase()]) return FAIL_TEXT[text.toUpperCase()];
|
||||
if (/^[A-Z0-9_\-.\/]{2,60}$/i.test(text)) return FAIL_FALLBACK;
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回原因码值转中文
|
||||
*
|
||||
* @param {string} raw 数据库原始 reason
|
||||
* @return {string} 可读中文
|
||||
*/
|
||||
function reasonText(raw) {
|
||||
var text = $.trim(raw || '');
|
||||
if (!text) return '';
|
||||
if (/^[0-9]+$/.test(text) || /^[A-Z0-9_\-.\/]{2,60}$/i.test(text)) return REASON_FALLBACK;
|
||||
return text;
|
||||
}
|
||||
|
||||
var Controller = {
|
||||
/**
|
||||
* 提现列表页初始化
|
||||
@@ -115,10 +179,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'backend/format'], fu
|
||||
return value && m[value] ? m[value] : (value || '-');
|
||||
}
|
||||
},
|
||||
{field: 'reason', title: '拒绝原因', operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
|
||||
{field: 'reason', title: '拒绝原因', operate: 'LIKE', table: table, class: 'autocontent', formatter: function (value) {
|
||||
return reasonText(value) || '-';
|
||||
}},
|
||||
{field: 'fail_reason', title: '转账失败原因', operate: 'LIKE', table: table, class: 'autocontent', formatter: function (value) {
|
||||
if (!value) return '-';
|
||||
return '<span class="text-danger" title="' + value + '">' + value + '</span>';
|
||||
var text = failText(value);
|
||||
if (!text) return '-';
|
||||
return '<span class="text-danger">' + text + '</span>';
|
||||
}},
|
||||
{field: 'paytime', title: __('Paytime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
|
||||
|
||||
在新工单中引用
屏蔽一个用户