Files
ywxapp 1d49e6f5ee feat: 公共表更名 common/member 前缀 + 插件命令自动加载 + 版本 1.1.1
- 18 张公共表更名(addon/attachment/configure/links/spider_log/spider_stat/sms/notice/ad/task/prop/medal/help/card -> common_*,member_wallets->member_wallet,score_rule/score_log -> member_*,addon_config->common_addonconf),模型全部对齐新表名,Db 直引用清零
- Attachment 模型补  表名绑定,修复富文本上传查 wxapp_attachment 1146 隐患
- install.sql + 迁移 SQL:backend_admin/backend_role delete_at 默认 0,修复软删除(NULL != 0)误过滤导致后台菜单为空
- AppService::boot() 支持插件 info.php 声明 commands 自动注册插件命令(psr-4 自动加载,坏类名自动跳过)
- 各插件(haonav/mqttbroker/wxchat/articles/blog/forum 等)字段与配置同步调整
- 框架版本 1.1.0 -> 1.1.1
2026-08-20 20:19:15 +08:00

181 lines
5.9 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* @Author: YwxApp <ywx@ywxapp.cn>
* @Date: 2026-08-07 10:22:47
* @LastEditors: YwxApp <ywx@ywxapp.cn>
* @LastEditTime: 2026-08-20 00:36:36
* @Description:
* @FilePath: \ywxapp_dev\ywxapp\model\CommonCard.php
* @CustomString: Copyright (c) 2026 YwxApp
*/
declare(strict_types=1);
namespace ywxapp\model;
use ywxapp\model\BaseModel;
use think\facade\Db;
use think\model\concern\SoftDelete;
/**
* 充值卡密
*/
class CommonCard extends BaseModel
{
use SoftDelete;
protected function getOptions(): array
{
return [
'strict' => false,
'autoWriteTimestamp' => 'int',
'createTime' => 'create_at',
'updateTime' => 'update_at',
'deleteTime' => 'delete_at',
'defaultSoftDelete' => 0,
'append' => ['target'],
'hidden' => ['create_at', 'update_at', 'delete_at'],
'readonly' => ['id'],
];
}
// 卡密状态
const STATUS_UNSOLD = 0; // 未售
const STATUS_SOLD = 1; // 已售
const STATUS_USED = 2; // 已用(已兑换)
/**
* 运行时自愈:确保 card 主表存在(install.sql 为事实源)。
*/
public static function ensureSchema(): void
{
BaseModel::ensureTableFromInstall(BaseModel::currentPrefix(), 'common_card');
}
/**
* 初始化:自愈建表,避免远程库缺失 wxapp_card 导致 1146。
*/
protected function initialize()
{
parent::initialize();
self::ensureSchema();
}
/**
* 兑换卡密(会员用卡号+密码充值余额)
*
* @param int $uid 会员ID
* @param string $cardno 卡号
* @param string $password 密码
* @return array ['success'=>bool,'msg'=>string,'data'=>array]
*/
public static function redeem(int $uid, string $cardno, string $password): array
{
if ($uid <= 0 || $cardno === '' || $password === '') {
return ['success' => false, 'msg' => '参数不完整'];
}
$card = self::where('cardno', $cardno)->find();
if (empty($card)) {
return ['success' => false, 'msg' => '卡密不存在'];
}
if ($card->delete_at > 0) {
return ['success' => false, 'msg' => '卡密已失效'];
}
if ((int)$card->status === self::STATUS_USED) {
return ['success' => false, 'msg' => '该卡密已被使用'];
}
// 密码校验(存储若为明文,按需改为 password_verify)
if ((string)$card->password !== (string)$password) {
return ['success' => false, 'msg' => '卡号或密码错误'];
}
$amount = (float)$card->amount;
if ($amount <= 0) {
return ['success' => false, 'msg' => '卡密面值异常'];
}
Db::startTrans();
try {
// 1) 卡密标记已用,绑定会员
$card->status = self::STATUS_USED;
$card->use_time = time();
$card->uid = $uid;
$card->save();
// 2) 会员钱包加余额 + 累计充值(无钱包则自动创建)
$wallet = Db::name('member_wallet')->where('uid', $uid)->find();
if (empty($wallet)) {
Db::name('member_wallet')->insert([
'uid' => $uid,
'balance' => $amount,
'total_recharge' => $amount,
'create_at' => time(),
'update_at' => time(),
]);
} else {
Db::name('member_wallet')
->where('uid', $uid)
->inc('balance', $amount)
->inc('total_recharge', $amount)
->update(['update_at' => time()]);
}
// 3) 充值流水
Db::name('member_bill')->insert([
'uid' => $uid,
'type' => 1, // 充值
'amount' => $amount,
'currency' => 1, // 人民币
'channel' => 'card',
'order_no' => 'CARD' . date('YmdHis') . $uid . mt_rand(100, 999),
'status' => 1, // 成功
'description' => '卡密充值:' . $cardno,
'create_at' => time(),
'update_at' => time(),
]);
Db::commit();
return [
'success' => true,
'msg' => '兑换成功,已充值 ¥' . number_format($amount, 2),
'data' => ['amount' => $amount],
];
} catch (\Throwable $e) {
Db::rollback();
throw $e;
}
}
/**
* 批量生成卡密
*
* @param int $count 生成数量
* @param float $amount 面值
* @param string $prefix 卡号前缀(如 YX)
* @return array 生成的卡号列表
*/
public static function generateBatch(int $count, float $amount, string $prefix = ''): array
{
$count = max(1, min(200, $count)); // 单次上限保护
$batchNo = date('YmdHis') . mt_rand(1000, 9999);
$list = [];
$rows = [];
for ($i = 0; $i < $count; $i++) {
$cardno = ($prefix ?: 'YX') . strtoupper(substr(md5(uniqid((string)mt_rand(), true)), 0, 16));
$password = strtoupper(substr(md5(uniqid((string)mt_rand(), true)), 0, 8));
$list[] = ['cardno' => $cardno, 'password' => $password];
$rows[] = [
'cardno' => $cardno,
'password' => $password,
'amount' => $amount,
'status' => self::STATUS_UNSOLD,
'batch_no' => $batchNo,
'create_at' => time(),
'update_at' => time(),
];
}
self::insertAll($rows);
return $list;
}
}