fix(withdraw): 修复提现台账导出PHP8兼容性与页面崩溃问题,统一大余额与导出体验

这个提交包含在:
chen
2026-09-21 15:11:58 +08:00
父节点 3bd0954df1
当前提交 dbd0ac5e02
共有 21 个文件被更改,包括 255 次插入 和 165 次删除

查看文件

@@ -188,7 +188,9 @@ class Export
'file_name' => $save_file
];
ob_end_clean();
if (ob_get_level() > 0) {
@ob_end_clean();
}
header('pragma:public');
header("Content-type:application/octet-stream; charset=utf-8; name=" . urlencode($save_file));
header("Content-Disposition:attachment; filename=" . urlencode($save_file)); //attachment新窗口打印inline本窗口打印
@@ -199,6 +201,13 @@ class Export
$writer = new $class_name($spreadsheet);
$writer->save($save_file);
if ($this->config['save_type'] != 'save') {
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
exit;
}
return $result;
// 修改为原始内存限制,会影响文件下载,暂时不修改回原来内存

查看文件

@@ -75,7 +75,7 @@ class Withdraw
$withdrawInfo = $this->getAccountInfo($type, $params);
$withdrawInfo['wallet_type'] = $walletType;
if ($walletType === 'money') {
$withdrawInfo['提现资产'] = '商城余额';
$withdrawInfo['提现资产'] = '钱包余额';
} elseif ($walletType === 'commission') {
$withdrawInfo['提现资产'] = '佣金钱包';
}
@@ -102,7 +102,7 @@ class Withdraw
'charge_rate' => $withdraw->charge_rate,
'wallet_type' => 'money',
], '申请提现扣除余额');
$this->handleLog($withdraw, '用户发起商城余额提现申请', $this->user);
$this->handleLog($withdraw, '用户发起钱包余额提现申请', $this->user);
} else {
WalletService::change($this->user, 'commission', -$money, 'withdraw', [
'withdraw_id' => $withdraw->id,
@@ -419,7 +419,7 @@ class Withdraw
|| (isset($info['提现资产']) && strcasecmp($info['提现资产'], 'dmepa') === 0);
$isMoney = (isset($info['wallet_type']) && $info['wallet_type'] === 'money')
|| (isset($info['提现资产']) && $info['提现资产'] === '商城余额');
|| (isset($info['提现资产']) && in_array($info['提现资产'], ['钱包余额', '商城余额'], true));
if ($isMadow) {
$madowRefund = $info['madow_amount'] ?? ($info['扣除DMEPA'] ?? ($info['扣除dmepa'] ?? 0));
@@ -464,7 +464,7 @@ class Withdraw
return $this->handleLog($withdraw, '拒绝:' . $refuse_msg . ',已退还提现佣金');
} else {
// 方案 B 一体化内扣:常规提现默认退回商城可用余额本金
// 方案 B 一体化内扣:常规提现默认退回钱包可用余额本金
WalletService::change($this->user, 'money', $withdraw->amount, 'withdraw_error', [
'withdraw_id' => $withdraw->id,
'amount' => $withdraw->amount,
@@ -473,7 +473,7 @@ class Withdraw
'wallet_type' => 'money',
], '提现驳回退还余额');
return $this->handleLog($withdraw, '拒绝:' . $refuse_msg . ',已退还提现商城余额');
return $this->handleLog($withdraw, '拒绝:' . $refuse_msg . ',已退还提现钱包余额');
}
}
@@ -500,7 +500,7 @@ class Withdraw
|| (isset($info['提现资产']) && strcasecmp($info['提现资产'], 'dmepa') === 0);
$isMoney = (isset($info['wallet_type']) && $info['wallet_type'] === 'money')
|| (isset($info['提现资产']) && $info['提现资产'] === '商城余额');
|| (isset($info['提现资产']) && in_array($info['提现资产'], ['钱包余额', '商城余额'], true));
if ($isMadow) {
$madowRefund = $info['madow_amount'] ?? ($info['扣除DMEPA'] ?? ($info['扣除dmepa'] ?? 0));
@@ -545,7 +545,7 @@ class Withdraw
return $this->handleLog($withdraw, '提现失败,已退还提现佣金:' . $refuse_msg);
} else {
// 方案 B 一体化内扣:常规提现默认退回商城可用余额本金
// 方案 B 一体化内扣:常规提现默认退回钱包可用余额本金
WalletService::change($this->user, 'money', $withdraw->amount, 'withdraw_error', [
'withdraw_id' => $withdraw->id,
'amount' => $withdraw->amount,
@@ -554,7 +554,7 @@ class Withdraw
'wallet_type' => 'money',
], '提现失败退还余额');
return $this->handleLog($withdraw, '提现失败,已退还提现商城余额:' . $refuse_msg);
return $this->handleLog($withdraw, '提现失败,已退还提现钱包余额:' . $refuse_msg);
}
}
@@ -778,7 +778,7 @@ class Withdraw
if ($walletType === 'money') {
if (bccomp((string)($this->user->money ?? 0), (string)$money, 2) < 0) {
throw new ShoproException('商城可用余额不足');
throw new ShoproException('钱包可用余额不足');
}
} else {
if (bccomp((string)($this->user->commission ?? 0), (string)$money, 2) < 0) {

查看文件

@@ -7,7 +7,7 @@ use app\admin\model\shopro\user\User as UserModel;
use addons\shopro\service\Wallet;
/**
* 历史收益全量结转至商城余额服务
* 历史收益全量结转至钱包余额服务
*/
class WalletMigrationService
{
@@ -94,14 +94,14 @@ class WalletMigrationService
// 1. 扣减佣金钱包
Wallet::change($user, 'commission', -$amount, 'transfer_to_money', [
'batch_migration' => 1,
'reason' => '全量历史收益结转至商城余额',
], '收益结转至商城余额');
'reason' => '全量历史收益结转至钱包余额',
], '收益结转至钱包余额');
// 2. 增加商城余额
// 2. 增加钱包余额
Wallet::change($user, 'money', $amount, 'transfer_by_commission', [
'batch_migration' => 1,
'reason' => '全量历史收益结转至商城余额',
], '收益结转至商城余额');
'reason' => '全量历史收益结转至钱包余额',
], '收益结转至钱包余额');
return $amount;
});

