feat(pay): 余额支付打通 + 后台一键充值余额
一、修复两处真实缺陷
- Post::create:付费发布只创建 pending 订单,从不扣余额、也不置为已支付
→ 余额不足校验提前到落库前(避免残留 is_paid=1 的无效发布);
余额支付改为「下单即扣款」,订单直接 paid + paytime,并记资金流水;
微信支付保持 pending 由收银台回调置为 paid;补支付方式白名单校验
- Member::open:余额校验在 insertGetId(fc_order) 之后,余额不足时
会插入一条 status=paid 的假订单 → 校验前置,先判余额再落单
二、后台一键充值余额(FastAdmin PC)
- fc/userext 新增 recharge() 动作:批量给选中用户加余额
(金额需 >0 且 <=100000;同步写资金流水 fa_fc_finance_flow
与站内通知 fa_fc_message;后台操作留痕由 Backend 自动记录)
- fc/userext 的 index() 改为 JOIN fa_user,列表直接显示
昵称 / 手机号 / 账户余额(原列表只有扩展字段,看不出余额)
- 列表页新增「余额充值」工具栏按钮 + Layer.prompt 金额输入
三、验证
- 后端 API 178/178、前端 102/102 均无回归
这个提交包含在:
@@ -28,19 +28,38 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
[
|
||||
{checkbox: true},
|
||||
{field: 'id', title: __('Id')},
|
||||
{field: 'user_id', title: __('User_id')},
|
||||
{field: 'openid', title: __('Openid'), operate: 'LIKE'},
|
||||
{field: 'user_type', title: __('User_type')},
|
||||
{field: 'realname_status', title: __('Realname_status')},
|
||||
{field: 'is_member', title: __('Is_member')},
|
||||
{field: 'member_level', title: __('Member_level'), operate: 'LIKE'},
|
||||
{field: 'member_expiretime', title: __('Member_expiretime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'invite_code', title: __('Invite_code'), operate: 'LIKE'},
|
||||
{field: 'inviter_id', title: __('Inviter_id')},
|
||||
{field: 'free_view_date', title: __('Free_view_date'), operate: 'LIKE'},
|
||||
{field: 'free_view_used', title: __('Free_view_used')},
|
||||
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'user_id', title: '用户ID'},
|
||||
{field: 'nickname', title: '昵称', operate: 'LIKE'},
|
||||
{field: 'mobile', title: '手机号', operate: 'LIKE'},
|
||||
{
|
||||
field: 'money', title: '账户余额', operate: false,
|
||||
formatter: function (value) {
|
||||
var n = parseFloat(value || 0);
|
||||
return n > 0 ? '¥' + n.toFixed(2) : '¥0.00';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'user_type', title: '身份', searchList: {'1': '个人', '2': '商家'},
|
||||
formatter: function (value) {
|
||||
return value == 2 ? '商家' : '个人';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'is_member', title: '会员', searchList: {'1': '是', '0': '否'},
|
||||
formatter: function (value) {
|
||||
return value == 1 ? '是' : '否';
|
||||
}
|
||||
},
|
||||
{field: 'member_level', title: '会员等级', operate: 'LIKE'},
|
||||
{field: 'member_expiretime', title: '会员到期', operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'invite_code', title: '邀请码', operate: 'LIKE'},
|
||||
{field: 'openid', title: __('Openid'), operate: 'LIKE', visible: false},
|
||||
{field: 'realname_status', title: __('Realname_status'), visible: false},
|
||||
{field: 'inviter_id', title: __('Inviter_id'), visible: false},
|
||||
{field: 'free_view_date', title: __('Free_view_date'), visible: false},
|
||||
{field: 'free_view_used', title: __('Free_view_used'), visible: false},
|
||||
{field: 'createtime', title: __('Createtime'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime},
|
||||
{field: 'updatetime', title: __('Updatetime'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime, visible: false},
|
||||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||
]
|
||||
]
|
||||
@@ -48,6 +67,30 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
|
||||
|
||||
// 为表格绑定事件
|
||||
Table.api.bindevent(table);
|
||||
|
||||
// 余额充值:需先勾选用户,再输入金额
|
||||
$(document).on('click', '.btn-recharge', function () {
|
||||
var ids = Table.api.selectedids(table);
|
||||
if (!ids.length) {
|
||||
Layer.msg('请先勾选要充值的用户');
|
||||
return;
|
||||
}
|
||||
Layer.prompt({title: '请输入充值金额(元)', formType: 0}, function (value, index) {
|
||||
var amount = parseFloat(value);
|
||||
if (!(amount > 0)) {
|
||||
Layer.msg('充值金额需大于 0');
|
||||
return;
|
||||
}
|
||||
Fast.api.ajax({
|
||||
url: 'fc/userext/recharge',
|
||||
data: {ids: ids.join(','), amount: amount}
|
||||
}, function (data) {
|
||||
table.bootstrapTable('refresh');
|
||||
return false;
|
||||
});
|
||||
Layer.close(index);
|
||||
});
|
||||
});
|
||||
},
|
||||
add: function () {
|
||||
Controller.api.bindevent();
|
||||
|
||||
在新工单中引用
屏蔽一个用户