文件
fenleixinxi/application/admin/controller/fc/Userext.php
linda 4b044ba7e8 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 均无回归
2026-10-15 15:32:55 +08:00

146 行
4.8 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace app\admin\controller\fc;
use app\common\controller\Backend;
use think\Db;
/**
* 同城-用户扩展
*
* @icon fa fa-circle-o
*/
class Userext extends Backend
{
/**
* FcUserExt模型对象
* @var \app\admin\model\FcUserExt
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\FcUserExt;
}
/**
* 会员列表(关联 fa_user 展示昵称 / 手机号 / 账户余额)
*
* 说明:余额money 存放在核心表 fa_user,本表只有业务扩展字段,
* 因此列表需要 JOIN fa_user 才能看出「谁有多少余额」。
* 注意 TP5.0 的 count() 会清空查询条件,必须分别构建查询。
*/
public function index()
{
if ($this->request->isAjax()) {
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model->alias('e')
->join('user u', 'u.id = e.user_id', 'LEFT')
->where($where)
->count();
$list = $this->model->alias('e')
->join('user u', 'u.id = e.user_id', 'LEFT')
->where($where)
->field('e.*, u.nickname, u.mobile, u.money')
->order($sort, $order)
->limit($offset, $limit)
->select();
return json(['total' => $total, 'rows' => $list]);
}
return $this->view->fetch();
}
/**
* 余额充值(给选中用户增加账户余额)
*
* POST /s.php/fc/userext/recharge
* 入参:{ ids: '1001,1002' , amount: 100, remark?: '备注' }
*
* 说明:
* 余额存放在核心表 fa_user.money,本表(fc_user_ext)仅作业务扩展,
* 因此这里按 user_id 关联 fa_user 进行加减。
* 为可追溯,每次充值同时写入 fa_fc_finance_flow(资金流水)与
* fa_fc_message(站内通知),后台操作留痕由 Backend 自动记录。
*/
public function recharge()
{
$ids = (string)$this->request->post('ids', '');
$userIds = array_filter(array_map('intval', explode(',', $ids)));
$userIds = array_values(array_unique($userIds));
if (!$userIds) {
$this->error('请选择要充值的用户');
}
$amount = round((float)$this->request->post('amount', 0), 2);
if ($amount <= 0) {
$this->error('充值金额需大于 0');
}
if ($amount > 100000) {
$this->error('单次充值金额过大');
}
$remark = trim((string)$this->request->post('remark', ''));
$now = time();
$done = 0;
foreach ($userIds as $uid) {
$user = Db::name('user')->where('id', $uid)->find();
if (!$user) {
continue;
}
$balance = round((float)$user['money'] + $amount, 2);
Db::name('user')->where('id', $uid)->update([
'money' => $balance,
'updatetime' => $now,
]);
// 资金流水(平台口径:余额充值属于收入)
Db::name('fc_finance_flow')->insert([
'flow_no' => 'R' . date('YmdHis') . mt_rand(100, 999) . $uid,
'type' => 'income',
'scene' => '余额充值',
'amount' => $amount,
'balance' => $balance,
'related_id' => $uid,
'remark' => $remark !== '' ? $remark : ('后台充值给用户 #' . $uid),
'createtime' => $now,
]);
// 站内通知
Db::name('fc_message')->insert([
'user_id' => $uid,
'type' => 'system',
'title' => '余额充值到账',
'content' => '您的账户已充值 ¥' . number_format($amount, 2, '.', '')
. ',当前余额 ¥' . number_format($balance, 2, '.', '')
. '。' . ($remark !== '' ? '备注:' . $remark : ''),
'isread' => 0,
'readtime' => null,
'createtime' => $now,
]);
$done++;
}
if (!$done) {
$this->error('未找到对应用户');
}
$this->success('充值成功:' . $done . ' 个用户,每人 ¥' . number_format($amount, 2, '.', ''));
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
}