chore: 添加静态资源文件和版本配置文件
添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材 添加系统版本配置文件(.version)和常量定义文件(.constant) 更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件 添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
133
app/services/activity/card/CardBatchServices.php
Normal file
133
app/services/activity/card/CardBatchServices.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardBatchDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
|
||||
/**
|
||||
* 卡次表
|
||||
* Class CardBatchServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardBatchDao
|
||||
*/
|
||||
class CardBatchServices extends BaseServices
|
||||
{
|
||||
/**
|
||||
* @var CardBatchDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardBatchDao $dao;
|
||||
|
||||
/**
|
||||
* 获取列表和总数
|
||||
*
|
||||
* 该方法主要用于根据给定的条件获取数据列表和总记录数
|
||||
* 它封装了分页逻辑和数据获取逻辑,以简化调用
|
||||
*
|
||||
* @param array $where 查询条件数组
|
||||
* @return array 包含数据列表和总记录数的数组
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getList(array $where): array
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->selectList($where, '*', $page, $limit, 'add_time desc', true);
|
||||
$count = $this->dao->count($where);
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据方法
|
||||
*
|
||||
* 该方法用于处理数据的保存操作,根据提供的标识$id判断是更新现有记录还是创建新记录
|
||||
* 使用事务确保数据一致性,在更新或创建过程中,涉及的操作要么全部完成,要么全部不完成
|
||||
*
|
||||
* @param int $id 要更新的记录的标识,如果为0则表示创建新记录
|
||||
* @param array $data 要保存的数据数组,包含需要更新或插入的字段和值
|
||||
*
|
||||
*/
|
||||
public function saveData(array $data): bool
|
||||
{
|
||||
// 使用事务处理数据保存操作,确保数据的一致性和完整性
|
||||
return $this->transaction(function () use ($data) {
|
||||
// 如果$id不存在,则创建新记录,并在成功后处理相关的卡片信息
|
||||
$saveData = $data;
|
||||
// $saveData['total_num'] = pow(10, $data['total_num']);
|
||||
unset($saveData['pwd_type'], $saveData['pwd_num']);
|
||||
$saveData['add_time'] = time();
|
||||
$res = $this->dao->save($saveData);
|
||||
$data['batch_id'] = $res->id;
|
||||
// 调用CardCodeServices服务的addCard方法,为新创建的记录添加卡片信息
|
||||
app()->make(CardCodeServices::class)->addCard($data);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定ID的批次记录
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/9 15:48
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
return $this->transaction(function () use ($id) {
|
||||
$this->update($id, ['is_del' => 1]);
|
||||
app()->make(CardCodeServices::class)->delete(['batch_id' => $id, 'card_id' => 0]);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卡密批次树形结构列表
|
||||
* @return array
|
||||
*/
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->search(['is_del' => 0])->field('id,name,total_num,used_num')->select()->toArray();
|
||||
foreach ($list as &$item) {
|
||||
$item['remain_num'] = $item['total_num'] - $item['used_num'];
|
||||
$item['remain_num'] = max($item['remain_num'], 0);
|
||||
unset($item['total_num'], $item['used_num']);
|
||||
}
|
||||
unset($item);
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配卡密码并更新使用数量
|
||||
* @param int $id 批次ID
|
||||
* @return bool
|
||||
*/
|
||||
public function allocationCode($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
return true;
|
||||
}
|
||||
$used_num = app()->make(CardCodeServices::class)->search(['batch_id' => $id])->where('status', '<>', 0)->count();
|
||||
$info->used_num = $used_num;
|
||||
$info->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
377
app/services/activity/card/CardCodeServices.php
Normal file
377
app/services/activity/card/CardCodeServices.php
Normal file
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardCodeDao;
|
||||
use app\jobs\activity\card\CardJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\order\StoreCartServices;
|
||||
use app\services\user\UserMoneyServices;
|
||||
use app\services\user\UserServices;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* 卡密
|
||||
* Class CardCodeServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardCodeDao
|
||||
*/
|
||||
class CardCodeServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardCodeDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardCodeDao $dao;
|
||||
|
||||
/**
|
||||
* 获取卡密列表
|
||||
* @param array $where 查询条件
|
||||
* @return array
|
||||
*/
|
||||
public function getList($where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$count = $this->dao->count($where);
|
||||
$list = $this->dao->getList($where, $page, $limit);
|
||||
if (!$list) {
|
||||
return [];
|
||||
}
|
||||
$uids = array_unique(array_column($list, 'uid'));
|
||||
$card_ids = array_unique(array_column($list, 'card_id'));
|
||||
$batch_ids = array_unique(array_column($list, 'batch_id'));
|
||||
$userList = app()->make(UserServices::class)->search(['uid' => $uids])->column('nickname', 'uid');
|
||||
$cardList = app()->make(CardGiftServices::class)->search(['id' => $card_ids])->column('name', 'id');
|
||||
$batchList = app()->make(CardBatchServices::class)->search(['id' => $batch_ids])->column('name', 'id');
|
||||
|
||||
foreach ($list as &$item) {
|
||||
$item['nickname'] = $userList[$item['uid']] ?? '';
|
||||
$item['card_name'] = $cardList[$item['card_id']] ?? '';
|
||||
$item['batch_name'] = $batchList[$item['batch_id']] ?? '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加卡信息
|
||||
*
|
||||
* 该方法用于批量添加卡号和密码信息到数据库中。它接受一个包含批次ID、卡的数量、卡号前缀和后缀、
|
||||
* 以及密码类型和长度的数组作为参数。方法首先校验输入数据的合法性,然后生成指定数量的卡号和密码,
|
||||
* 并将它们批量插入到数据库中。
|
||||
* @param array $data 包含批次ID、总数量、卡号前缀和后缀、密码类型和长度的数据数组
|
||||
* @return true
|
||||
* @throws \Random\RandomException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/9 11:30
|
||||
*/
|
||||
public function addCard(array $data): bool
|
||||
{
|
||||
// 参数校验优化:明确判断是否存在且大于0
|
||||
if (!isset($data['batch_id']) || (int)$data['batch_id'] <= 0) {
|
||||
throw new ValidateException('批次ID必须为正整数');
|
||||
}
|
||||
if (!isset($data['total_num']) || (int)$data['total_num'] <= 0) {
|
||||
throw new ValidateException('数量必须为正整数');
|
||||
}
|
||||
|
||||
// 校验 card_prefix 和 card_suffix 是否存在
|
||||
if (!isset($data['card_prefix'])) {
|
||||
$data['card_prefix'] = '';
|
||||
}
|
||||
if (!isset($data['card_suffix'])) {
|
||||
$data['card_suffix'] = '';
|
||||
}
|
||||
|
||||
// // 控制最大生成数量,防止内存溢出
|
||||
// $maxGenerateLimit = 100000; // 示例限制为10万张卡
|
||||
|
||||
// if ($length > 8 || pow(10, $length) > $maxGenerateLimit) {
|
||||
// throw new ValidateException("生成数量超出限制");
|
||||
// }
|
||||
|
||||
// 密码相关参数校验
|
||||
if (!isset($data['pwd_type']) || !isset($data['pwd_num'])) {
|
||||
throw new ValidateException('密码类型或长度缺失');
|
||||
}
|
||||
|
||||
$max = (int)$data['total_num'];
|
||||
$length = (int)strlen((string)$data['total_num']);
|
||||
$insertData = [];
|
||||
|
||||
for ($i = 1; $i <= $max; $i++) {
|
||||
$num = str_pad((string)$i, $length, '0', STR_PAD_LEFT);
|
||||
$insertData[] = [
|
||||
'card_number' => $data['card_prefix'] . $num . $data['card_suffix'],
|
||||
'card_pwd' => $this->generatePassword((array)$data['pwd_type'], (int)$data['pwd_num']),
|
||||
'batch_id' => $data['batch_id'],
|
||||
'add_time' => time(),
|
||||
];
|
||||
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($insertData) >= 1000) {
|
||||
$this->dao->saveAll($insertData);
|
||||
$insertData = [];
|
||||
}
|
||||
}
|
||||
|
||||
// 插入剩余数据
|
||||
if (!empty($insertData)) {
|
||||
$this->dao->saveAll($insertData);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定类型的随机密码
|
||||
*
|
||||
* @param array $types 密码包含的字符类型,1代表数字,2代表小写字母,3代表大写字母,默认包含所有类型
|
||||
* @param int $num 密码的长度,默认为10
|
||||
* @return string 生成的密码字符串
|
||||
* @throws ValidateException 如果密码长度小于等于0或密码类型不在允许范围内,则抛出异常
|
||||
*/
|
||||
public function generatePassword(array $types = [1, 2, 3], int $num = 10): string
|
||||
{
|
||||
// 参数校验
|
||||
if ($num <= 0) {
|
||||
throw new ValidateException('密码长度必须大于0');
|
||||
}
|
||||
|
||||
$validTypes = [1, 2, 3];
|
||||
foreach ($types as $type) {
|
||||
if (!is_int($type) || !in_array($type, $validTypes, true)) {
|
||||
throw new ValidateException('密码类型必须是 1、2 或 3');
|
||||
}
|
||||
}
|
||||
|
||||
// 定义每种类型的字符集合
|
||||
$typeMap = [
|
||||
1 => '0123456789',
|
||||
2 => 'abcdefghijklmnopqrstuvwxyz',
|
||||
3 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
];
|
||||
|
||||
// 根据选择的类型构建字符池
|
||||
$charPool = '';
|
||||
foreach ($types as $type) {
|
||||
$charPool .= $typeMap[$type];
|
||||
}
|
||||
|
||||
// 确保字符池不为空
|
||||
if ($charPool === '') {
|
||||
throw new ValidateException('至少选择一种密码类型');
|
||||
}
|
||||
|
||||
// 初始化密码字符串和字符池长度
|
||||
$password = '';
|
||||
$poolLength = strlen($charPool) - 1;
|
||||
|
||||
// 生成指定长度的密码
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$randomIndex = random_int(0, $poolLength);
|
||||
$password .= $charPool[$randomIndex];
|
||||
}
|
||||
|
||||
return $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备注
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:48
|
||||
*/
|
||||
public function formRemark(int $id)
|
||||
{
|
||||
$card = $this->dao->get($id);
|
||||
if (!$card) {
|
||||
throw new ValidateException('数据不存在');
|
||||
}
|
||||
$field[] = Form::input('remark', '备注', $card['remark'] ?? '')->required();
|
||||
return create_form('备注', $field, Url::buildUrl('/marketing/card/code/remark/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证礼品卡
|
||||
* @param string $card_number
|
||||
* @param string $card_pwd
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:49
|
||||
*/
|
||||
public function verifyGiftCode($card_number, $card_pwd)
|
||||
{
|
||||
$info = $this->dao->get(['card_number' => $card_number, 'card_pwd' => $card_pwd]);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡卡号或密码错误');
|
||||
}
|
||||
if ($info['status'] != 2) {
|
||||
throw new ValidateException('礼品卡已被使用');
|
||||
}
|
||||
if (!$info['card_id']) {
|
||||
throw new ValidateException('礼品卡未绑定');
|
||||
}
|
||||
$giftInfo = app()->make(CardGiftServices::class)->getInfo($info['card_id']);
|
||||
if (!$giftInfo) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
if ($giftInfo['status'] != 1) {
|
||||
throw new ValidateException('礼品卡已失效');
|
||||
}
|
||||
if ($giftInfo['valid_type'] == 2 && ($giftInfo['start_time'] > time() || $giftInfo['end_time'] < time())) {
|
||||
throw new ValidateException('请在有效期内激活~');
|
||||
}
|
||||
return $giftInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用
|
||||
* @param string $card_number
|
||||
* @param string $card_pwd
|
||||
* @param array $product
|
||||
* @param int $uid
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 16:49
|
||||
*/
|
||||
public function receiveGiftCode(string $card_number, string $card_pwd, array $product, int $uid)
|
||||
{
|
||||
$giftInfo = $this->verifyGiftCode($card_number, $card_pwd);
|
||||
$info = $this->dao->get(['card_number' => $card_number, 'card_pwd' => $card_pwd]);
|
||||
if ($giftInfo['type'] == 1) {
|
||||
$data = $this->transaction(function () use ($card_number, $card_pwd, $uid, $giftInfo, $info) {
|
||||
//兑换余额
|
||||
$userMoneyServices = app()->make(UserMoneyServices::class);
|
||||
$userServices = app()->make(UserServices::class);
|
||||
$user = $userServices->get($uid);
|
||||
$edit['now_money'] = bcadd($user['now_money'], $giftInfo['balance'], 2);
|
||||
$res = $userServices->update($uid, $edit);
|
||||
$res = $res && $userMoneyServices->income('card_add_money', $user['uid'], $giftInfo['balance'], $edit['now_money'], $info['id']);
|
||||
//修改卡密状态
|
||||
if ($res) {
|
||||
$info->uid = $uid;
|
||||
$info->status = 1;
|
||||
$info->active_time = time();
|
||||
$res = $info->save();
|
||||
}
|
||||
return !!$res;
|
||||
});
|
||||
} else {
|
||||
//验证商品
|
||||
if (!$giftInfo['product']) {
|
||||
throw new ValidateException('礼品卡未绑定商品');
|
||||
}
|
||||
if ($giftInfo['exchange_type'] == 1) {
|
||||
//固定
|
||||
$product_list = $giftInfo['product'];
|
||||
} else {
|
||||
//任选
|
||||
$uniques = array_column($giftInfo['product'], 'unique');
|
||||
foreach ($product as $item) {
|
||||
if (!in_array($item['unique'], $uniques)) {
|
||||
throw new ValidateException('礼品卡商品不匹配');
|
||||
}
|
||||
}
|
||||
$product_list = $product;
|
||||
}
|
||||
$storeCartServices = app()->make(StoreCartServices::class);
|
||||
$cartList = [];
|
||||
foreach ($product_list as $item) {
|
||||
if ($item['limit_num'] > 0) {
|
||||
[$cartIds, $cartNum] = $storeCartServices->setCart($uid, $item['product_id'], $item['limit_num'], $item['unique'], 9, true, $info['id']);
|
||||
$cartList[] = ['cartId' => $cartIds, 'cartNum' => $cartNum];
|
||||
}
|
||||
}
|
||||
$data = $cartList;
|
||||
}
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCardGift', [$giftInfo['id']]);
|
||||
return ['type' => $giftInfo['type'], 'data' => $data];
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡密使用
|
||||
* @param array $order
|
||||
* @return true
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/24 10:57
|
||||
*/
|
||||
public function useCode(array $order)
|
||||
{
|
||||
$info = $this->dao->get($order['activity_id']);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡数据不存在');
|
||||
}
|
||||
if ($info['status'] != 2) {
|
||||
throw new ValidateException('礼品卡已被使用');
|
||||
}
|
||||
//修改卡密状态
|
||||
$info->uid = $order['uid'];
|
||||
$info->status = 1;
|
||||
$info->active_time = time();
|
||||
$res = $info->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/6/5 17:14
|
||||
*/
|
||||
public function expireCode()
|
||||
{
|
||||
$list = $this->dao->search(['status' => 2])->where('end_time', '<>', 0)->where('end_time', '<', time())->order('id asc')->select()->toArray();
|
||||
if (!$list) {
|
||||
return true;
|
||||
}
|
||||
$updateData = [
|
||||
'status' => 3,
|
||||
];
|
||||
foreach ($list as $k => $item) {
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$this->dao->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$this->dao->batchUpdate($ids, $updateData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
34
app/services/activity/card/CardGiftAuxiliaryServices.php
Normal file
34
app/services/activity/card/CardGiftAuxiliaryServices.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftAuxiliaryDao;
|
||||
use app\services\BaseServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftAuxiliaryServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftAuxiliaryDao
|
||||
*/
|
||||
class CardGiftAuxiliaryServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftAuxiliaryDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftAuxiliaryDao $dao;
|
||||
}
|
||||
59
app/services/activity/card/CardGiftRecordServices.php
Normal file
59
app/services/activity/card/CardGiftRecordServices.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftRecordDao;
|
||||
use app\services\BaseServices;
|
||||
use app\services\system\admin\SystemAdminServices;
|
||||
use think\annotation\Inject;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftRecordDao
|
||||
*/
|
||||
class CardGiftRecordServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftRecordDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftRecordDao $dao;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:37
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', $page, $limit, 'add_time desc');
|
||||
$count = $this->dao->count($where);
|
||||
$adminIds = array_column($list, 'admin_id');
|
||||
$batchList = app()->make(SystemAdminServices::class)->search(['id' => $adminIds])->column('real_name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['admin_name'] = $batchList[$item['admin_id']] ?? '';
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
}
|
||||
441
app/services/activity/card/CardGiftServices.php
Normal file
441
app/services/activity/card/CardGiftServices.php
Normal file
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\services\activity\card;
|
||||
|
||||
use app\dao\activity\card\CardGiftDao;
|
||||
use app\jobs\activity\card\CardJob;
|
||||
use app\services\BaseServices;
|
||||
use app\services\product\product\StoreDescriptionServices;
|
||||
use app\services\product\product\StoreProductServices;
|
||||
use app\services\product\sku\StoreProductAttrValueServices;
|
||||
use crmeb\services\FormBuilder as Form;
|
||||
use think\annotation\Inject;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Route as Url;
|
||||
|
||||
|
||||
/**
|
||||
* 礼品卡
|
||||
* Class CardGiftServices
|
||||
* @package app\services\activity\card
|
||||
* @mixin CardGiftDao
|
||||
*/
|
||||
class CardGiftServices extends BaseServices
|
||||
{
|
||||
|
||||
/**
|
||||
* @var CardGiftDao
|
||||
*/
|
||||
#[Inject]
|
||||
protected CardGiftDao $dao;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
* @param array $where
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:37
|
||||
*/
|
||||
public function getList(array $where)
|
||||
{
|
||||
[$page, $limit] = $this->getPageValue();
|
||||
$where['is_del'] = 0;
|
||||
$list = $this->dao->getList($where, '*', $page, $limit, 'sort desc,add_time desc');
|
||||
$count = $this->dao->count($where);
|
||||
$bIds = array_column($list, 'batch_id');
|
||||
$batchList = app()->make(CardBatchServices::class)->search(['id', $bIds])->column('name', 'id');
|
||||
foreach ($list as &$item) {
|
||||
$item['batch_name'] = $batchList[$item['batch_id']] ?? '';
|
||||
$item['fixed_time'] = [
|
||||
$item['start_time'] ? date('Y-m-d H:i:s', $item['start_time']) : '',
|
||||
$item['end_time'] ? date('Y-m-d H:i:s', $item['end_time']) : '',
|
||||
];
|
||||
}
|
||||
return compact('list', 'count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
* @param array $data
|
||||
* @param int $id
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:46
|
||||
*/
|
||||
public function saveData(array $data, int $id = 0, int $admin_id = 0)
|
||||
{
|
||||
if ($id && !$info = $this->dao->get($id)) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
//验证卡密未使用的数量是否超过礼品卡填写的总量
|
||||
if (!$id) {
|
||||
$codeCount = app()->make(CardCodeServices::class)->count(['batch_id' => $data['batch_id'], 'status' => 0, 'card_id' => 0]);
|
||||
if ($codeCount < $data['total_num']) {
|
||||
throw new ValidateException('卡密未使用的数量不能超过礼品卡填写的总量');
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['valid_type'] == 2) {
|
||||
$data['start_time'] = isset($data['fixed_time'][0]) ? strtotime($data['fixed_time'][0]) : 0;
|
||||
$data['end_time'] = isset($data['fixed_time'][1]) ? strtotime($data['fixed_time'][1]) : 0;
|
||||
}
|
||||
unset($data['fixed_time']);
|
||||
$this->transaction(function () use ($id, $data, $admin_id) {
|
||||
$product = $data['product'];
|
||||
$description = $data['description'];
|
||||
unset($data['product'], $data['description']);
|
||||
$data['add_time'] = time();
|
||||
if ($id) {
|
||||
$this->dao->update($id, $data);
|
||||
} else {
|
||||
$res = $this->dao->save($data);
|
||||
$id = $res->id;
|
||||
//修改卡密
|
||||
$this->saveCode($id, $data, $admin_id);
|
||||
|
||||
}
|
||||
app()->make(StoreDescriptionServices::class)->saveDescription($id, $description, 5);
|
||||
//保存礼品卡商品
|
||||
$this->saveProduct($id, $product);
|
||||
return true;
|
||||
});
|
||||
$batch_id = $id ? $info['batch_id'] : $data['batch_id'];
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCode', [$batch_id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改卡密
|
||||
* @param int $id
|
||||
* @param array $data
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:46
|
||||
*/
|
||||
public function saveCode(int $id, array $data, int $admin_id = 0)
|
||||
{
|
||||
$cardCodeServices = app()->make(CardCodeServices::class);
|
||||
$list = $cardCodeServices->search(['batch_id' => $data['batch_id'], 'status' => 0, 'card_id' => 0])->order('id asc')->limit($data['total_num'])->select()->toArray();
|
||||
if (!$list) {
|
||||
throw new ValidateException('没有可操作的卡密');
|
||||
}
|
||||
$ids = [];
|
||||
$updateData = [
|
||||
'type' => $data['type'],
|
||||
'end_time' => $data['end_time'] ?? 0,
|
||||
'card_id' => $id,
|
||||
'status' => 2,
|
||||
];
|
||||
$str = '';
|
||||
$i = $list[0]['id'];
|
||||
$status = true;
|
||||
foreach ($list as $k => $item) {
|
||||
if ($k == 0) {
|
||||
$str .= $item['card_number'] . '--';
|
||||
} elseif ($k == count($list) - 1) {
|
||||
//获取列表最后一条数据
|
||||
$str .= $item['card_number'];
|
||||
} else {
|
||||
if ($item['id'] != $i) {
|
||||
if ($status) {
|
||||
$str .= $item['card_number'] . ',';
|
||||
$status = false;
|
||||
} else {
|
||||
$str .= $item['card_number'] . '--';
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i = $item['id'] + 1;
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
}
|
||||
app()->make(CardGiftRecordServices::class)->save([
|
||||
'gift_id' => $id,
|
||||
'record' => $str,
|
||||
'num' => count($list),
|
||||
'pm' => 1,
|
||||
'add_time' => time(),
|
||||
'admin_id' => $admin_id
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品
|
||||
* @param int $id
|
||||
* @param array $productData
|
||||
* @return true
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:45
|
||||
*/
|
||||
public function saveProduct(int $id, array $productData)
|
||||
{
|
||||
$auxiliary = app()->make(CardGiftAuxiliaryServices::class);
|
||||
$auxiliary->delete(['gift_id' => $id]);
|
||||
$saveData = [];
|
||||
foreach ($productData as $product) {
|
||||
$saveData[] = [
|
||||
'gift_id' => $id,
|
||||
'product_id' => $product['product_id'] ?? 0,
|
||||
'limit_num' => $product['limit_num'] ?? 0,
|
||||
'unique' => $product['unique'] ?? '',
|
||||
];
|
||||
}
|
||||
if (count($saveData)) {
|
||||
$auxiliary->saveAll($saveData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加卡密表单
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:41
|
||||
*/
|
||||
public function otherForm(int $id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$batchInfo = app()->make(CardBatchServices::class)->get($info['batch_id']);
|
||||
$remain_num = $batchInfo['total_num'] - $batchInfo['used_num'];
|
||||
$remain_num = max($remain_num, 0);
|
||||
$batchName = $batchInfo['name'] . "({$remain_num})";
|
||||
$field[] = Form::input('batch_name', '卡号批次', $batchName)->disabled(true);
|
||||
$field[] = Form::radio('type', '修改数量', $formData['status'] ?? 1)->options([
|
||||
['label' => '增加', 'value' => 1],
|
||||
['label' => '减少', 'value' => 2],
|
||||
]);
|
||||
$field[] = Form::number('number', '数量', 0)->min(0);
|
||||
return create_form('修改数量', $field, Url::buildUrl('/marketing/card/gift/update_other/' . $id), 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加卡密提交
|
||||
* @param int $id
|
||||
* @param int $type
|
||||
* @param int $number
|
||||
* @return true
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:42
|
||||
*/
|
||||
public function updateOther(int $id, int $type, int $number, int $admin_id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
if ($type == 1) {
|
||||
$total_num = $info->total_num + $number;
|
||||
//增加
|
||||
$count = app()->make(CardCodeServices::class)->count(['batch_id' => $info['batch_id'], 'status' => 0, 'card_id' => 0]);
|
||||
if ($count < $number) {
|
||||
throw new ValidateException('卡密不足');
|
||||
}
|
||||
$this->saveCode($id, ['total_num' => $number, 'batch_id' => $info['batch_id'], 'type' => $info['type']], $admin_id);
|
||||
} else {
|
||||
$total_num = $info->total_num - $number;
|
||||
//减少
|
||||
$count = app()->make(CardCodeServices::class)->count(['batch_id' => $info['batch_id'], 'status' => 2, 'card_id' => $id]);
|
||||
if ($count < $number) {
|
||||
throw new ValidateException('未卡密不足,无法减少,未使用卡密:' . $count);
|
||||
}
|
||||
$cardCodeServices = app()->make(CardCodeServices::class);
|
||||
$list = $cardCodeServices->search(['batch_id' => $info['batch_id'], 'status' => 2, 'card_id' => $id])->order('id asc')->limit($number)->select()->toArray();
|
||||
if (!$list) {
|
||||
throw new ValidateException('没有可操作的卡密');
|
||||
}
|
||||
$ids = [];
|
||||
$updateData = [
|
||||
'type' => 0,
|
||||
'card_id' => 0,
|
||||
'end_time' => 0,
|
||||
'status' => 0,
|
||||
];
|
||||
|
||||
$str = '';
|
||||
$i = $list[0]['id'];
|
||||
$status = true;
|
||||
|
||||
foreach ($list as $k => $item) {
|
||||
//检查 id 是否间断, 如果有给$str追加
|
||||
if ($k == 0) {
|
||||
$str .= $item['card_number'] . '--';
|
||||
} elseif ($k == count($list) - 1) {
|
||||
//获取列表最后一条数据
|
||||
$str .= $item['card_number'];
|
||||
} else {
|
||||
if ($item['id'] != $i) {
|
||||
if ($status) {
|
||||
$str .= $item['card_number'] . ',';
|
||||
$status = false;
|
||||
} else {
|
||||
$str .= $item['card_number'] . '--';
|
||||
$status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$i = $item['id'] + 1;
|
||||
$ids[] = $item['id'];
|
||||
// 每满100条插入一次并清空缓存
|
||||
if (count($ids) >= 500) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
$ids = [];
|
||||
}
|
||||
}
|
||||
if (count($ids)) {
|
||||
$cardCodeServices->batchUpdate($ids, $updateData);
|
||||
}
|
||||
app()->make(CardGiftRecordServices::class)->save([
|
||||
'gift_id' => $id,
|
||||
'record' => $str,
|
||||
'num' => count($list),
|
||||
'pm' => 2,
|
||||
'add_time' => time(),
|
||||
'admin_id' => $admin_id
|
||||
]);
|
||||
}
|
||||
$info->total_num = $total_num;
|
||||
$info->save();
|
||||
//校验卡密使用数量
|
||||
CardJob::dispatchDo('allocationCode', [$info['batch_id']]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
* @param $id
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 15:42
|
||||
*/
|
||||
public function getInfo($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
$info = $info->toArray();
|
||||
$auxiliaryList = app()->make(CardGiftAuxiliaryServices::class)->search(['gift_id' => $id])->select()->toArray();
|
||||
$info['product'] = [];
|
||||
$info['description'] = app()->make(StoreDescriptionServices::class)->getDescription(['product_id' => $id, 'type' => 5]);
|
||||
$info['fixed_time'] = [
|
||||
$info['start_time'] ? date('Y-m-d H:i:s', $info['start_time']) : '',
|
||||
$info['end_time'] ? date('Y-m-d H:i:s', $info['end_time']) : '',
|
||||
];
|
||||
if (!$auxiliaryList) {
|
||||
return $info;
|
||||
}
|
||||
$productIds = array_unique(array_column($auxiliaryList, 'product_id'));
|
||||
$uniques = array_unique(array_column($auxiliaryList, 'unique'));
|
||||
$productList = app()->make(StoreProductServices::class)->search(['id' => $productIds])->column('store_name', 'id');
|
||||
$uniqueList = app()->make(StoreProductAttrValueServices::class)->search(['unique' => $uniques])->column('unique,suk,stock,price,image', 'unique');
|
||||
foreach ($auxiliaryList as &$item) {
|
||||
$item['store_name'] = $productList[$item['product_id']] ?? '';
|
||||
$item['suk'] = $uniqueList[$item['unique']]['suk'] ?? '';
|
||||
$item['stock'] = $uniqueList[$item['unique']]['stock'] ?? '';
|
||||
$item['price'] = $uniqueList[$item['unique']]['price'] ?? '';
|
||||
$item['image'] = $uniqueList[$item['unique']]['image'] ?? '';
|
||||
}
|
||||
$info['product'] = $auxiliaryList;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param $id
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/12 09:45
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
//删除礼品卡,
|
||||
//删除礼品卡商品
|
||||
//删除未使用的礼品卡卡密
|
||||
|
||||
$info = $this->dao->get($id);
|
||||
if (!$info) {
|
||||
throw new ValidateException('礼品卡不存在');
|
||||
}
|
||||
return $this->transaction(function () use ($id, $info) {
|
||||
$res = $this->dao->update($id, ['is_del' => 1]);
|
||||
$res = $res && app()->make(CardGiftAuxiliaryServices::class)->delete(['gift_id' => $id]);
|
||||
$res = $res && app()->make(CardCodeServices::class)->update(['card_id' => $id, 'status' => 2], ['type' => 0, 'status' => 0, 'card_id' => 0]);
|
||||
return !!$res;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卡礼品树形结构列表
|
||||
* @return array
|
||||
*/
|
||||
public function getTree()
|
||||
{
|
||||
return $this->search(['is_del' => 0])->field('id,name')->order('sort desc,add_time desc')->select()->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用数量矫正
|
||||
* @return
|
||||
* User: liusl
|
||||
* DateTime: 2025/5/24 10:47
|
||||
*/
|
||||
public function allocationCardGift($id)
|
||||
{
|
||||
$info = $this->dao->get($id);
|
||||
$used_num = app()->make(CardCodeServices::class)->search(['card_id' => $id, 'status' => 1])->count();
|
||||
$info->used_num = $used_num;
|
||||
$info->save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user