166 lines
5.4 KiB
PHP
166 lines
5.4 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
namespace ywxapp\model;
|
||
|
||
use ywxapp\model\BaseModel;
|
||
|
||
use think\facade\Db;
|
||
use think\model\concern\SoftDelete;
|
||
|
||
/**
|
||
* 充值卡密
|
||
*/
|
||
class Card extends BaseModel
|
||
{
|
||
use SoftDelete;
|
||
|
||
protected $name = 'card';
|
||
protected $deleteTime = 'delete_at';
|
||
protected $defaultSoftDelete = 0;
|
||
|
||
// 时间戳自动写入
|
||
protected $autoWriteTimestamp = true;
|
||
protected $createTime = 'create_at';
|
||
protected $updateTime = 'update_at';
|
||
|
||
// 卡密状态
|
||
const STATUS_UNSOLD = 0; // 未售
|
||
const STATUS_SOLD = 1; // 已售
|
||
const STATUS_USED = 2; // 已用(已兑换)
|
||
|
||
/**
|
||
* 运行时自愈:确保 card 主表存在(install.sql 为事实源)。
|
||
*/
|
||
public static function ensureSchema(): void
|
||
{
|
||
BaseModel::ensureTableFromInstall(BaseModel::currentPrefix(), '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_wallets')->where('uid', $uid)->find();
|
||
if (empty($wallet)) {
|
||
Db::name('member_wallets')->insert([
|
||
'uid' => $uid,
|
||
'balance' => $amount,
|
||
'total_recharge' => $amount,
|
||
'create_at' => time(),
|
||
'update_at' => time(),
|
||
]);
|
||
} else {
|
||
Db::name('member_wallets')
|
||
->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;
|
||
}
|
||
}
|