查看文件

@@ -72,112 +72,109 @@ class Withdraw extends Common
'updatetime' => '操作时间',
];
$total = $this->model->sheepFilter()->count();
if ($total <= 0) {
$this->error('导出数据为空');
try {
$total = (new WithdrawModel)->sheepFilter()->count();
if ($total <= 0) {
$this->error('导出数据为空');
}
$export = new \addons\shopro\library\Export();
$params = [
'file_name' => '提现管理台账',
'cell_titles' => $cellTitles,
'total' => $total,
'is_sub_cell' => false,
];
$totalAmount = 0;
$totalPaidFee = 0;
$totalChargeFee = 0;
$result = $export->export($params, function ($pages) use (&$totalAmount, &$totalPaidFee, &$totalChargeFee, $total) {
$datas = (new WithdrawModel)->sheepFilter()->with(['user'])
->limit((($pages['page'] - 1) * $pages['list_rows']), $pages['list_rows'])
->select();
$newDatas = [];
foreach ($datas as $withdraw) {
$user = $withdraw['user'] ?? null;
$displayInfo = $withdraw['withdraw_info_display'] ?? ($withdraw['withdraw_info'] ?? []);
// 收款账户信息
$payeeName = $displayInfo['真实姓名'] ?? ($displayInfo['姓名'] ?? ($displayInfo['微信用户'] ?? ''));
$bankName = $displayInfo['开户行'] ?? ($displayInfo['开户银行'] ?? '');
$cardNo = $displayInfo['银行卡号'] ?? ($displayInfo['卡号'] ?? ($displayInfo['支付宝账户'] ?? ($displayInfo['支付宝账号'] ?? ($displayInfo['微信ID'] ?? ''))));
if ($cardNo !== '') {
$cardNo = "\t" . $cardNo;
}
// 提现资产类型
$assetType = !empty($withdraw['is_madow_withdraw']) ? 'DMEPA' : (!empty($withdraw['is_money_withdraw']) ? '钱包余额' : ($displayInfo['提现资产'] ?? '钱包余额'));
// 资产折算明细
$assetDetailParts = [];
if (!empty($displayInfo['扣除DMEPA'])) {
$assetDetailParts[] = '扣除: ' . $displayInfo['扣除DMEPA'];
}
if (!empty($displayInfo['市值汇率'])) {
$assetDetailParts[] = $displayInfo['市值汇率'];
}
if (!empty($displayInfo['换算市值'])) {
$assetDetailParts[] = '市值: ' . $displayInfo['换算市值'];
}
$assetDetail = implode('; ', $assetDetailParts);
$amount = floatval($withdraw['amount'] ?? 0);
$paidFee = floatval($withdraw['paid_fee'] ?? 0) > 0 ? floatval($withdraw['paid_fee']) : floatval($withdraw['real_amount'] ?? $amount);
$chargeFee = floatval($withdraw['charge_fee'] ?? 0);
$totalAmount = function_exists('bcadd') ? bcadd((string)$totalAmount, (string)$amount, 2) : ($totalAmount + $amount);
$totalPaidFee = function_exists('bcadd') ? bcadd((string)$totalPaidFee, (string)$paidFee, 2) : ($totalPaidFee + $paidFee);
$totalChargeFee = function_exists('bcadd') ? bcadd((string)$totalChargeFee, (string)$chargeFee, 2) : ($totalChargeFee + $chargeFee);
$createTime = is_numeric($withdraw['createtime'] ?? null) && intval($withdraw['createtime']) > 0
? date('Y-m-d H:i:s', intval($withdraw['createtime']))
: ($withdraw['createtime'] ?: '-');
$updateTime = is_numeric($withdraw['updatetime'] ?? null) && intval($withdraw['updatetime']) > 0
? date('Y-m-d H:i:s', intval($withdraw['updatetime']))
: ($withdraw['updatetime'] ?: '-');
$newDatas[] = [
'id' => $withdraw['id'],
'withdraw_sn' => "\t" . (string)($withdraw['withdraw_sn'] ?? ''),
'user_nickname' => $user['nickname'] ?? ('用户 ' . $withdraw['user_id']),
'user_mobile' => "\t" . (string)($user['mobile'] ?? ''),
'asset_type' => $assetType,
'amount' => number_format($amount, 2, '.', ''),
'paid_fee' => number_format($paidFee, 2, '.', ''),
'charge_rate_format' => $withdraw['charge_rate_format'] ?? '0.0%',
'charge_fee' => number_format($chargeFee, 2, '.', ''),
'withdraw_type_text' => $withdraw['withdraw_type_text'] ?? '-',
'payee_name' => $payeeName ?: '-',
'bank_name' => $bankName ?: '-',
'card_no' => $cardNo ?: '-',
'asset_detail' => $assetDetail ?: '-',
'status_text' => $withdraw['status_text'] ?? '-',
'createtime' => $createTime,
'updatetime' => $updateTime,
];
}
if ($pages['is_last_page']) {
$newDatas[] = [
'id' => '合计: 共 ' . $total . ' 条记录;提现总额:¥' . number_format((float)$totalAmount, 2, '.', '') . ';实际到账总额:¥' . number_format((float)$totalPaidFee, 2, '.', '') . ';手续费总额:¥' . number_format((float)$totalChargeFee, 2, '.', '')
];
}
return $newDatas;
});
$this->success('导出成功' . (isset($result['file_path']) && $result['file_path'] ? ',请在服务器: “' . $result['file_path'] . '” 查看' : ''), null, $result);
} catch (HttpResponseException $e) {
throw $e;
} catch (\Throwable $e) {
$this->error('导出处理失败: ' . $e->getMessage());
}
$export = new \addons\shopro\library\Export();
$params = [
'file_name' => '提现管理台账',
'cell_titles' => $cellTitles,
'total' => $total,
'is_sub_cell' => false,
];
$totalAmount = 0;
$totalPaidFee = 0;
$totalChargeFee = 0;
$result = $export->export($params, function ($pages) use (&$totalAmount, &$totalPaidFee, &$totalChargeFee, $total) {
$datas = $this->model->sheepFilter()->with(['user'])
->limit((($pages['page'] - 1) * $pages['list_rows']), $pages['list_rows'])
->select();
$newDatas = [];
foreach ($datas as $withdraw) {
$user = $withdraw['user'] ?? null;
$displayInfo = $withdraw['withdraw_info_display'] ?? ($withdraw['withdraw_info'] ?? []);
// 收款账户信息
$payeeName = $displayInfo['真实姓名'] ?? ($displayInfo['姓名'] ?? ($displayInfo['微信用户'] ?? ''));
$bankName = $displayInfo['开户行'] ?? ($displayInfo['开户银行'] ?? '');
$cardNo = $displayInfo['银行卡号'] ?? ($displayInfo['卡号'] ?? ($displayInfo['支付宝账户'] ?? ($displayInfo['支付宝账号'] ?? ($displayInfo['微信ID'] ?? ''))));
if ($cardNo !== '') {
$cardNo = "\t" . $cardNo;
}
// 提现资产类型
$assetType = $withdraw['is_madow_withdraw'] ? 'DMEPA' : ($withdraw['is_money_withdraw'] ? '商城余额' : ($displayInfo['提现资产'] ?? '商城余额'));
// 资产折算明细
$assetDetailParts = [];
if (!empty($displayInfo['扣除DMEPA'])) {
$assetDetailParts[] = '扣除: ' . $displayInfo['扣除DMEPA'];
}
if (!empty($displayInfo['市值汇率'])) {
$assetDetailParts[] = $displayInfo['市值汇率'];
}
if (!empty($displayInfo['换算市值'])) {
$assetDetailParts[] = '市值: ' . $displayInfo['换算市值'];
}
$assetDetail = implode('; ', $assetDetailParts);
$amount = floatval($withdraw['amount'] ?? 0);
$paidFee = floatval($withdraw['paid_fee'] ?? 0) > 0 ? floatval($withdraw['paid_fee']) : floatval($withdraw['real_amount'] ?? $amount);
$chargeFee = floatval($withdraw['charge_fee'] ?? 0);
$totalAmount = function_exists('bcadd') ? bcadd((string)$totalAmount, (string)$amount, 2) : ($totalAmount + $amount);
$totalPaidFee = function_exists('bcadd') ? bcadd((string)$totalPaidFee, (string)$paidFee, 2) : ($totalPaidFee + $paidFee);
$totalChargeFee = function_exists('bcadd') ? bcadd((string)$totalChargeFee, (string)$chargeFee, 2) : ($totalChargeFee + $chargeFee);
$newDatas[] = [
'id' => $withdraw['id'],
'withdraw_sn' => "\t" . (string)($withdraw['withdraw_sn'] ?? ''),
'user_nickname' => $user['nickname'] ?? ('用户 ' . $withdraw['user_id']),
'user_mobile' => "\t" . (string)($user['mobile'] ?? ''),
'asset_type' => $assetType,
'amount' => number_format($amount, 2, '.', ''),
'paid_fee' => number_format($paidFee, 2, '.', ''),
'charge_rate_format' => $withdraw['charge_rate_format'] ?? '0.0%',
'charge_fee' => number_format($chargeFee, 2, '.', ''),
'withdraw_type_text' => $withdraw['withdraw_type_text'] ?? '-',
'payee_name' => $payeeName ?: '-',
'bank_name' => $bankName ?: '-',
'card_no' => $cardNo ?: '-',
'asset_detail' => $assetDetail ?: '-',
'status_text' => $withdraw['status_text'] ?? '-',
'createtime' => $withdraw['createtime'] ?? '-',
'updatetime' => $withdraw['updatetime'] ?? '-',
];
}
if ($pages['is_last_page']) {
$newDatas[] = [
'id' => '合计: 共 ' . $total . ' 条记录',
'withdraw_sn' => '',
'user_nickname' => '',
'user_mobile' => '',
'asset_type' => '',
'amount' => number_format((float)$totalAmount, 2, '.', ''),
'paid_fee' => number_format((float)$totalPaidFee, 2, '.', ''),
'charge_rate_format' => '',
'charge_fee' => number_format((float)$totalChargeFee, 2, '.', ''),
'withdraw_type_text' => '',
'payee_name' => '',
'bank_name' => '',
'card_no' => '',
'asset_detail' => '',
'status_text' => '',
'createtime' => '',
'updatetime' => '',
];
}
return $newDatas;
});
return $result;
}

