This commit is contained in:
2025-08-14 17:19:26 +08:00
parent 30abda5ba7
commit 281248fd04
245 changed files with 21051 additions and 61 deletions

77
app/admin/model/Admin.php Normal file
View File

@@ -0,0 +1,77 @@
<?php
namespace app\admin\model;
use think\Model;
use think\facade\Db;
/**
* Admin模型
* @property int $id 管理员ID
* @property string $username 管理员用户名
* @property string $nickname 管理员昵称
* @property string $email 管理员邮箱
* @property string $mobile 管理员手机号
* @property string $last_login_ip 上次登录IP
* @property string $last_login_time 上次登录时间
* @property int $login_failure 登录失败次数
* @property string $password 密码密文
* @property string $salt 密码盐(废弃待删)
* @property string $status 状态:enable=启用,disable=禁用,...(string存储可自定义其他)
*/
class Admin extends Model
{
/**
* @var string 自动写入时间戳
*/
protected $autoWriteTimestamp = true;
/**
* 追加属性
*/
protected $append = [
'group_arr',
'group_name_arr',
];
public function getGroupArrAttr($value, $row): array
{
return Db::name('admin_group_access')
->where('uid', $row['id'])
->column('group_id');
}
public function getGroupNameArrAttr($value, $row): array
{
$groupAccess = Db::name('admin_group_access')
->where('uid', $row['id'])
->column('group_id');
return AdminGroup::whereIn('id', $groupAccess)->column('name');
}
public function getAvatarAttr($value): string
{
return full_url($value, false, config('buildadmin.default_avatar'));
}
public function setAvatarAttr($value): string
{
return $value == full_url('', false, config('buildadmin.default_avatar')) ? '' : $value;
}
public function getLastLoginTimeAttr($value): string
{
return $value ? date('Y-m-d H:i:s', $value) : '';
}
/**
* 重置用户密码
* @param int|string $uid 管理员ID
* @param string $newPassword 新密码
* @return int|Admin
*/
public function resetPassword(int|string $uid, string $newPassword): int|Admin
{
return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* AdminGroup模型
*/
class AdminGroup extends Model
{
protected $autoWriteTimestamp = true;
}

View File

@@ -0,0 +1,167 @@
<?php
namespace app\admin\model;
use think\facade\Db;
use Throwable;
use think\Model;
use app\admin\library\Auth;
use think\model\relation\BelongsTo;
/**
* AdminLog模型
*/
class AdminLog extends Model
{
protected $autoWriteTimestamp = true;
protected $updateTime = false;
/**
* 自定义日志标题
* @var string
*/
protected string $title = '';
/**
* 自定义日志内容
* @var string|array
*/
protected string|array $data = '';
/**
* 忽略的链接正则列表
* @var array
*/
protected array $urlIgnoreRegex = [
'/^(.*)\/(select|index|logout)$/i',
];
protected array $desensitizationRegex = [
'/(password|salt|token)/i'
];
public static function instance()
{
$request = request();
if (!isset($request->adminLog)) {
$request->adminLog = new static();
}
return $request->adminLog;
}
/**
* 设置标题
* @param string $title
*/
public function setTitle(string $title): void
{
$this->title = $title;
}
/**
* 设置日志内容
* @param string|array $data
*/
public function setData(string|array $data): void
{
$this->data = $data;
}
/**
* 设置忽略的链接正则列表
* @param array|string $regex
*/
public function setUrlIgnoreRegex(array|string $regex = []): void
{
$regex = is_array($regex) ? $regex : [$regex];
$this->urlIgnoreRegex = array_merge($this->urlIgnoreRegex, $regex);
}
/**
* 设置需要进行数据脱敏的正则列表
* @param array|string $regex
*/
public function setDesensitizationRegex(array|string $regex = []): void
{
$regex = is_array($regex) ? $regex : [$regex];
$this->desensitizationRegex = array_merge($this->desensitizationRegex, $regex);
}
/**
* 数据脱敏(只数组,根据数组 key 脱敏)
* @param array|string $data
* @return array|string
*/
protected function desensitization(array|string $data): array|string
{
if (!is_array($data) || !$this->desensitizationRegex) {
return $data;
}
foreach ($data as $index => &$item) {
foreach ($this->desensitizationRegex as $reg) {
if (preg_match($reg, $index)) {
$item = "***";
} elseif (is_array($item)) {
$item = $this->desensitization($item);
}
}
}
return $data;
}
/**
* 写入日志
* @param string $title
* @param string|array|null $data
* @throws Throwable
*/
public function record(string $title = '', string|array $data = null): void
{
$auth = Auth::instance();
$adminId = $auth->isLogin() ? $auth->user_id : 0;
$username = $auth->isLogin() ? $auth->username : request()->param('username', __('Unknown'));
$controller = str_replace('.', '/', request()->controller(true));
$action = request()->action(true);
$path = $controller . '/' . $action;
if ($this->urlIgnoreRegex) {
foreach ($this->urlIgnoreRegex as $item) {
if (preg_match($item, $path)) {
return;
}
}
}
$data = $data ?: $this->data;
if (!$data) {
$data = request()->param('', null, 'trim,strip_tags,htmlspecialchars');
}
$data = $this->desensitization($data);
$title = $title ?: $this->title;
if (!$title) {
$slave_db = Db::connect(config('database.search_library'));
$admin_rule = $slave_db->name('sys_menu');
$controllerTitle = $admin_rule->where('url', $controller)->value('name');
$title = $admin_rule->where('url', $path)->value('name');
$title = $title ?: __('Unknown') . '(' . $action . ')';
$title = $controllerTitle ? ($controllerTitle . '-' . $title) : $title;
}
// 主库写入
$master_db = Db::connect(config('database.z_library'));
$master_db->name('sys_log')->insert([
'username' => $username,
'method' => substr(request()->url(), 0, 1500),
'operation' => $title,
'params' => !is_scalar($data) ? json_encode($data) : $data,
'ip' => request()->ip(),
'time' => 0,
// 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255),
]);
}
public function admin(): BelongsTo
{
return $this->belongsTo(Admin::class);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* AdminRule 模型
* @property int $status 状态:0=禁用,1=启用
*/
class AdminRule extends Model
{
protected $autoWriteTimestamp = true;
public function setComponentAttr($value)
{
if ($value) $value = str_replace('\\', '/', $value);
return $value;
}
}

293
app/admin/model/Cash.php Normal file
View File

@@ -0,0 +1,293 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use ba\Exception;
use think\facade\Db;
use think\Model;
class Cash extends Model
{
public static function statisticsIncomeMoney($time, $flag, $num)
{
$rest = DatabaseRoute::getAllDbData('pay_details', function ($query) use ($time, $flag, $num) {
$query->where(['state' => 1]);
if(!empty($flag)) {
if($flag == 1) {
$query->whereTime('create_time', '>=', strtotime(date('Y-m-d 00:00:00', strtotime($time))));
$query->whereTime('create_time', '<=', strtotime(date('Y-m-d 23:59:59', strtotime($time))));
}
if($flag == 2) {
$query->whereTime('create_time', '>=', strtotime(date('Y-m-01 00:00:00', strtotime($time))));
$query->whereTime('create_time', '<=', strtotime(date('Y-m-t 23:59:59', strtotime($time))));
}
if($flag == 3) {
$query->whereTime('create_time', '>=', strtotime(date('Y-01-01 00:00:00', strtotime($time))));
$query->whereTime('create_time', '<=', strtotime(date('Y-12-31 23:59:59', strtotime($time))));
}
}
return $query;
})->sum('money');
return $rest;
}
public static function selectPayDetails($get)
{
return DatabaseRoute::paginateAllDb('pay_details', function ($query)use($get){
$query->alias('s')
->field([
's.id',
's.classify',
's.order_id as orderId',
's.money',
's.user_id as userId',
's.pay_diamond as payDiamond',
's.diamond',
's.state',
's.create_time as createTime',
's.pay_time as payTime',
'u.user_name as userName',
'u.phone'
])
->leftJoin('tb_user u', 'u.user_id = s.user_id');
// 添加动态查询条件
if (!empty($get['startTime']) && !empty($get['endTime'])) {
$query->whereBetween('s.create_time', [$get['startTime'], $get['endTime']]);
}
if (!empty($get['userName'])) {
$query->where('u.user_name', 'like', "%{$get['userName']}%");
}
if (!empty($get['orderId'])) {
$query->where('s.order_id', 'like', "%{$get['orderId']}%");
}
if (isset($get['userId']) && $get['userId'] !== null) {
$query->where('u.user_id', $get['userId']);
}
if (isset($get['state']) && $get['state'] !== -1) {
$query->where('s.state', $get['state']);
} elseif (!isset($get['state']) || $get['state'] === -1) {
$query->where('s.state', '<>', -1);
}
return $query;
}, $get['page'], $get['limit'], 's.create_time');
}
public static function selectCashOutList($page, $limit, $cashOut, $isApp = false):array
{
$cashOutList = DatabaseRoute::paginateAllDb('cash_out', function ($query)use($page, $limit, $cashOut, $isApp){
// 根据请求端设置不同查询条件
if ($isApp) {
// APP端查询用户自身的提现记录用户类型1
$query->where('user_id', $cashOut['user_id'] ?? 0)
->where('user_type', 1);
} else {
// 管理后台:根据条件查询
if (isset($cashOut['user_id'])) {
$query->where('user_id', $cashOut['user_id']);
} else {
if (!isset($cashOut['sys_user_id'])) {
return $query;
} else {
// 查询系统用户的提现记录用户类型2
$query->where('user_id', $cashOut['sys_user_id'])
->where('user_type', 2);
}
}
}
return $query;
}, $page, $limit, 'create_at');
if (!$isApp) {
// 管理后台:补充用户信息和统计数据
$userIdList = [];
foreach ($cashOutList['list'] as $out) {
$userIdList[] = $out['user_id'];
}
// 查询用户提现总数和总金额
$cashoutSumMap = [];
$cashoutVerifySumMap = [];
$userinfoMap = [];
if (!empty($userIdList)) {
// 获取已完成提现统计
$cashoutSumList = \app\api\model\Cash::selectSumByUserIdList($userIdList, 1);
$cashoutSumMap = array_column($cashoutSumList, null, 'user_id');
// 获取审核中提现统计
$cashoutVerifyList = \app\api\model\Cash::selectSumByUserIdList($userIdList, 3);
$cashoutVerifySumMap = array_column($cashoutVerifyList, null, 'user_id');
// 获取用户信息
$userList = DatabaseRoute::getAllDbData('tb_user', function ($query) use($userIdList) {
return $query->whereIn('user_id', $userIdList)
->field('user_id, user_name');
})->select();
$userinfoMap = array_column($userList->toArray(), 'user_name', 'user_id');
}
// 补充数据到提现记录
foreach ($cashOutList['list'] as &$item) {
$info = $cashoutSumMap[$item['user_id']] ?? null;
$info2 = $cashoutVerifySumMap[$item['user_id']] ?? null;
$item['user_name'] = $userinfoMap[$item['user_id']] ?? '';
$item['count'] = $info ? $info['count'] : 0;
$item['total'] = $info ? $info['total'] : 0.00;
$item['verify_count'] = $info2 ? $info2['count'] : 0;
$item['verify_total'] = $info2 ? $info2['total'] : 0.00;
}
}
if ($isApp) {
// APP端对敏感信息进行脱敏处理
foreach ($cashOutList['list'] as &$item) {
if (!empty($item['bank_name'])) {
// 银行卡号脱敏
$item['zhifubao'] = bankCard($item['zhifubao']);
} elseif (filter_var($item['zhifubao'], FILTER_VALIDATE_EMAIL)) {
// 邮箱脱敏
$item['zhifubao'] = email($item['zhifubao']);
} elseif (preg_match('/^1[3-9]\d{9}$/', $item['zhifubao'])) {
// 手机号脱敏
$item['zhifubao'] = maskPhoneNumber($item['zhifubao']);
}
}
}
return $cashOutList;
}
/**
* 退回提现金额
* @param array $entity 提现实体
* @throws Exception
*/
public static function backCashAmount($entity, $db)
{
// 开启事务确保数据一致性
$db->startTrans();
try {
if ($entity['user_type'] == 2) {
// 代理用户退款逻辑
$detailsData = [
'user_id' => $entity['user_id'],
'operate_id' => $entity['user_id'],
'title' => "提现失败存入余额",
'type' => 4,
'money_type' => 1,
'money' => $entity['money'],
'content' => "提现失败存入余额{$entity['money']}",
'status' => 1,
'create_time' => date('Y-m-d H:i:s')
];
// 记录资金流水
$db->name('sys_user_money_details')->insert($detailsData);
// 更新代理账户余额(增加余额)
self::updateSysMoney(1, $entity['user_id'], $entity['money']);
} else {
// 普通用户退款逻辑
self::updateByUserId($entity, $db);
$detailsData = [
'user_id' => $entity['user_id'],
'sys_user_id' => $entity['sys_user_id'] ?? null,
'title' => "[提现退款]",
'type' => 4,
'money_type' => 1,
'money' => $entity['money'],
'content' => "提现失败,自动退款{$entity['money']}",
'status' => 1,
'cash_out_id' => $entity['id'],
'create_time' => date('Y-m-d H:i:s')
];
// 记录资金流水
$db->name('user_money_details')->insert($detailsData);
// 归还用户余额
self::updateAmount(1, $entity['user_id'], $entity['money'], $db);
}
// 提交事务
$db->commit();
} catch (Exception $e) {
// 回滚事务
$db->rollback();
throw $e;
}
}
public static function updateSysMoney($type, $userId, $money)
{
$query = Db::name('sys_user_money')
->where('user_id', $userId);
// 根据类型决定是增加还是减少余额
if ($type == 1) {
// 增加余额
return $query->inc('money', $money)->update();
} elseif ($type == 2) {
// 减少余额
return $query->dec('money', $money)->update();
}
return 0; // 无效类型返回 0
}
public static function updateAmount($type, $userId, $amount, $db)
{
User::selectUserMoneyByUserId($userId);
// 构建基础查询
$query = $db->name('user_money')
->where('user_id', $userId);
// 根据类型执行增减操作
if ($type == 1) {
// 增加金额amount = amount + #{amount}
return $query->inc('amount', $amount)->update();
} elseif ($type == 2) {
// 减少金额amount = amount - #{amount}
// 可选:添加余额充足校验
return $query->where('amount', '>=', $amount) // 确保余额不小于要减少的金额
->dec('amount', $amount)
->update();
}
return 0; // 无效类型返回0
}
public static function updateByUserId($entity, $db)
{
// 验证userId是否存在
if (empty($entity['user_id'])) {
throw new Exception("cashOut修改失败: userId必须传递");
}
// 构建更新条件
$conditions = [
'user_id' => $entity['user_id'],
'id' => $entity['id']
];
// 过滤掉主键和条件字段,避免更新这些字段
$updateData = $entity;
unset($updateData['user_id'], $updateData['id']);
// 执行更新操作
$db->name('cash_out')
->where($conditions)
->update($updateData);
}
}

133
app/admin/model/Config.php Normal file
View File

@@ -0,0 +1,133 @@
<?php
namespace app\admin\model;
use Throwable;
use think\Model;
use think\facade\Cache;
/**
* 系统配置模型
* @property mixed $content
* @property mixed $rule
* @property mixed $extend
* @property mixed $allow_del
*/
class Config extends Model
{
public static string $cacheTag = 'sys_config';
protected $append = [
'value',
'content',
'extend',
'input_extend',
];
protected array $jsonDecodeType = ['checkbox', 'array', 'selects'];
protected array $needContent = ['radio', 'checkbox', 'select', 'selects'];
/**
* 入库前
* @throws Throwable
*/
public static function onBeforeInsert(Config $model): void
{
if (!in_array($model->getData('type'), $model->needContent)) {
$model->content = null;
} else {
$model->content = json_encode(str_attr_to_array($model->getData('content')));
}
if (is_array($model->rule)) {
$model->rule = implode(',', $model->rule);
}
if ($model->getData('extend') || $model->getData('inputExtend')) {
$extend = str_attr_to_array($model->getData('extend'));
$inputExtend = str_attr_to_array($model->getData('inputExtend'));
if ($inputExtend) $extend['baInputExtend'] = $inputExtend;
if ($extend) $model->extend = json_encode($extend);
}
$model->allow_del = 1;
}
/**
* 写入后
*/
public static function onAfterWrite(): void
{
// 清理配置缓存
Cache::tag(self::$cacheTag)->clear();
}
public function getValueAttr($value, $row)
{
if (!isset($row['type']) || $value == '0') return $value;
if (in_array($row['type'], $this->jsonDecodeType)) {
return empty($value) ? [] : json_decode($value, true);
} elseif ($row['type'] == 'switch') {
return (bool)$value;
} elseif ($row['type'] == 'editor') {
return !$value ? '' : htmlspecialchars_decode($value);
} elseif (in_array($row['type'], ['city', 'remoteSelects'])) {
if (!$value) return [];
if (!is_array($value)) return explode(',', $value);
return $value;
} else {
return $value ?: '';
}
}
public function setValueAttr(mixed $value, $row): mixed
{
if (in_array($row['type'], $this->jsonDecodeType)) {
return $value ? json_encode($value) : '';
} elseif ($row['type'] == 'switch') {
return $value ? '1' : '0';
} elseif ($row['type'] == 'time') {
return $value ? date('H:i:s', strtotime($value)) : '';
} elseif ($row['type'] == 'city') {
if ($value && is_array($value)) {
return implode(',', $value);
}
return $value ?: '';
} elseif (is_array($value)) {
return implode(',', $value);
}
return $value;
}
public function getContentAttr($value, $row)
{
if (!isset($row['type'])) return '';
if (in_array($row['type'], $this->needContent)) {
$arr = json_decode($value, true);
return $arr ?: [];
} else {
return '';
}
}
public function getExtendAttr($value)
{
if ($value) {
$arr = json_decode($value, true);
if ($arr) {
unset($arr['baInputExtend']);
return $arr;
}
}
return [];
}
public function getInputExtendAttr($value, $row)
{
if ($row && $row['extend']) {
$arr = json_decode($row['extend'], true);
if ($arr && isset($arr['baInputExtend'])) {
return $arr['baInputExtend'];
}
}
return [];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* Log
*/
class CrudLog extends Model
{
// 表名
protected $name = 'crud_log';
// 自动写入时间戳字段
protected $autoWriteTimestamp = true;
protected $updateTime = false;
protected $type = [
'table' => 'array',
'fields' => 'array',
];
}

View File

@@ -0,0 +1,15 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* DataRecycle 模型
*/
class DataRecycle extends Model
{
protected $name = 'security_data_recycle';
protected $autoWriteTimestamp = true;
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\admin\model;
use think\Model;
use think\model\relation\BelongsTo;
/**
* DataRecycleLog 模型
*/
class DataRecycleLog extends Model
{
protected $name = 'security_data_recycle_log';
protected $autoWriteTimestamp = true;
protected $updateTime = false;
public function recycle(): BelongsTo
{
return $this->belongsTo(DataRecycle::class, 'recycle_id');
}
public function admin(): BelongsTo
{
return $this->belongsTo(Admin::class, 'admin_id');
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use ba\Exception;
use think\facade\Db;
use think\facade\Log;
use think\Model;
/**
* UserGroup 模型
*/
class DiscSpinning extends Model
{
public static function updateBatchById(array $entityList, int $batchSize = 50)
{
// 验证实体列表非空
if (empty($entityList)) {
throw new Exception("error: entityList must not be empty");
}
// 获取主键字段名(默认假设为 'id',可根据实际情况调整)
$primaryKey = 'id';
$modelName = 'disc_spinning';
// 开启事务确保数据一致性
Db::startTrans();
try {
$count = 0;
foreach ($entityList as $entity) {
// 验证实体包含主键
if (!isset($entity[$primaryKey])) {
throw new Exception("Entity must contain primary key '{$primaryKey}'");
}
// 构建更新数据(排除主键字段)
$updateData = array_diff_key($entity, [$primaryKey => null]);
// 执行更新使用模型或Db类
Db::name($modelName)
->where($primaryKey, $entity[$primaryKey])
->update($updateData);
// 每batchSize条记录刷新一次提交部分事务
$count++;
if ($count % $batchSize === 0) {
Db::commit();
Db::startTrans(); // 重新开启事务
}
}
// 提交剩余事务
Db::commit();
return true;
} catch (Exception $e) {
// 回滚事务
Db::rollback();
throw $e;
}
}
public static function receive1($receive)
{
$userId = $receive['user_id'] ?? 0;
$drawCount = self::countDraw($userId);
$maxDraws = Db::name('common_info')
->where('type', 901)
->value('value');
// 校验是否超过限制
if ($drawCount > $maxDraws) {
Log::write('超过限制' . $receive['id'] . '/' . $drawCount);
return false; // 超过次数限制,终止处理
}
// 查询抽奖记录
$recordId = $receive['id'] ?? 0;
$db = Db::connect(DatabaseRoute::getConnection('disc_spinning_record', ['user_id' => $userId]));
$record = $db->name('disc_spinning_record')->find($recordId);
// 校验记录是否已处理
if (!empty($record['target_id'])) {
Log::write('记录已处理无需继续处理' . $record['id'] . '/' . $record['target_id']);
return false; // 已处理,终止处理
}
self::receiveAsync($record);
}
public static function countDraw($userId)
{
return DatabaseRoute::getDb('disc_spinning_record', $userId)->where('source', 'order')->where('draw_day', date('Y-m-d'))
->count();
}
public static function receiveAsync($receive)
{
Log::write('正式补偿' . $receive['id']);
// 校验奖励类型必须为2
if (($receive['type'] ?? 0) != 2) {
Log::info("非现金转盘奖励type={$receive['type']}");
return false;
}
$db_name = DatabaseRoute::getConnection('tb_user', ['user_id' => $receive['user_id']], true);
$db = Db::connect($db_name);
// 获取用户信息
$userInfo = $db->name('tb_user')->where('user_id', $receive['user_id'])->find();
if (!$userInfo || $userInfo['status'] == 0) {
Log::info("用户状态无效user_id={$receive['user_id']}");
return false;
}
// 开启事务确保数据一致性
$db->startTrans();
try {
// 创建资金流水记录
$moneyDetails = [
'user_id' => $receive['user_id'],
'title' => "[现金大转盘]",
'type' => 1,
'money_type' => 1,
'money' => $receive['number'],
'content' => "现金红包奖励{$receive['number']}",
'source_id' => $receive['id'],
'create_time' => date('Y-m-d H:i:s', time() - 1) // 上一秒时间
];
$detailId = $db->name('user_money_details')->insertGetId($moneyDetails);
// 更新奖励记录
$a = $db->name('disc_spinning_record')
->where('id', $receive['id'])
->update([
'target' => "2",
'target_id' => $detailId
]);
Log::write('更新奖励' . $a);
Cash::updateAmount(1, $receive['user_id'], $receive['number'], $db);
// 提交事务
$db->commit();
return true;
} catch (\Exception $e) {
// 回滚事务
$db->rollback();
Log::error("现金转盘奖励处理失败:{$e->getMessage()}");
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use think\facade\Db;
use Throwable;
use think\Model;
use think\facade\Cache;
class MessageInfo extends Model
{
public static function selectMessageList($params)
{
// 解析查询参数
$userId = $params['userId'] ?? null;
$state = $params['state'] ?? null;
$type = $params['type'] ?? null;
$pageNum = $params['page'] ?? 1;
$pageSize = $params['limit'] ?? 10;
$query = Db::connect(get_slave_connect_name())->name('message_info');
// 添加条件(仅当参数不为空时)
if ($userId !== null) {
$query = $query->where('user_id', $userId);
}
if ($state !== null) {
$query = $query->where('state', $state);
}
if ($type !== null) {
$query = $query->where('type', $type);
}
$total = $query->count();
// 构建查询
$messageList = $query->order('create_at', 'desc')->limit(page($pageNum, $pageSize), $pageSize)->select()->toArray();
// 关联用户信息
foreach ($messageList as &$message) {
if ($message['user_id'] !== null) {
$user = DatabaseRoute::getDb('tb_user', $message['user_id'])->find();
$message['user_entity'] = $user ?: null;
}
}
return [
'list' => $messageList,
'totalCount' => $total,
'totalPage' => (int)ceil($total / $pageSize),
'currPage' => $pageNum,
'pageSize' => $pageSize,
];
}
}

490
app/admin/model/Order.php Normal file
View File

@@ -0,0 +1,490 @@
<?php
namespace app\admin\model;
use app\api\model\UserMoney;
use app\common\library\DatabaseRoute;
use think\facade\Db;
use think\Model;
class Order extends Model
{
public static function selectOrdersCountStatisticsByYear($flag, $time, $status)
{
return DatabaseRoute::getAllDbData('orders', function ($query)use($flag, $time, $status) {
// 添加状态条件
if (!is_null($status) && $status != 0) {
$query->where('status', $status);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
return $query;
})->count();
}
public static function selectFenXiaoMoney($type, $sysUserId, $flag, $time)
{
$result = DatabaseRoute::getAllDbData('orders', function($query)use($type, $sysUserId, $flag, $time) {
$query->where('status', 1); // 固定条件订单状态为1已完成
// 2. 根据类型设置聚合字段处理null值为0.00
switch ($type) {
case 1:
$query->field('sum(ifnull(one_money, 0.00)) as total'); // 一级分销金额
break;
case 2:
$query->field('sum(ifnull(two_money, 0.00)) as total'); // 二级分销金额
break;
case 3:
$query->field('sum(ifnull(qd_money, 0.00)) as total'); // 渠道分销金额
break;
default:
throw new \InvalidArgumentException("无效的金额类型:{$type}");
}
// 3. 添加系统用户ID条件
if (!is_null($sysUserId)) {
$query->where('sys_user_id', $sysUserId);
}
// 4. 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配
$query->whereRaw("date_format(create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配
$query->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配
$query->whereRaw("date_format(create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
throw new \InvalidArgumentException("无效的时间标志:{$flag}");
}
}
return $query;
})->find();
return $result['total'] ?? 0.00;
}
public static function selectOrdersCount($status, $orderType, $flag, $time, $sysUserId)
{
return DatabaseRoute::getAllDbData('orders', function($query)use($status, $orderType, $flag, $time, $sysUserId) {
$query->where('pay_way', 9);
// 添加系统用户ID条件排除sysUserId=1的情况
if (!is_null($sysUserId) && $sysUserId != 1) {
$query->where('sys_user_id', $sysUserId);
}
// 添加订单状态条件
if (!is_null($status)) {
$query->where('status', $status);
}
// 添加订单类型条件
if (!is_null($orderType)) {
$query->where('orders_type', $orderType);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
return $query;
})->count();
}
public static function selectOrdersMoney($status, $orderType, $flag, $time, $courseId, $sysUserId)
{
$result = DatabaseRoute::getAllDbData('orders', function($query)use($status, $orderType, $flag, $time, $sysUserId, $courseId) {
// 初始化查询
$query->where('pay_way', 9) // 固定条件支付方式为9
->where('status', 1) // 固定条件订单状态为1
->field('sum(pay_money) as total'); // 聚合计算总支付金额
// 添加系统用户ID条件
if (!is_null($sysUserId) && $sysUserId != 1) {
$query->where('sys_user_id', $sysUserId);
}
// 添加订单状态条件
if (!is_null($status)) {
$query->where('status', $status);
}
// 添加课程ID条件
if (!is_null($courseId)) {
$query->where('course_id', $courseId);
}
// 添加订单类型条件
if (!is_null($orderType)) {
$query->where('orders_type', $orderType);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
return $query;
})->find();
return (float)$result['total'] ?? 0.00;
}
public static function selectSignInAwardMoney($flag, $time, $sysUserId)
{
$db = Db::connect(get_slave_connect_name());
// 初始化查询
$query = $db->name('v_user_money_detail_temp')
->alias('x')
->where('x.classify', 6) // 固定条件分类为6
->where('x.type', 1) // 固定条件类型为1
->where('x.state', 2) // 固定条件状态为2
->where('x.user_id', '<>', 1) // 固定条件用户ID不为1
->where('x.title', '签到奖励') // 固定条件:标题为"签到奖励"
->field('ifnull(sum(x.money), 0) as total'); // 聚合计算总金额
// 添加系统用户ID条件
if (!is_null($sysUserId) && $sysUserId != 1) {
$query = $query->where('x.sys_user_id', $sysUserId);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query = $query->whereRaw("date_format(x.create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query = $query->whereRaw("date_format(x.create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query = $query->whereRaw("date_format(x.create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
// 执行查询并返回结果
$result = $query->find();
return (float)$result['total'];
}
public static function selectShareAwardMoney($flag, $time, $sysUserId)
{
$db = Db::connect(get_slave_connect_name());
// 初始化查询
$query = $db->name('v_user_money_detail_temp')
->alias('x')
->where('x.classify', 6) // 固定条件分类为6
->where('x.type', 1) // 固定条件类型为1
->where('x.state', 2) // 固定条件状态为2
->where('x.user_id', '<>', 1) // 固定条件用户ID不为1
->where('x.title', '分享达标奖励') // 固定条件:标题为"分享达标奖励"
->field('ifnull(sum(x.money), 0) as total'); // 聚合计算总金额
// 添加系统用户ID条件
if (!is_null($sysUserId) && $sysUserId != 1) {
$query->where('x.sys_user_id', $sysUserId);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(x.create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(x.create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(x.create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
// 执行查询并返回结果
$result = $query->find();
return (float)$result['total'];
}
public static function selectNewUserTaskDoneAwardMoney($flag, $time, $sysUserId)
{
$db = Db::connect(get_slave_connect_name());
// 初始化查询
$query = $db->name('v_user_money_detail_temp')
->alias('x')
->where('x.classify', 7) // 固定条件分类为7
->where('x.type', 1) // 固定条件类型为1
->where('x.state', 2) // 固定条件状态为2
->where('x.user_id', '<>', 1) // 固定条件用户ID不为1
->where('x.money_type', 1) // 新增条件金额类型为1
->field('ifnull(sum(x.money), 0) as total'); // 聚合计算总金额
// 添加系统用户ID条件
if (!is_null($sysUserId) && $sysUserId != 1) {
$query->where('x.sys_user_id', $sysUserId);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(x.create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(x.create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(x.create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
// 执行查询并返回结果
$result = $query->find();
return (float)$result['total'];
}
public static function selectInviteTaskDoneAwardMoney($flag, $time, $sysUserId)
{
$db = Db::connect(get_slave_connect_name());
// 初始化查询
$query = $db->name('v_user_money_detail_temp')
->alias('x')
->where('x.classify', 6) // 固定条件分类为6
->where('x.type', 1) // 固定条件类型为1
->where('x.state', 2) // 固定条件状态为2
->where('x.user_id', '<>', 1) // 固定条件用户ID不为1
->where('x.title', '[分享达标额外奖励]') // 固定条件:标题为"[分享达标额外奖励]"
->field('ifnull(sum(x.money), 0) as total'); // 聚合计算总金额
// 添加系统用户ID条件
if (!is_null($sysUserId) && $sysUserId != 1) {
$query->where('x.sys_user_id', $sysUserId);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(x.create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(x.create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(x.create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
// 执行查询并返回结果
$result = $query->find();
return (float)$result['total'];
}
public static function executeExtractCallback(mixed $cashOut, ?array $baseResp)
{
$state = 0;
if (!empty($baseResp['status']) && $baseResp['status'] == 2) {
$state = 1;
}else if (!empty($baseResp['status']) && ($baseResp['status'] == 3 || $baseResp['status'] == 99999)) {
$state = 2;
}
$reason = '';
if (!empty($baseResp['reason']) && $baseResp['reason'] == '已驳回') {
$reason = '提现失败,请检查收款账号与收款人姓名后重试。';
}
if ($state == 1) {
$cashOut['state'] = 1;
$cashOut['out_at'] = getNormalDate();
$cashOut['refund'] = null;
DatabaseRoute::getDb('cash_out', $cashOut['user_id'], true)->where([
'id' => $cashOut['id']
])->update($cashOut);
$userMoney = UserMoney::selectUserMoneyfind($cashOut['user_id']);
if ($userMoney) {
DatabaseRoute::getDb('user_money', $cashOut['user_id'], true)->where([
'id' => $userMoney['id']
])->update([
'cash_count' => $userMoney['cash_count'] + 1,
'cash_amount' => $userMoney['cash_amount'] ?? 0 + $cashOut['amount'],
]);
}
return 1;
}
if ($state == 2) {
// 设置失败状态
$cashOut['out_at'] = date('Y-m-d H:i:s');
$cashOut['state'] = 2;
$cashOut['refund'] = $reason;
// 企业用户
if ($cashOut['user_type'] === 2) {
// 判断是否已经返还过
$count = DatabaseRoute::getDb('sys_user_money_details', $cashOut['user_id'])->where([
'user_id' => $cashOut['user_id'],
'classify' => 4,
'state' => 2,
'money_type' => 1,
'type' => 1,
'source_id' => $cashOut['id'],
])->count();
if ($count > 0) {
return 0;
}
// 写入返还明细
DatabaseRoute::getDb('sys_user_money_details', $cashOut['user_id'], true)->insert([
'user_id' => $cashOut['user_id'],
'relation_id'=> $cashOut['user_id'],
'title' => '提现失败存入余额',
'classify' => 4,
'money_type' => 1,
'state' => 2,
'money' => $cashOut['money'],
'content' => '提现失败存入余额' . $cashOut['money'] . '元',
'type' => 1,
]);
// 更新余额
$userMoney = SysUserMoney::selectSysUserMoneyByUserId($cashOut['user_id']);
Db::name('sys_user_money')->where([
'id' => $userMoney['id']
])->dec('money', $cashOut['money'])->update();
} else {
// 普通用户
$count = DatabaseRoute::getDb('user_money_details', $cashOut['user_id'])->where([
'user_id' => $cashOut['user_id'],
'classify' => 4,
'state' => 2,
'money_type' => 1,
'type' => 1,
'source_id' => $cashOut['id'],
])->count();
if ($count > 0) {
return 0;
}
// 写入返还明细
DatabaseRoute::getDb('user_money_details', $cashOut['user_id'], true)->insert([
'user_id' => $cashOut['user_id'],
'title' => '提现失败存入余额',
'classify' => 4,
'money_type' => 1,
'state' => 2,
'money' => $cashOut['money'],
'content' => '提现失败存入余额' . $cashOut['money'] . '元',
'type' => 1,
'create_time'=> date('Y-m-d H:i:s'),
'source_id' => $cashOut['id'],
]);
// 更新余额
(new UserMoney())->updateAmount($cashOut['user_id'], $cashOut['money'], false);
}
// 更新提现记录
DatabaseRoute::getDb('cash_out', $cashOut['user_id'], true)->where('user_id', $cashOut->user_id)
->where('id', $cashOut['id'])
->update([
'out_at' => $cashOut['out_at'],
'state' => $cashOut['state'],
'refund' => $cashOut['refund'],
]);
}
return 0;
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use think\Model;
/**
* UserGroup 模型
*/
class PayDetails extends Model
{
protected $autoWriteTimestamp = true;
public static function selectSumPayByClassify($classify, $flag, $time, $payClassify)
{
$result = DatabaseRoute::getAllDbData('pay_details', function ($query) use($time, $flag, $classify, $payClassify){
$query->where('state', 1) // 固定条件state=1
->field('sum(money) as total'); // 聚合计算总金额
// 添加分类条件
if (!is_null($classify)) {
$query->where('classify', $classify);
}
// 添加时间条件
if (!is_null($flag)) {
switch ($flag) {
case 1:
// 按日匹配(精确到天)
$query->whereRaw("date_format(create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$time]);
break;
case 2:
// 按月匹配(精确到月)
$query->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$time]);
break;
case 3:
// 按年匹配(精确到年)
$query->whereRaw("date_format(create_time, '%Y') = date_format(?, '%Y')", [$time]);
break;
default:
// 无效flag不添加时间条件
break;
}
}
// 添加支付分类条件
if (!is_null($payClassify) && $payClassify != 0) {
$query->where('pay_classify', $payClassify);
}
return $query;
})->find();
return $result['total'] ?? 0.0;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* SensitiveData 模型
*/
class SensitiveData extends Model
{
protected $name = 'security_sensitive_data';
protected $autoWriteTimestamp = true;
protected $type = [
'data_fields' => 'array',
];
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\admin\model;
use think\Model;
use think\model\relation\BelongsTo;
/**
* SensitiveDataLog 模型
*/
class SensitiveDataLog extends Model
{
protected $name = 'security_sensitive_data_log';
protected $autoWriteTimestamp = true;
protected $updateTime = false;
public function sensitive(): BelongsTo
{
return $this->belongsTo(SensitiveData::class, 'sensitive_id');
}
public function admin(): BelongsTo
{
return $this->belongsTo(Admin::class, 'admin_id');
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace app\admin\model;
use think\Model;
use think\captcha\facade\Captcha as thinkCaptcha;
class SysCaptcha extends Model
{
public static function getCode($uuid)
{
$code_data = thinkCaptcha::create('czg');
// 保存至数据库
self::create([
'uuid' => $uuid,
'code' => $code_data['code'],
'expire_time' => date('Y-m-d H:i:s', time() + config('captcha.expire_time')),
]);
return ['img' => $code_data['img']];
}
}

103
app/admin/model/SysMenu.php Normal file
View File

@@ -0,0 +1,103 @@
<?php
namespace app\admin\model;
use ba\Exception;
use think\facade\Db;
use think\model;
/**
* 菜单模型
*/
class SysMenu extends model
{
// 菜单类型常量
const MENU_TYPE_CATALOG = 0; // 目录
const MENU_TYPE_MENU = 1; // 菜单
const MENU_TYPE_BUTTON = 2; // 按钮
public static function getMenuList($menu):array
{
$one_menu = [];
$t_menu = [];
$p_list = [];
foreach ($menu as $k => $v) {
if(in_array($v['type'], [0, 1])) {
if($v['parent_id'] == 0) {
$one_menu[] = $v;
}else {
$t_menu[] = $v;
}
}
// 权限处理
if($v['perms'] ) {
if(strpos($v['perms'], ',') !== false) {
foreach (explode(',', $v['perms']) as $item) {
$p_list[] = $item;
}
}else {
$p_list[] = $v['perms'];
}
}
}
foreach ($one_menu as $k => &$one_value) {
foreach ($t_menu as $two_k => $two_value) {
if($two_value['parent_id'] == $one_value['menu_id']) {
$one_value['list'][] = convertToCamelCase($two_value);
}
}
}
$return['menuList'] = convertToCamelCase($one_menu);
$return['permissions'] = $p_list;
return $return;
}
public static function verifyForm($menu)
{
// 验证菜单名称
if (empty($menu['name'])) {
throw new Exception("菜单名称不能为空");
}
// 验证上级菜单
if (!isset($menu['parentId'])) {
throw new Exception("上级菜单不能为空");
}
// 菜单类型为菜单时,验证 URL
if ($menu['type'] == self::MENU_TYPE_MENU) {
if (empty($menu['url'])) {
throw new Exception("菜单URL不能为空");
}
}
// 获取上级菜单类型
$parentType = self::MENU_TYPE_CATALOG;
if ($menu['parentId'] != 0) {
$parentMenu = Db::name('sys_menu')->where(['menu_id' => $menu['parentId']])->find();
if (!$parentMenu) {
throw new Exception("上级菜单不存在");
}
$parentType = $parentMenu['type'];
}
// 目录、菜单类型验证
if ($menu['type'] == self::MENU_TYPE_CATALOG || $menu['type'] == self::MENU_TYPE_MENU) {
if ($parentType != self::MENU_TYPE_CATALOG) {
throw new Exception("上级菜单只能为目录类型");
}
return;
}
// 按钮类型验证
if ($menu['type'] == self::MENU_TYPE_BUTTON) {
if ($parentType != self::MENU_TYPE_MENU) {
throw new Exception("上级菜单只能为菜单类型");
}
return;
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace app\admin\model;
use think\facade\Db;
use think\Model;
class SysUser extends Model
{
}

View File

@@ -0,0 +1,33 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use ba\Random;
use think\facade\Cache;
use think\facade\Db;
use think\Model;
use think\model\relation\BelongsTo;
class SysUserMoney extends Model
{
public static function selectSysUserMoneyByUserId($userId):array
{
$db = Db::connect(get_slave_connect_name());
// 查询用户钱包信息
$userMoney = $db->name('sys_user_money')->where('user_id', $userId)->find();
// 若不存在,则创建新记录
if (is_null($userMoney)) {
$userMoney = [
'user_id' => $userId,
'money' => 0.00,
'id' => Random::generateRandomPrefixedId(19),
];
$id = Db::connect(get_master_connect_name())->name('sys_user_money')->insert($userMoney);
}
return $db->name('sys_user_money')->where('user_id', $userId)->find();
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use think\facade\Cache;
use think\facade\Db;
use think\Model;
use think\model\relation\BelongsTo;
class SysUserMoneyDetails extends Model
{
public static function queryUserMoneyDetails($page, $limit, $sysUserId, $userId, $classify, $type, $moneyType, $viewType)
{
if ($sysUserId !== null) {
$sysUserId = intval($sysUserId);
$db = DatabaseRoute::getDb('sys_user_money_details', $sysUserId);
$total = $db->name('sys_user_money_details')->where('user_id', $sysUserId)->count();
// 系统用户模式:查询系统用户资金明细
$list = $db->name('sys_user_money_details')->where('user_id', $sysUserId)
->order('create_time', 'desc')
->limit(page($page, $limit), $limit)
->select()
->toArray();
return [
'list' => $list,
'totalCount' => $total,
'totalPage' => (int)ceil($total / $limit),
'currPage' => $page,
'pageSize' => $limit,
];
}
if($userId !== null) {
$db = DatabaseRoute::getDb('user_money_details', $userId)->name('user_money_details');
$query = $db->where('user_id', $userId);
if ($classify !== null) {
$query = $query->where('classify', $classify);
}
if ($type !== null) {
$query = $query->where('type', $type);
}
if ($moneyType !== null) {
$query = $query->where('money_type', $moneyType);
}
if ($viewType == 1) {
// 视图类型1特殊分类1和6
$query = $query->whereIn('classify', [1, 6]);
}
$total = $query->count();
$query = $query->limit(page($page, $limit), $limit)
->order('create_time', 'desc')
->select()
->toArray();
return [
'list' => $query,
'totalCount' => $total,
'totalPage' => (int)ceil($total / $limit),
'currPage' => $page,
'pageSize' => $limit,
];
}else {
return DatabaseRoute::paginateAllDb('user_money_details', function ($query)use($page, $limit, $sysUserId, $userId, $classify, $type, $moneyType, $viewType) {
if ($classify !== null) {
$query->where('classify', $classify);
}
if ($type !== null) {
$query->where('type', $type);
}
if ($moneyType !== null) {
$query->where('money_type', $moneyType);
}
if ($viewType == 1) {
// 视图类型1特殊分类1和6
$query->whereIn('classify', [1, 6]);
}
return $query;
}, $page, $limit);
}
}
}

606
app/admin/model/User.php Normal file
View File

@@ -0,0 +1,606 @@
<?php
namespace app\admin\model;
use app\common\library\DatabaseRoute;
use think\facade\Cache;
use think\facade\Db;
use think\Model;
use think\model\relation\BelongsTo;
/**
* User 模型
* @property int $id 用户ID
* @property string password 密码密文
*/
class User extends Model
{
protected $autoWriteTimestamp = true;
public function getAvatarAttr($value): string
{
return full_url($value, false, config('buildadmin.default_avatar'));
}
public function setAvatarAttr($value): string
{
return $value == full_url('', false, config('buildadmin.default_avatar')) ? '' : $value;
}
public function getMoneyAttr($value): string
{
return bcdiv($value, 100, 2);
}
public function setMoneyAttr($value): string
{
return bcmul($value, 100, 2);
}
public function userGroup(): BelongsTo
{
return $this->belongsTo(UserGroup::class, 'group_id');
}
/**
* 重置用户密码
* @param int|string $uid 用户ID
* @param string $newPassword 新密码
* @return int|User
*/
public function resetPassword(int|string $uid, string $newPassword): int|User
{
return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']);
}
public static function queryCourseOrder($page, $limit, $type, $date, $sysUserId):array
{
// 1. 处理时间范围
$timestamp = strtotime($date);
if ($type == 2) {
// 按月统计
$startTime = date('Y-m-01 00:00:00', $timestamp);
$endTime = date('Y-m-t 23:59:59', $timestamp);
} elseif ($type == 3) {
// 按年统计
$startTime = date('Y-01-01 00:00:00', $timestamp);
$endTime = date('Y-12-31 23:59:59', $timestamp);
} else {
// 按日统计
$startTime = date('Y-m-d 00:00:00', $timestamp);
$endTime = date('Y-m-d 23:59:59', $timestamp);
}
// 2. 查询课程订单统计数据(带分页)
$courseList = self::selectGroupCourseId($startTime, $endTime, $page, $limit);
// 3. 提取课程ID集合
$courseIds = array_column($courseList['list'], 'orders_id');
// 4. 批量查询课程信息并构建映射
if (!empty($courseIds)) {
$courseMap = [];
$db = Db::connect(get_slave_connect_name());
$courses = $db->name('course')
->whereIn('course_id', $courseIds)
->field('course_id, title')
->select()
->toArray();
// 构建ID到课程的映射
foreach ($courses as $course) {
$courseMap[$course['course_id']] = $course;
}
// 5. 关联课程名称到订单统计数据
foreach ($courseList['list'] as &$item) {
if (isset($courseMap[$item['orders_id']])) {
$item['coursename'] = $courseMap[$item['orders_id']]['title'];
}
}
unset($item); // 释放引用
$courseList['list'] = convertToCamelCase($courseList['list']);
}
return $courseList;
}
public static function selectGroupCourseId($startTime, $endTime, $page, $limit)
{
return DatabaseRoute::paginateAllDb('orders', function($query) use($startTime, $endTime) {
return $query->alias('o')
->field([
'sum(o.pay_money) as coursemoney',
'count(*) as coursenum',
'o.course_id as courseId'
])
->where('o.status', 1)
->where('o.orders_type', 1)
->whereBetween('o.create_time', [$startTime, $endTime])
->group('o.course_id');
}, $page, $limit, 'coursenum');
}
public static function queryUserCount($type, $date, $platform, $qdCode)
{
// 检查日期是否为空
if (empty($date)) {
// 格式化当前时间注意PHP时间格式符与Java略有不同
$date = date('Y-m-d H:i:s');
}
return DatabaseRoute::getAllDbData('tb_user', function($query) use($type, $date, $platform, $qdCode) {
// 处理时间条件
$dateTime = strtotime($date);
if ($dateTime === false) {
throw new \InvalidArgumentException("无效的日期格式:{$date}");
}
switch ($type) {
case 1:
// 按日统计(精确到天)
$startDate = date('Y-m-d 00:00:00', $dateTime);
$endDate = date('Y-m-d 23:59:59', $dateTime);
$query->whereBetweenTime('create_time', $startDate, $endDate);
break;
case 2:
// 按月统计
$startDate = date('Y-m-01 00:00:00', $dateTime);
$endDate = date('Y-m-t 23:59:59', $dateTime);
$query->whereBetweenTime('create_time', $startDate, $endDate);
break;
case 3:
// 按年统计
$startDate = date('Y-01-01 00:00:00', $dateTime);
$endDate = date('Y-12-31 23:59:59', $dateTime);
$query->whereBetweenTime('create_time', $startDate, $endDate);
break;
default:
// 无效类型,不添加时间条件
break;
}
// 处理平台条件
if (!is_null($platform)) {
$query->where('platform', $platform);
}
// 处理渠道码条件
if (!is_null($qdCode)) {
$query->where('qd_code', $qdCode);
}
return $query;
})->count();
}
public static function queryPayMoney($type, $qdCode)
{
$date = date('Y-m-d H:i:s');
$result = DatabaseRoute::getAllDbData('pay_details', function($query) use($type, $date, $qdCode) {
$query->alias('p')
->leftJoin('tb_user u', 'u.user_id = p.user_id')
->where('p.state', 1) // 支付状态为1成功
->field('sum(p.money) as total_money'); // 聚合计算总金额
// 根据类型添加时间条件匹配date_format的逻辑
switch ($type) {
case 1:
// 按日:日期部分完全匹配
$query->whereRaw("date_format(p.create_time, '%Y-%m-%d') = date_format(?, '%Y-%m-%d')", [$date]);
break;
case 2:
// 按月:年月部分匹配
$query->whereRaw("date_format(p.create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$date]);
break;
case 3:
// 按年:年份部分匹配
$query->whereRaw("date_format(p.create_time, '%Y') = date_format(?, '%Y')", [$date]);
break;
default:
// 默认为空,可根据业务补充默认条件
break;
}
// 可选条件:渠道码
if (!empty($qdCode)) {
$query->where('u.qd_code', $qdCode);
}
return $query;
})->find();
return $result['total_money'] ?? 0.0;
}
public static function userMessage($date, $type, $qdCode, $vipType)
{
// 1. 处理时间条件
$timestamp = strtotime($date);
if ($timestamp === false) {
throw new \InvalidArgumentException("无效的日期格式:{$date}");
}
if ($type == 1) {
// 按日开始00:00:00
$startTime = date('Y-m-d 00:00:00', $timestamp);
} elseif ($type == 2) {
// 按月开始当月1日 00:00:00
$startTime = date('Y-m-01 00:00:00', $timestamp);
} else {
// 按年开始当年1月1日 00:00:00
$startTime = date('Y-01-01 00:00:00', $timestamp);
}
$cachestr = 'userMessageUserIdList';
$userIds = Cache::get($cachestr);
if(!$userIds) {
if (!empty($qdCode)) {
$userIds = DatabaseRoute::getAllDbData('tb_user', function($query) use($qdCode, $startTime) {
$query->where('qd_code', $qdCode);
// 2. 查询符合条件的用户ID集合
$query->where('create_time', '>=', $startTime)
->field('user_id');
return $query;
})->column('user_id');
}
// 3. 若用户ID集合为空直接返回0
if (empty($userIds)) {
return 0;
}
Cache::set($cachestr, json_encode($userIds));
}else {
$userIds = json_decode($userIds, true);
}
$db = Db::connect(get_slave_connect_name());
// 4. 查询符合条件的VIP用户数量
$query = $db->name('user_vip');
if($userIds) {
$query = $query->whereIn('user_id', $userIds);
}
$query = $query->where('is_vip', 2);
if (!is_null($vipType)) {
$query = $query->where('vip_type', $vipType);
}
return $query->count();
}
/**
* 查询今日支付和提现统计信息
* @return array 包含支付金额、支付次数、提现金额、提现次数的关联数组
*/
public static function queryPayAndExtractInfo()
{
// 1. 计算今日开始和结束时间
$beginOfDay = date('Y-m-d 00:00:00'); // 今日0点
$endOfDay = date('Y-m-d 23:59:59'); // 今日23点59分59秒
// 2. 查询今日支付信息
$payInfo = self::queryPayInfo($beginOfDay, $endOfDay);
// 3. 查询今日提现信息
$extractInfo = self::queryExtractInfo($beginOfDay, $endOfDay);
// 4. 合并结果
return [
'payAmount' => $payInfo['totalMoney'] ?? null,
'payCount' => $payInfo['totalCount'] ?? null,
'extractAmount' => $extractInfo['totalMoney'] ?? null,
'extractCount' => $extractInfo['totalCount'] ?? null
];
}
/**
* 查询指定时间范围内的支付信息
* @param string $begin 开始时间格式Y-m-d H:i:s
* @param string $end 结束时间格式Y-m-d H:i:s
* @return array 支付统计数据
*/
private static function queryPayInfo($begin, $end)
{
return DatabaseRoute::getAllDbData('orders', function($query) use($begin, $end) {
return $query->where('create_time', 'between', [$begin, $end])
->where('status', 1) // 假设1表示支付成功
->where('pay_way', 9) // 假设1表示支付成功
->field([
'SUM(pay_money) as totalMoney', // 总支付金额
'COUNT(1) as totalCount' // 支付次数
]);
})->find() ?: [];
}
/**
* 查询指定时间范围内的提现信息
* @param string $begin 开始时间格式Y-m-d H:i:s
* @param string $end 结束时间格式Y-m-d H:i:s
* @return array 提现统计数据
*/
private static function queryExtractInfo($begin, $end)
{
return DatabaseRoute::getAllDbData('cash_out', function($query) use($begin, $end) {
return $query->where('create_at', 'between', [$begin, $end])
->where('state', 1)
->field([
'SUM(money) as totalMoney', // 总提现金额
'COUNT(1) as totalCount' // 提现次数
]);
})->find() ?: [];
}
public static function selectUserPage($page, $limit, $phone, $sex, $platform, $sysPhone, $status, $member,
$inviterCode, $userName, $invitationCode, $startTime, $endTime, $qdCode, $sysUserName, $vipType, $delegate)
{
$result = DatabaseRoute::paginateAllDb('tb_user', function ($query) use($page, $limit, $phone, $sex, $platform, $sysPhone, $status, $member,
$inviterCode, $userName, $invitationCode, $startTime, $endTime, $qdCode, $sysUserName, $vipType, $delegate) {
// 初始化查询
$query->alias('u')
// 左连接sys_user表别名s
->leftJoin('sys_user s', 's.qd_code = u.qd_code')
// 左连接user_money表别名m
->leftJoin('user_money m', 'm.user_id = u.user_id')
// 固定条件s.sys_user_id is null
->where('s.sys_user_id', null)
// 字段选择与原SQL一致
->field([
'u.*',
'1 as member',
's.username as sysUserName',
'm.cash_count as cashCount',
'm.cash_amount as cashAmount',
'm.amount as balance'
]);
// 搜索条件user_id/phone/user_name匹配
if (!is_null($phone) && $phone !== '') {
$query->where(function ($query) use ($phone) {
$query->where('u.user_id', $phone)
->whereOr('u.phone', $phone)
->whereOr('u.user_name', $phone);
});
}
// 系统用户名模糊查询
if (!is_null($sysUserName) && $sysUserName !== '') {
$query->where('s.username', 'like', "%{$sysUserName}%");
}
// 用户名模糊查询
if (!is_null($userName) && $userName !== '') {
$query->where('u.user_name', 'like', "%{$userName}%");
}
// 性别筛选非0值
if (!is_null($sex) && $sex != 0) {
$query->where('u.sex', $sex);
}
// 平台筛选
if (!is_null($platform) && $platform !== '') {
$query->where('u.platform', $platform);
}
// 系统手机号筛选
if (!is_null($sysPhone) && $sysPhone !== '') {
$query->where('u.sys_phone', $sysPhone);
}
// 邀请人编码模糊查询
if (!is_null($inviterCode) && $inviterCode !== '') {
$query->where('u.inviter_code', 'like', "%{$inviterCode}%");
}
// 邀请码模糊查询
if (!is_null($invitationCode) && $invitationCode !== '') {
$query->where('u.invitation_code', 'like', "%{$invitationCode}%");
}
// 渠道码精确匹配
if (!is_null($qdCode) && $qdCode !== '') {
$query->where('u.qd_code', $qdCode);
}
// 时间范围筛选
if (!is_null($startTime) && $startTime !== '' && !is_null($endTime) && $endTime !== '') {
// 开始时间和结束时间都存在
$query->whereBetween('u.create_time', [$startTime, $endTime]);
} elseif (!is_null($startTime) && $startTime !== '') {
// 仅开始时间
$query->where('u.create_time', '>=', $startTime);
} elseif (!is_null($endTime) && $endTime !== '') {
// 仅结束时间
$query->where('u.create_time', '<=', $endTime);
}
// 邀请人数筛选delegate
if (!is_null($delegate)) {
if ($delegate == 0) {
// 邀请人数=0
$query->where('u.invite_count', 0);
} elseif ($delegate == 1) {
// 邀请人数>0
$query->where('u.invite_count', '>', 0);
}
}
return $query;
}, $page, $limit, 'u.create_time');
return $result;
}
public static function upUserBlack($user, $status, $db)
{
$userId = $user['user_id']; // 获取用户ID
if ($status == 0) {
// 拉黑操作设置状态为0并更新
$db->name('tb_user')->where(['user_id' => $userId])->update(['status' => 0]);
return true;
}
// 解除拉黑操作设置状态为1平台为h5并更新
$db->name('tb_user')->where(['user_id' => $userId])->update(['status' => 1, 'platform' => 'h5']);
// 查询用户信息(身份证号)
$userInfo = $db->name('user_info')->where('user_id', $userId)->find();
// 若存在身份证号,则删除黑名单记录
if (!is_null($userInfo) && !empty($userInfo['cert_no'])) {
Db::connect(get_master_connect_name())->name('tb_user_blacklist')
->where('id_card_no', $userInfo['cert_no'])
->delete();
}
return true;
}
public static function selectInviteMoneyByUserId($user_id, $db)
{
return $db->name('invite_money')->where(['user_id' => $user_id])->find();
}
public static function instantselectSumPay($date, $userId, $db)
{
$startTime = date('Y-m-01 00:00:00', strtotime($date));
$endTime = date('Y-m-t 23:59:59', strtotime($date));
$sumMoney = $db->name('pay_details')
->where('create_time', '>', $startTime) // 创建时间大于开始时间
->where('create_time', '<', $endTime) // 创建时间小于结束时间
->where('state', 1) // 支付状态为1成功
->where('user_id', $userId) // 指定用户ID
->sum('money'); // 计算金额总和
return $sumMoney !== null ? (float)$sumMoney : 0.00;
}
public static function monthIncome($date, $userId, $db)
{
// 构建查询
$sumMoney = $db->name('user_money_details')
->where('user_id', $userId) // 固定条件用户ID匹配
->where('classify', 4) // 固定条件分类为4
->where('type', 2) // 固定条件类型为2
->where('state', 2) // 固定条件状态为2
// 时间条件当月匹配与原SQL的date_format逻辑一致
->whereRaw("date_format(create_time, '%Y-%m') = date_format(?, '%Y-%m')", [$date])
->sum('money'); // 计算金额总和
// 处理空值并保留两位小数
return $sumMoney !== null ? number_format($sumMoney, 2) : '0.00';
}
public static function queryInviterCount($inviterCode)
{
return DatabaseRoute::getAllDbData('tb_user', function($query) use($inviterCode) {
return $query->where('inviter_code', $inviterCode);
})->count();
}
public static function selectUserVipByUserId($userId)
{
return Db::connect(get_slave_connect_name())->name('user_vip')->where(['user_id' => $userId])->find();
}
public static function selectUserMoneyByUserId($userId)
{
$db_name = DatabaseRoute::getConnection('user_money', ['user_id' => $userId]);
$db = Db::connect($db_name);
// 查询用户钱包信息
$userMoney = $db->name('user_money')->where('user_id', $userId)->find();
// 若不存在,则创建新记录
if (is_null($userMoney)) {
$db_name = DatabaseRoute::getConnection('user_money', ['user_id' => $userId], true);
$userMoney = [
'user_id' => $userId,
'money' => 0.00,
'amount' => 0.00,
];
Db::connect($db_name)->name('user_money')->insert($userMoney);
}
return $userMoney;
}
public static function userListExcel($startTime, $endTime, $page = 1, $limit = 20, $userEntity = [])
{
$list = DatabaseRoute::getAllDbData('tb_user', function ($query) use ($startTime, $endTime, $page, $limit, $userEntity) {
$query->alias('u');
// 处理 phone 条件
if (!empty($userEntity['phone'])) {
$query->where('u.phone', 'like', "%{$userEntity['phone']}%");
}
// 处理 userName 条件
if (!empty($userEntity['userName'])) {
$query->where('u.user_name', 'like', "%{$userEntity['userName']}%");
}
// 处理 invitationCode 条件
if (!empty($userEntity['invitationCode'])) {
$query->where('u.invitation_code', 'like', "%{$userEntity['invitationCode']}%");
}
// 处理 inviterCode 条件
if (!empty($userEntity['inviterCode'])) {
$query->where('u.inviter_code', 'like', "%{$userEntity['inviterCode']}%");
}
// 处理 platform 条件
if (!empty($userEntity['platform'])) {
$query->where('u.platform', $userEntity['platform']);
}
// 处理时间范围条件
if (!empty($startTime) && !empty($endTime)) {
$query->whereTime('u.create_time', 'between', [$startTime, $endTime]);
} elseif (!empty($startTime)) {
$query->whereTime('u.create_time', '>=', $startTime);
} elseif (!empty($endTime)) {
$query->whereTime('u.create_time', '<=', $endTime);
}
if (!empty($page) && !empty($limit)) {
$query->limit(page($page, $limit), $limit);
}
return $query;
})->select()->toArray();
$export = new \alei\Export('用户列表');
$export->setColumn([
['field' => 'user_id', 'title' => '用户ID'],
['field' => 'user_name', 'title' => '用户名'], //格式化时间,时间戳格式化为时间日期格式,默认格式: “Y-m-d H:i:s”
['field' => 'phone', 'title' => '手机号'],
['field' => 'sys_phone', 'title' => '手机类型 1安卓 2ios'],
['field' => 'jifen', 'title' => '积分'],
['field' => 'invitation_code', 'title' => '邀请码'],
['field' => 'inviter_code', 'title' => '邀请人邀请码'],
['field' => 'zhi_fu_bao_name', 'title' => '支付宝名称'],
['field' => 'zhi_fu_bao', 'title' => '支付宝账号'],
['field' => 'cert_name', 'title' => '姓名'],
['field' => 'cert_no', 'title' => '身份证号码'],
['field' => 'create_time', 'title' => '创建时间'],
]);
//设置数据
$export->setData($list);
//生成表格返回url
$url = $export->build(); //'export/文章.xlsx'
return ['data' => config('buildadmin.run_api_url') . $url];
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace app\admin\model;
use think\Model;
/**
* UserGroup 模型
*/
class UserGroup extends Model
{
protected $autoWriteTimestamp = true;
}

View File

@@ -0,0 +1,57 @@
<?php
namespace app\admin\model;
use think\facade\Db;
use think\Model;
/**
* UserGroup 模型
*/
class UserIntegral extends Model
{
public static function selectUserIntegralDetailsByUserId($page, $limit, $userId)
{
$query = Db::connect(get_slave_connect_name())->name('user_integral_details');
// 添加用户ID条件如果不为空
if ($userId !== null) {
$query = $query->where('user_id', $userId);
}
$count = $query->count();
$query = $query->order('create_time', 'desc')->limit(page($page, $limit), $limit)->select()->toArray();
return [
'currPage' => $page,
'pageSize' => $limit,
'list' => convertToCamelCase($query),
'totalCount' => $count,
'totalPage' => ceil($count / $limit),
];
}
public static function updateIntegral($type, $userId, $num, $db)
{
$db = $db->name('user_integral');
$query = $db->where('user_id', $userId);
// 根据类型决定是增加还是减少积分
if ($type == 1) {
// 增加积分
$query->inc('integral_num', $num);
} elseif ($type == 2) {
// 减少积分
$query->where('integral_num', '>=', $num);
$query->dec('integral_num', $num);
}
// 执行更新
return $query->update();
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace app\admin\model;
use Throwable;
use think\model;
use think\Exception;
use think\model\relation\BelongsTo;
/**
* UserMoneyLog 模型
* 1. 创建余额日志自动完成会员余额的添加
* 2. 创建余额日志时,请开启事务
*/
class UserMoneyLog extends model
{
protected $autoWriteTimestamp = true;
protected $updateTime = false;
/**
* 入库前
* @throws Throwable
*/
public static function onBeforeInsert($model): void
{
$user = User::where('id', $model->user_id)->lock(true)->find();
if (!$user) {
throw new Exception("The user can't find it");
}
if (!$model->memo) {
throw new Exception("Change note cannot be blank");
}
$model->before = $user->money;
$user->money += $model->money;
$user->save();
$model->after = $user->money;
}
public static function onBeforeDelete(): bool
{
return false;
}
public function getMoneyAttr($value): string
{
return bcdiv($value, 100, 2);
}
public function setMoneyAttr($value): string
{
return bcmul($value, 100, 2);
}
public function getBeforeAttr($value): string
{
return bcdiv($value, 100, 2);
}
public function setBeforeAttr($value): string
{
return bcmul($value, 100, 2);
}
public function getAfterAttr($value): string
{
return bcdiv($value, 100, 2);
}
public function setAfterAttr($value): string
{
return bcmul($value, 100, 2);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace app\admin\model;
use think\model;
/**
* UserRule 模型
* @property int $status 状态:0=禁用,1=启用
*/
class UserRule extends model
{
protected $autoWriteTimestamp = true;
protected static function onAfterInsert($model): void
{
$pk = $model->getPk();
$model->where($pk, $model[$pk])->update(['weigh' => $model[$pk]]);
}
public function setComponentAttr($value)
{
if ($value) $value = str_replace('\\', '/', $value);
return $value;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace app\admin\model;
use Throwable;
use think\model;
use think\Exception;
use think\model\relation\BelongsTo;
/**
* UserScoreLog 模型
* 1. 创建积分日志自动完成会员积分的添加
* 2. 创建积分日志时,请开启事务
*/
class UserScoreLog extends model
{
protected $autoWriteTimestamp = true;
protected $updateTime = false;
/**
* 入库前
* @throws Throwable
*/
public static function onBeforeInsert($model): void
{
$user = User::where('id', $model->user_id)->lock(true)->find();
if (!$user) {
throw new Exception("The user can't find it");
}
if (!$model->memo) {
throw new Exception("Change note cannot be blank");
}
$model->before = $user->score;
$user->score += $model->score;
$user->save();
$model->after = $user->score;
}
public static function onBeforeDelete(): bool
{
return false;
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
}