查看文件

@@ -275,7 +275,7 @@ class Order extends Common
'formula' => (string) ($row->formula ?? ''),
'skip_reason_text' => (string) ($row->skip_reason_text ?? ''),
'wallet_type' => (string) ($row->wallet_type ?? ($amount > 0 ? \addons\shopro\service\partner\PartnerConfig::rewardWalletType() : 'system')),
'wallet_type_text' => (string) ($row->wallet_type_text ?: ($amount > 0 ? (\addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '商城余额' : '佣金钱包') : '平台留存')),
'wallet_type_text' => (string) ($row->wallet_type_text ?: ($amount > 0 ? (\addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '钱包余额' : '佣金钱包') : '平台留存')),
];
}
@@ -385,7 +385,7 @@ class Order extends Common
'unit' => '元',
'order_contrib' => $venueRuleContrib,
'wallet_type' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType(),
'wallet_type_text' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '商城余额' : '佣金钱包',
'wallet_type_text' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '钱包余额' : '佣金钱包',
'settled_key' => 'venue_settled',
'default_user_count' => $activeVenueCount,
],
@@ -396,7 +396,7 @@ class Order extends Common
'unit' => '元',
'order_contrib' => $countyRuleContrib,
'wallet_type' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType(),
'wallet_type_text' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '商城余额' : '佣金钱包',
'wallet_type_text' => \addons\shopro\service\partner\PartnerConfig::rewardWalletType() === 'money' ? '钱包余额' : '佣金钱包',
'settled_key' => 'county_settled',
'default_user_count' => $activeCountyCount,
],
@@ -586,7 +586,7 @@ class Order extends Common
return [
'items' => $items,
'total_cash' => number_format($totalInstantCash, 2, '.', ''), // 直入商城余额的即时现金
'total_cash' => number_format($totalInstantCash, 2, '.', ''), // 直入钱包余额的即时现金
'total_instant_cash' => number_format($totalInstantCash, 2, '.', ''),
'total_share_cash' => number_format($totalShareCash, 2, '.', ''),
'total_all_cash' => number_format($totalAllCash, 2, '.', ''),

查看文件

@@ -84,7 +84,7 @@ class Reward extends Common
'reward_type_text' => $reward['reward_type_text'],
'role_text' => $reward['role_text'] ?? $reward['role'],
'amount' => $reward['amount'],
'wallet_type_text' => $reward['wallet_type_text'] ?? '商城余额',
'wallet_type_text' => $reward['wallet_type_text'] ?? '钱包余额',
'madow' => \addons\shopro\service\partner\IdentityService::formatMadow($reward['madow']),
'base_amount' => $reward['base_amount'],
'status_text' => $reward['status_text'],
@@ -282,7 +282,7 @@ class Reward extends Common
}
/**
* 执行全量结转收益至商城余额
* 执行全量结转收益至钱包余额
*/
public function transferAllCommission()
{

查看文件

@@ -89,9 +89,10 @@ class Withdraw extends Common
public function getChargeRateFormatAttr($value, $data)
{
$value = $value ?: ($data['charge_rate'] ?? null);
$rate = $value !== null && $value !== '' ? $value : ($data['charge_rate'] ?? 0);
$rate = is_numeric($rate) ? (string)$rate : '0';
return bcmul((string)$value, '100', 1) . '%';
return function_exists('bcmul') ? (bcmul($rate, '100', 1) . '%') : (round(floatval($rate) * 100, 1) . '%');
}
public function getIsMadowWithdrawAttr($value, $data)
@@ -117,14 +118,16 @@ class Withdraw extends Common
return false;
}
return (isset($info['wallet_type']) && $info['wallet_type'] === 'money')
|| (isset($info['提现资产']) && $info['提现资产'] === '商城余额');
|| (isset($info['提现资产']) && in_array($info['提现资产'], ['钱包余额', '商城余额'], true));
}
public function getRealAmountAttr($value, $data)
{
$amount = $data['amount'] ?? ($this->amount ?? 0);
$chargeFee = $data['charge_fee'] ?? ($this->charge_fee ?? 0);
$real = bcsub((string)$amount, (string)$chargeFee, 2);
$amount = isset($data['amount']) && is_numeric($data['amount']) ? (string)$data['amount'] : (string)($this->amount ?? '0');
$chargeFee = isset($data['charge_fee']) && is_numeric($data['charge_fee']) ? (string)$data['charge_fee'] : (string)($this->charge_fee ?? '0');
$amount = is_numeric($amount) ? $amount : '0';
$chargeFee = is_numeric($chargeFee) ? $chargeFee : '0';
$real = function_exists('bcsub') ? bcsub($amount, $chargeFee, 2) : number_format(floatval($amount) - floatval($chargeFee), 2, '.', '');
return max(0, floatval($real));
}
@@ -142,7 +145,7 @@ class Withdraw extends Common
$isMadow = (isset($info['wallet_type']) && $info['wallet_type'] === 'madow')
|| (isset($info['提现资产']) && strcasecmp($info['提现资产'], 'dmepa') === 0);
$isMoney = (isset($info['wallet_type']) && $info['wallet_type'] === 'money')
|| (isset($info['提现资产']) && $info['提现资产'] === '商城余额');
|| (isset($info['提现资产']) && in_array($info['提现资产'], ['钱包余额', '商城余额'], true));
if ($isMadow) {
$display['提现资产'] = 'DMEPA';
@@ -177,18 +180,23 @@ class Withdraw extends Common
// 手续费与预计到账
$chargeFee = $data['charge_fee'] ?? ($this->charge_fee ?? ($info['charge_fee'] ?? 0));
$chargeRate = $data['charge_rate'] ?? ($this->charge_rate ?? ($info['charge_rate'] ?? 0));
$chargeFee = is_numeric($chargeFee) ? (string)$chargeFee : '0';
$chargeRate = is_numeric($chargeRate) ? (string)$chargeRate : '0';
if (floatval($chargeFee) > 0 || floatval($chargeRate) > 0) {
$ratePercent = bcmul((string)$chargeRate, '100', 1);
$ratePercent = function_exists('bcmul') ? bcmul($chargeRate, '100', 1) : round(floatval($chargeRate) * 100, 1);
$display['提现手续费'] = number_format(floatval($chargeFee), 2, '.', '') . ' 元 (' . $ratePercent . '%)';
}
$amount = $data['amount'] ?? ($this->amount ?? 0);
$real = bcsub((string)$amount, (string)$chargeFee, 2);
$amount = is_numeric($amount) ? (string)$amount : '0';
$real = function_exists('bcsub') ? bcsub($amount, $chargeFee, 2) : number_format(floatval($amount) - floatval($chargeFee), 2, '.', '');
$display['预计到账'] = number_format(max(0, floatval($real)), 2, '.', '') . ' 元';
} elseif ($isMoney) {
$display['提现资产'] = '商城余额';
$display['提现资产'] = '钱包余额';
$amount = $data['amount'] ?? ($this->amount ?? 0);
$chargeFee = $data['charge_fee'] ?? ($this->charge_fee ?? 0);
$real = bcsub((string)$amount, (string)$chargeFee, 2);
$amount = is_numeric($amount) ? (string)$amount : '0';
$chargeFee = is_numeric($chargeFee) ? (string)$chargeFee : '0';
$real = function_exists('bcsub') ? bcsub($amount, $chargeFee, 2) : number_format(floatval($amount) - floatval($chargeFee), 2, '.', '');
$display['预计到账'] = number_format(max(0, floatval($real)), 2, '.', '') . ' 元';
}

查看文件

@@ -119,13 +119,13 @@ class Reward extends Common
{
$type = $this->getWalletTypeAttr(null, $data);
$map = [
'money' => '商城余额',
'money' => '钱包余额',
'commission' => '佣金钱包',
'voucher' => '消费补贴券',
'madow' => '分红dmepa',
'system' => '平台留存',
];
return $map[$type] ?? '商城余额';
return $map[$type] ?? '钱包余额';
}
public function buyer()

查看文件

@@ -385,7 +385,7 @@
{{ state.data.total_income || state.data.income_total_cash || '0.00' }}
</span>
<span class="ml-1" style="font-size: 12px; color: var(--sa-subfont);">元</span>
<el-tag size="small" type="success" style="margin-left: 8px;">直入商城余额</el-tag>
<el-tag size="small" type="success" style="margin-left: 8px;">直入钱包余额</el-tag>
</el-form-item>
<el-form-item>
<el-button type="primary" link
@@ -626,7 +626,7 @@
</div>
</el-col>
<el-col class="item" :xs="12" :sm="6" :md="6" :lg="6" :xl="6">
<div class="left">商城可用余额:</div>
<div class="left">钱包可用余额:</div>
<div class="right" style="color: #67c23a;">
{{ state.data.user?.money || state.data.user_money || '0.00' }}
<span class="unit">元</span>

查看文件

@@ -6,7 +6,7 @@
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">历史佣金</div>
<el-tag size="small" type="info" style="margin-left: 10px;">注:当前收益分成已全额直入商城余额,历史未转佣金可批量转入余额</el-tag>
<el-tag size="small" type="info" style="margin-left: 10px;">注:当前收益分成已全额直入钱包余额,历史未转佣金可批量转入余额</el-tag>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>

查看文件

@@ -887,7 +887,7 @@
<div v-if="state.detail.partner_split" style="font-size:13px;font-weight:400;color:var(--sa-subfont)">
<span v-if="Number(state.detail.partner_split.total_instant_cash || state.detail.partner_split.total_cash) > 0" style="margin-right: 14px;">
即时现金分成 <strong style="color:#ff4d4f;font-size:14px">¥{{ state.detail.partner_split.total_instant_cash || state.detail.partner_split.total_cash }}</strong>
<el-tag size="small" type="success" style="margin-left: 6px;">直入商城余额</el-tag>
<el-tag size="small" type="success" style="margin-left: 6px;">直入钱包余额</el-tag>
</span>
<span v-if="Number(state.detail.partner_split.total_share_cash) > 0" style="margin-right: 14px;">
均分奖池现金贡献 <strong style="color:#409eff;font-size:14px">¥{{ state.detail.partner_split.total_share_cash }}</strong>
@@ -965,7 +965,7 @@
size="small"
:type="scope.row.wallet_type === 'money' ? 'success' : (scope.row.wallet_type === 'commission' ? 'warning' : (scope.row.wallet_type === 'madow' ? 'primary' : 'info'))"
>
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '商城余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '平台留存')) }}
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '钱包余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '平台留存')) }}
</el-tag>
</template>
</el-table-column>

查看文件

@@ -58,7 +58,7 @@
size="small"
:type="scope.row.wallet_type === 'money' ? 'success' : (scope.row.wallet_type === 'madow' ? 'primary' : (scope.row.wallet_type === 'commission' ? 'warning' : 'info'))"
>
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '商城余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '消费补贴')) }}
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '钱包余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '消费补贴')) }}
</el-tag>
</template>
</el-table-column>
@@ -177,7 +177,7 @@
size="small"
:type="scope.row.wallet_type === 'money' ? 'success' : (scope.row.wallet_type === 'madow' ? 'primary' : 'info')"
>
{{ scope.row.wallet_type_text || '商城余额' }}
{{ scope.row.wallet_type_text || '钱包余额' }}
</el-tag>
</template>
</el-table-column>

查看文件

@@ -426,7 +426,7 @@
¥{{ state.detail.total_income || state.detail.income_total_cash || '0.00' }}
</div>
<div class="asset-card-desc">
当前商城余额: ¥{{ state.detail.money || '0.00' }}
当前钱包余额: ¥{{ state.detail.money || '0.00' }}
</div>
<div class="asset-card-desc">
历史未转佣金: ¥{{ state.detail.commission || '0.00' }}
@@ -480,7 +480,7 @@
<el-col :xs="24" :sm="12" :md="6">
<div class="asset-card-box">
<div class="asset-card-label sa-flex sa-row-between" style="display: flex; justify-content: space-between; align-items: center;">
<span>商城余额 / 积分</span>
<span>钱包余额 / 积分</span>
{if $auth->check('shopro/user/user/recharge')}
<div>
<el-button type="primary" link size="small" @click="onRecharge('money')">充余额</el-button>
@@ -544,7 +544,7 @@
<el-table-column label="入账账户" min-width="110">
<template #default="scope">
<el-tag size="small" :type="scope.row.wallet_type === 'money' ? 'success' : (scope.row.wallet_type === 'madow' ? 'primary' : (scope.row.wallet_type === 'commission' ? 'warning' : 'info'))">
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '商城余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '消费补贴')) }}
{{ scope.row.wallet_type_text || (Number(scope.row.amount) > 0 ? '钱包余额' : (Number(scope.row.madow) > 0 ? '分红dmepa' : '消费补贴')) }}
</el-tag>
</template>
</el-table-column>
@@ -665,7 +665,7 @@
<el-table-column label="钱包类别" min-width="110" v-if="log.tabActive=='commission'">
<template #default="scope">
<el-tag size="small" :type="scope.row.type == 'money' ? 'success' : 'warning'">
{{ scope.row.type == 'money' ? '商城余额' : '佣金钱包' }}
{{ scope.row.type == 'money' ? '钱包余额' : '佣金钱包' }}
</el-tag>
</template>
</el-table-column>

查看文件

@@ -152,7 +152,7 @@
<el-table-column label="收益中心资产" min-width="190">
<template #default="scope">
<div><span class="asset-sub">累计收益:</span> <b style="color: #409eff;">¥{{ scope.row.total_income || scope.row.income_total_cash || '0.00' }}</b></div>
<div class="asset-sub">商城余额: ¥{{ scope.row.money || '0.00' }}</div>
<div class="asset-sub">钱包余额: ¥{{ scope.row.money || '0.00' }}</div>
<div class="asset-sub">未转佣金: ¥{{ scope.row.commission || '0.00' }}</div>
</template>
</el-table-column>

查看文件

@@ -22,7 +22,7 @@
<el-row :gutter="8">
<el-col :span="6">
<div style="background: #ffffff; padding: 8px 10px; border-radius: 6px; border: 1px solid #edf2f7; text-align: center;">
<div style="font-size: 11px; color: #64748b;">商城余额</div>
<div style="font-size: 11px; color: #64748b;">钱包余额</div>
<div style="font-size: 13px; font-weight: 600; color: #2563eb; margin-top: 2px;">¥{{ state.user.money || '0.00' }}</div>
</div>
</el-col>

查看文件

@@ -66,7 +66,7 @@
<template v-else-if="scope.row.is_money_withdraw">
<div class="sa-flex" style="margin-bottom: 2px;">
<el-tag size="small" type="success" effect="plain" style="border-radius: 4px; height: 20px; line-height: 20px; padding: 0 6px; font-weight: 500;">
商城余额
钱包余额
</el-tag>
</div>
<div class="sa-table-line-1" style="font-weight: 500;">

查看文件

@@ -147,8 +147,17 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
updatetime: 'range',
});
if (Config.save_type == 'download') {
window.location.href = `${Config.moduleurl}/shopro/withdraw/${type}?page=${pagination.page}&list_rows=${pagination.list_rows}&order=${state.order}&sort=${state.sort}&search=${search.search}`;
exportLoading.value = false;
const downloadUrl = `${Config.moduleurl}/shopro/withdraw/${type}?page=${pagination.page}&list_rows=${pagination.list_rows}&order=${state.order}&sort=${state.sort}&search=${encodeURIComponent(search.search || '')}`;
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = downloadUrl;
document.body.appendChild(iframe);
setTimeout(() => {
if (iframe && iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
exportLoading.value = false;
}, 3000);
} else {
Fast.api.ajax({
url: `shopro/withdraw/${type}`,

查看文件

@@ -0,0 +1,67 @@
/**
* 提现管理导出防崩溃与 PHP 8.0 兼容性回归测试
*/
const fs = require('fs');
const path = require('path');
const assert = require('assert');
console.log('========================================================');
console.log(' 开始执行提现台账导出防崩溃与全链路加固测试');
console.log('========================================================\n');
// 1. 测试模型层 PHP 8.0 bcmath 防崩溃模拟
function simulateChargeRateFormat(value, chargeRate) {
const rate = (value !== null && value !== undefined && value !== '') ? value : (chargeRate ?? 0);
const safeRate = (!isNaN(rate) && rate !== '' && rate !== null && rate !== undefined) ? String(rate) : '0';
return (Number(safeRate) * 100).toFixed(1) + '%';
}
function simulateRealAmount(amount, chargeFee) {
const safeAmount = (!isNaN(amount) && amount !== '' && amount !== null) ? Number(amount) : 0;
const safeFee = (!isNaN(chargeFee) && chargeFee !== '' && chargeFee !== null) ? Number(chargeFee) : 0;
return Math.max(0, safeAmount - safeFee);
}
// 模拟各种异常输入,确保不抛出错误
assert.strictEqual(simulateChargeRateFormat(null, null), '0.0%');
assert.strictEqual(simulateChargeRateFormat('', ''), '0.0%');
assert.strictEqual(simulateChargeRateFormat(0, 0), '0.0%');
assert.strictEqual(simulateChargeRateFormat(undefined, 0.06), '6.0%');
assert.strictEqual(simulateRealAmount(null, null), 0);
assert.strictEqual(simulateRealAmount('', ''), 0);
assert.strictEqual(simulateRealAmount(100, 6), 94);
assert.strictEqual(simulateRealAmount(10, 0.60), 9.4);
console.log('[测试点 1] 模型层 PHP 8.0 bcmath 边界参数容错模拟断言通过');
// 2. 检查 application/admin/model/shopro/Withdraw.php 包含加固逻辑
const modelContent = fs.readFileSync(path.resolve(__dirname, '../../application/admin/model/shopro/Withdraw.php'), 'utf8');
assert(modelContent.includes('is_numeric($rate)'), 'getChargeRateFormatAttr 包含 is_numeric 校验');
assert(modelContent.includes('is_numeric($amount)'), 'getRealAmountAttr 包含 is_numeric 校验');
console.log('[测试点 2] Withdraw 模型源代码加固断言通过');
// 3. 检查 addons/shopro/library/Export.php 包含缓冲检查与下载退出
const exportContent = fs.readFileSync(path.resolve(__dirname, '../../addons/shopro/library/Export.php'), 'utf8');
assert(exportContent.includes('ob_get_level() > 0'), 'Export.php 包含 ob_get_level() 检查防 Notice');
assert(exportContent.includes("if ($this->config['save_type'] != 'save')"), 'Export.php 包含下载模式检查');
assert(exportContent.includes('exit;'), 'Export.php 下载完成安全退出');
console.log('[测试点 3] Export.php 缓冲区安全清理与下载模式防污染退出断言通过');
// 4. 检查 application/admin/controller/shopro/Withdraw.php 包含异常捕获、单 key 汇总、时间格式化
const controllerContent = fs.readFileSync(path.resolve(__dirname, '../../application/admin/controller/shopro/Withdraw.php'), 'utf8');
assert(controllerContent.includes('catch (\\Throwable $e)'), 'Withdraw.php 包含 \\Throwable 全局异常捕获');
assert(controllerContent.includes("(new WithdrawModel)->sheepFilter()"), 'Withdraw.php 使用全新实例查询防状态污染');
assert(controllerContent.includes("date('Y-m-d H:i:s'"), 'Withdraw.php 包含时间戳转格式化日期');
assert(controllerContent.includes("'id' => '合计: 共 ' . $total"), 'Withdraw.php 汇总行符合 Export.php 单 key 自动合并规范');
console.log('[测试点 4] Withdraw.php 控制器异常保护与导出规范断言通过');
// 5. 检查 public/assets/js/backend/shopro/withdraw.js 采用隐藏 iframe 下载
const jsContent = fs.readFileSync(path.resolve(__dirname, '../../public/assets/js/backend/shopro/withdraw.js'), 'utf8');
assert(jsContent.includes("document.createElement('iframe')"), 'withdraw.js 使用隐藏 iframe 触发下载');
assert(jsContent.includes('encodeURIComponent(search.search'), 'withdraw.js 对 search 参数进行安全 URI 编码');
assert(!jsContent.includes('window.location.href = `${Config.moduleurl}/shopro/withdraw/${type}'), '已移除直接 window.location 避免后台页面被替换');
console.log('[测试点 5] withdraw.js 前端静默下载与主页面安全隔离断言通过');
console.log('\n========================================================');
console.log(' 所有提现导出防崩溃加固测试全部通过![100% OK]');
console.log('========================================================');

查看文件

@@ -39,12 +39,12 @@
<view class="grid-v-divider"></view>
<!-- 商城余额 -->
<!-- 钱包余额 -->
<view
class="bento-cell ss-flex-1 ss-flex-col ss-col-center metric-item"
@tap="sheep.$router.go('/pages/user/wallet/money')"
>
<view class="item-title">商城余额(元)</view>
<view class="item-title">钱包余额(元)</view>
<view class="item-detail text-dark">
{{ state.showMoney ? userInfo?.money || '0.00' : '***' }}
</view>

查看文件

@@ -21,7 +21,7 @@
<view class="num-title">可提现佣金(元)</view>
<view class="wallet-num">{{ userInfo.commission || '0.00' }}</view>
<view class="ss-m-t-10" style="font-size: 22rpx; color: rgba(255,255,255,0.85);">
商城可用余额:¥{{ userInfo.money || '0.00' }}
钱包可用余额:¥{{ userInfo.money || '0.00' }}
</view>
</view>
<view class="" v-else>
@@ -120,7 +120,7 @@
<view class="draw-notice">
<view class="title ss-m-b-20">提现说明</view>
<view class="tip-banner ss-m-b-20" v-if="state.walletType !== 'madow'" style="background: #fff8f2; color: #ff6000; font-size: 22rpx; padding: 16rpx 20rpx; border-radius: 12rpx; line-height: 1.5;">
💡 提示:提现金额须为100的整数倍(如100、200、1200等)。商城收益分成已全额直接入账商城余额,支持随时申请提现至银行卡/微信/支付宝,也可用于下单直接抵扣。历史存量佣金可转入商城余额消费。
💡 提示:提现金额须为100的整数倍(如100、200、1200等)。商城收益分成已全额直接入账钱包余额,支持随时申请提现至银行卡/微信/支付宝,也可用于下单直接抵扣。历史存量佣金可转入钱包余额消费。
</view>
<view class="tip-banner ss-m-b-20" v-else style="background: #fdfbf7; color: #b78328; font-size: 22rpx; padding: 16rpx 20rpx; border-radius: 12rpx; line-height: 1.5;">
💡 提示:DMEPA 按大盘实时汇率折算为现金并内扣手续费打款,提现渠道限定为银行卡转账。审核驳回后对应 DMEPA 将全额原路退回。
@@ -402,7 +402,7 @@
return;
}
if (Number(payload.money) > Number(userInfo.value?.money || 0)) {
sheep.$helper.toast('商城可用余额不足');
sheep.$helper.toast('钱包可用余额不足');
return;
}
@@ -427,7 +427,7 @@
sheep.$platform.useProvider('wechat').bind();
}
if (code === 1) {
// 刷新用户佣金与商城余额
// 刷新用户佣金与钱包余额
userStore.getInfo();
if (state.walletType === 'madow') {
getMadowInfo();

查看文件

@@ -4,7 +4,7 @@
<view class="header-box ss-flex ss-row-center ss-col-center">
<view class="card-box ui-BG-Main ui-Shadow-Main">
<view class="card-head ss-flex ss-col-center">
<view class="card-title ss-m-r-10">商城可用余额(元)</view>
<view class="card-title ss-m-r-10">钱包可用余额(元)</view>
<view
@tap="state.showMoney = !state.showMoney"
class="ss-eye-icon"
@@ -92,7 +92,7 @@
>
<view class="ss-p-x-20 ss-p-y-30">
<view class="model-title ss-m-b-30 ss-m-l-20">转余额</view>
<view class="model-subtitle ss-m-b-100 ss-m-l-20">将您的服务收益转入商城余额继续消费</view>
<view class="model-subtitle ss-m-b-100 ss-m-l-20">将您的服务收益转入钱包余额继续消费</view>
<view class="input-box ss-flex ss-col-center border-bottom ss-m-b-70 ss-m-x-20">
<view class="unit">¥</view>
<uni-easyinput
@@ -149,7 +149,7 @@
contentdown: '上拉加载更多',
}"
/>
<view class="wallet-tip">收益分成已全额直接入账商城可用余额,可用于下单消费抵扣。dmepa与兑换券请前往收益中心查看。</view>
<view class="wallet-tip">收益分成已全额直接入账钱包可用余额,可用于下单消费抵扣。dmepa与兑换券请前往收益中心查看。</view>
</s-layout>
</template>