diff --git a/app/InvitationCodeUtil.php b/app/InvitationCodeUtil.php new file mode 100644 index 0000000..d577704 --- /dev/null +++ b/app/InvitationCodeUtil.php @@ -0,0 +1,131 @@ + $ch) { + if ($ch === self::$b) { + break; + } + + $index = array_search($ch, self::$r, true); + if ($index === false) { + continue; + } + + $res = $i === 0 ? $index : $res * self::$binLen + $index; + } + + return $res; + } + + /** + * 雪花 ID(需引入 PHP 雪花 ID 工具) + * 推荐使用: https://github.com/Gerardojbaez/laravel-snowflake 或你自己的封装 + * + * @return int + */ + public static function getSnowFlakeId(): int + { + // 简化版本,实际应使用类库如 Godruoyi\Snowflake + if (!class_exists('Snowflake')) { + throw new \RuntimeException("Snowflake class not found."); + } + return Random::generateRandomPrefixedId(); + } + + /** + * 进制转换编码主逻辑 + * + * @param int $id + * @return string + */ + private static function encodeBase(int $id): string + { + $buf = []; + do { + $index = $id % self::$binLen; + array_unshift($buf, self::$r[$index]); + $id = intdiv($id, self::$binLen); + } while ($id > 0); + + return implode('', $buf); + } +} diff --git a/app/admin/library/Auth.php b/app/admin/library/Auth.php index 74f4c74..6c86a51 100644 --- a/app/admin/library/Auth.php +++ b/app/admin/library/Auth.php @@ -10,10 +10,10 @@ use think\facade\Log; use Throwable; use ba\Random; use think\facade\Db; -use think\facade\Config; use app\admin\model\Admin; use app\common\facade\Token; use app\admin\model\AdminGroup; +use Webman\Config; /** * 管理员权限类 @@ -23,7 +23,7 @@ use app\admin\model\AdminGroup; * @property string $email 管理员邮箱 * @property string $mobile 管理员手机号 */ -class Auth extends \ba\Auth +class Auth extends \extend\ba\Auth { /** * 需要登录时/无需登录时的响应状态代码 @@ -352,38 +352,9 @@ class Auth extends \ba\Auth } - public function checkmenus($url, $uid): bool - { - return parent::checkmenus($url, $uid ?: $this->user_id); - } - public function getUserMenus($uid):array - { - return parent::getUserMenus($uid); - } - public function check(string $name, int $uid = 0, string $relation = 'or', string $mode = 'url'): bool - { - return parent::check($name, $uid ?: $this->id, $relation, $mode); - } - public function getGroups(int $uid = 0): array - { - return parent::getGroups($uid ?: $this->id); - } - public function getRuleList(int $uid = 0): array - { - return parent::getRuleList($uid ?: $this->id); - } - public function getRuleIds(int $uid = 0): array - { - return parent::getRuleIds($uid ?: $this->id); - } - - public function getMenus(int $uid = 0): array - { - return parent::getMenus($uid ?: $this->id); - } /** * 是否是超级管理员 diff --git a/app/admin/model/SysCaptcha.php b/app/admin/model/SysCaptcha.php index cbc8079..c3904ad 100644 --- a/app/admin/model/SysCaptcha.php +++ b/app/admin/model/SysCaptcha.php @@ -3,19 +3,25 @@ namespace app\admin\model; use think\Model; -use think\captcha\facade\Captcha as thinkCaptcha; +use Webman\Captcha\CaptchaBuilder; +use support\Request; class SysCaptcha extends Model { - public static function getCode($uuid) + public static function getCode($uuid, $request) { - $code_data = thinkCaptcha::create('czg'); + // 初始化验证码类 + $builder = new CaptchaBuilder; + // 生成验证码 + $builder->build(); + // 获得验证码图片二进制数据 + $img_content = $builder->inline(); // 保存至数据库 self::create([ 'uuid' => $uuid, - 'code' => $code_data['code'], - 'expire_time' => date('Y-m-d H:i:s', time() + config('captcha.expire_time')), + 'code' => $builder->getPhrase(), + 'expire_time' => date('Y-m-d H:i:s', time() + 600), ]); - return ['img' => $code_data['img']]; + return ['img' => $img_content]; } } \ No newline at end of file diff --git a/app/admin/model/User.php b/app/admin/model/User.php index 3bf52f6..e4c5c47 100644 --- a/app/admin/model/User.php +++ b/app/admin/model/User.php @@ -3,7 +3,7 @@ namespace app\admin\model; use app\common\library\DatabaseRoute; -use think\facade\Cache; +use support\think\Cache; use think\facade\Db; use think\Model; use think\model\relation\BelongsTo; diff --git a/app/common/controller/Backend.php b/app/common/controller/Backend.php new file mode 100644 index 0000000..6d94c32 --- /dev/null +++ b/app/common/controller/Backend.php @@ -0,0 +1,526 @@ + 'desc'] + */ + protected string|array $defaultSortField = []; + + /** + * 有序保证 + * 查询数据时总是需要指定 ORDER BY 子句,否则 MySQL 不保证排序,即先查到哪行就输出哪行且不保证多次查询中的输出顺序 + * 将以下配置作为数据有序保证(用于无排序字段时、默认排序字段相同时继续保持数据有序),不设置将自动使用 pk 字段 + * @var string|array id,desc 或 ['id' => 'desc'](有更方便的格式,此处为了保持和 $defaultSortField 属性的配置格式一致) + */ + protected string|array $orderGuarantee = []; + + /** + * 快速搜索字段 + * @var string|array + */ + protected string|array $quickSearchField = 'id'; + + /** + * 是否开启模型验证 + * @var bool + */ + protected bool $modelValidate = true; + + /** + * 是否开启模型场景验证 + * @var bool + */ + protected bool $modelSceneValidate = false; + + /** + * 关联查询方法名,方法应定义在模型中 + * @var array + */ + protected array $withJoinTable = []; + + /** + * 关联查询JOIN方式 + * @var string + */ + protected string $withJoinType = 'LEFT'; + + /** + * 开启数据限制 + * false=关闭 + * personal=仅限个人 + * allAuth=拥有某管理员所有的权限时 + * allAuthAndOthers=拥有某管理员所有的权限并且还有其他权限时 + * parent=上级分组中的管理员可查 + * 指定分组中的管理员可查,比如 $dataLimit = 2; + * 启用请确保数据表内存在 admin_id 字段,可以查询/编辑数据的管理员为admin_id对应的管理员+数据限制所表示的管理员们 + * @var bool|string|int + */ + protected bool|string|int $dataLimit = false; + + /** + * 数据限制字段 + * @var string + */ + protected string $dataLimitField = 'admin_id'; + + /** + * 数据限制开启时自动填充字段值为当前管理员id + * @var bool + */ + protected bool $dataLimitFieldAutoFill = true; + + /** + * 查看请求返回的主表字段控制 + * @var string|array + */ + protected string|array $indexField = ['*']; + + protected Request $request; + /** + * 引入traits + * traits内实现了index、add、edit等方法 + */ + use \app\admin\library\traits\Backend; + + /** + * 初始化 + * @throws Throwable + */ + public function __construct() + { + $this->request = request(); + $needLogin = !action_in_arr($this->noNeedLogin); + + try { + + // 初始化管理员鉴权实例 + $this->auth = Auth::instance(); + $token = request()->header('token'); + if ($token) $this->auth->init($token); + } catch (TokenExpirationException) { + if ($needLogin) { + $this->error(__('Token expiration'), [], 409); + } + } + + if ($needLogin) { + if (!$this->auth->isLogin()) { + $this->error('Please login first', [ + 'type' => $this->auth::NEED_LOGIN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + + if (!action_in_arr($this->noNeedPermission)) { +// $routePath = ($this->app->request->controllerPath ?? '') . '/' . $this->request->action(true); + $routePath = substr(request()->path(), 5); + + if (!$this->auth->checkmenus($routePath, $this->auth->user_id)) { + $this->error('You have no permission', []); + } + } + } + } + + public function initialize() + { + + } + + + + /** + * 查询参数构建器 + * @throws Throwable + */ + public function queryBuilder(): array + { + if (empty($this->model)) { + return []; + } + $pk = $this->model->getPk(); + $quickSearch = $this->request->get("quickSearch/s", ''); + $limit = $this->request->get("limit/d", 10); + $search = $this->request->get("search/a", []); + $initKey = $this->request->get("initKey/s", $pk); + $initValue = $this->request->get("initValue", ''); + $initOperator = $this->request->get("initOperator/s", 'in'); + + $where = []; + $modelTable = strtolower($this->model->getTable()); + $alias[$modelTable] = parse_name(basename(str_replace('\\', '/', get_class($this->model)))); + $mainTableAlias = $alias[$modelTable] . '.'; + + // 快速搜索 + if ($quickSearch) { + $quickSearchArr = is_array($this->quickSearchField) ? $this->quickSearchField : explode(',', $this->quickSearchField); + foreach ($quickSearchArr as $k => $v) { + $quickSearchArr[$k] = str_contains($v, '.') ? $v : $mainTableAlias . $v; + } + $where[] = [implode("|", $quickSearchArr), "LIKE", '%' . str_replace('%', '\%', $quickSearch) . '%']; + } + if ($initValue) { + $where[] = [$initKey, $initOperator, $initValue]; + $limit = 999999; + } + + // 通用搜索组装 + foreach ($search as $field) { + if (!is_array($field) || !isset($field['operator']) || !isset($field['field']) || !isset($field['val'])) { + continue; + } + + $field['operator'] = $this->getOperatorByAlias($field['operator']); + + // 查询关联表字段,转换表别名(驼峰转小写下划线) + if (str_contains($field['field'], '.')) { + $fieldNameParts = explode('.', $field['field']); + $fieldNamePartsLastKey = array_key_last($fieldNameParts); + + // 忽略最后一个元素(字段名) + foreach ($fieldNameParts as $fieldNamePartsKey => $fieldNamePart) { + if ($fieldNamePartsKey !== $fieldNamePartsLastKey) { + $fieldNameParts[$fieldNamePartsKey] = parse_name($fieldNamePart); + } + } + + $fieldName = implode('.', $fieldNameParts); + } else { + $fieldName = $mainTableAlias . $field['field']; + } + + // 日期时间 + if (isset($field['render']) && $field['render'] == 'datetime') { + if ($field['operator'] == 'RANGE') { + $datetimeArr = explode(',', $field['val']); + if (!isset($datetimeArr[1])) { + continue; + } + $datetimeArr = array_filter(array_map("strtotime", $datetimeArr)); + $where[] = [$fieldName, str_replace('RANGE', 'BETWEEN', $field['operator']), $datetimeArr]; + continue; + } + $where[] = [$fieldName, '=', strtotime($field['val'])]; + continue; + } + + // 范围查询 + if ($field['operator'] == 'RANGE' || $field['operator'] == 'NOT RANGE') { + $arr = explode(',', $field['val']); + // 重新确定操作符 + if (!isset($arr[0]) || $arr[0] === '') { + $operator = $field['operator'] == 'RANGE' ? '<=' : '>'; + $arr = $arr[1]; + } elseif (!isset($arr[1]) || $arr[1] === '') { + $operator = $field['operator'] == 'RANGE' ? '>=' : '<'; + $arr = $arr[0]; + } else { + $operator = str_replace('RANGE', 'BETWEEN', $field['operator']); + } + $where[] = [$fieldName, $operator, $arr]; + continue; + } + + switch ($field['operator']) { + case '=': + case '<>': + $where[] = [$fieldName, $field['operator'], (string)$field['val']]; + break; + case 'LIKE': + case 'NOT LIKE': + $where[] = [$fieldName, $field['operator'], '%' . str_replace('%', '\%', $field['val']) . '%']; + break; + case '>': + case '>=': + case '<': + case '<=': + $where[] = [$fieldName, $field['operator'], intval($field['val'])]; + break; + case 'FIND_IN_SET': + if (is_array($field['val'])) { + foreach ($field['val'] as $val) { + $where[] = [$fieldName, 'find in set', $val]; + } + } else { + $where[] = [$fieldName, 'find in set', $field['val']]; + } + break; + case 'IN': + case 'NOT IN': + $where[] = [$fieldName, $field['operator'], is_array($field['val']) ? $field['val'] : explode(',', $field['val'])]; + break; + case 'NULL': + case 'NOT NULL': + $where[] = [$fieldName, strtolower($field['operator']), '']; + break; + } + } + + // 数据权限 + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$mainTableAlias . $this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + return [$where, $alias, $limit, $this->queryOrderBuilder()]; + } + + /** + * 查询的排序参数构建器 + */ + public function queryOrderBuilder() + { + $pk = $this->model->getPk(); + $order = $this->request->get("order/s") ?: $this->defaultSortField; + + if ($order && is_string($order)) { + $order = explode(',', $order); + $order = [$order[0] => $order[1] ?? 'asc']; + } + if (!$this->orderGuarantee) { + $this->orderGuarantee = [$pk => 'desc']; + } elseif (is_string($this->orderGuarantee)) { + $this->orderGuarantee = explode(',', $this->orderGuarantee); + $this->orderGuarantee = [$this->orderGuarantee[0] => $this->orderGuarantee[1] ?? 'asc']; + } + $orderGuaranteeKey = array_key_first($this->orderGuarantee); + if (!array_key_exists($orderGuaranteeKey, $order)) { + $order[$orderGuaranteeKey] = $this->orderGuarantee[$orderGuaranteeKey]; + } + + return $order; + } + + /** + * 数据权限控制-获取有权限访问的管理员Ids + * @throws Throwable + */ + protected function getDataLimitAdminIds(): array + { + if (!$this->dataLimit || $this->auth->isSuperAdmin()) { + return []; + } + $adminIds = []; + if ($this->dataLimit == 'parent') { + // 取得当前管理员的下级分组们 + $parentGroups = $this->auth->getAdminChildGroups(); + if ($parentGroups) { + // 取得分组内的所有管理员 + $adminIds = $this->auth->getGroupAdmins($parentGroups); + } + } elseif (is_numeric($this->dataLimit) && $this->dataLimit > 0) { + // 在组内,可查看所有,不在组内,可查看自己的 + $adminIds = $this->auth->getGroupAdmins([$this->dataLimit]); + return in_array($this->auth->id, $adminIds) ? [] : [$this->auth->id]; + } elseif ($this->dataLimit == 'allAuth' || $this->dataLimit == 'allAuthAndOthers') { + // 取得拥有他所有权限的分组 + $allAuthGroups = $this->auth->getAllAuthGroups($this->dataLimit); + // 取得分组内的所有管理员 + $adminIds = $this->auth->getGroupAdmins($allAuthGroups); + } + $adminIds[] = $this->auth->id; + return array_unique($adminIds); + } + + /** + * 从别名获取原始的逻辑运算符 + * @param string $operator 逻辑运算符别名 + * @return string 原始的逻辑运算符,无别名则原样返回 + */ + protected function getOperatorByAlias(string $operator): string + { + $alias = [ + 'ne' => '<>', + 'eq' => '=', + 'gt' => '>', + 'egt' => '>=', + 'lt' => '<', + 'elt' => '<=', + ]; + + return $alias[$operator] ?? $operator; + } + + + /** + * 操作成功 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function success(string $msg = '', mixed $data = null, int $code = 0, string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options); + } + + + protected function successWithData(mixed $data = null, string $msg = '', int $code = 0, string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options); + } + + /** + * 操作失败 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function error(string $msg = '', mixed $data = null, int $code = -1, string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options); + } + + protected function errorMsg(string $msg = '', mixed $data = null, int $code = -1, string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options, 'data', 'msg'); + } + + + + /** + * 操作成功 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function n_success(array $data, string $msg = 'ok', int $code = 0, string $type = null, array $header = [], array $options = []): void + { + $this->resultApi($data, $msg, $code, $type, $header, $options); + } + + /** + * 操作失败 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function n_error(string $msg, array $data = [], int $code = -1, string $type = null, array $header = [], array $options = []): void + { + $this->resultApi($data, $msg, $code, $type, $header, $options); + } + + /** + * 多种操作结果 + */ + public function resultApi(array $data = [], string $msg = 'ok', int $code = 0, string $type = null, array $header = [], array $options = []) + { + $data['code'] = $code; + $data['message'] = $msg; + $data['time'] = time(); + if(isset($data['data']['records'])) { + $data['data']['records'] = apiconvertToCamelCase($data['data']['records']); + } + if(isset($data['page']['list'])) { + $data['page']['list'] = apiconvertToCamelCase($data['page']['list']); + } + if(isset($data['data']['list'])) { + $data['data']['list'] = apiconvertToCamelCase($data['data']['list']); + } + if(isset($data['data']['userEntity'])) { + $data['data']['userEntity'] = apiconvertToCamelCase($data['data']['userEntity']); + } + $result = $data; + + throw new MyBusinessException(json_encode($result)); + } + + + + /** + * 返回 API 数据 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + public function result(string $msg, mixed $data = null, int $code = 0, string $type = null, array $header = [], array $options = [], string $dataKey = 'data', string $msgKey = 'message') + { + if(isset($data['records'])) { + $data['records'] = apiconvertToCamelCase($data['records']); + } + if(isset($data['page'])) { + $data['page'] = apiconvertToCamelCase($data['page']); + } + if(isset($data['list'])) { + $data['list'] = apiconvertToCamelCase($data['list']); + } + $result = [ + 'code' => $code, + 'message' => $msg, + 'time' => time(), + $dataKey => $data, + ]; + throw new MyBusinessException(json_encode($result)); + } + + public function ApiDataReturn($data) + { + return json($data); + } + + +} \ No newline at end of file diff --git a/app/common/model/SysUser.php b/app/common/model/SysUser.php index f2ccd86..5f4f94c 100644 --- a/app/common/model/SysUser.php +++ b/app/common/model/SysUser.php @@ -6,7 +6,7 @@ namespace app\common\model; use app\common\library\DatabaseRoute; use extend\ba\Random; use think\facade\Db; - +use support\think\Cache; class SysUser extends BaseModel { diff --git a/app/czg/auth/controller/AdminController.php b/app/czg/auth/controller/AdminController.php new file mode 100644 index 0000000..43d48ef --- /dev/null +++ b/app/czg/auth/controller/AdminController.php @@ -0,0 +1,260 @@ +model = new AdminModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('login_failure,password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('add')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + $passwd = $data['password']; // 密码将被排除不直接入库 + $data = $this->excludeFields($data); + $result = false; + if ($data['group_arr']) $this->checkGroupAuth($data['group_arr']); + $this->model->startTrans(); + try { + $result = $this->model->save($data); + if ($data['group_arr']) { + $groupAccess = []; + foreach ($data['group_arr'] as $datum) { + $groupAccess[] = [ + 'uid' => $this->model->id, + 'group_id' => $datum, + ]; + } + Db::name('admin_group_access')->insertAll($groupAccess); + } + $this->model->commit(); + + if (!empty($passwd)) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('edit')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + if ($this->auth->id == $data['id'] && $data['status'] == 'disable') { + $this->error(__('Please use another administrator account to disable the current account!')); + } + + if (!empty($data['password'])) { + $this->model->resetPassword($row->id, $data['password']); + } + + $groupAccess = []; + if ($data['group_arr']) { + $checkGroups = []; + foreach ($data['group_arr'] as $datum) { + if (!in_array($datum, $row->group_arr)) { + $checkGroups[] = $datum; + } + $groupAccess[] = [ + 'uid' => $id, + 'group_id' => $datum, + ]; + } + $this->checkGroupAuth($checkGroups); + } + + Db::name('admin_group_access') + ->where('uid', $id) + ->delete(); + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + $result = $row->save($data); + if ($groupAccess) Db::name('admin_group_access')->insertAll($groupAccess); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + unset($row['salt'], $row['login_failure']); + $row['password'] = ''; + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request->param('ids/a', []); + $where[] = [$this->model->getPk(), 'in', $ids]; + $data = $this->model->where($where)->select(); + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $v) { + if ($v->id != $this->auth->id) { + $count += $v->delete(); + Db::name('admin_group_access') + ->where('uid', $v['id']) + ->delete(); + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($count) { + $this->success(__('Deleted successfully')); + } else { + $this->error(__('No rows were deleted')); + } + } + + /** + * 检查分组权限 + * @throws Throwable + */ + private function checkGroupAuth(array $groups): void + { + if ($this->auth->isSuperAdmin()) { + return; + } + $authGroups = $this->auth->getAllAuthGroups('allAuthAndOthers'); + foreach ($groups as $group) { + if (!in_array($group, $authGroups)) { + $this->error(__('You have no permission to add an administrator to this group!')); + } + } + } +} \ No newline at end of file diff --git a/app/czg/auth/controller/AdminLogController.php b/app/czg/auth/controller/AdminLogController.php new file mode 100644 index 0000000..9ed3be7 --- /dev/null +++ b/app/czg/auth/controller/AdminLogController.php @@ -0,0 +1,54 @@ +model = new AdminLogModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + if (!$this->auth->isSuperAdmin()) { + $where[] = ['admin_id', '=', $this->auth->id]; + } + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } +} \ No newline at end of file diff --git a/app/czg/auth/controller/GroupController.php b/app/czg/auth/controller/GroupController.php new file mode 100644 index 0000000..61fb2dd --- /dev/null +++ b/app/czg/auth/controller/GroupController.php @@ -0,0 +1,379 @@ +model = new AdminGroup(); + $this->tree = Tree::instance(); + + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get("initValue/a", []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request("quickSearch", ''); + + // 有初始化值时不组装树状(初始化出来的值更好看) + $this->assembleTree = $isTree && !$this->initValue; + + $this->adminGroups = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getGroups(), + 'group' => $this->adminGroups, + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $this->checkAuth($id); + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $adminGroup = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + if (in_array($data['id'], $adminGroup)) { + $this->error(__('You cannot modify your own management group!')); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('edit')->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + // 读取所有pid,全部从节点数组移除,父级选择状态由子级决定 + $pidArr = AdminRule::field('pid') + ->distinct() + ->where('id', 'in', $row->rules) + ->select() + ->toArray(); + $rules = $row->rules ? explode(',', $row->rules) : []; + foreach ($pidArr as $item) { + $ruKey = array_search($item['pid'], $rules); + if ($ruKey !== false) { + unset($rules[$ruKey]); + } + } + $row->rules = array_values($rules); + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where($this->model->getPk(), 'in', $ids)->select(); + foreach ($data as $v) { + $this->checkAuth($v->id); + } + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + $adminGroup = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $v) { + if (!in_array($v['id'], $adminGroup)) { + $count += $v->delete(); + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($count) { + $this->success(__('Deleted successfully')); + } else { + $this->error(__('No rows were deleted')); + } + } + + /** + * 远程下拉 + * @return void + * @throws Throwable + */ + public function select(): void + { + $data = $this->getGroups([['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data)); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 权限节点入库前处理 + * @throws Throwable + */ + private function handleRules(array &$data): array + { + if (!empty($data['rules']) && is_array($data['rules'])) { + $superAdmin = true; + $checkedRules = []; + $allRuleIds = AdminRule::column('id'); + + // 遍历检查权限ID是否存在(以免传递了可预测的未来权限ID号) + foreach ($data['rules'] as $postRuleId) { + if (in_array($postRuleId, $allRuleIds)) { + $checkedRules[] = $postRuleId; + } + } + + // 正在建立超管级分组? + foreach ($allRuleIds as $ruleId) { + if (!in_array($ruleId, $checkedRules)) { + $superAdmin = false; + } + } + + if ($superAdmin && $this->auth->isSuperAdmin()) { + // 允许超管建立超管级分组 + $data['rules'] = '*'; + } else { + // 当前管理员所拥有的权限节点 + $ownedRuleIds = $this->auth->getRuleIds(); + + // 禁止添加`拥有自己全部权限`的分组 + if (!array_diff($ownedRuleIds, $checkedRules)) { + $this->error(__('Role group has all your rights, please contact the upper administrator to add or do not need to add!')); + } + + // 检查分组权限是否超出了自己的权限(超管的 $ownedRuleIds 为 ['*'],不便且可以不做此项检查) + if (array_diff($checkedRules, $ownedRuleIds) && !$this->auth->isSuperAdmin()) { + $this->error(__('The group permission node exceeds the range that can be allocated')); + } + + $data['rules'] = implode(',', $checkedRules); + } + } else { + unset($data['rules']); + } + return $data; + } + + /** + * 获取分组 + * @param array $where + * @return array + * @throws Throwable + */ + private function getGroups(array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + // 下拉选择时只获取:拥有所有权限并且有额外权限的分组 + $absoluteAuth = $this->request->get('absoluteAuth/b', false); + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + if (!$this->auth->isSuperAdmin()) { + $authGroups = $this->auth->getAllAuthGroups($this->authMethod, $where); + if (!$absoluteAuth) $authGroups = array_merge($this->adminGroups, $authGroups); + $where[] = ['id', 'in', $authGroups]; + } + $data = $this->model->where($where)->select()->toArray(); + + // 获取第一个权限的名称供列表显示-s + foreach ($data as &$datum) { + if ($datum['rules']) { + if ($datum['rules'] == '*') { + $datum['rules'] = __('Super administrator'); + } else { + $rules = explode(',', $datum['rules']); + if ($rules) { + $rulesFirstTitle = AdminRule::where('id', $rules[0])->value('title'); + $datum['rules'] = count($rules) == 1 ? $rulesFirstTitle : $rulesFirstTitle . '等 ' . count($rules) . ' 项'; + } + } + } else { + $datum['rules'] = __('No permission'); + } + } + // 获取第一个权限的名称供列表显示-e + + // 如果要求树状,此处先组装好 children + return $this->assembleTree ? $this->tree->assembleChild($data) : $data; + } + + /** + * 检查权限 + * @param $groupId + * @return void + * @throws Throwable + */ + private function checkAuth($groupId): void + { + $authGroups = $this->auth->getAllAuthGroups($this->authMethod, []); + if (!$this->auth->isSuperAdmin() && !in_array($groupId, $authGroups)) { + $this->error(__($this->authMethod == 'allAuth' ? 'You need to have all permissions of this group to operate this group~' : 'You need to have all the permissions of the group and have additional permissions before you can operate the group~')); + } + } + +} \ No newline at end of file diff --git a/app/czg/auth/controller/RuleController.php b/app/czg/auth/controller/RuleController.php new file mode 100644 index 0000000..7639fd7 --- /dev/null +++ b/app/czg/auth/controller/RuleController.php @@ -0,0 +1,274 @@ + 'desc']; + + protected string|array $quickSearchField = 'title'; + + /** + * @var object + * @phpstan-var AdminRule + */ + protected object $model; + + /** + * @var Tree + */ + protected Tree $tree; + + /** + * 远程select初始化传值 + * @var array + */ + protected array $initValue; + + /** + * 搜索关键词 + * @var string + */ + protected string $keyword; + + /** + * 是否组装Tree + * @var bool + */ + protected bool $assembleTree; + + /** + * 开启模型验证 + * @var bool + */ + protected bool $modelValidate = false; + + public function initialize(): void + { + parent::initialize(); + + // 防止 URL 中的特殊符号被默认的 filter 函数转义 + $this->request->filter('clean_xss'); + + $this->model = new AdminRule(); + $this->tree = Tree::instance(); + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get('initValue/a', []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request('quickSearch', ''); + $this->assembleTree = $isTree && !$this->initValue; // 有初始化值时不组装树状(初始化出来的值更好看) + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getMenus(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + + // 检查所有非超管的分组是否应该拥有此权限 + if (!empty($data['pid'])) { + $groups = AdminGroup::where('rules', '<>', '*')->select(); + foreach ($groups as $group) { + $rules = explode(',', $group->rules); + if (in_array($data['pid'], $rules) && !in_array($this->model->id, $rules)) { + $rules[] = $this->model->id; + $group->rules = implode(',', $rules); + $group->save(); + } + } + } + + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $id = $this->request->param($this->model->getPk()); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + if (isset($data['pid']) && $data['pid'] > 0) { + // 满足意图并消除副作用 + $parent = $this->model->where('id', $data['pid'])->find(); + if ($parent['pid'] == $row['id']) { + $parent->pid = 0; + $parent->save(); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + + // 子级元素检查 + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + parent::del(); + } + + /** + * 重写select方法 + * @throws Throwable + */ + public function select(): void + { + $data = $this->getMenus([['type', 'in', ['menu_dir', 'menu']], ['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title')); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 获取菜单列表 + * @throws Throwable + */ + protected function getMenus($where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + $ids = $this->auth->getRuleIds(); + + // 如果没有 * 则只获取用户拥有的规则 + if (!in_array('*', $ids)) { + $where[] = ['id', 'in', $ids]; + } + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + // 读取用户组所有权限规则 + $rules = $this->model + ->where($where) + ->order($this->queryOrderBuilder()) + ->select() + ->toArray(); + + // 如果要求树状,此处先组装好 children + return $this->assembleTree ? $this->tree->assembleChild($rules) : $rules; + } +} \ No newline at end of file diff --git a/app/czg/controller/AjaxController.php b/app/czg/controller/AjaxController.php new file mode 100644 index 0000000..9e59af5 --- /dev/null +++ b/app/czg/controller/AjaxController.php @@ -0,0 +1,217 @@ +setTitle(__('upload')); + $file = $this->request->file('file'); + $driver = $this->request->param('driver', 'local'); + $topic = $this->request->param('topic', 'default'); + try { + $upload = new Upload(); + $attachment = $upload + ->setFile($file) + ->setDriver($driver) + ->setTopic($topic) + ->upload(null, $this->auth->id); + unset($attachment['create_time'], $attachment['quote']); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + $this->success(__('File uploaded successfully'), [ + 'file' => $attachment ?? [] + ]); + } + + /** + * 获取省市区数据 + * @throws Throwable + */ + public function area(): void + { + $this->success('', get_area()); + } + + public function buildSuffixSvg(): Response + { + $suffix = $this->request->param('suffix', 'file'); + $background = $this->request->param('background'); + $content = build_suffix_svg((string)$suffix, (string)$background); + return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/svg+xml'); + } + + /** + * 获取已脱敏的数据库连接配置列表 + * @throws Throwable + */ + public function getDatabaseConnectionList(): void + { + $quickSearch = $this->request->get("quickSearch/s", ''); + $connections = config('database.connections'); + $desensitization = []; + foreach ($connections as $key => $connection) { + $connection = TableManager::getConnectionConfig($key); + $desensitization[] = [ + 'type' => $connection['type'], + 'database' => substr_replace($connection['database'], '****', 1, strlen($connection['database']) > 4 ? 2 : 1), + 'key' => $key, + ]; + } + + if ($quickSearch) { + $desensitization = array_filter($desensitization, function ($item) use ($quickSearch) { + return preg_match("/$quickSearch/i", $item['key']); + }); + $desensitization = array_values($desensitization); + } + + $this->success('', [ + 'list' => $desensitization, + ]); + } + + /** + * 获取表主键字段 + * @param ?string $table + * @param ?string $connection + * @throws Throwable + */ + public function getTablePk(?string $table = null, ?string $connection = null): void + { + if (!$table) { + $this->error(__('Parameter error')); + } + + $table = TableManager::tableName($table, true, $connection); + if (!TableManager::phinxAdapter(false, $connection)->hasTable($table)) { + $this->error(__('Data table does not exist')); + } + + $tablePk = Db::connect(TableManager::getConnection($connection)) + ->table($table) + ->getPk(); + $this->success('', ['pk' => $tablePk]); + } + + /** + * 获取数据表列表 + * @throws Throwable + */ + public function getTableList(): void + { + $quickSearch = $this->request->get("quickSearch/s", ''); + $connection = $this->request->request('connection');// 数据库连接配置标识 + $samePrefix = $this->request->request('samePrefix/b', true);// 是否仅返回项目数据表(前缀同项目一致的) + $excludeTable = $this->request->request('excludeTable/a', []);// 要排除的数据表数组(表名无需带前缀) + + $outTables = []; + $dbConfig = TableManager::getConnectionConfig($connection); + $tables = TableManager::getTableList($connection); + + if ($quickSearch) { + $tables = array_filter($tables, function ($comment) use ($quickSearch) { + return preg_match("/$quickSearch/i", $comment); + }); + } + + $pattern = '/^' . $dbConfig['prefix'] . '/i'; + foreach ($tables as $table => $comment) { + if ($samePrefix && !preg_match($pattern, $table)) continue; + + $table = preg_replace($pattern, '', $table); + if (!in_array($table, $excludeTable)) { + $outTables[] = [ + 'table' => $table, + 'comment' => $comment, + 'connection' => $connection, + 'prefix' => $dbConfig['prefix'], + ]; + } + } + + $this->success('', [ + 'list' => $outTables, + ]); + } + + /** + * 获取数据表字段列表 + * @throws Throwable + */ + public function getTableFieldList(): void + { + $table = $this->request->param('table'); + $clean = $this->request->param('clean', true); + $connection = $this->request->request('connection'); + if (!$table) { + $this->error(__('Parameter error')); + } + + $connection = TableManager::getConnection($connection); + $tablePk = Db::connect($connection)->name($table)->getPk(); + $this->success('', [ + 'pk' => $tablePk, + 'fieldList' => TableManager::getTableColumns($table, $clean, $connection), + ]); + } + + public function changeTerminalConfig(): void + { + AdminLog::instance()->setTitle(__('Change terminal config')); + if (Terminal::changeTerminalConfig()) { + $this->success(); + } else { + $this->error(__('Failed to modify the terminal configuration. Please modify the configuration file manually:%s', ['/config/buildadmin.php'])); + } + } + + public function clearCache(): void + { + AdminLog::instance()->setTitle(__('Clear cache')); + $type = $this->request->post('type'); + if ($type == 'tp' || $type == 'all') { + Cache::clear(); + } else { + $this->error(__('Parameter error')); + } + Event::trigger('cacheClearAfter', $this->app); + $this->success(__('Cache cleaned~')); + } + + /** + * 终端 + * @throws Throwable + */ + public function terminal(): void + { + (new Terminal())->exec(); + } +} \ No newline at end of file diff --git a/app/czg/controller/AliossController.php b/app/czg/controller/AliossController.php new file mode 100644 index 0000000..86654c9 --- /dev/null +++ b/app/czg/controller/AliossController.php @@ -0,0 +1,116 @@ +file('file'); + if(empty($file)) { + $this->error('参数不能为空'); + } + $commoninfo = Db::connect(config('database.search_library')); + $endpoint = $commoninfo->name('common_info')->where(['type' => 68])->find()['value']; + $accessKeyId = $commoninfo->name('common_info')->where(['type' => 69])->find()['value']; + $secretAccessKey = $commoninfo->name('common_info')->where(['type' => 70])->find()['value']; + $bucket = $commoninfo->name('common_info')->where(['type' => 71])->find()['value']; + $befor_url = $commoninfo->name('common_info')->where(['type' => 72])->find()['value']; + + putenv('OSS_ACCESS_KEY_ID=' . $accessKeyId); + putenv('OSS_ACCESS_KEY_SECRET='. $secretAccessKey); + $provider = new EnvironmentVariableCredentialsProvider(); + + $object = date('Ymd') . '/' . uniqid() . '.' .$file->getOriginalExtension(); + try{ + $config = array( + "provider" => $provider, + "endpoint" => $endpoint, + "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V1, + ); + $ossClient = new OssClient($config); + // 以二进制模式读取文件内容 + $handle = fopen($file->getRealPath(), 'rb'); + $content = stream_get_contents($handle); + fclose($handle); + + // 上传二进制内容,明确指定Content-Type + $options = [ + OssClient::OSS_CONTENT_LENGTH => strlen($content), + OssClient::OSS_CONTENT_TYPE => $file->getMime(), + // 禁用字符编码转换 + 'Content-Encoding' => 'binary', + ]; + $res = $ossClient->putObject($bucket, $object, $content, $options); + Log::write('上传文件结果' . json_encode($res)); + if(!empty($res['info'])) { + return $this->ApiDataReturn(['data' => $befor_url . '/' . $object, 'msg' => 'success', 'code' => 0]); + }else { + $this->error('上传失败'); + } + } catch(OssException $e) { + $this->error($e->getMessage()); + } + } + + // 获取阿里云oss存储相关配置 + public function getCredentials() + { + $commoninfo = Db::connect(config('database.search_library')); + $configItems = $commoninfo->name('common_info')->whereIn('type', [66, 67, 69, 70]) + ->column('value', 'type'); + AlibabaCloud::accessKeyClient($configItems[69], $configItems[70]) + ->regionId('cn-nanjing') + ->asDefaultClient(); + try { + $result = AlibabaCloud::rpc()->product('Sts') + ->options([ + "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V1 + ]) + ->version('2015-04-01') + ->action('AssumeRole') + ->method('POST') + ->host($configItems[66]) // Endpoint + ->scheme('https') + ->options([ + 'query' => [ + 'RoleArn' => $configItems[67], // 角色ARN + 'RoleSessionName' => 'test', // 会话名称 + 'DurationSeconds' => 3600, // 凭证有效期(秒) + ], + ]) + ->request(); + // 获取响应中的凭证信息。 + $credentials = $result['Credentials']; + $this->n_success(['data' => [ + 'accessKeyId' => $credentials['AccessKeyId'], + 'accessKeySecret' => $credentials['AccessKeySecret'], + 'expiration' => $credentials['Expiration'], + 'securityToken' => $credentials['SecurityToken'], + ]]); + } catch (ClientException $e) { + // 处理客户端异常。 + echo $e->getErrorMessage() . PHP_EOL; + } catch (ServerException $e) { + // 处理服务端异常。 + echo $e->getErrorMessage() . PHP_EOL; + } + + + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/AnnouncementController.php b/app/czg/controller/AnnouncementController.php new file mode 100644 index 0000000..fc2ca31 --- /dev/null +++ b/app/czg/controller/AnnouncementController.php @@ -0,0 +1,70 @@ +request->param(); + $where = []; + if (!empty($params['title'])) { + $where[] = ['title', '=', $params['title']]; + } + + if (!empty($params['type'])) { + $where[] = ['type', '=', $params['type']]; + } + + if (!empty($params['state'])) { + $where[] = ['state', '=', $params['state']]; + } + + if (!empty($params['id'])) { + $where[] = ['id', '=', $params['id']]; + } + + $this->successWithData(apiconvertToCamelCase(Db::name('announcement')->where($where)->select()->toArray())); + } + + public function save() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['create_time'] = getNormalDate(); + Db::name('announcement')->insert($params); + $this->success(); + } + + public function update() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + Db::name('announcement')->where([ + 'id' => $params['id'] + ])->update($params); + + $this->success(); + } + + public function delete() + { + $id = $this->request->post('id'); + Db::name('announcement')->delete([ + 'id' => $id + ]); + + $this->success(); + } + + + + +} \ No newline at end of file diff --git a/app/czg/controller/AppinfoController.php b/app/czg/controller/AppinfoController.php new file mode 100644 index 0000000..61ca5eb --- /dev/null +++ b/app/czg/controller/AppinfoController.php @@ -0,0 +1,48 @@ +request->param(); + $list = Db::name('app')->paginate([ + 'page' => $params['page'], + 'list_rows' => $params['limit'] + ]); + $this->successWithData([ + 'records' => convertToCamelCase($list->items()), // 当前页数据 + 'totalCount' => $list->total(), // 总记录数 + 'currPage' => $list->currentPage(), + 'last_page' => $list->lastPage(), + 'pageSize' => $params['limit'] + ]); + } + + public function save() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + if (empty($params['id'])) { + $params['create_at'] = getNormalDate(); + Db::name('app')->insert($params); + }else { + Db::name('app')->where([ + 'id' => $params['id'] + ])->update($params); + } + + $this->success(); + + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/BannerController.php b/app/czg/controller/BannerController.php new file mode 100644 index 0000000..6f6f7ff --- /dev/null +++ b/app/czg/controller/BannerController.php @@ -0,0 +1,99 @@ +request->get(); + $info = cache('banner'.$params['page'].$params['limit']); + if ($info) { + $this->successWithData($info); + } + $info = DatabaseRoute::paginateDb('banner', function ($query) use ($params) { + if (!empty($params['classify'])) { + $query->where([ + 'classify' => $params['classify'] + ]); + } + + if (!empty($params['state'])) { +// $query->where([ +// 'state' => $params['state'] +// ]); + } + return $query; + }, $params['page'], $params['limit']); + cache('banner'.$params['page'].$params['limit'], $info, -1); + $this->successWithData($info); + + } + + public function updateBannerById() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + unset($params['course']); + Db::name('banner')->where([ + 'id' => $params['id'] + ])->update($params); + deleteRedisKeysByPattern('banner*'); + $this->success(); + } + + public function insertBanner() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['state'] = 2; + $params['create_time'] = getNormalDate(); + unset($params['id']); + Db::name('banner')->insert($params); + deleteRedisKeysByPattern('banner*'); + $this->success(); + + } + + public function deleteBannerById() + { + $params = $this->request->param(); + $params['ids'] = explode(',', $params['ids']); + foreach ($params['ids'] as $id) { + Db::name('banner')->delete([ + 'id' => $id + ]); + } + deleteRedisKeysByPattern('banner*'); + $this->success(); + } + + + // 隐藏banner图 + public function updateBannerStateById() + { + $get = $this->request->get(); + if(empty($get['id'])) { + $this->error('参数不玩这'); + } + $id = $get['id']; + $banner = Db::connect(get_slave_connect_name())->name('banner')->where(['id' => $id])->find(); + if(!$banner) { + $this->error('记录不存在'); + } + Db::connect(get_master_connect_name())->name('banner')->where(['id' => $id])->update([ + 'state' => $banner['state'] == 1 ? 2 : 1, + ]); + $this->success(); + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/CashController.php b/app/czg/controller/CashController.php new file mode 100644 index 0000000..4ba518d --- /dev/null +++ b/app/czg/controller/CashController.php @@ -0,0 +1,270 @@ +request->param(); + $this->successWithData(DatabaseRoute::paginateAllDb('pay_details', function ($query) use ($params) { + $query->alias('s') + ->leftJoin('tb_user u', 'u.user_id = s.user_id') + ->field([ + 's.id', 's.classify', + 's.order_id' => 'orderId', + 's.money', + 's.user_id' => 'userId', + 's.pay_diamond' => 'payDiamond', + 's.diamond', + 's.state', + 's.create_time' => 'createTime', + 's.pay_time' => 'payTime', + 'u.user_name' => 'userName', + 'u.phone', + ]); + // 动态条件拼接 + if (!empty($params['startTime']) && !empty($params['endTime'])) { + $query->whereBetween('s.create_time', [$params['startTime'], $params['endTime']]); + } + + if (!empty($params['userName'])) { + $query->whereLike('u.user_name', '%' . $params['userName'] . '%'); + } + + if (!empty($params['orderId'])) { + $query->whereLike('s.order_id', '%' . $params['orderId'] . '%'); + } + + if (isset($params['userId'])) { + $query->where('u.user_id', $params['userId']); + } + + if (isset($params['state']) && $params['state'] !== -1) { + $query->where('s.state', $params['state']); + } else { + $query->where('s.state', '<>', -1); + } + + + return $query; + }, $params['page'], $params['limit'], 's.create_time')); + } + + + public function statisticsIncomeMoney() + { + $get = $this->request->get(); + // 调用统计服务方法 + $sumMoney = \app\admin\model\Cash::statisticsIncomeMoney($get['time'], $get['flag'], null); + $courseMoney = \app\admin\model\Cash::statisticsIncomeMoney($get['time'], $get['flag'], 1); + $vipMoney = \app\admin\model\Cash::statisticsIncomeMoney($get['time'], $get['flag'], 2); + + // 构建返回数据 + $map = [ + 'sumMoney' => is_null($sumMoney) ? 0.00 : $sumMoney, + 'courseMoney' => is_null($courseMoney) ? 0.00 : $courseMoney, + 'vipMoney' => is_null($vipMoney) ? 0.00 : $vipMoney + ]; + $this->n_success(['data' => $map]); ; + } + + // 财务提现统计 + public function statisticsCashMoney() + { + $get = $this->request->get(); + $time = $get['time']; + $flag = $get['flag']; + // 验证时间格式并转换为时间戳 + $timestamp = strtotime($time); + if ($timestamp === false) { + $this->error('无效的时间格式,请使用 yyyy-MM-dd 格式'); + } + + // 初始化开始和结束时间(默认按日) + $startTime = date('Y-m-d 00:00:00', $timestamp); + $endTime = date('Y-m-d 23:59:59', $timestamp); + + // 根据flag调整时间范围 + if ($flag == 2) { + // 按月:当月第一天 00:00:00 至 当月最后一天 23:59:59 + $startTime = date('Y-m-01 00:00:00', $timestamp); // 当月1号 + $lastDay = date('t', $timestamp); // 获取当月总天数(t是原生格式化符) + $endTime = date('Y-m-' . $lastDay . ' 23:59:59', $timestamp); + } elseif ($flag == 3) { + // 按年:当年第一天 00:00:00 至 当年最后一天 23:59:59 + $startTime = date('Y-01-01 00:00:00', $timestamp); // 当年1月1号 + $endTime = date('Y-12-31 23:59:59', $timestamp); // 当年12月31号 + } + + $sumMoney = DatabaseRoute::getAllDbData('cash_out', function($query) use ($startTime, $endTime) { + $query->where(['state' => 1]); + $query->whereBetween('create_at', [$startTime, $endTime]); + return $query; + })->sum('money'); + + $countMoney = DatabaseRoute::getAllDbData('cash_out', function($query) use ($startTime, $endTime) { + $query->whereBetween('create_at', [$startTime, $endTime]); + return $query; + })->count(); + + $stayMoney = DatabaseRoute::getAllDbData('cash_out', function($query) use ($startTime, $endTime) { + $query->where(['state' => 0]); + $query->whereBetween('create_at', [$startTime, $endTime]); + return $query; + })->count(); + + $map = [ + // 金额字段,若为null则赋值0.00(保留两位小数) + 'sumMoney' => is_null($sumMoney) ? 0.00 : (float)$sumMoney, + // 计数字段,若为null则赋值0(整数) + 'countMoney' => is_null($countMoney) ? 0 : (int)$countMoney, + // 待处理金额字段,处理逻辑同上 + 'stayMoney' => is_null($stayMoney) ? 0 : (int)$stayMoney + ]; + $this->n_success(['data' => $map]); + } + + // 查询所有用户充值信息列表 + public function selectUserRecharge() + { + $get = $this->request->get(); + if(!empty($get['state']) && $get['state'] == -1) { + $get['state'] = null; + } + $get['startTime'] = date('Y-m-d 00:00:00', strtotime($get['startTime'])); + $get['endTime'] = date('Y-m-d 23:59:59', strtotime($get['endTime'])); + $this->n_success(['data' => \app\admin\model\Cash::selectPayDetails($get)]); + } + + + public function payMember() + { + $get = $this->request->get(); + $time = $get['time'];$flag = $get['flag'];$payClassify = empty($get['payClassify'])?null:$get['payClassify']; + // 1. 统计总支付金额(不指定分类) + $sumMoney = PayDetails::selectSumPayByClassify(null, $flag, $time, $payClassify); + + // 2. 按支付渠道分别统计(1-8对应不同渠道) + $channelMoneys = [ + 1 => PayDetails::selectSumPayByClassify(1, $flag, $time, $payClassify), // 微信App + 2 => PayDetails::selectSumPayByClassify(2, $flag, $time, $payClassify), // 微信公众号 + 3 => PayDetails::selectSumPayByClassify(3, $flag, $time, $payClassify), // 微信小程序 + 4 => PayDetails::selectSumPayByClassify(4, $flag, $time, $payClassify), // 支付宝App + 5 => PayDetails::selectSumPayByClassify(5, $flag, $time, $payClassify), // 支付宝H5 + 6 => PayDetails::selectSumPayByClassify(6, $flag, $time, $payClassify), // 抖音 + 7 => PayDetails::selectSumPayByClassify(7, $flag, $time, $payClassify), // 苹果 + 8 => PayDetails::selectSumPayByClassify(8, $flag, $time, $payClassify) // 快手 + ]; + + // 3. 构建结果映射(处理null值,默认为0.00) + $result = [ + 'sumMoney' => $sumMoney ?? 0.00, + 'weiXinAppMoney' => $channelMoneys[1] ?? 0.00, + 'weiXinGZHMoney' => $channelMoneys[2] ?? 0.00, + 'weiXinXCXMoney' => $channelMoneys[3] ?? 0.00, + 'zhiFuBaoAppMoney' => $channelMoneys[4] ?? 0.00, + 'zhiFuBaoH5Money' => $channelMoneys[5] ?? 0.00, + 'dyMoney' => $channelMoneys[6] ?? 0.00, + 'iosMoney' => $channelMoneys[7] ?? 0.00, + 'ksMoney' => $channelMoneys[8] ?? 0.00 + ]; + $this->n_success(['data' => $result]); + } + + public static function send($userInfo, $title, $content) + { + if (!empty($userInfo['client_id'])) { + + } + + Db::name('message_info')->insert([ + 'content' => $content, + 'title' => $title, + 'state' => 5, + 'is_see' => 0, + 'user_name' => $userInfo['user_name'], + 'user_id' => $userInfo['user_id'] + ]); + + + } + + + public function sendMsg() + { + $params = $this->request->param(); + if ($params['flag'] == 1) { + $userInfo = DatabaseRoute::getAllDbData('tb_user', function ($query) use ($params) { + return $query->where([ + 'phone' => $params['phone'] + ]); + })->find(); + + if (!$userInfo) { + $this->error('用户不存在'); + } + $this->send($userInfo, $params['title'], $params['content']); + + }else{ + $userList = DatabaseRoute::getAllDbData('tb_user', function ($query) use ($params) { + return $query; + })->list(); + $chunks = array_chunk($userList, ceil(count($userList) / 3)); + pushQueue($chunks[0]); + pushQueue($chunks[1]); + pushQueue($chunks[2]); + + } + + $this->success(); + + } + + + // 用户提现记录 + public function selectPayDetails() + { + $get = $this->request->get(); + $cashOut = []; + if(isset($get['userId'])) { + $cashOut['userId'] = $get['userId']; + } + $res = \app\admin\model\Cash::selectCashOutList($get['page'], $get['limit'], $cashOut); + $this->n_success(['data' => $res]); + + } + + + /** + * 提现接口 + */ + public function withdraw() + { + $get = $this->request->get(); + $userId = $get['userId'] ?? null; + $money = $get['money'] ?? null; + $msg = $get['msg'] ?? null; + // 验证验证码是否为空 + if (empty($msg)) { + $this->error('请输入验证码'); + } + debounce("withdraw:".$userId, 30); + runWithLock("lock:withdraw:{$userId}", 300, function () use ($userId, $money, $msg) { + WithDraw::goWithDraw($userId, $money, $msg, true, true); + }); + $this->success('提现成功,将在三个工作日内到账,请耐心等待!'); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/CashOutAuditController.php b/app/czg/controller/CashOutAuditController.php new file mode 100644 index 0000000..806382f --- /dev/null +++ b/app/czg/controller/CashOutAuditController.php @@ -0,0 +1,325 @@ +request->get(); + $cashOut = []; + if (!empty($params)) { + $cashOut = array_intersect_key($params, array_flip([ + 'user_id', 'user_name', 'zhifubao_name', 'zhifubao', + 'bank_name', 'user_type', 'state', 'start_time', 'end_time' + ])); + } + $cashOutList = DatabaseRoute::paginateAllDb('cash_out', function ($query) use($cashOut) { + if (!empty($cashOut['user_id'])) { + $query->where('user_id', $cashOut['user_id']); + } + // 用户名模糊查询(对应Java的userName匹配zhifubaoName) + if (!empty($cashOut['user_name'])) { + $query->whereLike('zhifubao_name', "%{$cashOut['user_name']}%"); + } + // 支付宝姓名模糊查询 + if (!empty($cashOut['zhifubao_name'])) { + $query->whereLike('zhifubao_name', "%{$cashOut['zhifubao_name']}%"); + } + // 支付宝账号模糊查询 + if (!empty($cashOut['zhifubao'])) { + $query->whereLike('zhifubao', "%{$cashOut['zhifubao']}%"); + } + // 银行名称模糊查询 + if (!empty($cashOut['bank_name'])) { + $query->whereLike('bank_name', "%{$cashOut['bank_name']}%"); + } + // 用户类型条件 + if (isset($cashOut['user_type']) && $cashOut['user_type'] !== '') { + $query->where('user_type', $cashOut['user_type']); + } + // 状态条件 + if (isset($cashOut['state']) && $cashOut['state'] !== '') { + $query->where('state', $cashOut['state']); + } + // 时间范围条件 + $startTime = isset($cashOut['start_time']) ? $cashOut['start_time'] : ''; + $endTime = isset($cashOut['end_time']) ? $cashOut['end_time'] : ''; + if ($startTime && $endTime) { + $query->whereBetween('create_at', $startTime, $endTime); + } elseif ($startTime) { + $query->where('create_at', '>=', $startTime); + } elseif ($endTime) { + $query->where('create_at', '<=', $endTime); + } + return $query; + }, $params['page'], $params['limit'], 'create_at'); + + // 补充关联数据 + if (!empty($cashOutList['list'])) { + // 提取所有用户ID + $userIdList = Collection::make($cashOutList['list'])->column('user_id'); + $userIdList = array_unique(array_filter($userIdList)); // 去重并过滤空值 + if($userIdList) { + $countInfoList_n = []; + foreach ($userIdList as $k => $user_id) { + $db_name = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $user_id])); + $userNameMap[] = $db_name->name('tb_user')->where(['user_id' => $user_id])->field('user_id, user_name') + ->select() + ->column('user_name', 'user_id'); + + $countInfoList[] = $db_name + ->query("SELECT user_id as userId, + ROUND(SUM(CASE WHEN state = 1 THEN money ELSE 0 END), 2) AS total, + COUNT(CASE WHEN state = 1 THEN 1 END) AS count, + ROUND(SUM(CASE WHEN state = 3 THEN money ELSE 0 END), 2) AS verifyTotal, + COUNT(CASE WHEN state = 3 THEN 1 END) AS verifyCount + FROM cash_out + WHERE user_id=" . $user_id . " + GROUP BY user_id")[0]; + } + $countInfoMap = []; + foreach ($countInfoList as $item) { + + $countInfoMap[$item['userId']] = $item; + } + + // 补充字段到结果集 + foreach ($cashOutList['list'] as &$item) { + // 补充用户名 + $item['user_name'] = $userNameMap[$item['user_id']] ?? ''; + + // 补充统计信息 + if (isset($countInfoMap[$item['user_id']])) { + $countInfo = $countInfoMap[$item['user_id']]; + $item['total'] = $countInfo['total']; + $item['count'] = $countInfo['count']; + $item['verify_count'] = $countInfo['verifyCount']; + $item['verify_total'] = $countInfo['verifyTotal']; + } else { + $item['total'] = 0; + $item['count'] = 0; + $item['verify_count'] = 0; + $item['verify_total'] = 0; + } + } + unset($item); // 解除引用 + } + } + $this->n_success(['page' => $cashOutList]); + } + + // + public function alipaytransfersummaryquery() + { + $get = $this->request->get(); + // 校验支付宝账户名 + if (empty($get['alipayAccountName'])) { + $this->error('支付宝账号不能为空'); + } + $alipayAccountName = $get['alipayAccountName']; + // 初始化返回数据结构 + $data = [ + 'alipayAccountName' => $alipayAccountName, + 'sum' => 0.00, + 'count' => 0, + 'list' => [] + ]; + + $cashOutList = DatabaseRoute::getAllDbData('cash_out', function ($query) use($alipayAccountName) { + return $query->where('state', 1) + ->where('zhifubao_name', $alipayAccountName); + })->select()->toArray(); + // 无记录则直接返回 + if (empty($cashOutList)) { + $this->n_success($data); + } + // 按用户ID分组(替代Java的Collectors.groupingBy) + $groupedByUserId = []; + foreach ($cashOutList as $record) { + $userId = $record['user_id']; + $groupedByUserId[$userId][] = $record; + } + + + // 处理每个用户的汇总数据 + foreach ($groupedByUserId as $userId => $userRecords) { + // 计算该用户的提现总金额 + $subSum = array_sum(array_column($userRecords, 'money')); + + // 初始化用户记录 + $record = [ + 'userId' => $userId, + 'userName' => '未知', + 'inviterCode' => '', + 'phone' => '', + 'zhiFuBaoName' => implode(' / ', array_unique(array_column($userRecords, 'zhifubao_name'))), + 'zhiFuBao' => implode(' / ', array_unique(array_column($userRecords, 'zhifubao'))), + 'subTotal' => $subSum, + 'subCount' => count($userRecords) + ]; + + // 查询用户信息 + $userEntity = Db::name('user') + ->where('user_id', $userId) + ->find(); + + // 补充用户信息 + if ($userEntity) { + $record['userId'] = $userEntity['user_id']; + $record['userName'] = $userEntity['user_name']; + $record['inviterCode'] = $userEntity['inviter_code']; + $record['phone'] = $userEntity['phone']; + } + + // 添加到结果列表 + $data['list'][] = $record; + + // 更新总统计 + $data['sum'] += $subSum; + $data['count'] += count($userRecords); + } + $this->n_success($data); + } + + + public function audit() + { + $cashOut = $this->request->post(); + // 1. 验证审核状态 + $isAgree = $cashOut['isAgree'] ?? null; + + if ($isAgree === null) { + $this->error("请选择同意或者拒绝!"); + } + // 拒绝时必须填写原因 + if ($isAgree == 0 && trim($cashOut['refund'] ?? '') === '') { + $this->error("请输入拒绝原因!"); + } + + $db = Db::connect(DatabaseRoute::getConnection('cash_out', ['user_id' => $cashOut['userId']], true)); + + // 2. 查询提现申请实体 + $entity = $db->name('cash_out') + ->where('user_id', $cashOut['userId']) + ->where('id', $cashOut['id']) + ->find(); + if (!$entity) { + $this->error("提现申请不存在!"); + } + + // 3. 验证申请状态(必须为待审核状态:state=3) + if ($entity['state'] != 3) { + $this->error("提现申请状态无效,请刷新后重试!"); + } + + // 4. 根据审核结果更新状态 + if ($isAgree == 1) { + $entity['state'] = 0; // 同意 + } else { + $entity['state'] = 2; // 拒绝 + $entity['refund'] = $cashOut['refund']; // 拒绝原因 + } + + // 5. 验证用户/代理信息是否存在 + $isUser = true; + if ($entity['user_type'] == 2) { + $isUser = false; // 代理用户 + } + + if ($isUser) { + // 普通用户 + $user = $db->name('tb_user')->where('user_id', $entity['user_id'])->find(); + if (!$user) { + $this->error("提现用户信息不存在!"); + } + } else { + // 代理用户 + $sysUser = $db->name('sys_user')->where('user_id', $entity['user_id'])->find(); + if (!$sysUser) { + $this->error("提现代理信息不存在!"); + } + } + + // 6. 拒绝时退回金额并返回 + if ($isAgree == 0) { + \app\admin\model\Cash::backCashAmount($entity, $db); + $this->success(); + } + + // 7. 同意时处理提现逻辑 + $isHistoryData = false; + // 历史数据判断(无银行名称的普通用户) + if ($isUser && trim($entity['bank_name'] ?? '') === '') { + $isHistoryData = true; + } + + // 更新状态为处理中 + $entity['state'] = 4; + $db->name('cash_out') + ->where('user_id', $entity['user_id']) + ->where('id', $entity['id']) + ->update([ + 'state' => 4 + ]); + + // 生成订单号(为空时) + if (trim($entity['order_number'] ?? '') === '') { + $entity['order_number'] = Random::generateRandomPrefixedId(19); + $db->name('cash_out') + ->where('id', $entity['id']) + ->update(['order_number' => $entity['order_number']]); + } + + // 8. 调用支付接口执行提现 + $baseResp = WuYouPayUtils::extractOrder( + $isHistoryData, + $entity['order_number'], + $entity['user_id'], + $entity['money'], + $isUser, + $entity['zhifubao'] ?? '', + $entity['zhifubao_name'] ?? '', + $entity['bank_name'] ?? '', + empty($entity['province']) ? '1' : $entity['province'], + empty($entity['city']) ? '1' : $entity['city'], + empty($entity['bank_branch']) ? '1' : $entity['bank_branch'] + ); + + // 9. 根据支付结果更新状态 + $updateData = []; + if (isset($baseResp['status']) && ($baseResp['status'] == 2 || $baseResp['status'] == 10000)) { + $entity['state'] = 1; // 提现成功 + } elseif (!empty($baseResp['error_msg'])) { + $entity['state'] = 2; // 提现失败 + if (strpos($baseResp['error_msg'], '收款人账户号出款属性不匹配') !== false) { + $entity['refund'] = "提现失败,请检查收款账号与收款人姓名后重试。"; + } else { + $entity['refund'] = $baseResp['error_msg']; + } + \app\admin\model\Cash::backCashAmount($entity, $db); // 失败时退回金额 + } elseif (!empty($baseResp['msg'])) { + $entity['state'] = 2; // 提现失败 + $entity['refund'] = "提现失败,请检查收款账号与收款人姓名后重试。"; + \app\admin\model\Cash::backCashAmount($entity, $db); // 失败时退回金额 + } + // 调用用户ID更新方法(原updateByUserId) + \app\admin\model\Cash::updateByUserId($entity, $db); + } + + + + +} \ No newline at end of file diff --git a/app/czg/controller/CommonController.php b/app/czg/controller/CommonController.php new file mode 100644 index 0000000..4322fe3 --- /dev/null +++ b/app/czg/controller/CommonController.php @@ -0,0 +1,44 @@ +request->param(); + $this->successWithData(Db::name('common_info')->where([ + 'condition_from' => $condition['condition'] + ])->select()->toArray()); + } + + public function update() + { + $params = $this->request->post(); + $params['create_at'] = getNormalDate(); + Db::name('common_info')->where([ + 'id' => $params['id'] + ])->update(convertKeysCamelToSnakeRecursive($params)); + + $info = Db::name('common_info')->where([ + 'id' => $params['id'] + ])->find(); + cache('common_info:'.$info['type'], null); + $this->success(); + } + + public function type() + { + $get = $this->request->param(); + if(empty($get['num'])) { + $this->error('type 不能为空'); + } + $data = convertToCamelCase(Db::connect(config('database.search_library'))->name('common_info')->where('type', $get['num'])->find()); + $this->success('ok', $data); + } +} \ No newline at end of file diff --git a/app/czg/controller/CompletAwardController.php b/app/czg/controller/CompletAwardController.php new file mode 100644 index 0000000..4edd4d9 --- /dev/null +++ b/app/czg/controller/CompletAwardController.php @@ -0,0 +1,34 @@ +request->post(); + $db = Db::connect(get_master_connect_name()); + $post['create_time'] = date('Y-m-d H:i:s'); + $data = []; + foreach ($post as $k => $v) { + $data[toSnakeCase($k)] = $v; + } + unset($data['invite_img']); + unset($data['id']); + $db->name('complet_award')->insert($data); + $this->success(); + } + +} \ No newline at end of file diff --git a/app/czg/controller/CourseClassificationController.php b/app/czg/controller/CourseClassificationController.php new file mode 100644 index 0000000..3c4d196 --- /dev/null +++ b/app/czg/controller/CourseClassificationController.php @@ -0,0 +1,62 @@ +request->param(); + if (!isset($params['page'])) { + $params['page'] = 1; + } + if (!isset($params['limit'])) { + $params['limit'] = 10; + } + + $this->n_success(['data' => DatabaseRoute::paginateDb('course_classification', function ($query) use ($params) { + if (isset($params['classificationName'])) { + $query->whereLike('classification_name', '%' . $params['classificationName'] . '%'); + } + return $query->where([ + 'is_delete' => 0 + ]); + }, $params['page'], $params['limit'])]); + } + + public function insertCourseClassification() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['is_delete'] = 0; + Db::name('course_classification')->insert($params); + $this->success(); + } + + public function updateCourseClassification() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + Db::name('course_classification')->where([ + 'classification_id' => $params['classification_id'] + ])->update($params); + $this->success(); + } + + public function updateDelete() + { + $params = $this->request->param(); + Db::name('course_classification')->where([ + 'classification_id' => $params['id'] + ])->delete(); + $this->success(); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/CourseCollectController.php b/app/czg/controller/CourseCollectController.php new file mode 100644 index 0000000..d1e1892 --- /dev/null +++ b/app/czg/controller/CourseCollectController.php @@ -0,0 +1,23 @@ +request->get(); + return $this->ApiDataReturn(\app\api\model\Course::selectByUserId($get, $this->auth->user_id)); + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/CourseController.php b/app/czg/controller/CourseController.php new file mode 100644 index 0000000..55700b9 --- /dev/null +++ b/app/czg/controller/CourseController.php @@ -0,0 +1,139 @@ +request->param(); + $res = \app\api\model\Course::selectCourse($params); + $this->successWithData($res['data']); + } + + public function insertCourse() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['is_delete'] = 0; + $params['create_time'] = getNormalDate(); + $params['course_id'] = Random::generateRandomPrefixedId(); + $params['banner_id'] = empty($params['banner_id']) ? null : $params['banner_id']; + if ($params['course_type'] == 2 || $params['course_type'] == 3) { + $copy = unserialize(serialize($params)); + unset($copy['remark']); + $id = Db::name('course')->insert($copy); + DatabaseRoute::getDb('course_details', $id, true)->insert([ + 'course_id' => $id, + 'video_url' => $params['remark'] ?? '', + 'view_count' => 0, + 'play_complete_count' => 0, + ]); + }else { + unset($params['remark']); + $id = Db::name('course')->insert($params); + } + + $this->success(); + } + + public function updateCourse() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + unset($params['banner_id']); + Db::name('course')->where([ + 'course_id' => $params['course_id'] + ])->update($params); + $this->success(); + } + + public function selectCourseById() + { + $params = $this->request->param(); + $where = [ + 'course_id' => $params['id'] + ]; + if (!empty($params['good'])) { + if ($params['good'] == 1) { + $where['good'] = $params['good']; + }else{ + $where['good'] = $params['good']; + } + } + $this->successWithData(DatabaseRoute::paginateDb('course_details', function ($query) use($where) { + $query->where($where); + return $query->order('sort', false); + }, $params['page'], $params['limit'], [ + 'course_id' => $params['id'] + ])); + + } + + public function updateDelete() + { + $params = $this->request->param(); + Db::name('course')->where([ + 'course_id' => $params['id'] + ])->delete(); + $this->success(); + } + + public function updateCourseStatus() + { + $params = $this->request->param(); + $params['ids'] = explode(',', $params['ids']); + foreach ($params['ids'] as $id) { + Db::name('course')->where([ + 'course_id' => $id + ])->update([ + 'status' => $params['status'] + ]); + } + + $this->success(); + } + + public function updateCourseDetails() + { + $param = $this->request->param(); + $param['ids'] = explode(',', $param['ids']); + foreach ($param['ids'] as $id) { + DatabaseRoute::getAllDbData('course_details', function ($query) use ($id, $param) { + return $query->where([ + 'course_details_id' => $id + ]); + })->update([ + 'is_price' => bccomp($param['price'],0, 4) == 0 ? 2 : 1, + 'content' => $param['content'], + 'title_img' => $param['titleImg'], + ]); + } + + $this->success(); + } + + public function deleteCourseDetailsByIds() + { + $params = $this->request->param(); + $params['ids'] = explode(',', $params['ids']); + foreach ($params['ids'] as $id) { + DatabaseRoute::getAllDbData('course_details', function ($query) use ($id) { + return $query->where([ + 'course_details_id' => $id + ]); + })->delete(); + } + + $this->success(); + } +} \ No newline at end of file diff --git a/app/czg/controller/CourseDetailsController.php b/app/czg/controller/CourseDetailsController.php new file mode 100644 index 0000000..7409906 --- /dev/null +++ b/app/czg/controller/CourseDetailsController.php @@ -0,0 +1,56 @@ +request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['create_time'] = getNormalDate(); + $params['course_details_id'] = Random::generateRandomPrefixedId(); + if (empty($params['good_num'])) { + $params['good_num'] = 0; + } + DatabaseRoute::getDb('course_details', [ + 'course_id' => $params['course_id'] + ], true)->insert($params); + $this->success(); + } + + public function updateCourseDetails() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $db = Db::connect(DatabaseRoute::getConnection('course_details', ['course_id' => $params['course_id']], true)); + $course_details_id = $params['course_details_id']; + unset($params['course_id']); + unset($params['course_details_id']); + $db->name('course_details')->where('course_details_id', $course_details_id)->update($params); + $this->success(); + } + + public function deleteCourseDetails() + { + $ids = $this->request->param('ids'); + $ids = explode(',', $ids); + foreach ($ids as $id) { + DatabaseRoute::deleteAllDbDirect('course_details', function ($query) use ($id) { + return $query->where([ + 'course_details_id' => $id + ]); + }); + } + $this->success(); + } + +} \ No newline at end of file diff --git a/app/czg/controller/DashboardController.php b/app/czg/controller/DashboardController.php new file mode 100644 index 0000000..de6d2a7 --- /dev/null +++ b/app/czg/controller/DashboardController.php @@ -0,0 +1,20 @@ +success('', [ + 'remark' => get_route_remark() + ]); + } +} \ No newline at end of file diff --git a/app/czg/controller/DiscSpinningAmountController.php b/app/czg/controller/DiscSpinningAmountController.php new file mode 100644 index 0000000..380e041 --- /dev/null +++ b/app/czg/controller/DiscSpinningAmountController.php @@ -0,0 +1,122 @@ +request->get(); + if(empty($get['page'])) { + $get['page'] = 1; + } + if(empty($get['limit'])) { + $get['limit'] = 20; + } + $db = Db::connect(get_slave_connect_name()); + $count = $db->name('disc_spinning_amount')->where('type', $get['type'])->count(); + // 构建查询条件 + $res = $db->name('disc_spinning_amount') + ->where('type', $get['type']) + ->order('status', 'desc') + ->order('num', 'asc') + ->order('random', 'asc') + ->order('max_amount', 'asc') + ->limit(page($get['page'], $get['limit'])) + ->select() + ->toArray(); + foreach ($res as $k => &$v) { + $scaleFactor = 100; + $intValue = (int)round($v['max_amount'] * $scaleFactor, 0); + $v['max_amount'] = $intValue / $scaleFactor; + + $intValue = (int)round($v['random'] * $scaleFactor, 0); + $v['random'] = $intValue / $scaleFactor; + + } + // 转换为前端需要的格式 + $data = [ + 'totalCount' => $count, + 'pageSize' => $get['limit'], + 'totalPage' => ceil($count / $get['limit']), + 'currPage' => $get['page'], + 'list' => null, + 'records' => $res + ]; + $this->n_success(['data' => $data]); + } + + + // 添加现金红包 抽奖配置 + public function insertDiscSpinningAmount() + { + $post = $this->request->post(); + // 保存数据到数据库 + $result = Db::name('disc_spinning_amount')->insert([ + 'name' => $post['name'], + 'random' => $post['random'], + 'max_amount' => $post['maxAmount'], + 'type' => $post['type'], + 'status' => $post['status'], + 'num' => $post['num'] ?? 0, + ]); + if (!$result) { + $this->error("保存转盘金额配置失败"); + } + // 删除Redis缓存(使用Cache门面) + $cacheKey = "spinning:amount:{$post['type']}"; + Cache::delete($cacheKey); + $this->success(); + } + + // 修改现金红包 抽奖配置 + public function updateDiscSpinningAmount() + { + $post = $this->request->post(); + // 保存数据到数据库 + Db::name('disc_spinning_amount')->where(['id' => $post['id']])->update([ + 'name' => $post['name'], + 'random' => $post['random'], + 'max_amount' => $post['maxAmount'], + 'type' => $post['type'], + 'status' => $post['status'], + 'num' => $post['num'], + ]); +// if (!$result) { +// $this->error("保存转盘金额配置失败"); +// } + // 删除Redis缓存(使用Cache门面) + $cacheKey = "spinning:amount:{$post['type']}"; + Cache::delete($cacheKey); + $this->success(); + } + + + + public function deleteDiscSpinningAmount() + { + $post = $this->request->param(); + // 保存数据到数据库 + $result = Db::name('disc_spinning_amount')->where(['id' => $post['id']])->delete(); + if (!$result) { + $this->error("保存转盘金额配置失败"); + } + // 删除Redis缓存(使用Cache门面) + $cacheKey = "spinning:amount"; + Cache::delete($cacheKey); + $this->success(); + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/DiscSpinningController.php b/app/czg/controller/DiscSpinningController.php new file mode 100644 index 0000000..1ff046e --- /dev/null +++ b/app/czg/controller/DiscSpinningController.php @@ -0,0 +1,126 @@ +request->get(); + $db = Db::connect(get_slave_connect_name()); + $count = $db->name('disc_spinning')->where(['disc_type' => $get['source']])->count(); + $res = $db->name('disc_spinning')->where(['disc_type' => $get['source']])->limit(page($get['page'], $get['limit']), $get['limit'])->order('disc_type', 'asc')->order('odds', 'asc')->select()->toArray(); + $this->n_success(['data' => [ + 'totalCount' => $count, + 'pageSize' => $get['limit'], + 'totalPage' => ceil($count / $get['limit']), + 'currPage' => $get['page'], + 'list' => null, + 'records' => $res + ]]); + } + + + // 修改大转盘 + public function updateDiscSpinning() + { + $post = $this->request->post(); +// if(empty($post['name']) || empty($post['url']) || empty($post['type']) || empty($post['odds']) || empty($post['discType']) || empty($post['id'])) { +// $this->error('参数不完整'); +// } + + // 查询指定类型的奖品列表(按type和id升序排列) + $prizes = Db::name('disc_spinning') + ->where('disc_type', $post['discType']) + ->order('type', 'asc') + ->order('id', 'asc') + ->select() + ->toArray(); + + // 处理奖品概率累加 + $upPrizes = []; + $number = 0; // 概率累加值(PHP使用浮点数,需注意精度问题) + + foreach ($prizes as $key => $prize) { + // 如果是当前编辑的奖品,使用传入的数据覆盖 + if ($prize['id'] == $post['id']) { + $prizes[$key] = $post; + $prize = $post; + } + + // 累加概率 + $number += $prize['odds']; + $prizes[$key]['number'] = $number; // 记录累加后的概率值 + + // 添加到结果列表 + $upPrizes[] = convertKeysCamelToSnakeRecursive($prizes[$key]); + } + + // 验证概率总和是否超过100 + if ($number > 100) { + $this->error("中奖概率总和 不可超过100"); + } + + \app\admin\model\DiscSpinning::updateBatchById($upPrizes); + $this->success(); + } + + // 删除大转盘 + public function deleteDiscSpinning() + { + $post = $this->request->post(); + if(empty($post['id'])) { + $this->error('id不能为空'); + } + $db = Db::connect(get_master_connect_name()); + if($db->name('disc_spinning')->where(['id' => $post['id']])->delete()) { + $this->success(); + } + $this->error(); + } + + // 转盘添加抽奖项 + public function insertDiscSpinning() + { + $post = $this->request->post(); + if(empty($post['name']) || empty($post['url']) || empty($post['type']) || empty($post['odds']) || empty($post['discType'])) { + $this->error('参数不完整'); + } + // 查询指定类型的奖品列表(按type和id升序排列) + $prizes = Db::name('disc_spinning') + ->where('disc_type', $post['discType']) + ->order('type', 'asc') + ->order('id', 'asc') + ->select() + ->toArray(); + // 计算当前奖品总概率 + $totalOdds = 0; + foreach ($prizes as &$prize) { + $totalOdds += $prize['odds']; + $prize['number'] = $totalOdds; + } + unset($prize); // 释放引用 + // 计算新增奖品后的总概率 + $newTotalOdds = $totalOdds + $post['odds']; + // 验证概率总和是否超过100 + if ($newTotalOdds > 100) { + $this->error("中奖概率总和 不可超过100"); + } + // 设置创建时间(使用当前时间戳) + $post['create_time'] = date('Y-m-d H:i:s'); + $post['number'] = $post['odds']; + \app\admin\model\DiscSpinning::updateBatchById($prizes); + Db::name('disc_spinning')->insert($post); + $this->success(); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/ExtSysController.php b/app/czg/controller/ExtSysController.php new file mode 100644 index 0000000..badeac1 --- /dev/null +++ b/app/czg/controller/ExtSysController.php @@ -0,0 +1,78 @@ + $code + ])->find(); + if($commonInfo) { + $commonInfo = $commonInfo->toArray(); + } + cache('common_info:'.$code, $commonInfo, 60 * 60 * 24); + } + if (!$commonInfo) { + $this->success(); + } + + $this->successWithData([ + 'imageUrl' => $commonInfo['value'], + 'tips' => $commonInfo['max'] + ]); + + } + + public function friendConfigSave() + { + $params = $this->request->post(); + if (empty($params['imageUrl'])) { + $this->error('顶部图片地址不能为空'); + } + + if (empty($params['tips'])) { + $this->error('邀请文案不能为空'); + } + + if (strlen($params['tips']) > 20) { + $this->error('邀请文案不能大于20个字符'); + } + + $commonInfo = (new CommonInfo())->getByCode(999); + if ($commonInfo) { + Db::name('common_info')->where([ + 'id' => $commonInfo['id'] + ])->update([ + 'max' => $params['tips'], + 'value' => $params['imageUrl'] + ]); + }else{ + Db::name('common_info')->insert([ + 'code' => 999, + 'max' => $params['tips'], + 'value' => $params['imageUrl'], + 'min' => '邀请好友配置', + 'is_app_use' => 1, + 'create_at' => getNormalDate() + ]); + } + cache('common_info:999', Db::name('common_info')->where([ + 'type' => 999 + ])->find()); + $this->success(); + + } + + +} \ No newline at end of file diff --git a/app/czg/controller/HelpWordController.php b/app/czg/controller/HelpWordController.php new file mode 100644 index 0000000..acb78cc --- /dev/null +++ b/app/czg/controller/HelpWordController.php @@ -0,0 +1,119 @@ +request->get(); + $page = $get['page'] ?? 1; + $limit = $get['limit'] ?? 10; + $types = $get['types'] ?? null; + $helpClassifyName = $get['helpClassifyName'] ?? null; + $parentId = $get['parentId'] ?? null; + $db = Db::connect(get_slave_connect_name()); + // 构建查询 + $query = $db->name('help_classify'); + $query = $query->when($types !== null, function ($query) use ($types) { + return $query->where('types', $types); + }); + $query = $query->when(!empty($helpClassifyName), function ($query) use ($helpClassifyName) { + return $query->where('help_classify_name', $helpClassifyName); + }); + + $query = $query->when($parentId !== null, function ($query) use ($parentId) { + return $query->where('parent_id', $parentId); + }); + $count = $query->count(); + $res = $query->order('sort', 'asc')->limit(page($page, $limit), $limit)->select()->toArray(); + $data = [ + 'totalCount' => $count, + 'pageSize' => $limit, + 'totalPage' => ceil($count / $limit), + 'currPage' => $page, + 'list' => $res, + 'records' => $res + ]; + $this->n_success(['data' => $data]); + } + + // 删除帮助分类 + public function deleteHelpClassify() + { + $post = $this->request->param(); + if(empty($post['helpClassifyId'])) { + $this->error('参数不完整'); + } + + $db = Db::connect(get_master_connect_name()); + $db->name('help_classify')->where(['help_classify_id' => $post['helpClassifyId']])->delete(); + $this->success(); + + + } + + // 添加帮助分类 + public function insertHelpClassify() + { + $post = $this->request->post(); + $createTime = date('Y-m-d H:i:s'); + if(empty($post['helpClassifyName']) || !isset($post['sort']) || empty($post['state']) || empty($post['types'])) { + $this->error('参数不完整'); + } + Db::name('help_classify')->insert([ + 'help_classify_id' => Random::generateRandomPrefixedId(), + 'help_classify_name' => $post['helpClassifyName'], + 'sort' => $post['sort'], + 'types' => $post['types'], + 'create_time' => $createTime, + ]); + $this->success(); + } + + + public function selectHelpWordList() + { + $get = $this->request->get(); + $helpClassifyId = $get['helpClassifyId'] ?? null; + $helpWordTitle = $get['helpWordTitle'] ?? null; + $page = $get['page'] ?? null; + $limit = $get['limit'] ?? null; + $query = Db::name('help_word'); + // 条件筛选 + if (!is_null($helpClassifyId)) { + $query->where('help_classify_id', $helpClassifyId); + } + if (!empty($helpWordTitle)) { + $query->where('help_word_title', $helpWordTitle); + } + // 排序和分页 + $list = $query->order('sort', 'asc') + ->page($page, $limit) + ->limit(page($page, $limit), $limit) + ->select() + ->toArray(); + // 获取总数(用于分页信息) + $count = $query->count(); + $this->n_success(['data' => [ + 'totalCount' => $count, + 'pageSize' => $get['limit'], + 'totalPage' => ceil($count / $get['limit']), + 'currPage' => $get['page'], + 'list' => $list, + ]]); + + + } + + + + +} \ No newline at end of file diff --git a/app/czg/controller/IndetcodeController.php b/app/czg/controller/IndetcodeController.php new file mode 100644 index 0000000..52af965 --- /dev/null +++ b/app/czg/controller/IndetcodeController.php @@ -0,0 +1,18 @@ +get(); + if(empty($data['uuid']))$this->error('参数不完整'); + $this->success('ok', SysCaptcha::getCode($data['uuid'], $request)); + } +} \ No newline at end of file diff --git a/app/czg/controller/IndexController.php b/app/czg/controller/IndexController.php new file mode 100644 index 0000000..667301a --- /dev/null +++ b/app/czg/controller/IndexController.php @@ -0,0 +1,133 @@ +auth->getInfo(); + $adminInfo['super'] = $this->auth->isSuperAdmin(); + unset($adminInfo['token'], $adminInfo['refresh_token']); + + $menus = $this->auth->getMenus(); + if (!$menus) { + $this->error(__('No background menu, please contact super administrator!')); + } + $this->success('', [ + 'adminInfo' => $adminInfo, + 'menus' => $menus, + 'siteConfig' => [ + 'siteName' => get_sys_config('site_name'), + 'version' => get_sys_config('version'), + 'apiUrl' => Config::get('buildadmin.api_url'), + 'upload' => keys_to_camel_case(get_upload_config(), ['max_size', 'save_name', 'allowed_suffixes', 'allowed_mime_types']), + 'cdnUrl' => full_url(), + 'cdnUrlParams' => Config::get('buildadmin.cdn_url_params'), + ], + 'terminal' => [ + 'phpDevelopmentServer' => str_contains($_SERVER['SERVER_SOFTWARE'], 'Development Server'), + 'npmPackageManager' => Config::get('terminal.npm_package_manager'), + ] + ]); + } + + /** + * 管理员登录 + * @return void + * @throws Throwable + */ + public function login(): void + { + // 检查登录态 + if ($this->auth->isLogin()) { + $this->success(__('You have already logged in. There is no need to log in again~'), [ + 'type' => $this->auth::LOGGED_IN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + + $captchaSwitch = Config::get('buildadmin.admin_login_captcha'); + + // 检查提交 + if ($this->request->isPost()) { + $username = $this->request->post('username'); + $password = $this->request->post('password'); + $keep = $this->request->post('keep'); + + $rule = [ + 'username|' . __('Username') => 'require|length:3,30', + 'password|' . __('Password') => 'require|regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + ]; + $data = [ + 'username' => $username, + 'password' => $password, + ]; + if ($captchaSwitch) { + $rule['captchaId|' . __('CaptchaId')] = 'require'; + $rule['captchaInfo|' . __('Captcha')] = 'require'; + + $data['captchaId'] = $this->request->post('captchaId'); + $data['captchaInfo'] = $this->request->post('captchaInfo'); + } + $validate = Validate::rule($rule); + if (!$validate->check($data)) { + $this->error($validate->getError()); + } + + if ($captchaSwitch) { + $captchaObj = new ClickCaptcha(); + if (!$captchaObj->check($data['captchaId'], $data['captchaInfo'])) { + $this->error(__('Captcha error')); + } + } + + AdminLog::instance()->setTitle(__('Login')); + + $res = $this->auth->login($username, $password, (bool)$keep); + if ($res === true) { + $this->success(__('Login succeeded!'), [ + 'userInfo' => $this->auth->getInfo() + ]); + } else { + $msg = $this->auth->getError(); + $msg = $msg ?: __('Incorrect user name or password!'); + $this->error($msg); + } + } + + $this->success('', [ + 'captcha' => $captchaSwitch + ]); + } + + /** + * 管理员注销 + * @return void + */ + public function logout(): void + { + if ($this->request->isPost()) { + $refreshToken = $this->request->post('refreshToken', ''); + if ($refreshToken) Token::delete((string)$refreshToken); + $this->auth->logout(); + $this->success(); + } + } +} diff --git a/app/czg/controller/IntegralController.php b/app/czg/controller/IntegralController.php new file mode 100644 index 0000000..c2143ec --- /dev/null +++ b/app/czg/controller/IntegralController.php @@ -0,0 +1,83 @@ +request->get(); + if(empty($get['userId'])) { + $this->error('userId is not empty'); + } + + $data = Db::connect(get_slave_connect_name())->name('user_integral')->where(['user_id' => $get['userId']])->find(); + $data = [ + 'user_id' => (string)$get['userId'], + 'integral_num' => !empty($data['integral_num'])?$data['integral_num']:'0', + ]; + $this->n_success(['data' => convertToCamelCase($data)]); + } + + public function details() + { + $get = $this->request->get(); + if(empty($get['userId'])) { + $this->error('userId is not empty'); + } + $this->n_success(['data' => UserIntegral::selectUserIntegralDetailsByUserId($get['page'], $get['limit'], $get['userId'])]); + } + + public function updateUserIntegral() + { + $post = $this->request->post(); + $userId = $post['userId'] ?? $this->error('参数不完整'); + $type = $post['type'] ?? $this->error('参数不完整'); + $integral = $post['integral'] ?? $this->error('参数不完整'); + + + Db::startTrans(); + try { + $db = Db::connect(get_master_connect_name()); + if(UserIntegral::updateIntegral($type, $userId, $integral, $db)) { + // 记录积分变动明细 + $details['classify'] = 2; + $details['content'] = $type == 1 + ? "系统增加积分:{$integral}" + : "系统减少积分:{$integral}"; + + $currentTime = time(); + $details['create_time'] = date('Y-m-d H:i:s', $currentTime); + + $details['num'] = $integral; + $details['type'] = $type; + $details['user_id'] = $userId; + $db->name('user_integral_details')->insert($details); + Db::commit(); + } + $this->success(); + }catch (Exception $e) { + Db::rollback(); + $this->error($e->getMessage()); + } + + + + + + + + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/InviteAwardController.php b/app/czg/controller/InviteAwardController.php new file mode 100644 index 0000000..d7471eb --- /dev/null +++ b/app/czg/controller/InviteAwardController.php @@ -0,0 +1,31 @@ +order('invite_count', 'asc')->select(); + $this->successWithData(buildPageInfo(convertToCamelCase($inviteList->toArray()), true)); + } + + public function deleteInviteAward() + { + $post = $this->request->param(); + $inviteAwardId = !empty($post['inviteAwardId'])?$post['inviteAwardId']:$this->error('参数不完整'); + $db = Db::connect(get_master_connect_name()); + if($db->name('invite_award')->where(['invite_award_id' => $inviteAwardId])->delete()) { + $this->success(); + } + $this->error(); + } + +} \ No newline at end of file diff --git a/app/czg/controller/InviteController.php b/app/czg/controller/InviteController.php new file mode 100644 index 0000000..e960fba --- /dev/null +++ b/app/czg/controller/InviteController.php @@ -0,0 +1,29 @@ +request->get(); + if(empty($get['userId'])) { + $this->error('userId 不能为空'); + } + $user = DatabaseRoute::getDb('tb_user', $get['userId'])->find(); + if(empty($user)) { + $this->error('用户不存在'); + } + return $this->ApiDataReturn(\app\api\model\Invite::selectInviteByUserIdLists($user, $get, 'admin')); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/LoginController.php b/app/czg/controller/LoginController.php new file mode 100644 index 0000000..f611023 --- /dev/null +++ b/app/czg/controller/LoginController.php @@ -0,0 +1,28 @@ +request->route->param(); + return $this->ApiDataReturn(Msg::sendMsg($get['phone'], $get['event'])); + } +} \ No newline at end of file diff --git a/app/czg/controller/MessageController.php b/app/czg/controller/MessageController.php new file mode 100644 index 0000000..2c5c7fc --- /dev/null +++ b/app/czg/controller/MessageController.php @@ -0,0 +1,85 @@ +request->param(); + $pageInfo = DatabaseRoute::paginateDb('message_info', function ($query) use ($params) { + if (!empty($params['state'])) { + $query->where([ + 'state' => $params['state'] + ]); + } + return $query; + }, $params['page'], $params['limit']); + foreach ($pageInfo['list'] as &$info) { + if (!empty($info['user_id'])) { + $info['userEntity'] = DatabaseRoute::getDb('tb_user', $info['user_id'])->find(); + } + } + + $this->successWithData($pageInfo); + } + + public function save() + { + $params = $this->request->post(); + $params['create_at'] = getNormalDate(); + Db::name('message_info')->insert(convertKeysCamelToSnakeRecursive($params)); + $this->success(); + } + + public function update() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + Db::name('message_info')->where([ + 'id' => $params['id'] + ])->update($params); + + $this->success(); + + } + + public function delete() + { + $params = $this->request->get(); + Db::name('message_info')->delete([ + 'id' => $params['id'] + ]); + + $this->success(); + + } + + + public function selectMessageByUserId() + { + $get = $this->request->get(); + $this->n_success(['data' => MessageInfo::selectMessageList($get)]); + } + + public function selectMessageByType() + { + $get = $this->request->get(); + $this->n_success(['data' => MessageInfo::selectMessageList($get)]); + } + + + + + + +} \ No newline at end of file diff --git a/app/czg/controller/ModuleController.php b/app/czg/controller/ModuleController.php new file mode 100644 index 0000000..11f2c1e --- /dev/null +++ b/app/czg/controller/ModuleController.php @@ -0,0 +1,156 @@ +success('', [ + 'sysVersion' => Config::get('buildadmin.version'), + 'installed' => Server::installedList(root_path() . 'modules' . DIRECTORY_SEPARATOR), + ]); + } + + public function state(): void + { + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + $this->success('', [ + 'state' => Manage::instance($uid)->getInstallState() + ]); + } + + public function install(): void + { + AdminLog::instance()->setTitle(__('Install module')); + $uid = $this->request->get("uid/s", ''); + $token = $this->request->get("token/s", ''); + $orderId = $this->request->get("orderId/d", 0); + if (!$uid) { + $this->error(__('Parameter error')); + } + $res = []; + try { + $res = Manage::instance($uid)->install($token, $orderId); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'data' => $res, + ]); + } + + public function dependentInstallComplete(): void + { + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->dependentInstallComplete('all'); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success(); + } + + public function changeState(): void + { + AdminLog::instance()->setTitle(__('Change module state')); + $uid = $this->request->post("uid/s", ''); + $state = $this->request->post("state/b", false); + if (!$uid) { + $this->error(__('Parameter error')); + } + $info = []; + try { + $info = Manage::instance($uid)->changeState($state); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'info' => $info, + ]); + } + + public function uninstall(): void + { + AdminLog::instance()->setTitle(__('Unload module')); + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->uninstall(); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success(); + } + + public function update(): void + { + AdminLog::instance()->setTitle(__('Update module')); + $uid = $this->request->get("uid/s", ''); + $token = $this->request->get("token/s", ''); + $orderId = $this->request->get("orderId/d", 0); + if (!$token || !$uid) { + $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->update($token, $orderId); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success(); + } + + public function upload(): void + { + AdminLog::instance()->setTitle(__('Upload install module')); + $file = $this->request->get("file/s", ''); + $token = $this->request->get("token/s", ''); + if (!$file) $this->error(__('Parameter error')); + if (!$token) $this->error(__('Please login to the official website account first')); + + $info = []; + try { + $info = Manage::instance()->upload($token, $file); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'info' => $info + ]); + } +} \ No newline at end of file diff --git a/app/czg/controller/MoneyDetailsController.php b/app/czg/controller/MoneyDetailsController.php new file mode 100644 index 0000000..0d9b306 --- /dev/null +++ b/app/czg/controller/MoneyDetailsController.php @@ -0,0 +1,52 @@ +request->get(); + if(empty($get['userId'])) { + $this->error('userId is not empty'); + } + + $this->n_success(['data' => User::selectUserMoneyByUserId($get['userId'])]); + + + } + + public function queryUserMoneyDetails() + { + $get = $this->request->get(); + $page = $get['page']; + $limit = $get['limit']; + $userId = $get['userId'] ?? ''; + $classify = $get['classify'] ?? null; + + $this->n_success(['data' => SysUserMoneyDetails::queryUserMoneyDetails($page, $limit, $get['sysUserId'] ?? '', $userId, $classify, null, null, null)]); + + + } + + public function selectSysUserMoney() + { + $get = $this->request->get(); + if(empty($get['userId'])) { + $this->error('userId is not empty'); + } + $this->n_success(['data' => SysUserMoney::selectSysUserMoneyByUserId($get['userId'])]); + + + } +} \ No newline at end of file diff --git a/app/czg/controller/OrderController.php b/app/czg/controller/OrderController.php new file mode 100644 index 0000000..4903dd0 --- /dev/null +++ b/app/czg/controller/OrderController.php @@ -0,0 +1,498 @@ +where([ + 'orders_id' => $id + ]); + }); + } + $this->success(); + } + + public function selectOrders() + { + $params = $this->request->get(); + $this->successWithData(DatabaseRoute::paginateAllDb('orders', function ($query) use ($params) { + // 动态拼接查询条件 + if (!empty($params['userName'])) { + $query->whereLike('u.user_name', '%' . $params['userName'] . '%'); + } + + if (!empty($params['qdCode'])) { + $query->where('s.qd_code', $params['qdCode']); + } + + if (!empty($params['sysUserName'])) { + $query->whereLike('s.username', '%' . $params['sysUserName'] . '%'); + } + + if (!empty($params['ordersNo'])) { + $query->whereLike('o.orders_no', '%' . $params['ordersNo'] . '%'); + } + + if (isset($params['status']) && $params['status'] !== -1) { + $query->where('o.status', $params['status']); + } + + if (!empty($params['userId'])) { + $query->where('o.user_id', $params['userId']); + } + + if (!empty($params['ordersType'])) { + $query->where('o.orders_type', $params['ordersType']); + } + + if (!empty($params['courseId'])) { + $query->where('o.course_id', $params['courseId']); + } + + if (!empty($params['sysUserId'])) { + $query->where('o.sys_user_id', $params['sysUserId']); + } + + // 时间范围 + if (!empty($params['startTime']) && !empty($params['endTime'])) { + $query->whereBetween('o.create_time', [$params['startTime'], $params['endTime']]); + } elseif (!empty($params['startTime'])) { + $query->where('o.create_time', '>=', $params['startTime']); + } elseif (!empty($params['endTime'])) { + $query->where('o.create_time', '<=', $params['endTime']); + } + + // 排序 + $query->order('o.create_time', 'desc'); + return $query->alias('o') + ->field('o.*, u.user_name as userName, s.username as sysUserName, s.qd_code as qdCode') + ->leftJoin('tb_user u', 'o.user_id = u.user_id') + ->leftJoin('sys_user s', 's.user_id = o.sys_user_id'); + }, $params['page'], $params['limit'])); + } + + private function sumOrder($params) + { + // 总收益 + return DatabaseRoute::getAllDbData('orders', function ($query) use ($params) { + // 条件拼接 + if (!empty($params['sysUserId']) && $params['sysUserId'] != 1) { + $query->where('sys_user_id', $params['sysUserId']); + } + + if (isset($params['status'])) { + $query->where('status', $params['status']); + } + + if (isset($params['courseId'])) { + $query->where('course_id', $params['courseId']); + } + + if (isset($params['ordersType'])) { + $query->where('orders_type', $params['ordersType']); + } + + if (isset($params['flag']) && !empty($params['time'])) { + switch ((int)$params['flag']) { + case 1: + // 按日 + $query->whereRaw("DATE_FORMAT(create_time, '%Y-%m-%d') = DATE_FORMAT(:time, '%Y-%m-%d')", ['time' => $params['time']]); + break; + case 2: + // 按月 + $query->whereRaw("DATE_FORMAT(create_time, '%Y-%m') = DATE_FORMAT(:time, '%Y-%m')", ['time' => $params['time']]); + break; + case 3: + // 按年 + $query->whereRaw("DATE_FORMAT(create_time, '%Y') = DATE_FORMAT(:time, '%Y')", ['time' => $params['time']]); + break; + } + } + + $query->where('pay_way', 9) + ->where('status', 1); // 强制条件 + return $query; + })->sum('pay_money'); + } + + + public function selectCourseOrdersMoneyCount() + { + $params = $this->request->param(); + + $params['ordersType'] = 1; + $params['time'] = date('Y-m-d 00:00:00'); + // 总收益 + $sumMoney = $this->sumOrder($params); + $params['flag'] = 3; + $yearMoney = $this->sumOrder($params); + $params['flag'] = 2; + $monthMoney = $this->sumOrder($params); + $params['flag'] = 1; + $dayMoney = $this->sumOrder($params); + $this->successWithData([ + 'sumMoney' => $sumMoney ?? 0, + 'yearMoney' => $yearMoney ?? 0, + 'monthMoney' => $monthMoney ?? 0, + 'dayMoney' => $dayMoney ?? 0 + ]); + } + + + // 订单数量统计 + public function selectOrdersCountStatisticsByYear() + { + $get = $this->request->get(); + $startTime = $get['startTime']; + $endTime = $get['endTime']; + + // 初始化结果数组 + $ordersCountList = []; + $ordersDaiFuKuanCountList = []; + $ordersYiZhiFuCountList = []; + $ordersYiTuiKuanLunCountList = []; + $dateList = []; + + // 日期处理 + $currentDate = strtotime($startTime); + $endDate = strtotime($endTime); + + // 循环遍历日期范围 + while ($currentDate <= $endDate) { + $date = date('Y-m-d', $currentDate); + + // 总订单数 + $ordersCount = \app\admin\model\Order::selectOrdersCountStatisticsByYear(1, $date, null); + $ordersCountList[] = $ordersCount; + + // 0待支付 + $ordersDaiFuKuanCount = \app\admin\model\Order::selectOrdersCountStatisticsByYear(1, $date, 0); + $ordersDaiFuKuanCountList[] = $ordersDaiFuKuanCount; + + // 1已支付 + $ordersJinXinCount = \app\admin\model\Order::selectOrdersCountStatisticsByYear(1, $date, 1); + $ordersYiZhiFuCountList[] = $ordersJinXinCount; + + // 2已退款 + $ordersQuXiaoCount = \app\admin\model\Order::selectOrdersCountStatisticsByYear(1, $date, 2); + $ordersYiTuiKuanLunCountList[] = $ordersQuXiaoCount; + + // 记录日期 + $dateList[] = $date; + + // 日期加1天 + $currentDate = strtotime('+1 day', $currentDate); + } + $result = [ + 'ordersCountList' => $ordersCountList, + 'ordersDaiFuKuanCountList' => $ordersDaiFuKuanCountList, + 'ordersYiZhiFuCountList' => $ordersYiZhiFuCountList, + 'ordersYiTuiKuanLunCountList' => $ordersYiTuiKuanLunCountList, + 'year' => $dateList + ]; + $this->n_success(['data' => $result]); + } + + // 统计分销金币 + public function selectFenXiaoMoney() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + $sysUserId = $admin['user_id']; + $flag = $get['flag']; + $time = $get['time']; + + // 1. 分别查询一级、二级和渠道分销金额 + $oneMoney = \app\admin\model\Order::selectFenXiaoMoney(1, $sysUserId, $flag, $time); + $twoMoney = \app\admin\model\Order::selectFenXiaoMoney(2, $sysUserId, $flag, $time); + $qdMoney = \app\admin\model\Order::selectFenXiaoMoney(3, $sysUserId, $flag, $time); + + // 2. 计算总分销金额(使用BCMath确保精度) + $sumMoney = bcadd( + bcadd($oneMoney, $twoMoney, 2), // 一级 + 二级 + $qdMoney, // + 渠道 + 2 // 精度保留两位小数 + ); + + $result = [ + 'oneMoney' => $oneMoney, + 'twoMoney' => $twoMoney, + 'qdMoney' => $qdMoney, + 'sumMoney' => $sumMoney + ]; + $this->n_success(['data' => $result]); + } + + // 订单统计 + public function selectOrdersCount() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + $sysUserId = $admin['user_id']; + $flag = $get['flag']; + $time = $get['time']; + + // 1. 短剧订单统计(数量) + $sumCourseOrdersCount = \app\admin\model\Order::selectOrdersCount(null, 1, $flag, $time, $sysUserId); + $daiCourseKeOrdersCount = \app\admin\model\Order::selectOrdersCount(0, 1, $flag, $time, $sysUserId); + $wanCourseKeOrdersCount = \app\admin\model\Order::selectOrdersCount(1, 1, $flag, $time, $sysUserId); + $tuiCourseOrdersCount = \app\admin\model\Order::selectOrdersCount(2, 1, $flag, $time, $sysUserId); + + // 2. 短剧订单统计(金额) + $sumCourseOrdersMoney = \app\admin\model\Order::selectOrdersMoney(null, 1, $flag, $time, null, $sysUserId); + $daiCourseOrdersMoney = \app\admin\model\Order::selectOrdersMoney(0, 1, $flag, $time, null, $sysUserId); + $wanCourseOrdersMoney = \app\admin\model\Order::selectOrdersMoney(1, 1, $flag, $time, null, $sysUserId); + $tuiCourseOrdersMoney = \app\admin\model\Order::selectOrdersMoney(2, 1, $flag, $time, null, $sysUserId); + + // 3. 会员订单统计(数量) + $sumMemberOrdersCount = \app\admin\model\Order::selectOrdersCount(null, 2, $flag, $time, $sysUserId); + $daiMemberKeOrdersCount = \app\admin\model\Order::selectOrdersCount(0, 2, $flag, $time, $sysUserId); + $wanMemberKeOrdersCount = \app\admin\model\Order::selectOrdersCount(1, 2, $flag, $time, $sysUserId); + $tuiMemberOrdersCount = \app\admin\model\Order::selectOrdersCount(2, 2, $flag, $time, $sysUserId); + + // 4. 会员订单统计(金额) + $sumMemberOrdersMoney = \app\admin\model\Order::selectOrdersMoney(null, 2, $flag, $time, null, $sysUserId); + $daiMemberOrdersMoney = \app\admin\model\Order::selectOrdersMoney(0, 2, $flag, $time, null, $sysUserId); + $wanMemberOrdersMoney = \app\admin\model\Order::selectOrdersMoney(1, 2, $flag, $time, null, $sysUserId); + $tuiMemberOrdersMoney = \app\admin\model\Order::selectOrdersMoney(2, 2, $flag, $time, null, $sysUserId); + + // 5. 提现统计 + $timestamp = strtotime($time); // 将日期字符串转为时间戳 + $beginOfDay = date('Y-m-d 00:00:00', $timestamp); // 当天开始时间 + $endOfDay = date('Y-m-d 23:59:59', $timestamp); // 当天结束时间 + + $cashCount = DatabaseRoute::getAllDbData('cash_out', function ($query) use($sysUserId, $beginOfDay) { + if (!is_null($sysUserId)) { + $query->where(['sys_user_id' => $sysUserId]); + } + $query->where('state', 1)->where('create_at', '>', $beginOfDay); + return $query; + })->count(); + + + $cashSum = DatabaseRoute::getAllDbData('cash_out', function ($query) use($sysUserId, $beginOfDay, $endOfDay) { + if (!is_null($sysUserId)) { + $query->where(['sys_user_id' => $sysUserId]); + } + $query->whereBetween('create_at', [$beginOfDay, $endOfDay]); + return $query; + })->sum('money') ?? 0; + + + + $cashSum = number_format($cashSum, 2, '.', ''); // 保留两位小数 + + // 6. 奖励金额统计 + $signInAwardMoney = \app\admin\model\Order::selectSignInAwardMoney($flag, $time, $sysUserId); + $shareAwardMoney = \app\admin\model\Order::selectShareAwardMoney($flag, $time, $sysUserId); + $newUserTaskDoneAwardMoney = \app\admin\model\Order::selectNewUserTaskDoneAwardMoney($flag, $time, $sysUserId); + $inviteTaskDoneAwardMoney = \app\admin\model\Order::selectInviteTaskDoneAwardMoney($flag, $time, $sysUserId); + + // 7. 组装结果 + $result = [ + // 短剧订单数量 + 'sumCourseOrdersCount' => $sumCourseOrdersCount ?? 0, + 'daiCourseKeOrdersCount' => $daiCourseKeOrdersCount ?? 0, + 'wanCourseKeOrdersCount' => $wanCourseKeOrdersCount ?? 0, + 'tuiCourseOrdersCount' => $tuiCourseOrdersCount ?? 0, + // 短剧订单金额 + 'sumCourseOrdersMoney' => $sumCourseOrdersMoney ?? 0.00, + 'daiCourseOrdersMoney' => $daiCourseOrdersMoney ?? 0.00, + 'wanCourseOrdersMoney' => $wanCourseOrdersMoney ?? 0.00, + 'tuiCourseOrdersMoney' => $tuiCourseOrdersMoney ?? 0.00, + // 会员订单数量 + 'sumMemberOrdersCount' => $sumMemberOrdersCount ?? 0, + 'daiMemberKeOrdersCount' => $daiMemberKeOrdersCount ?? 0, + 'wanMemberKeOrdersCount' => $wanMemberKeOrdersCount ?? 0, + 'tuiMemberOrdersCount' => $tuiMemberOrdersCount ?? 0, + // 会员订单金额 + 'sumMemberOrdersMoney' => $sumMemberOrdersMoney ?? 0.00, + 'daiMemberOrdersMoney' => $daiMemberOrdersMoney ?? 0.00, + 'wanMemberOrdersMoney' => $wanMemberOrdersMoney ?? 0.00, + 'tuiMemberOrdersMoney' => $tuiMemberOrdersMoney ?? 0.00, + // 提现数据 + 'cashCount' => $cashCount ?? 0, + 'cashSum' => $cashSum, + // 奖励金额 + 'signInAwardMoney' => $signInAwardMoney ?? 0.00, + 'shareAwardMoney' => $shareAwardMoney ?? 0.00, + 'newUserTaskDoneAwardMoney' => $newUserTaskDoneAwardMoney ?? 0.00, + 'inviteTaskDoneAwardMoney' => $inviteTaskDoneAwardMoney ?? 0.00, + ]; + + $this->n_success(['data' => $result]); + } + + public function queryByTradeNo() + { + $get = $this->request->get(); + if (empty($get['outTradeNo'])) { + $this->error('参数不能为空'); + } + $outTradeNo = $get['outTradeNo']; + $tradeNo = null; + $userId = null; + try { + // 解析外部交易号(提现回调格式:xxx-xxx:xxx) + if (strpos($outTradeNo, '-') !== false && strpos($outTradeNo, ':') !== false) { + $parts = explode('-', $outTradeNo); + $tradeNo = $parts[0]; + $userIdPart = explode(':', $parts[1])[0]; + $userId = (int)$userIdPart; + } + // 解析支付回调格式(xxx-xxx) + elseif (strpos($outTradeNo, '-') !== false) { + $parts = explode('-', $outTradeNo); + $tradeNo = $parts[0]; + $userId = (int)$parts[1]; + } + } catch (\Exception $e) { + $this->error("交易订单号不合法"); + } + + // 验证解析结果 + if (empty($tradeNo) || $userId === null) { + $this->error("交易订单号不合法"); + } + + // 初始化汇总数据 + $data = []; + + // 查询用户基本信息 + $user = TbUser::selectUserById($userId); + $data['user_info'] = $user ?: []; + + // 查询用户实名认证信息 + $realNameAuth = \app\api\model\UserInfo::getByUserIdOrSave($userId); + $data['auth_info'] = $realNameAuth ?: []; + + // 初始化提现统计(success:成功, fail:失败, auditing:审核中, other:其他) + $withdrawTotal = [ + 'success' => ['total' => 0.00, 'count' => 0], + 'fail' => ['total' => 0.00, 'count' => 0], + 'auditing' => ['total' => 0.00, 'count' => 0], + 'other' => ['total' => 0.00, 'count' => 0], + ]; + + // 初始化支付统计(success:成功, fail:失败, unpaid:未支付) + $payTotal = [ + 'success' => ['total' => 0.00, 'count' => 0], + 'fail' => ['total' => 0.00, 'count' => 0], + 'unpaid' => ['total' => 0.00, 'count' => 0], + ]; + + + // 查询提现记录并统计 + $cashOutList = DatabaseRoute::getDb('cash_out', $userId)->select()->toArray(); + if (!empty($cashOutList)) { + // 按状态分组统计总金额和数量 + $cashOutSum = []; // 金额统计:[状态 => 总金额] + $cashOutCount = []; // 数量统计:[状态 => 总条数] + + foreach ($cashOutList as $cash) { + $state = $cash['state']; + $money = (float)$cash['money']; + + // 累加金额 + if (!isset($cashOutSum[$state])) { + $cashOutSum[$state] = 0.00; + } + $cashOutSum[$state] += $money; + + // 累加数量 + if (!isset($cashOutCount[$state])) { + $cashOutCount[$state] = 0; + } + $cashOutCount[$state]++; + } + + // 更新成功/失败/审核中状态的统计 + $withdrawTotal['success'] = [ + 'total' => $cashOutSum[1] ?? 0.00, + 'count' => $cashOutCount[1] ?? 0 + ]; + $withdrawTotal['fail'] = [ + 'total' => $cashOutSum[2] ?? 0.00, + 'count' => $cashOutCount[2] ?? 0 + ]; + $withdrawTotal['auditing'] = [ + 'total' => $cashOutSum[3] ?? 0.00, + 'count' => $cashOutCount[3] ?? 0 + ]; + + // 统计其他状态(排除1/2/3) + $otherStates = [1, 2, 3]; + $otherMoney = 0.00; + $otherCount = 0; + foreach ($cashOutList as $cash) { + if (!in_array($cash['state'], $otherStates)) { + $otherMoney += (float)$cash['money']; + $otherCount++; + } + } + $withdrawTotal['other'] = [ + 'total' => $otherMoney, + 'count' => $otherCount + ]; + } + $data['withdraw_total'] = $withdrawTotal; + + // 查询支付记录并统计 + $payDetailsList = DatabaseRoute::getDb('pay_details', $userId)->select()->toArray(); + if (!empty($payDetailsList)) { + // 按状态分组统计总金额和数量 + $paySum = []; // 金额统计:[状态 => 总金额] + $payCount = []; // 数量统计:[状态 => 总条数] + + foreach ($payDetailsList as $pay) { + $state = $pay['state']; + $money = (float)$pay['money']; + + // 累加金额 + if (!isset($paySum[$state])) { + $paySum[$state] = 0.00; + } + $paySum[$state] += $money; + + // 累加数量 + if (!isset($payCount[$state])) { + $payCount[$state] = 0; + } + $payCount[$state]++; + } + + // 更新支付统计(1:成功, 2:失败, 0:未支付) + $payTotal['success'] = [ + 'total' => $paySum[1] ?? 0.00, + 'count' => $payCount[1] ?? 0 + ]; + $payTotal['fail'] = [ + 'total' => $paySum[2] ?? 0.00, + 'count' => $payCount[2] ?? 0 + ]; + $payTotal['unpaid'] = [ + 'total' => $paySum[0] ?? 0.00, + 'count' => $payCount[0] ?? 0 + ]; + } + $data['pay_total'] = $payTotal; + $this->n_success(['data' => $data]); + } + + + + + +} \ No newline at end of file diff --git a/app/czg/controller/PayClassifyController.php b/app/czg/controller/PayClassifyController.php new file mode 100644 index 0000000..cff9dd5 --- /dev/null +++ b/app/czg/controller/PayClassifyController.php @@ -0,0 +1,63 @@ +select()->toArray(); + foreach ($infos as $k => &$v) { + $v['pay_classify_id'] = (string) $v['pay_classify_id']; + } + $this->successWithData([ + 'currPage' => 1, + 'pageSize' => count($infos), + 'totalCount' => count($infos), + 'totalPage' => 1, + 'list' => convertToCamelCase($infos) + ]); + } + + public function updatePayClassify() + { + $params = $this->request->post(); + if (empty($params['payClassifyId'])) { + $this->error('参数错误'); + } + unset($params['memberId']); + Db::name('pay_classify')->where([ + 'pay_classify_id' => $params['payClassifyId'] + ])->update(convertKeysCamelToSnakeRecursive($params)); + $this->success(); + } + + public function insertPayClassify() + { + $params = $this->request->post(); + $params['create_time'] = getNormalDate(); + unset($params['memberId']); + unset($params['payClassifyId']); + Db::name('pay_classify')->insert(convertKeysCamelToSnakeRecursive($params)); + $this->success(); + } + + public function deletePayClassify() + { + $params = $this->request->get(); + if (empty($params['payClassifyId'])) { + $this->error('参数错误'); + } + Db::name('pay_classify')->delete([ + 'pay_classify_id' => $params['payClassifyId'] + ]); + $this->success(); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/SdkController.php b/app/czg/controller/SdkController.php new file mode 100644 index 0000000..5958d07 --- /dev/null +++ b/app/czg/controller/SdkController.php @@ -0,0 +1,38 @@ +request->get(); + if(empty($get['userId'])) { + $this->error('userId 不能为空'); + } + $sdkINfo = [ + 'sdkRemarks' => $get['sdkRemarks'] ?? null, + 'status' => $get['status'] ?? null, + 'typeId' => $get['typeId'] ?? null, + 'nickName' => $get['nickName'] ?? null, + 'sdkContent' => $get['sdkContent'] ?? null, + ]; + $this->n_success(['data' => [ + 'list' => [], + 'totalCount' => 0, + 'totalPage' => 0, + 'currPage' => 1, + 'pageSize' => 0, + ]]); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/SysController.php b/app/czg/controller/SysController.php new file mode 100644 index 0000000..2e80ad9 --- /dev/null +++ b/app/czg/controller/SysController.php @@ -0,0 +1,242 @@ +request->post(); + if(empty($data['username']) || empty($data['password']) || empty($data['uuid']) || empty($data['captcha']) || empty($data['adminType'])){ + $this->n_error('参数不完整'); + } + $uuid = $data['uuid']; + $connect = Db::connect(get_slave_connect_name()); + $captcha = $connect->name('sys_captcha')->where(['uuid' => $uuid, 'code' => $data['captcha']])->find(); + if(!$captcha) { + $this->n_error('验证码错误', [], 500); + } + $ext_time = strtotime($captcha['expire_time']); + if(time() > $ext_time) { + $this->n_error('验证码已经过期', [], 500); + } + $res = $this->auth->login($data['username'], $data['password']); + if (isset($res) && $res === true) { + $user = $this->auth->getAdmin(); + if($data['adminType'] == 1 && $user['is_channel'] != null && $user['is_channel'] == 1) { + $this->n_error('代理账号请登录代理端', [], 500); + } + if($data['adminType'] == 2 && $user['is_channel'] == null) { + $this->n_error('管理员请登录管理端', [], 500); + } + $this->n_success([ + 'token' => $this->auth->getToken() + ]); + } else { + $msg = $this->auth->getError(); + $msg = $msg ?: __('Check in failed, please try again or contact the website administrator~'); + $this->n_error($msg); + } + } + + /** + * 管理员注销 + * @return void + */ + public function logout(): void + { + if ($this->request->isPost()) { + $refreshToken = $this->request->post('refreshToken', ''); + if ($refreshToken) Token::delete((string)$refreshToken); + $this->auth->logout(); + $this->success(); + } + } + + + /** + * 邀请好友奖励分页 + * @return void + */ + public function invitefriendaward() + { + $params = $this->request->get(); + $subQuery = DatabaseRoute::getAllDbData('user_money_details', function ($query) use ($params) { + return $query->field('user_id, SUM(money) as awardAmount, SUM(IF(title = "签到奖励", 1, 0)) as signInNum') + ->where('classify', 6)->group('user_id'); + })->buildSql(); + + $result = DatabaseRoute::paginateAllDb('tb_user', function ($query) use ($subQuery , $params) { + $query->alias('t1') + ->field([ + 't1.user_id as userId', + 't1.user_name as userName', + 't1.phone', + 't1.avatar', + 'IFNULL(t2.signInNum, 0) as signInNum', + 'IFNULL(t2.awardAmount, 0) as awardAmount' + ]) + ->leftJoin("{$subQuery} t2", 't1.user_id = t2.user_id'); + if(!empty($params['keywords'])) { + $query->where('t1.user_name', $params['keywords'])->whereOr('t1.phone', $params['keywords']); + } + $query->order('t2.signInNum', 'desc'); + $query->order('t1.user_id', 'asc'); + return $query; + }, (int)$params['page'], (int)$params['limit']); + $this->n_success(['data' => $result]); + } + /** + * 奖励详情 + * @return void + */ + public function invitefrienddetail() + { + $params = $this->request->get(); + $userId = $params['userId']; + $result = DatabaseRoute::paginateAllDb('user_money_details', function ($query) use ($params, $userId) { + $query->alias('t1') + ->field([ + 't1.by_user_id AS userId', + 't1.money AS amount', + 't2.phone AS userPhone', + 't1.create_time AS createTime' + ]) + ->leftJoin('tb_user t2', 't1.by_user_id = t2.user_id') + ->where('t1.user_id', $userId) + ->where('t1.classify', 6) + ->whereNotNull('t1.by_user_id') + ->whereNotNull('t2.user_id') + ->order('t1.create_time', 'desc') + ->order('t1.by_user_id', 'asc'); + return $query; + }, (int)$params['page'], (int)$params['limit'], 'createTime'); + $this->successWithData($result); + } + + /** + * 邀请好友奖励-签到人数分页 + * @return void + */ + public function signindetailpage() + { + $params = $this->request->get(); + $userId = $params['userId']; + // 先获取总数 + $count = DatabaseRoute::getAllDbData('user_money_details', function ($query) use($userId) { + return $query->alias('t') + ->field('t.by_user_id') + ->where('t.user_id', $userId) + ->where('t.classify', 6) + ->where('t.title', '签到奖励') + ->group('t.by_user_id'); + })->count(); + $v_db_name = config('database.connections.' . get_slave_connect_name() . '.database'); + $result = DatabaseRoute::paginateAllDbBySqlAutoCount(function () use($userId, $v_db_name) { + return "select + t1.by_user_id as userId, + t1.createTime, + t2.user_name as userName, + t2.phone, + t3.cert_name as realName, + t3.cert_no as idCardNo, + t3.bank_name as bankName, + t3.account_no as bankCardNo, + t3.mobile, + t3.province, + t3.city, + t3.bank_branch as bankBranch + from ( + SELECT + t.by_user_id, + MIN( t.create_time ) as createTime + FROM + " . $v_db_name . ".v_user_money_details t + WHERE 1=1 + AND t.user_id = ".$userId." + AND t.classify = 6 + AND t.title = '签到奖励' + GROUP BY t.by_user_id + ) t1 + LEFT JOIN " . $v_db_name . ".v_tb_user t2 on t1.by_user_id = t2.user_id + LEFT JOIN " . $v_db_name . ".v_user_info t3 on t1.by_user_id = t3.user_id + order by t1.createTime desc,t1.by_user_id asc"; + }, $params['page'], $params['limit'], null, $count); + $this->successWithData($result); + } + + /** + * 抽奖次数查询-分页 + * @return void + */ + public function lotterypage() + { + $params = $this->request->get(); + $keywords = $params['keywords']; + $v_db_name = config('database.connections.' . get_slave_connect_name() . '.database'); + $result = DatabaseRoute::paginateAllDb('tb_user', function ($query) use($keywords, $v_db_name) { + return $query->alias('t1') + ->field([ + 't1.user_id as userId', + 't1.avatar', + 't1.user_name as userName', + 't1.phone', + // 今日解锁订单数 + '(SELECT COUNT(1) FROM '. $v_db_name .'.v_orders WHERE STATUS = 1 AND pay_way = 9 AND user_id = t1.user_id AND pay_time >= DATE_FORMAT(CURDATE(), "%Y-%m-%d 00:00:00") AND pay_time <= DATE_FORMAT(CURDATE(), "%Y-%m-%d 23:59:59")) as todayUnlocked', + // 今日抽奖次数 + '(SELECT COUNT(1) FROM '. $v_db_name .'.v_disc_spinning_record WHERE user_id = t1.user_id AND DATE_FORMAT(create_time, "%Y-%m-%d") = CURDATE()) as todayDrawCount' + ]) + ->where(function ($query) use ($keywords) { + $query->where('t1.user_name', $keywords) + ->whereOr('t1.phone', $keywords); + }) + ->order('todayUnlocked', 'desc') + ->order('t1.user_id', 'asc'); + }, $params['page'], $params['limit']); + + $this->n_success(['data' => $result]); + } + + /** + * 抽奖详情-分页 + * @return void + */ + public function lotterydetailpage() + { + $params = $this->request->get(); + $userId = $params['userId']; + // 先获取总数 + $count = Db::connect(get_slave_connect_name())->query("select + count(*) count + from v_disc_spinning_record t1 + where t1.user_id = ".$userId); + $count = $count[0]['count']; + $v_db_name = config('database.connections.' . get_slave_connect_name() . '.database'); + $result = DatabaseRoute::paginateAllDbBySqlAutoCount(function () use($userId, $v_db_name) { + return "select + t1.id, + t1.name, + t1.number, + t1.create_time + from ". $v_db_name .".v_disc_spinning_record t1 + where t1.user_id = " . $userId . " + order by t1.id desc"; + }, $params['page'], $params['limit'], null, $count); + $this->successWithData($result); + } + + // 发送验证码 + public function sendMsg() + { + $get = $this->request->get(); + return $this->ApiDataReturn(Msg::sendMsg($get['phone'], $get['event'])); + } +} \ No newline at end of file diff --git a/app/czg/controller/TaskCenterController.php b/app/czg/controller/TaskCenterController.php new file mode 100644 index 0000000..9a4911c --- /dev/null +++ b/app/czg/controller/TaskCenterController.php @@ -0,0 +1,56 @@ +request->param(); + $this->successWithData(DatabaseRoute::paginateDb('task_center', function ($query) use ($params) { + return $query->order('sort'); + }, $params['page'], $params['limit'], null, true)); + } + + public function updateTaskCenter() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['update_time'] = getNormalDate(); + unset($params['disc_number']); + unset($params['disabled']); + Db::name('task_center')->where([ + 'id' => $params['id'] + ])->update($params); + $this->success(); + + } + + public function insertTaskCenter() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['create_time'] = getNormalDate(); + unset($params['is_trusted']); + Db::name('task_center')->insert($params); + $this->success(); + } + + public function deleteTaskCenter() + { + $id = $this->request->param('id'); + Db::name('task_center')->delete([ + 'id' => $id + ]); + + $this->success(); + } + +} \ No newline at end of file diff --git a/app/czg/controller/TaskCenterRewardController.php b/app/czg/controller/TaskCenterRewardController.php new file mode 100644 index 0000000..42a8c58 --- /dev/null +++ b/app/czg/controller/TaskCenterRewardController.php @@ -0,0 +1,69 @@ +request->param(); + $this->successWithData(DatabaseRoute::paginateDb('task_center_reward', function ($query) use ($params) { + if (!empty($params['taskId'])) { + $query->where([ + 'task_id' => $params['taskId'] + ]); + } + return $query->order('id', false); + + }, $params['page'] ?? 1, $params['limit'] ?? 10)); + } + + public function updateTaskCenterReward() + { + $params = $this->request->param(); + $params = convertKeysCamelToSnakeRecursive($params); + $info = Db::name('task_center_reward')->where([ + 'id' => $params['id'] + ]); + + if (!empty($info['total_number']) && !empty($params['total_number']) && $info['total_number'] != $params['total_number']) { + $surplusNumber = $params['total_number'] - $info['total_number']; + $surplusNumber = $surplusNumber > 0 ?? $params['total_number']; + $params['total_number'] = $surplusNumber; + } + + $params['update_time'] = getNormalDate(); + Db::name('task_center_reward')->where([ + 'id' => $params['id'] + ])->update($params); + + $this->success(); + } + + public function insertTaskCenterReward() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + $params['surplus_number'] = $params['total_number']; + unset($params['is_trusted']); + unset($params['id']); + Db::name('task_center_reward')->insert($params); + $this->success(); + } + + public function deleteTaskCenterReward() + { + $id = $this->request->param('id'); + Db::name('task_center_reward')->delete([ + 'id' => $id + ]); + $this->success(); + } +} \ No newline at end of file diff --git a/app/czg/controller/UrlAddressController.php b/app/czg/controller/UrlAddressController.php new file mode 100644 index 0000000..c9dc693 --- /dev/null +++ b/app/czg/controller/UrlAddressController.php @@ -0,0 +1,97 @@ +order('num', 'asc')->limit(1)->find(); + if ($info) { + $info['num'] = $info['num'] ? $info['num'] + 1 : 1; + Db::name('url_address')->where([ + 'url_id' => $info['url_id'] + ])->update([ + 'num' => $info['num'] + ]); + } + + $this->successWithData(convertToCamelCase($info)); + + } + + public function selectUrlAddressList() + { + $get = $this->request->get(); + $page = $get['page']; // 页码,默认1 + $limit = $get['limit']; // 每页条数,默认10 + $urlAddress = $get['urlAddress']; // URL地址关键词 + $status = $get['status']; // 状态值 + $db = Db::connect(get_master_connect_name()); + // 构建查询 + $query = $db->name('url_address'); + if(!empty($urlAddress)) { + $query->where('url_address', 'like', "%{$urlAddress}%"); + } + if(!empty($status)) { + $query->where('status', $status); + } + $count = $query->count(); + $info = $query->limit(page($page, $limit), $limit)->select()->toArray(); + $this->n_success(['data' => [ + 'totalCount' => $count, + 'pageSize' => $get['limit'], + 'totalPage' => ceil($count / $get['limit']), + 'currPage' => $get['page'], + 'list' => $info, + 'records' => null + ]]); + } + + + public function updateUrlAddress() + { + $post = $this->request->post(); + + $url_id = $post['urlId'] ?? null; + $data['num'] = $post['num'] ?? null; + $data['url_address'] = $post['urlAddress'] ?? null; + $data['status'] = $post['status'] ?? null; + Db::name('url_address')->where(['url_id' => $url_id])->update($data); + $this->success(); + } + + + // 创建域名 + public function insertUrlAddress() + { + $post = $this->request->post(); + $data['num'] = $post['num'] ?? null; + $data['url_address'] = $post['urlAddress'] ?? null; + $data['status'] = $post['status'] ?? null; + $data['create_time'] = date('Y-m-d H:i:s'); + Db::name('url_address')->insert($data); + $this->success(); + } + + public function deleteUrlAddress() + { + $param = $this->request->get(); + if(empty($param['addressId'])) { + $this->error('参数错误'); + } + Db::name('url_address')->where(['url_id' => $param['addressId']])->delete(); + $this->success(); + } + + + + + + +} \ No newline at end of file diff --git a/app/czg/controller/UserController.php b/app/czg/controller/UserController.php new file mode 100644 index 0000000..6e70ada --- /dev/null +++ b/app/czg/controller/UserController.php @@ -0,0 +1,542 @@ +model = new UserModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $result = false; + $passwd = $data['password']; // 密码将被排除不直接入库 + $data = $this->excludeFields($data); + + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + + if (!empty($passwd)) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $password = $this->request->post('password', ''); + if ($password) { + $this->model->resetPassword($id, $password); + } + parent::edit(); + } + + unset($row->salt); + $row->password = ''; + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 重写select + * @throws Throwable + */ + public function select(): void + { + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res as $re) { + $re->nickname_text = $re->username . '(ID:' . $re->id . ')'; + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + // 短剧分析 + public function courseMessage() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + $pageUtils = \app\admin\model\User::queryCourseOrder($get['page'], $get['limit'], $get['type'], completeStartTime($get['date']), $admin['user_id']); + $this->n_success(['data' => $pageUtils]); + } + + // 用户分析 + public function userMessage() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + // 补全开始时间(调用之前实现的函数) + $date = completeStartTime($get['date']); // 假设已实现该函数 + $qdCode = $admin['qd_code']; + $sumUserCount = \app\admin\model\User::queryUserCount($get['type'], $date, null, $qdCode); + $h5Count = \app\admin\model\User::queryUserCount($get['type'], $date, "h5", $qdCode); + $appCount = \app\admin\model\User::queryUserCount($get['type'], $date, "app", $qdCode); + $wxCount = \app\admin\model\User::queryUserCount($get['type'], $date, "小程序", $qdCode); + $dyCount = \app\admin\model\User::queryUserCount($get['type'], $date, "抖音", $qdCode); + $giveMemberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, 1); + $moneyMemberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, 2); + $memberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, null); + $userCount = $sumUserCount - $memberCount; + $this->n_success(['data' => [ + 'sumUserCount' => $sumUserCount, + 'h5Count' => $h5Count, + 'appCount' => $appCount, + 'wxCount' => $wxCount, + 'dyCount' => $dyCount, + 'memberCount' => $memberCount, + 'giveMemberCount' => $giveMemberCount, + 'moneyMemberCount' => $moneyMemberCount, + 'userCount' => $userCount, + ]]); + } + + // 当前在线人数统计 + public function selectUserOnLineCount() + { + $admin = $this->auth->getAdmin(); + $qdCode = $admin['qd_code']; + $selectUserOnLineCount = DatabaseRoute::getAllDbData('tb_user', function($query)use($qdCode) { + if($query) { + $query->where(['qd_code' => $qdCode]); + } + return $query->where('on_line_time', '>=', Db::raw('DATE_SUB(NOW(), INTERVAL 10 MINUTE)')); + })->count(); + $this->n_success(['data' => $selectUserOnLineCount]); + } + + // 用户统计 + public function homeMessage() + { + $admin = $this->auth->getAdmin(); + $qdCode = $admin['qd_code']; + $data = []; + $data['totalUsers'] = \app\admin\model\User::queryUserCount(0, null, null, $qdCode); + $data['newToday'] = \app\admin\model\User::queryUserCount(1, null, null, $qdCode); + $data['newMonth'] = \app\admin\model\User::queryUserCount(2, null, null, $qdCode); + $data['newYear'] = \app\admin\model\User::queryUserCount(3, null, null, $qdCode); + $data['totalRevenue'] = \app\admin\model\User::queryPayMoney(0, $qdCode); + $data['todayRevenue'] = \app\admin\model\User::queryPayMoney(1, $qdCode); + $data['monthRevenue'] = \app\admin\model\User::queryPayMoney(2, $qdCode); + $data['yearRevenue'] = \app\admin\model\User::queryPayMoney(3, $qdCode); + $map = \app\admin\model\User::queryPayAndExtractInfo(); + $data['todayPayAmount'] = isset($map['payAmount']) + ? round((float)$map['payAmount'], 2, PHP_ROUND_HALF_UP) + : 0.00; + $data['todayPayCount'] = isset($map['payCount']) + ? (int)$map['payCount'] + : 0; + $data['todayExtractAmount'] = isset($map['extractAmount']) + ? round((float)$map['extractAmount'], 2, PHP_ROUND_HALF_UP) + : 0.00; + + $data['todayExtractCount'] = isset($map['extractCount']) + ? (int)$map['extractCount'] + : 0; + $this->n_success(['data' => $data]); + } + + // 用户增长折线图 + public function selectUserCountStatisticsByTime() + { + $get = $this->request->get(); + $startTime = $get['startTime']; + $endTime = $get['endTime']; + + // 初始化结果数组 + $userCountList = []; + $dateList = []; + + // 日期处理 + $currentDate = strtotime($startTime); + $endDate = strtotime($endTime); + + // 循环遍历日期范围 + while ($currentDate <= $endDate) { + $date = date('Y-m-d', $currentDate); + + // 查询当日用户注册数量 + $userCount = \app\admin\model\User::queryUserCount(1, $date, null, null); + + // 记录数据 + $userCountList[] = $userCount; + $dateList[] = $date; + + // 日期加1天 + $currentDate = strtotime('+1 day', $currentDate); + } + + // 构建结果数据 + $result = [ + 'userCountList' => $userCountList, + 'year' => $dateList // 注:原Java代码中使用year变量,但实际存储的是日期列表 + ]; + + $this->n_success(['data' => $result]); + + } + + + + // 查询所有用户列表 + public function selectUserList() + { + $params = $this->request->get(); + p(2312); + $vipType = $params['vipType'] ?? null; + $member = $params['member'] ?? null; + $status = $params['status'] ?? null; + $page = $params['page'] ?? null; + $limit = $params['limit'] ?? null; + $phone = $params['phone'] ?? null; + $sysUserName = $params['sysUserName'] ?? null; + $userName = $params['userName'] ?? null; + $sex = $params['sex'] ?? null; + $platform = $params['platform'] ?? null; + $sysPhone = $params['sysPhone'] ?? null; + $inviterCode = $params['inviterCode'] ?? null; + $invitationCode = $params['invitationCode'] ?? null; + $qdCode = $params['qdCode'] ?? null; + $startTime = $params['startTime'] ?? null; + $endTime = $params['endTime'] ?? null; + $delegate = $params['delegate'] ?? null; + $this->n_success(['data' => \app\admin\model\User::selectUserPage( + $page, $limit, $phone, $sex, $platform, $sysPhone, $status, $member, + $inviterCode, $userName, $invitationCode, $startTime, $endTime, $qdCode, $sysUserName, $vipType, $delegate + )]); + } + + // 修改用户状态 + public function updateUserStatusByUserId() + { + $get = $this->request->get(); + if(empty($get['userId'])) { + $this->error('userId 不能为空'); + } + if(empty($get['status']) && $get['status'] == null) { + $this->error('status 不能为空'); + } + $status = $get['status']; + $userId = $get['userId']; + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId], true)); + // 查询用户是否存在 + $user = $db->name('tb_user')->where(['user_id' => $userId])->find(); + if (is_null($user)) { + $this->error('用户不存在'); + } + + // 根据状态执行不同操作 + switch ($status) { + case 1: + // 状态1:设置状态为1,并调用upUserBlack方法(拉黑) + \app\admin\model\User::upUserBlack($user, 1, $db); + break; + case 2: + // 状态2:直接更新状态为2 + $db->name('tb_user')->where('user_id', $userId) + ->update(['status' => 2]); + break; + case 0: + // 状态0:调用upUserBlack方法(解封) + \app\admin\model\User::upUserBlack($user, 0, $db); + break; + default: + // 无效状态 + $this->error('状态不正确'); + } + $this->success(); + } + + + // 更新用户邀请奖励金额 + public function inviteAmount() + { + $userInviteDTO = $this->request->post(); + // 验证用户ID不能为空 + if (empty($userInviteDTO['userId'])) { + $this->error('用户id不能为空'); + } + + // 验证邀请奖励金额必须大于0 + $inviteAmount = $userInviteDTO['inviteAmount'] ?? null; + if (is_null($inviteAmount) || bccomp($inviteAmount, 0) <= 0) { + $this->error('邀请奖励金额必须大于0'); + } + + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userInviteDTO['userId']], true))->name('tb_user'); + // 查询用户是否存在 + $userEntity = $db->where(['user_id' => $userInviteDTO['userId']])->find($userInviteDTO['userId']); + if (is_null($userEntity)) { + $this->error('用户不存在'); + } + // 更新用户邀请奖励金额 + $db->where(['user_id' => $userInviteDTO['userId']])->update(['invite_amount' => $inviteAmount]); + $this->success(); + } + + + public function updatePwd() + { + $get = $this->request->get(); + if(empty($get['userId']) || empty($get['pwd'])) { + $this->error('参数不完整'); + } + $userId = $get['userId']; + $pwd = $get['pwd']; + $db = Db::connect(DatabaseRoute::getConnection('sys_user', ['user_id' => $userId])); + $user = $db->name('sys_user')->where(['user_id' => $userId])->find(); + if(!$user) { + $this->error('用户不存在'); + } + $db = Db::connect(DatabaseRoute::getConnection('sys_user', ['user_id' => $userId], true)); + $user = $db->name('sys_user')->where(['user_id' => $userId])->update(['password' => shiro_simple_hash_hex_salt('sha256', $pwd, $user['salt'])]); + if($user) { + $this->success(); + } + $this->error(); + } + + public function deleteUserByUserId() + { + $post = $this->request->post(); + if(empty($post['userId'])) { + $this->error('userId 不能为空'); + } + $userId = $post['userId']; + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId], true)); + $user = $db->name('tb_user')->where(['user_id' => $userId])->delete(); + if($user) { + $this->success(); + } + $this->error('操作失败'); + } + + + public function getuserinfo() + { + $userId = $this->request->get('userId'); + if(empty($userId)) { + $this->error('userId 不能为空'); + } + + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId])); + $user = $db->name('tb_user')->where(['user_id' => $userId])->find(); + if(!$user) { + $this->error('用户不存在'); + } + + $inviteMoney = \app\admin\model\User::selectInviteMoneyByUserId($userId, $db); + if(empty($inviteMoney)) { + $inviteMoney = [ + 'user_id' => $userId, + 'money_sum' => 0.00, + 'money' => 0.00, + 'cash_out' => 0.00, + ]; + Db::connect(DatabaseRoute::getConnection('invite_money', ['user_id' => $userId], true), true)->name('invite_money')->insert($inviteMoney); + } + $money = $inviteMoney['money']; + + // 获取当前日期(格式:YYYY-MM-DD HH:mm:ss) + $date = date('Y-m-d H:i:s'); + + // 查询本月充值(复用之前的instantselectSumPay方法) + $consume = \app\admin\model\User::instantselectSumPay(date('Y-m'), $userId, $db); + + // 查询本月提现(假设monthIncome方法已实现) + $income = \app\admin\model\User::monthIncome(date('Y-m'), $userId, $db); + + // 查询邀请人数(复用之前的countUsersByInviterCode方法) + $count = \app\admin\model\User::queryInviterCount($user['invitation_code']); + + // 查询VIP信息 + $userVip = \app\admin\model\User::selectUserVipByUserId($userId); + if ($userVip) { + $user['member'] = $userVip['is_vip']; + $user['end_time'] = $userVip['end_time']; + $user['vip_type'] = $userVip['vip_type']; + } + + // 组装结果数据 + $resultData = [ + 'userEntity' => $user, + 'money' => $money, + 'consume' => $consume, + 'income' => $income, + 'count' => $count + ]; + $this->n_success(['data' => $resultData]); + + } + + public function userListExcel() + { + $get = $this->request->get(); + $startTime = $get['startTime'] ?? null; + $endTime = $get['endTime'] ?? null; + $this->n_success(\app\admin\model\User::userListExcel($startTime, $endTime)); + } + + + + // 获取用户详细信息 + public function selectUserByInvitationCode() + { + $get = $this->request->get(); + if(empty($get['invitationCode'])) { + $this->error('参数不完整'); + } + $invitationCode = $get['invitationCode']; + $userEntity = TbUser::GetByusername($invitationCode, 'invitation_code'); + if(empty($userEntity)) { + $this->error('用户信息不存在'); + } + $userId = $userEntity['user_id']; + + $db = Db::connect(DatabaseRoute::getConnection('invite_money', ['user_id' => $userId])); + // 查询用户钱包 + $inviteMoney = \app\admin\model\User::selectInviteMoneyByUserId($userId, $db); + $money = $inviteMoney['money']; + // 获取当前时间(格式:Y-m-d H:i:s) + $currentDate = date('Y-m-d H:i:s'); + // 查询本月充值总额 + $consume = \app\admin\model\User::instantselectSumPay($currentDate, $userId, $db); + $income = \app\admin\model\User::monthIncome($currentDate, $userId, $db); + //查询邀请人数 + $count = \app\admin\model\User::queryInviterCount($userEntity['invitation_code']); + $userVip = \app\admin\model\User::selectUserVipByUserId($userId); + if ($userVip) { + $userEntity['member'] = $userVip['is_vip']; + $userEntity['end_time'] = $userVip['end_time']; + $userEntity['vip_type'] = $userVip['vip_type']; + } + $data = [ + 'userEntity' => $userEntity, + 'money' => $money, + 'consume' => $consume, + 'income' => $income, + 'count' => $count + ]; + $this->n_success(['data' => $data]); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/UserInfoController.php b/app/czg/controller/UserInfoController.php new file mode 100644 index 0000000..600ef01 --- /dev/null +++ b/app/czg/controller/UserInfoController.php @@ -0,0 +1,84 @@ +request->param(); + $result = DatabaseRoute::paginateAllDb('user_info', function ($query) use ($params) { + if (!empty($params['phone'])) { + $user = DatabaseRoute::getAllDbData('tb_user', function ($q) use ($params) { + return $q->where('phone', $params['phone']); + })->find(); + $userId = $user ? $user['user_id'] : -99999; + $query->where('user_id', $userId); + } + + if (!empty($name)) { + $query->whereLike('cert_name', "%{$name}%"); + } + + return $query; + }, $params['page'], $params['limit'], 'id', 'id'); + + // 用户信息补全 + $userInfoList = $result['list']; + $userIds = array_column($userInfoList, 'user_id'); + + if (!empty($userIds)) { + $userMap = DatabaseRoute::getAllDbData('tb_user', function ($query) use ($params, $userIds) { + return $query + ->whereIn('user_id', $userIds); + })->select(); + + foreach ($userInfoList as &$item) { + $user = $userMap[$item['user_id']] ?? null; + $item['name'] = $user['user_name'] ?? null; + $item['phone'] = $user['phone'] ?? null; + } + unset($item); + + $result['list'] = $userInfoList; + } + + $this->successWithData($result); + } + + + public function update() + { + $params = input(); + if (empty($params['userId'])) { + $this->error('参数错误'); + } + + $params['update_time'] = getNormalDate(); + DatabaseRoute::getDb('user_info', $params['userId'], true, true)->update([ + 'cert_name' => $params['certName'] ?? '', + 'cert_no' => $params['certNo'] ?? '', + 'account_no' => $params['accountNo'] ?? '', + 'mobile' => $params['mobile'] ?? '', + 'bank_name' => $params['bankName'] ?? '', + ]); + $this->success(); + } + + public function delete() + { + $params = $this->request->get(); + if (empty($params['userId'])) { + $this->error('参数错误'); + } + DatabaseRoute::getDb('user_info', $params['userId'], true, true)->delete(); + $this->success(); + } + + +} \ No newline at end of file diff --git a/app/czg/controller/UserPrizeExchangeController.php b/app/czg/controller/UserPrizeExchangeController.php new file mode 100644 index 0000000..b3de8d8 --- /dev/null +++ b/app/czg/controller/UserPrizeExchangeController.php @@ -0,0 +1,84 @@ +request->param(); + $this->successWithData(DatabaseRoute::paginateDb('user_prize_exchange', function ($query) use ($params) { + if (!empty($params['foreignId'])) { + $query->where('foreign_id', $params['foreignId']); + } + if (!empty($params['foreignType'])) { + $query->where('foreign_type', $params['foreignType']); + } + if (!empty($params['userId'])) { + $query->where('user_id', $params['userId']); + } + if (!empty($params['userName'])) { + $query->where('user_name', 'like', "%". $params['userName']."%"); + } + if (!empty($params['prizeName'])) { + $query->where('prize_name', 'like', "%" . $params['prizeName'] . "%"); + } + if (!empty($params['status'])) { + $query->where('status', $params['status']); + } + if (!empty($params['phone'])) { + $query->where('phone', 'like', "%". $params['phone'] ."%"); + } + if (!empty($params['remark'])) { + $query->where('remark', 'like', "%" . $params['remark'] . "%"); + } + + if (!empty($params['beginDate'])) { + $query->where('create_time', '>=', $params['beginDate'] . ' 00:00:00'); + } + if (!empty($params['endDate'])) { + $query->where('create_time', '<=', $params['endDate'] . ' 23:59:59'); + } + $query->order('id', false); + })); + } + + public function deliver() + { + $params = $this->request->post(); + if (empty($params['id'])) { + $this->error('兑奖id不能为空'); + } + + $info = Db::name('user_prize_exchange')->where([ + 'id' => $params['id'] + ])->find(); + if (!$info) { + $this->error('兑奖订单不存在'); + } + + Db::name('user_prize_exchange')->where([ + 'id' => $params['id'] + ])->update([ + 'status' => 1, + 'address' => $params['address'] ?? '', + 'remark' => $params['remark'] ?? '', + 'update_time' => getNormalDate() + ]); + + $this->success(); + + + } + + + +} \ No newline at end of file diff --git a/app/czg/controller/VipDetailsController.php b/app/czg/controller/VipDetailsController.php new file mode 100644 index 0000000..d292deb --- /dev/null +++ b/app/czg/controller/VipDetailsController.php @@ -0,0 +1,128 @@ +request->post(); + $userId = $data['userId'] ?? null; + $num = $data['num'] ?? null; + $userVip = \app\admin\model\User::selectUserVipByUserId($userId); + + // 获取当前时间戳 + $currentTime = time(); + + // 如果用户已有 VIP 记录 + if ($userVip) { + // 如果当前是 VIP 会员(假设 is_vip=2 表示 VIP) + if ($userVip['is_vip'] == 2) { + // 从现有结束时间开始叠加(转换为时间戳) + $endTime = strtotime($userVip['end_time']); + } else { + // 非 VIP 从当前时间开始 + $endTime = $currentTime; + } + } else { + // 新建 VIP 记录 + $userVip = [ + 'user_id' => $userId, + 'create_time' => date('Y-m-d H:i:s', $currentTime) + ]; + $endTime = $currentTime; + } + + // 设置 VIP 类型和状态 + $userVip['vip_type'] = 1; + $userVip['is_vip'] = 2; + + // 计算新的结束时间(增加指定天数,每天 86400 秒) + $endTime += $num * 86400; + $userVip['end_time'] = date('Y-m-d H:i:s', $endTime); + $db = Db::connect(get_master_connect_name())->name('user_vip'); + // 保存或更新记录 + if (isset($userVip['vip_id'])) { + // 更新记录 + $db->where('vip_id', $userVip['vip_id']) + ->update($userVip); + } else { + // 插入新记录 + $db->insert($userVip); + } + $this->success(); + + } + + + public function selectVipDetailsList() + { + $get = $this->request->get(); + $page = $get['page'] ?? null; + $limit = $get['limit'] ?? null; + $db = Db::connect(get_slave_connect_name())->name('vip_details'); + $count = $db->count(); + $data = $db->limit(page($page, $limit), $limit)->select()->toArray(); + $this->n_success(['data' => [ + 'currPage' => $get['page'], + 'pageSize' => $get['limit'], + 'list' => array_map(function ($item) { + $item['id'] = (string)$item['id']; + return $item; + }, $data), + 'totalCount' => $count, + 'totalPage' => ceil($count / $get['limit']), + ]]); + } + + + public function insertVipDetails() + { + $post = $this->request->post(); + $data['vip_name_type'] = $post['vipNameType'] ?? null; + $data['money'] = $post['money'] ?? null; + $data['pay_diamond'] = $post['payDiamond'] ?? null; + $db = Db::connect(get_master_connect_name()); + $res = $db->name('vip_details')->insert($data); + if($res) { + $this->success('成功'); + }else { + $this->error('失败'); + } + } + + + public function updateVipDetails() + { + $post = $this->request->post(); + $id = $post['id'] ?? null; + $data['vip_name_type'] = $post['vipNameType'] ?? null; + $data['money'] = $post['money'] ?? null; + $data['pay_diamond'] = $post['payDiamond'] ?? null; + $db = Db::connect(get_master_connect_name()); + $res = $db->name('vip_details')->where(['id' => $id])->update($data); + $this->success('成功'); + } + + public function deleteVipDetails() + { + $post = $this->request->param(); + if(empty($post['id'])) { + $this->error('参数不完整'); + } + $id = $post['id']; + $db = Db::connect(get_master_connect_name()); + $res = $db->name('vip_details')->where(['id' => $id])->delete(); + $this->success('成功'); + } + + + + +} \ No newline at end of file diff --git a/app/czg/crud/controller/CrudController.php b/app/czg/crud/controller/CrudController.php new file mode 100644 index 0000000..973d6ed --- /dev/null +++ b/app/czg/crud/controller/CrudController.php @@ -0,0 +1,992 @@ +request->post('type', ''); + $table = $this->request->post('table', []); + $fields = $this->request->post('fields', [], 'clean_xss,htmlspecialchars_decode_improve'); + + if (!$table || !$fields || !isset($table['name']) || !$table['name']) { + $this->error(__('Parameter error')); + } + + try { + // 记录日志 + $crudLogId = Helper::recordCrudStatus([ + 'table' => $table, + 'fields' => $fields, + 'status' => 'start', + ]); + + // 表名称 + $tableName = TableManager::tableName($table['name'], false, $table['databaseConnection']); + + if ($type == 'create' || $table['rebuild'] == 'Yes') { + // 数据表存在则删除 + TableManager::phinxTable($tableName, [], true, $table['databaseConnection'])->drop()->save(); + } + + // 处理表设计 + [$tablePk] = Helper::handleTableDesign($table, $fields); + + // 表注释 + $tableComment = mb_substr($table['comment'], -1) == '表' ? mb_substr($table['comment'], 0, -1) . '管理' : $table['comment']; + + // 生成文件信息解析 + $modelFile = Helper::parseNameData($table['isCommonModel'] ? 'common' : 'admin', $tableName, 'model', $table['modelFile']); + $validateFile = Helper::parseNameData($table['isCommonModel'] ? 'common' : 'admin', $tableName, 'validate', $table['validateFile']); + $controllerFile = Helper::parseNameData('admin', $tableName, 'controller', $table['controllerFile']); + $webViewsDir = Helper::parseWebDirNameData($tableName, 'views', $table['webViewsDir']); + $webLangDir = Helper::parseWebDirNameData($tableName, 'lang', $table['webViewsDir']); + + // 语言翻译前缀 + $this->webTranslate = implode('.', $webLangDir['lang']) . '.'; + + // 快速搜索字段 + if (!in_array($tablePk, $table['quickSearchField'])) { + $table['quickSearchField'][] = $tablePk; + } + $quickSearchFieldZhCnTitle = []; + + // 模型数据 + $this->modelData['append'] = []; + $this->modelData['methods'] = []; + $this->modelData['fieldType'] = []; + $this->modelData['createTime'] = ''; + $this->modelData['updateTime'] = ''; + $this->modelData['beforeInsertMixins'] = []; + $this->modelData['beforeInsert'] = ''; + $this->modelData['afterInsert'] = ''; + $this->modelData['connection'] = $table['databaseConnection']; + $this->modelData['name'] = $tableName; + $this->modelData['className'] = $modelFile['lastName']; + $this->modelData['namespace'] = $modelFile['namespace']; + $this->modelData['relationMethodList'] = []; + + // 控制器数据 + $this->controllerData['use'] = []; + $this->controllerData['attr'] = []; + $this->controllerData['methods'] = []; + $this->controllerData['filterRule'] = ''; + $this->controllerData['className'] = $controllerFile['lastName']; + $this->controllerData['namespace'] = $controllerFile['namespace']; + $this->controllerData['tableComment'] = $tableComment; + $this->controllerData['modelName'] = $modelFile['lastName']; + $this->controllerData['modelNamespace'] = $modelFile['namespace']; + + // index.vue数据 + $this->indexVueData['enableDragSort'] = false; + $this->indexVueData['defaultItems'] = []; + $this->indexVueData['tableColumn'] = [ + [ + 'type' => 'selection', + 'align' => 'center', + 'operator' => 'false', + ], + ]; + $this->indexVueData['dblClickNotEditColumn'] = ['undefined']; + $this->indexVueData['optButtons'] = ['edit', 'delete']; + $this->indexVueData['defaultOrder'] = ''; + + // form.vue数据 + $this->formVueData['bigDialog'] = false; + $this->formVueData['formFields'] = []; + $this->formVueData['formValidatorRules'] = []; + $this->formVueData['imports'] = []; + + // 语言包数据 + $this->langTsData = [ + 'en' => [], + 'zh-cn' => [], + ]; + + // 简化的字段数据 + $fieldsMap = []; + + foreach ($fields as $key => $field) { + + $fieldsMap[$field['name']] = $field['designType']; + + // 分析字段 + Helper::analyseField($field); + + Helper::getDictData($this->langTsData['en'], $field, 'en'); + Helper::getDictData($this->langTsData['zh-cn'], $field, 'zh-cn'); + + // 快速搜索字段 + if (in_array($field['name'], $table['quickSearchField'])) { + $quickSearchFieldZhCnTitle[] = $this->langTsData['zh-cn'][$field['name']] ?? $field['name']; + } + + // 不允许双击编辑的字段 + if ($field['designType'] == 'switch') { + $this->indexVueData['dblClickNotEditColumn'][] = $field['name']; + } + + // 列字典数据 + $columnDict = $this->getColumnDict($field); + + // 表单项 + if (in_array($field['name'], $table['formFields'])) { + $this->formVueData['formFields'][] = $this->getFormField($field, $columnDict, $table['databaseConnection']); + } + + // 表格列 + if (in_array($field['name'], $table['columnFields'])) { + $this->indexVueData['tableColumn'][] = $this->getTableColumn($field, $columnDict); + } + + // 关联表数据解析 + if (in_array($field['designType'], ['remoteSelect', 'remoteSelects'])) { + $this->parseJoinData($field, $table); + } + + // 模型方法 + $this->parseModelMethods($field, $this->modelData); + + // 控制器/模型等文件的一些杂项属性解析 + $this->parseSundryData($field, $table); + + if (!in_array($field['name'], $table['formFields'])) { + $this->controllerData['attr']['preExcludeFields'][] = $field['name']; + } + } + + // 快速搜索提示 + $this->langTsData['en']['quick Search Fields'] = implode(',', $table['quickSearchField']); + $this->langTsData['zh-cn']['quick Search Fields'] = implode('、', $quickSearchFieldZhCnTitle); + $this->controllerData['attr']['quickSearchField'] = $table['quickSearchField']; + + // 开启字段排序 + $weighKey = array_search('weigh', $fieldsMap); + if ($weighKey !== false) { + $this->indexVueData['enableDragSort'] = true; + $this->modelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', [ + 'field' => $weighKey + ]); + } + + // 表格的操作列 + $this->indexVueData['tableColumn'][] = [ + 'label' => "t('Operate')", + 'align' => 'center', + 'width' => $this->indexVueData['enableDragSort'] ? 140 : 100, + 'render' => 'buttons', + 'buttons' => 'optButtons', + 'operator' => 'false', + ]; + if ($this->indexVueData['enableDragSort']) { + array_unshift($this->indexVueData['optButtons'], 'weigh-sort'); + } + + // 写入语言包代码 + Helper::writeWebLangFile($this->langTsData, $webLangDir); + + // 写入模型代码 + Helper::writeModelFile($tablePk, $fieldsMap, $this->modelData, $modelFile); + + // 写入控制器代码 + Helper::writeControllerFile($this->controllerData, $controllerFile); + + // 写入验证器代码 + $validateContent = Helper::assembleStub('mixins/validate/validate', [ + 'namespace' => $validateFile['namespace'], + 'className' => $validateFile['lastName'], + ]); + Helper::writeFile($validateFile['parseFile'], $validateContent); + + // 写入index.vue代码 + $this->indexVueData['tablePk'] = $tablePk; + $this->indexVueData['webTranslate'] = $this->webTranslate; + Helper::writeIndexFile($this->indexVueData, $webViewsDir, $controllerFile); + + // 写入form.vue代码 + Helper::writeFormFile($this->formVueData, $webViewsDir, $fields, $this->webTranslate); + + // 生成菜单 + Helper::createMenu($webViewsDir, $tableComment); + + Helper::recordCrudStatus([ + 'id' => $crudLogId, + 'status' => 'success', + ]); + } catch (Exception $e) { + Helper::recordCrudStatus([ + 'id' => $crudLogId ?? 0, + 'status' => 'error', + ]); + $this->error($e->getMessage()); + } catch (Throwable $e) { + Helper::recordCrudStatus([ + 'id' => $crudLogId ?? 0, + 'status' => 'error', + ]); + if (env('app_debug', false)) throw $e; + $this->error($e->getMessage()); + } + + $this->success('', [ + 'crudLog' => CrudLog::find($crudLogId), + ]); + } + + /** + * 从log开始 + * @throws Throwable + */ + public function logStart(): void + { + $id = $this->request->post('id'); + $type = $this->request->post('type', ''); + + if ($type == 'Cloud history') { + // 云端 历史记录 + $client = get_ba_client(); + $response = $client->request('GET', '/api/v6.Crud/info', [ + 'query' => [ + 'id' => $id, + 'server' => 1, + 'ba-user-token' => $this->request->post('token', ''), + ] + ]); + $body = $response->getBody(); + $statusCode = $response->getStatusCode(); + $content = $body->getContents(); + if ($content == '' || stripos($content, '系统发生错误') !== false || $statusCode != 200) { + $this->error(__('Failed to load cloud data')); + } + $json = json_decode($content, true); + if (json_last_error() != JSON_ERROR_NONE) { + $this->error(__('Failed to load cloud data')); + } + if (is_array($json)) { + if ($json['code'] != 1) { + $this->error($json['msg']); + } + + $info = $json['data']['info']; + } + } else { + // 本地记录 + $info = CrudLog::find($id)->toArray(); + } + + if (!isset($info) || !$info) { + $this->error(__('Record not found')); + } + + // 数据表是否有数据 + $connection = TableManager::getConnection($info['table']['databaseConnection'] ?? ''); + $tableName = TableManager::tableName($info['table']['name'], false, $connection); + $adapter = TableManager::phinxAdapter(true, $connection); + if ($adapter->hasTable($tableName)) { + $info['table']['empty'] = Db::connect($connection) + ->name($tableName) + ->limit(1) + ->select() + ->isEmpty(); + } else { + $info['table']['empty'] = true; + } + + AdminLog::instance()->setTitle(__('Log start')); + + $this->success('', [ + 'table' => $info['table'], + 'fields' => $info['fields'], + 'sync' => $info['sync'], + ]); + } + + /** + * 删除CRUD记录和生成的文件 + * @throws Throwable + */ + public function delete(): void + { + $id = $this->request->post('id'); + $info = CrudLog::find($id)->toArray(); + if (!$info) { + $this->error(__('Record not found')); + } + $webLangDir = Helper::parseWebDirNameData($info['table']['name'], 'lang', $info['table']['webViewsDir']); + $files = [ + $webLangDir['en'] . '.ts', + $webLangDir['zh-cn'] . '.ts', + $info['table']['webViewsDir'] . '/' . 'index.vue', + $info['table']['webViewsDir'] . '/' . 'popupForm.vue', + $info['table']['controllerFile'], + $info['table']['modelFile'], + $info['table']['validateFile'], + ]; + try { + foreach ($files as &$file) { + $file = Filesystem::fsFit(root_path() . $file); + if (file_exists($file)) { + unlink($file); + } + Filesystem::delEmptyDir(dirname($file)); + } + + // 删除菜单 + Menu::delete(Helper::getMenuName($webLangDir), true); + + Helper::recordCrudStatus([ + 'id' => $id, + 'status' => 'delete', + ]); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + $this->success(__('Deleted successfully')); + } + + /** + * 获取文件路径数据 + * @throws Throwable + */ + public function getFileData(): void + { + $table = $this->request->get('table'); + $commonModel = $this->request->get('commonModel/b'); + + if (!$table) { + $this->error(__('Parameter error')); + } + + try { + $modelFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'model'); + $validateFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'validate'); + $controllerFile = Helper::parseNameData('admin', $table, 'controller'); + $webViewsDir = Helper::parseWebDirNameData($table, 'views'); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + // 模型和控制器文件和文件列表 + $adminModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR); + $commonModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR); + $adminControllerFiles = get_controller_list(); + + $modelFileList = []; + $controllerFiles = []; + foreach ($adminModelFiles as $item) { + $item = Filesystem::fsFit('app/admin/model/' . $item); + $modelFileList[$item] = $item; + } + foreach ($commonModelFiles as $item) { + $item = Filesystem::fsFit('app/common/model/' . $item); + $modelFileList[$item] = $item; + } + + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Dashboard.php', + 'Index.php', + 'Module.php', + 'Terminal.php', + 'routine/AdminInfo.php', + 'routine/Config.php', + ]; + foreach ($adminControllerFiles as $item) { + if (in_array($item, $outExcludeController)) { + continue; + } + $item = Filesystem::fsFit('app/admin/controller/' . $item); + $controllerFiles[$item] = $item; + } + + $this->success('', [ + 'modelFile' => $modelFile['rootFileName'], + 'controllerFile' => $controllerFile['rootFileName'], + 'validateFile' => $validateFile['rootFileName'], + 'controllerFileList' => $controllerFiles, + 'modelFileList' => $modelFileList, + 'webViewsDir' => $webViewsDir['views'], + ]); + } + + /** + * 检查是否已有CRUD记录 + * @throws Throwable + */ + public function checkCrudLog(): void + { + $table = $this->request->get('table'); + $connection = $this->request->get('connection'); + $connection = $connection ?: config('database.default'); + + $crudLog = Db::name('crud_log') + ->where('table_name', $table) + ->where('connection', $connection) + ->order('create_time desc') + ->find(); + $this->success('', [ + 'id' => ($crudLog && $crudLog['status'] == 'success') ? $crudLog['id'] : 0, + ]); + } + + /** + * 解析字段数据 + * @throws Throwable + */ + public function parseFieldData(): void + { + AdminLog::instance()->setTitle(__('Parse field data')); + $type = $this->request->post('type'); + $table = $this->request->post('table'); + $connection = $this->request->post('connection'); + $connection = TableManager::getConnection($connection); + + $table = TableManager::tableName($table, true, $connection); + $connectionConfig = TableManager::getConnectionConfig($connection); + + if ($type == 'db') { + $sql = 'SELECT * FROM `information_schema`.`tables` ' + . 'WHERE TABLE_SCHEMA = ? AND table_name = ?'; + $tableInfo = Db::connect($connection)->query($sql, [$connectionConfig['database'], $table]); + if (!$tableInfo) { + $this->error(__('Record not found')); + } + + // 数据表是否有数据 + $adapter = TableManager::phinxAdapter(false, $connection); + if ($adapter->hasTable($table)) { + $empty = Db::connect($connection) + ->table($table) + ->limit(1) + ->select() + ->isEmpty(); + } else { + $empty = true; + } + + $this->success('', [ + 'columns' => Helper::parseTableColumns($table, false, $connection), + 'comment' => $tableInfo[0]['TABLE_COMMENT'] ?? '', + 'empty' => $empty, + ]); + } + } + + /** + * 生成前检查 + * @throws Throwable + */ + public function generateCheck(): void + { + $table = $this->request->post('table'); + $connection = $this->request->post('connection'); + $webViewsDir = $this->request->post('webViewsDir', ''); + $controllerFile = $this->request->post('controllerFile', ''); + + if (!$table) { + $this->error(__('Parameter error')); + } + + AdminLog::instance()->setTitle(__('Generate check')); + + try { + $webViewsDir = Helper::parseWebDirNameData($table, 'views', $webViewsDir); + $controllerFile = Helper::parseNameData('admin', $table, 'controller', $controllerFile)['rootFileName']; + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + // 数据表是否存在 + $tableList = TableManager::getTableList($connection); + $tableExist = array_key_exists(TableManager::tableName($table, true, $connection), $tableList); + + // 控制器是否存在 + $controllerExist = file_exists(root_path() . $controllerFile); + + // 菜单规则是否存在 + $menuName = Helper::getMenuName($webViewsDir); + $menuExist = AdminRule::where('name', $menuName)->value('id'); + + if ($controllerExist || $tableExist || $menuExist) { + $this->error('', [ + 'menu' => $menuExist, + 'table' => $tableExist, + 'controller' => $controllerExist, + ], -1); + } + $this->success(); + } + + /** + * CRUD 设计记录上传成功标记 + * @throws Throwable + */ + public function uploadCompleted(): void + { + $syncIds = $this->request->post('syncIds/a', []); + $cancelSync = $this->request->post('cancelSync/b', false); + $crudLogModel = new CrudLog(); + + if ($cancelSync) { + $logData = $crudLogModel->where('id', 'in', array_keys($syncIds))->select(); + foreach ($logData as $logDatum) { + if ($logDatum->sync == $syncIds[$logDatum->id]) { + $logDatum->sync = 0; + $logDatum->save(); + } + } + $this->success(); + } + + $saveData = []; + foreach ($syncIds as $key => $syncId) { + $saveData[] = [ + 'id' => $key, + 'sync' => $syncId, + ]; + } + $crudLogModel->saveAll($saveData); + $this->success(); + } + + /** + * 关联表数据解析 + * @param $field + * @param $table + * @throws Throwable + */ + private function parseJoinData($field, $table): void + { + $dictEn = []; + $dictZhCn = []; + + if ($field['form']['relation-fields'] && $field['form']['remote-table']) { + $columns = Helper::parseTableColumns($field['form']['remote-table'], true, $table['databaseConnection']); + $relationFields = explode(',', $field['form']['relation-fields']); + $tableName = TableManager::tableName($field['form']['remote-table'], false, $table['databaseConnection']); + $rnPattern = '/(.*)(_ids|_id)$/'; + if (preg_match($rnPattern, $field['name'])) { + $relationName = parse_name(preg_replace($rnPattern, '$1', $field['name']), 1, false); + } else { + $relationName = parse_name($field['name'] . '_table', 1, false); + } + + // 建立关联模型代码文件 + if (!$field['form']['remote-model'] || !file_exists(root_path() . $field['form']['remote-model'])) { + $joinModelFile = Helper::parseNameData('admin', $tableName, 'model', $field['form']['remote-model']); + if (!file_exists(root_path() . $joinModelFile['rootFileName'])) { + $joinModelData['append'] = []; + $joinModelData['methods'] = []; + $joinModelData['fieldType'] = []; + $joinModelData['createTime'] = ''; + $joinModelData['updateTime'] = ''; + $joinModelData['beforeInsertMixins'] = []; + $joinModelData['beforeInsert'] = ''; + $joinModelData['afterInsert'] = ''; + $joinModelData['connection'] = $table['databaseConnection']; + $joinModelData['name'] = $tableName; + $joinModelData['className'] = $joinModelFile['lastName']; + $joinModelData['namespace'] = $joinModelFile['namespace']; + $joinTablePk = 'id'; + $joinFieldsMap = []; + foreach ($columns as $column) { + $joinFieldsMap[$column['name']] = $column['designType']; + $this->parseModelMethods($column, $joinModelData); + if ($column['primaryKey']) $joinTablePk = $column['name']; + } + $weighKey = array_search('weigh', $joinFieldsMap); + if ($weighKey !== false) { + $joinModelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', [ + 'field' => $joinFieldsMap[$weighKey] + ]); + } + Helper::writeModelFile($joinTablePk, $joinFieldsMap, $joinModelData, $joinModelFile); + } + $field['form']['remote-model'] = $joinModelFile['rootFileName']; + } + + if ($field['designType'] == 'remoteSelect') { + // 关联预载入方法 + $this->controllerData['attr']['withJoinTable'][$relationName] = $relationName; + + // 模型方法代码 + $relationData = [ + 'relationMethod' => $relationName, + 'relationMode' => 'belongsTo', + 'relationPrimaryKey' => $field['form']['remote-pk'] ?? 'id', + 'relationForeignKey' => $field['name'], + 'relationClassName' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']) . "::class", + ]; + $this->modelData['relationMethodList'][$relationName] = Helper::assembleStub('mixins/model/belongsTo', $relationData); + + // 查询时显示的字段 + if ($relationFields) { + $this->controllerData['relationVisibleFieldList'][$relationData['relationMethod']] = $relationFields; + } + } elseif ($field['designType'] == 'remoteSelects') { + $this->modelData['append'][] = $relationName; + $this->modelData['methods'][] = Helper::assembleStub('mixins/model/getters/remoteSelectLabels', [ + 'field' => parse_name($relationName, 1), + 'className' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']), + 'primaryKey' => $field['form']['remote-pk'] ?? 'id', + 'foreignKey' => $field['name'], + 'labelFieldName' => $field['form']['remote-field'] ?? 'name', + ]); + } + + foreach ($relationFields as $relationField) { + if (!array_key_exists($relationField, $columns)) continue; + $relationFieldPrefix = $relationName . '.'; + $relationFieldLangPrefix = strtolower($relationName) . '__'; + Helper::getDictData($dictEn, $columns[$relationField], 'en', $relationFieldLangPrefix); + Helper::getDictData($dictZhCn, $columns[$relationField], 'zh-cn', $relationFieldLangPrefix); + + // 不允许双击编辑的字段 + if ($columns[$relationField]['designType'] == 'switch') { + $this->indexVueData['dblClickNotEditColumn'][] = $field['name']; + } + + // 列字典数据 + $columnDict = $this->getColumnDict($columns[$relationField], $relationFieldLangPrefix); + + // 表格列 + $columns[$relationField]['designType'] = $field['designType']; + $columns[$relationField]['table']['render'] = 'tags'; + if ($field['designType'] == 'remoteSelects') { + $columns[$relationField]['table']['operator'] = 'false'; + $this->indexVueData['tableColumn'][] = $this->getTableColumn($columns[$relationField], $columnDict, $relationFieldPrefix, $relationFieldLangPrefix); + + // 额外生成一个公共搜索,渲染为远程下拉的列 + unset($columns[$relationField]['table']['render']); + $columns[$relationField]['table']['label'] = "t('" . $this->webTranslate . $relationFieldLangPrefix . $columns[$relationField]['name'] . "')"; + $columns[$relationField]['name'] = $field['name']; + $columns[$relationField]['table']['show'] = 'false'; + $columns[$relationField]['table']['operator'] = 'FIND_IN_SET'; + $columns[$relationField]['table']['comSearchRender'] = 'remoteSelect'; + + $columns[$relationField]['table']['remote'] = [ + 'pk' => $this->getRemoteSelectPk($field), + 'field' => $field['form']['remote-field'] ?? 'name', + 'remoteUrl' => $this->getRemoteSelectUrl($field), + 'multiple' => 'true', + ]; + $this->indexVueData['tableColumn'][] = $this->getTableColumn($columns[$relationField], $columnDict, '', $relationFieldLangPrefix); + } else { + $columns[$relationField]['table']['operator'] = 'LIKE'; + $this->indexVueData['tableColumn'][] = $this->getTableColumn($columns[$relationField], $columnDict, $relationFieldPrefix, $relationFieldLangPrefix); + } + } + } + $this->langTsData['en'] = array_merge($this->langTsData['en'], $dictEn); + $this->langTsData['zh-cn'] = array_merge($this->langTsData['zh-cn'], $dictZhCn); + } + + /** + * 解析模型方法(设置器、获取器等) + */ + private function parseModelMethods($field, &$modelData): void + { + // fieldType + if ($field['designType'] == 'array') { + $modelData['fieldType'][$field['name']] = 'json'; + } elseif (!in_array($field['name'], ['create_time', 'update_time', 'updatetime', 'createtime']) && $field['designType'] == 'datetime' && (in_array($field['type'], ['int', 'bigint']))) { + $modelData['fieldType'][$field['name']] = 'timestamp:Y-m-d H:i:s'; + } + + // beforeInsertMixins + if ($field['designType'] == 'spk') { + $modelData['beforeInsertMixins']['snowflake'] = Helper::assembleStub('mixins/model/mixins/beforeInsertWithSnowflake', []); + } + + // methods + $fieldName = parse_name($field['name'], 1); + if (in_array($field['designType'], $this->dtStringToArray)) { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/stringToArray', [ + 'field' => $fieldName + ]); + $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/arrayToString', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'array') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/jsonDecode', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'time') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/time', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'editor') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/htmlDecode', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'spk') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/string', [ + 'field' => $fieldName + ]); + } elseif (in_array($field['type'], ['float', 'decimal', 'double'])) { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/float', [ + 'field' => $fieldName + ]); + } + + if ($field['designType'] == 'city') { + $modelData['append'][] = $field['name'] . '_text'; + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/cityNames', [ + 'field' => $fieldName . 'Text', + 'originalFieldName' => $field['name'], + ]); + } + } + + /** + * 控制器/模型等文件的一些杂项属性解析 + */ + private function parseSundryData($field, $table): void + { + if ($field['designType'] == 'editor') { + $this->formVueData['bigDialog'] = true; // 加宽 dialog + $this->controllerData['filterRule'] = "\n" . Helper::tab(2) . '$this->request->filter(\'clean_xss\');'; // 修改变量过滤规则 + } + + // 默认排序字段 + if ($table['defaultSortField'] && $table['defaultSortType']) { + $defaultSortField = "{$table['defaultSortField']},{$table['defaultSortType']}"; + if ($defaultSortField == 'id,desc') { + $this->controllerData['attr']['defaultSortField'] = ''; + } else { + $this->controllerData['attr']['defaultSortField'] = $defaultSortField; + $this->indexVueData['defaultOrder'] = Helper::buildDefaultOrder($table['defaultSortField'], $table['defaultSortType']); + } + } + + // 自定义了权重字段名称 + if ($field['originalDesignType'] == 'weigh' && $field['name'] != 'weigh') { + $this->controllerData['attr']['weighField'] = $field['name']; + } + } + + /** + * 组装前台表单的数据 + * @throws Throwable + */ + private function getFormField($field, $columnDict, ?string $dbConnection = null): array + { + // 表单项属性 + $formField = [ + ':label' => 't(\'' . $this->webTranslate . $field['name'] . '\')', + 'type' => $field['designType'], + 'v-model' => 'baTable.form.items!.' . $field['name'], + 'prop' => $field['name'], + ]; + + // 不同输入框的属性处理 + if ($columnDict || in_array($field['designType'], ['radio', 'checkbox', 'select', 'selects'])) { + $formField[':input-attr']['content'] = $columnDict; + } elseif ($field['designType'] == 'textarea') { + $formField[':input-attr']['rows'] = (int)($field['form']['rows'] ?? 3); + $formField['@keyup.enter.stop'] = ''; + $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)'; + } elseif ($field['designType'] == 'remoteSelect' || $field['designType'] == 'remoteSelects') { + $formField[':input-attr']['pk'] = $this->getRemoteSelectPk($field); + $formField[':input-attr']['field'] = $field['form']['remote-field'] ?? 'name'; + $formField[':input-attr']['remoteUrl'] = $this->getRemoteSelectUrl($field); + } elseif ($field['designType'] == 'number') { + $formField[':input-attr']['step'] = (int)($field['form']['step'] ?? 1); + } elseif ($field['designType'] == 'icon') { + $formField[':input-attr']['placement'] = 'top'; + } elseif ($field['designType'] == 'editor') { + $formField['@keyup.enter.stop'] = ''; + $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)'; + } + + // placeholder + if (!in_array($field['designType'], ['image', 'images', 'file', 'files', 'switch'])) { + if (in_array($field['designType'], ['radio', 'checkbox', 'datetime', 'year', 'date', 'time', 'select', 'selects', 'remoteSelect', 'remoteSelects', 'city', 'icon'])) { + $formField[':placeholder'] = "t('Please select field', { field: t('" . $this->webTranslate . $field['name'] . "') })"; + } else { + $formField[':placeholder'] = "t('Please input field', { field: t('" . $this->webTranslate . $field['name'] . "') })"; + } + } + + // 默认值 + if ($field['defaultType'] == 'INPUT') { + $this->indexVueData['defaultItems'][$field['name']] = $field['default']; + } + + // 部分生成类型的默认值需要额外处理 + if ($field['designType'] == 'editor') { + $this->indexVueData['defaultItems'][$field['name']] = ($field['defaultType'] == 'INPUT' && $field['default']) ? $field['default'] : ''; + } elseif ($field['designType'] == 'array') { + $this->indexVueData['defaultItems'][$field['name']] = "[]"; + } elseif ($field['defaultType'] == 'INPUT' && in_array($field['designType'], $this->dtStringToArray) && str_contains($field['default'], ',')) { + $this->indexVueData['defaultItems'][$field['name']] = Helper::buildSimpleArray(explode(',', $field['default'])); + } elseif ($field['defaultType'] == 'INPUT' && in_array($field['designType'], ['number', 'float'])) { + $this->indexVueData['defaultItems'][$field['name']] = (float)$field['default']; + } + + // 无意义的默认值 + if (isset($field['default']) && in_array($field['designType'], ['switch', 'number', 'float', 'remoteSelect']) && $field['default'] == 0) { + unset($this->indexVueData['defaultItems'][$field['name']]); + } + + return $formField; + } + + private function getRemoteSelectPk($field): string + { + $pk = $field['form']['remote-pk'] ?? 'id'; + if (!str_contains($pk, '.')) { + if ($field['form']['remote-source-config-type'] == 'crud' && $field['form']['remote-model']) { + $alias = parse_name(basename(str_replace('\\', '/', $field['form']['remote-model']), '.php')); + } else { + $alias = $field['form']['remote-primary-table-alias'] ?? ''; + } + } + return !empty($alias) ? "$alias.$pk" : $pk; + } + + private function getRemoteSelectUrl($field): string + { + if ($field['form']['remote-source-config-type'] == 'crud' && $field['form']['remote-controller']) { + $pathArr = []; + $controller = explode(DIRECTORY_SEPARATOR, $field['form']['remote-controller']); + $controller = str_replace('.php', '', $controller); + $redundantDir = [ + 'app' => 0, + 'admin' => 1, + 'controller' => 2, + ]; + foreach ($controller as $key => $item) { + if (!array_key_exists($item, $redundantDir) || $key !== $redundantDir[$item]) { + $pathArr[] = $item; + } + } + $url = count($pathArr) > 1 ? implode('.', $pathArr) : $pathArr[0]; + return '/admin/' . $url . '/index'; + } + return $field['form']['remote-url']; + } + + private function getTableColumn($field, $columnDict, $fieldNamePrefix = '', $translationPrefix = ''): array + { + $column = [ + 'label' => "t('" . $this->webTranslate . $translationPrefix . $field['name'] . "')", + 'prop' => $fieldNamePrefix . $field['name'] . ($field['designType'] == 'city' ? '_text' : ''), + 'align' => 'center', + ]; + + // 模糊搜索增加一个placeholder + if (isset($field['table']['operator']) && $field['table']['operator'] == 'LIKE') { + $column['operatorPlaceholder'] = "t('Fuzzy query')"; + } + + // 合并前端预设的字段表格属性 + if (isset($field['table']) && $field['table']) { + $column = array_merge($column, $field['table']); + } + + // 需要值替换的渲染类型 + $columnReplaceValue = ['tag', 'tags', 'switch']; + if (!in_array($field['designType'], ['remoteSelect', 'remoteSelects']) && ($columnDict || (isset($field['table']['render']) && in_array($field['table']['render'], $columnReplaceValue)))) { + $column['replaceValue'] = $columnDict; + } + + if (isset($column['render']) && $column['render'] == 'none') { + unset($column['render']); + } + return $column; + } + + private function getColumnDict($column, $translationPrefix = ''): array + { + $dict = []; + // 确保字典中无翻译也可以识别到该值 + if (in_array($column['type'], ['enum', 'set'])) { + $dataType = str_replace(' ', '', $column['dataType']); + $columnData = substr($dataType, stripos($dataType, '(') + 1, -1); + $columnData = explode(',', str_replace(["'", '"'], '', $columnData)); + foreach ($columnData as $columnDatum) { + $dict[$columnDatum] = $column['name'] . ' ' . $columnDatum; + } + } + $dictData = []; + Helper::getDictData($dictData, $column, 'zh-cn', $translationPrefix); + if ($dictData) { + unset($dictData[$translationPrefix . $column['name']]); + foreach ($dictData as $key => $item) { + $keyName = str_replace($translationPrefix . $column['name'] . ' ', '', $key); + $dict[$keyName] = "t('" . $this->webTranslate . $key . "')"; + } + } + return $dict; + } +} \ No newline at end of file diff --git a/app/czg/crud/controller/LogController.php b/app/czg/crud/controller/LogController.php new file mode 100644 index 0000000..8eba8df --- /dev/null +++ b/app/czg/crud/controller/LogController.php @@ -0,0 +1,37 @@ +model = new CrudLog(); + + if (!$this->auth->check('crud/crud/index')) { + $this->error(__('You have no permission'), [], 401); + } + } + +} \ No newline at end of file diff --git a/app/czg/routine/controller/AdminInfoController.php b/app/czg/routine/controller/AdminInfoController.php new file mode 100644 index 0000000..0a0fe32 --- /dev/null +++ b/app/czg/routine/controller/AdminInfoController.php @@ -0,0 +1,90 @@ +auth->setAllowFields($this->authAllowFields); + $this->model = $this->auth->getAdmin(); + } + + public function index(): void + { + $info = $this->auth->getInfo(); + $this->success('', [ + 'info' => $info + ]); + } + + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if (!empty($data['avatar'])) { + $row->avatar = $data['avatar']; + if ($row->save()) { + $this->success(__('Avatar modified successfully!')); + } + } + + // 数据验证 + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('info')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + if (!empty($data['password'])) { + $this->model->resetPassword($this->auth->id, $data['password']); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + } +} \ No newline at end of file diff --git a/app/czg/routine/controller/AttachmentController.php b/app/czg/routine/controller/AttachmentController.php new file mode 100644 index 0000000..1503dde --- /dev/null +++ b/app/czg/routine/controller/AttachmentController.php @@ -0,0 +1,59 @@ +model = new AttachmentModel(); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request->param('ids/a', []); + $where[] = [$this->model->getPk(), 'in', $ids]; + $data = $this->model->where($where)->select(); + + $count = 0; + try { + foreach ($data as $v) { + $count += $v->delete(); + } + } catch (Throwable $e) { + $this->error(__('%d records and files have been deleted', [$count]) . $e->getMessage()); + } + if ($count) { + $this->success(__('%d records and files have been deleted', [$count])); + } else { + $this->error(__('No rows were deleted')); + } + } +} \ No newline at end of file diff --git a/app/czg/routine/controller/ConfigController.php b/app/czg/routine/controller/ConfigController.php new file mode 100644 index 0000000..bfb3e87 --- /dev/null +++ b/app/czg/routine/controller/ConfigController.php @@ -0,0 +1,246 @@ + 'config/app.php', + 'webAdminBase' => 'web/src/router/static/adminBase.ts', + 'backendEntranceStub' => 'app/admin/library/stubs/backendEntrance.stub', + ]; + + public function initialize(): void + { + parent::initialize(); + $this->model = new ConfigModel(); + } + + public function index(): void + { + $configGroup = get_sys_config('config_group'); + $config = $this->model->order('weigh desc')->select()->toArray(); + + $list = []; + $newConfigGroup = []; + foreach ($configGroup as $item) { + $list[$item['key']]['name'] = $item['key']; + $list[$item['key']]['title'] = __($item['value']); + $newConfigGroup[$item['key']] = $list[$item['key']]['title']; + } + foreach ($config as $item) { + if (array_key_exists($item['group'], $newConfigGroup)) { + $item['title'] = __($item['title']); + $list[$item['group']]['list'][] = $item; + } + } + + $this->success('', [ + 'list' => $list, + 'remark' => get_route_remark(), + 'configGroup' => $newConfigGroup ?? [], + 'quickEntrance' => get_sys_config('config_quick_entrance'), + ]); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $all = $this->model->select(); + foreach ($all as $item) { + if ($item['type'] == 'editor') { + $this->request->filter('clean_xss'); + break; + } + } + if ($this->request->isPost()) { + $this->modelValidate = false; + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + + $configValue = []; + foreach ($all as $item) { + if (array_key_exists($item->name, $data)) { + $configValue[] = [ + 'id' => $item->id, + 'type' => $item->getData('type'), + 'value' => $data[$item->name] + ]; + + // 自定义后台入口 + if ($item->name == 'backend_entrance') { + $backendEntrance = get_sys_config('backend_entrance'); + if ($backendEntrance == $data[$item->name]) continue; + + if (!preg_match("/^\/[a-zA-Z0-9]+$/", $data[$item->name])) { + $this->error(__('Backend entrance rule')); + } + + // 修改 adminBaseRoutePath + $adminBaseFilePath = Filesystem::fsFit(root_path() . $this->filePath['webAdminBase']); + $adminBaseContent = @file_get_contents($adminBaseFilePath); + if (!$adminBaseContent) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']])); + + $adminBaseContent = str_replace("export const adminBaseRoutePath = '$backendEntrance'", "export const adminBaseRoutePath = '{$data[$item->name]}'", $adminBaseContent); + $result = @file_put_contents($adminBaseFilePath, $adminBaseContent); + if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']])); + + // 去除后台入口开头的斜杠 + $oldBackendEntrance = ltrim($backendEntrance, '/'); + $newBackendEntrance = ltrim($data[$item->name], '/'); + + // 设置应用别名映射 + $appMap = config('app.app_map'); + $adminMapKey = array_search('admin', $appMap); + if ($adminMapKey !== false) { + unset($appMap[$adminMapKey]); + } + if ($newBackendEntrance != 'admin') { + $appMap[$newBackendEntrance] = 'admin'; + } + $appConfigFilePath = Filesystem::fsFit(root_path() . $this->filePath['appConfig']); + $appConfigContent = @file_get_contents($appConfigFilePath); + if (!$appConfigContent) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']])); + + $appMapStr = ''; + foreach ($appMap as $newAppName => $oldAppName) { + $appMapStr .= "'$newAppName' => '$oldAppName', "; + } + $appMapStr = rtrim($appMapStr, ', '); + $appMapStr = "[$appMapStr]"; + + $appConfigContent = preg_replace("/'app_map'(\s+)=>(\s+)(.*)\/\/ 域名/s", "'app_map'\$1=>\$2$appMapStr,\n // 域名", $appConfigContent); + $result = @file_put_contents($appConfigFilePath, $appConfigContent); + if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']])); + + // 建立API入口文件 + $oldBackendEntranceFile = Filesystem::fsFit(public_path() . $oldBackendEntrance . '.php'); + $newBackendEntranceFile = Filesystem::fsFit(public_path() . $newBackendEntrance . '.php'); + if (file_exists($oldBackendEntranceFile)) @unlink($oldBackendEntranceFile); + + if ($newBackendEntrance != 'admin') { + $backendEntranceStub = @file_get_contents(Filesystem::fsFit(root_path() . $this->filePath['backendEntranceStub'])); + if (!$backendEntranceStub) $this->error(__('Configuration write failed: %s', [$this->filePath['backendEntranceStub']])); + + $result = @file_put_contents($newBackendEntranceFile, $backendEntranceStub); + if (!$result) $this->error(__('Configuration write failed: %s', [$newBackendEntranceFile])); + } + } + } + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + $result = $this->model->saveAll($configValue); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('The current page configuration item was updated successfully')); + } else { + $this->error(__('No rows updated')); + } + + } + } + + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 发送邮件测试 + * @throws Throwable + */ + public function sendTestMail(): void + { + $data = $this->request->post(); + $mail = new Email(); + try { + $mail->Host = $data['smtp_server']; + $mail->SMTPAuth = true; + $mail->Username = $data['smtp_user']; + $mail->Password = $data['smtp_pass']; + $mail->SMTPSecure = $data['smtp_verification'] == 'SSL' ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS; + $mail->Port = $data['smtp_port']; + + $mail->setFrom($data['smtp_sender_mail'], $data['smtp_user']); + + $mail->isSMTP(); + $mail->addAddress($data['testMail']); + $mail->isHTML(); + $mail->setSubject(__('This is a test email') . '-' . get_sys_config('site_name')); + $mail->Body = __('Congratulations, receiving this email means that your email service has been configured correctly'); + $mail->send(); + } catch (PHPMailerException) { + $this->error($mail->ErrorInfo); + } + $this->success(__('Test mail sent successfully~')); + } +} \ No newline at end of file diff --git a/app/czg/security/controller/DataRecycleController.php b/app/czg/security/controller/DataRecycleController.php new file mode 100644 index 0000000..b7386c8 --- /dev/null +++ b/app/czg/security/controller/DataRecycleController.php @@ -0,0 +1,150 @@ +model = new DataRecycleModel(); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + // 放在add方法内,就不需要额外添加权限节点了 + $this->success('', [ + 'controllers' => $this->getControllerList(), + ]); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row + ]); + } + + protected function getControllerList(): array + { + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Module.php', + 'Terminal.php', + 'Dashboard.php', + 'Index.php', + 'routine/AdminInfo.php', + 'user/MoneyLog.php', + 'user/ScoreLog.php', + ]; + $outControllers = []; + $controllers = get_controller_list(); + foreach ($controllers as $key => $controller) { + if (!in_array($controller, $outExcludeController)) { + $outControllers[$key] = $controller; + } + } + return $outControllers; + } +} \ No newline at end of file diff --git a/app/czg/security/controller/DataRecycleLogController.php b/app/czg/security/controller/DataRecycleLogController.php new file mode 100644 index 0000000..1df51a7 --- /dev/null +++ b/app/czg/security/controller/DataRecycleLogController.php @@ -0,0 +1,106 @@ +model = new DataRecycleLogModel(); + } + + /** + * 还原 + * @throws Throwable + */ + public function restore(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + $this->error(__('Record not found')); + } + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $row) { + $recycleData = json_decode($row['data'], true); + if (is_array($recycleData) && Db::connect(TableManager::getConnection($row->connection))->name($row->data_table)->insert($recycleData)) { + $row->delete(); + $count++; + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + if ($count) { + $this->success(); + } else { + $this->error(__('No rows were restore')); + } + } + + /** + * 详情 + * @throws Throwable + */ + public function info(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('data_recycle_log.id', $id) + ->find(); + if (!$row) { + $this->error(__('Record not found')); + } + $data = $this->jsonToArray($row['data']); + if (is_array($data)) { + foreach ($data as $key => $item) { + $data[$key] = $this->jsonToArray($item); + } + } + $row['data'] = $data; + + $this->success('', [ + 'row' => $row + ]); + } + + protected function jsonToArray($value = '') + { + if (!is_string($value)) { + return $value; + } + $data = json_decode($value, true); + if (($data && is_object($data)) || (is_array($data) && !empty($data))) { + return $data; + } + return $value; + } +} \ No newline at end of file diff --git a/app/czg/security/controller/SensitiveDataController.php b/app/czg/security/controller/SensitiveDataController.php new file mode 100644 index 0000000..612e3f8 --- /dev/null +++ b/app/czg/security/controller/SensitiveDataController.php @@ -0,0 +1,204 @@ +model = new SensitiveDataModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res->items() as $item) { + if ($item->data_fields) { + $fields = []; + foreach ($item->data_fields as $key => $field) { + $fields[] = $field ?: $key; + } + $item->data_fields = $fields; + } + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加重写 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + + if (is_array($data['fields'])) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + // 放在add方法内,就不需要额外添加权限节点了 + $this->success('', [ + 'controllers' => $this->getControllerList(), + ]); + } + + /** + * 编辑重写 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + + if (is_array($data['fields'])) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row, + 'controllers' => $this->getControllerList(), + ]); + } + + protected function getControllerList(): array + { + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Dashboard.php', + 'Index.php', + 'Module.php', + 'Terminal.php', + 'auth/AdminLog.php', + 'routine/AdminInfo.php', + 'routine/Config.php', + 'user/MoneyLog.php', + 'user/ScoreLog.php', + ]; + $outControllers = []; + $controllers = get_controller_list(); + foreach ($controllers as $key => $controller) { + if (!in_array($controller, $outExcludeController)) { + $outControllers[$key] = $controller; + } + } + return $outControllers; + } +} \ No newline at end of file diff --git a/app/czg/security/controller/SensitiveDataLogController.php b/app/czg/security/controller/SensitiveDataLogController.php new file mode 100644 index 0000000..4ee9412 --- /dev/null +++ b/app/czg/security/controller/SensitiveDataLogController.php @@ -0,0 +1,117 @@ +model = new SensitiveDataLogModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res->items() as $item) { + $item->id_value = $item['primary_key'] . '=' . $item->id_value; + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 详情 + * @throws Throwable + */ + public function info(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('sensitive_data_log.id', $id) + ->find(); + if (!$row) { + $this->error(__('Record not found')); + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 回滚 + * @throws Throwable + */ + public function rollback(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + $this->error(__('Record not found')); + } + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $row) { + if (Db::connect(TableManager::getConnection($row->connection))->name($row->data_table)->where($row->primary_key, $row->id_value)->update([ + $row->data_field => $row->before + ])) { + $row->delete(); + $count++; + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + if ($count) { + $this->success(); + } else { + $this->error(__('No rows were rollback')); + } + } +} \ No newline at end of file diff --git a/app/czg/sys/controller/ConfigController.php b/app/czg/sys/controller/ConfigController.php new file mode 100644 index 0000000..422c77a --- /dev/null +++ b/app/czg/sys/controller/ConfigController.php @@ -0,0 +1,29 @@ +request->get(); + $db = Db::connect(get_slave_connect_name()); + $count = $db->name('sys_config')->count(); + $config_list= $db->name('sys_config')->where(['status' => 1])->limit(page($get['page'], $get['limit']), $get['limit'])->select()->toArray(); + $this->n_success(['page' => [ + 'totalCount' => $count, + 'pageSize' => $get['limit'], + 'totalPage' => ceil($count / $get['limit']), + 'currPage' => $get['page'], + 'list' => $config_list, + ]]); + } + +} \ No newline at end of file diff --git a/app/czg/sys/controller/LogController.php b/app/czg/sys/controller/LogController.php new file mode 100644 index 0000000..264836c --- /dev/null +++ b/app/czg/sys/controller/LogController.php @@ -0,0 +1,24 @@ +request->param(); + $this->result('成功', DatabaseRoute::paginateDb('sys_log', function ($query) { + return $query->order('id', 'desc'); + }, $params['page'], $params['limit']), 0, null, [], [], 'page'); + } + + + +} \ No newline at end of file diff --git a/app/czg/sys/controller/MenuController.php b/app/czg/sys/controller/MenuController.php new file mode 100644 index 0000000..ef87858 --- /dev/null +++ b/app/czg/sys/controller/MenuController.php @@ -0,0 +1,127 @@ +auth->getAdmin(); + $return = SysMenu::getMenuList($this->auth->getUserMenus($admin['user_id'])); + + $this->n_success([ + 'menuList' => convertToCamelCase($return['menuList']), + 'permissions' => $return['permissions'], + ]); + } + + public function list() + { + $menuList = Db::name('sys_menu')->order('order_num', 'asc')->select()->toArray(); + + // 收集所有 parent_id + $parentIds = array_column($menuList, 'parent_id'); + $parentIds = array_unique(array_filter($parentIds)); + + // 批量查询父级菜单 + $parentMap = []; + if (!empty($parentIds)) { + $parents = Db::name('sys_menu')->whereIn('menu_id', $parentIds)->column('name', 'menu_id'); + $parentMap = $parents; + } + + // 设置 parentName + foreach ($menuList as &$menu) { + $menu['menu_id'] = (string) $menu['menu_id']; + $menu['parent_id'] = (string) $menu['parent_id']; + + $menu['parent_name'] = $parentMap[$menu['parent_id']] ?? ''; + } + unset($menu); + + return $this->ApiDataReturn(convertToCamelCase($menuList)); + } + + public function info() + { + $data = Db::name('sys_menu')->where([ + 'menu_id' => $this->request->route->param('id') + ])->find(); + $data['menu_id'] = (string) $data['menu_id']; + $data['parent_id'] = (string) $data['parent_id']; + $data = convertToCamelCase($data); + $this->n_success(['menu' => $data]); + } + + + + public function save() + { + $menu = $this->request->post(); + SysMenu::verifyForm($menu); + $menu = convertKeysCamelToSnakeRecursive($menu); + Db::connect(get_master_connect_name())->name('sys_menu')->insert($menu); + $this->success(); + } + + + + public function selectInfo() + { + $list = Db::name('sys_menu')->where([ + 'type' => ['!=', 2] + ])->order('order_num')->select()->toArray(); + + $list[] = [ + 'menu_id' => 0, + 'name' => '一级菜单', + 'parent_id' => -1, + 'open' => true, + ]; + $list = convertToCamelCase($list); + $this->n_success(['menuList' => $list]); +// $this->successWithData([ +// 'menuList' => $list +// ]); + } + + public function update() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + Db::name('sys_menu')->where([ + 'menu_id' => $params['menu_id'] + ])->update($params); + $this->success(); + } + + public function delete() + { + $post = $this->request->post(); + if(empty($post['menuId'])) { + $this->error('参数错误'); + } + $menuId = $post['menuId']; + if($menuId <= 31) { + $this->error('系统菜单,不能删除'); + } + + // 判断是否有子菜单或按钮 + $menuList = Db::connect(get_slave_connect_name())->name('sys_menu')->where(['parent_id' => $menuId])->order('order_num', 'asc')->select()->toArray(); + if($menuList) { + $this->error('请先删除子菜单或按钮'); + } + + if(Db::name('sys_menu')->where(['menu_id' => $menuId])->delete()) { + $this->success('删除成功'); + } + $this->error('操作失败'); + } + +} \ No newline at end of file diff --git a/app/czg/sys/controller/OssController.php b/app/czg/sys/controller/OssController.php new file mode 100644 index 0000000..7985da7 --- /dev/null +++ b/app/czg/sys/controller/OssController.php @@ -0,0 +1,43 @@ +request->param(); + $data = DatabaseRoute::paginateDb('sys_oss', function ($query) { + return $query->order('id', 'desc'); + }, $params['page'], $params['limit']); + $this->n_success(['page' => $data]); + } + + public function config() + { + $data = Db::connect(get_slave_connect_name())->name('sys_config')->where(['param_key' => 'CLOUD_STORAGE_CONFIG_KEY'])->column('param_value')[0]; + $data = json_decode($data, true); + $this->n_success(['config' => $data]); + + } + + + public function saveConfig() + { + $post = $this->request->post(); + if(is_array($post)) { + $post = json_encode($post); + }else { + $this->error('参数错误'); + } + Db::name('sys_config')->where(['param_key' => 'CLOUD_STORAGE_CONFIG_KEY'])->update(['param_value' => $post]); + $this->success(); + } + + +} \ No newline at end of file diff --git a/app/czg/sys/controller/RoleController.php b/app/czg/sys/controller/RoleController.php new file mode 100644 index 0000000..64b80de --- /dev/null +++ b/app/czg/sys/controller/RoleController.php @@ -0,0 +1,108 @@ +request->get(); + $data = DatabaseRoute::paginateDb('sys_role', function ($query) { + return $query; + }, $prams['page'], $prams['limit']); + $this->n_success(['page' => $data]); + } + + private function saveRoleMenu($roleId, $params) + { + if (!empty($params['menu_id_list'])) { + Db::name('sys_role_menu')->where([ + 'role_id' => $roleId + ])->delete(); + + foreach ($params['menu_id_list'] as $menuId) { + Db::name('sys_role_menu')->insert([ + 'role_id' => $roleId, + 'menu_id' => $menuId + ]); + } + } + + } + + public function save() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + + $id = Db::name('sys_role')->insertGetId([ + 'role_name' => $params['role_name'], + 'create_time' => getNormalDate(), + 'remark' => $params['remark'] ?? '' + ]); + $this->saveRoleMenu($id, $params); + $this->success(); + } + + public function update() + { + $params = $this->request->post(); + $params = convertKeysCamelToSnakeRecursive($params); + Db::name('sys_role')->where([ + 'role_id' => $params['role_id'] + ])->update([ + 'role_name' => $params['role_name'], + 'remark' => $params['remark'] ?? '' + ]); + + $this->saveRoleMenu($params['role_id'], $params); + } + + public function delete() + { + $params = $this->request->post(); + Db::name('sys_role')->where([ + ['role_id', 'in', $params] + ])->delete(); + $this->success(); + } + + public function selects() + { + + $this->n_success(['list' => convertToCamelCase(array_map(function ($item) { + $item['role_id'] = (string)$item['role_id']; + return $item; + }, Db::connect(get_slave_connect_name())->name('sys_role')->select()->toArray()))]); + } + + + // 角色信息 + public function info() + { + $get = $this->request->get(); + if(empty($get['roleId'])) { + $this->error('roleId 不能为空'); + } + $db = Db::connect(get_slave_connect_name()); + + $role = $db->name('sys_role')->where(['role_id' => $get['roleId']])->find(); + if (!$role) { + $this->error('角色不存在'); + } + $role = apiconvertToCamelCase($role); + $menuIdList = $db->name('sys_role_menu')->where(['role_id' => $get['roleId']])->column('menu_id'); + + $role['menuIdList'] = $menuIdList; + $this->n_success(['role' => $role]); + + } + + +} \ No newline at end of file diff --git a/app/czg/sys/controller/UserController.php b/app/czg/sys/controller/UserController.php new file mode 100644 index 0000000..3c44577 --- /dev/null +++ b/app/czg/sys/controller/UserController.php @@ -0,0 +1,232 @@ +request->get(); + if (empty($get['userId'])) { + $info = $this->auth->getAdmin(); + } else { + $info = DatabaseRoute::getDb('sys_user', $get['userId'])->find(); + } + $info = convertToCamelCase($info); + $info['password'] = null; +// $info['salt'] = null; + $roleIdList = array_column(Db::name('sys_user_role')->where([ + 'user_id' => $info['userId'] + ])->select()->toArray(), 'role_id'); + foreach ($roleIdList as $k => &$v) { + $v = (string) $v; + } + $info['roleIdList'] = $roleIdList; + $this->n_success(['user' => $info]); + } + + public function list() + { + $params = $this->request->get(); + $data = DatabaseRoute::paginateAllDb('sys_user', function ($query) use ($params) { + if (!empty($params['username'])) { + $query->whereLike('username', '%' . $params['username'] . '%'); + } + + if (!empty($params['isChannel'])) { + $query->where('is_channel', $params['isChannel']); + } + return $query; + }, $params['page'], $params['limit']); + $data['list'] = convertToCamelCase($data['list']); + $this->n_success(['page' => $data]); + + } + + public function detail() + { + $id = $this->request->route->param('id'); + $sysInfo = DatabaseRoute::getDb('sys_user', $id)->find(); + if (!$sysInfo) { + $this->error('用户不存在'); + } + $userRoleList = Db::name('sys_user_role')->where([ + 'user_id' => $sysInfo['user_id'] + ])->select()->toArray(); + $sysInfo = convertToCamelCase($sysInfo); + $sysInfo['roleIdList'] =array_map('strval', array_column($userRoleList, 'role_id')); + $this->successWithData([ + 'user' => $sysInfo + ]); + + } + + public function updateRoleInfo($params) + { + if (!empty($params['role_id_list'])) { + Db::name('sys_user_role')->where([ + 'user_id' => $params['user_id'] + ])->delete(); + + foreach ($params['role_id_list'] as $roleId) { + Db::name('sys_user_role')->insert([ + 'user_id' => $params['user_id'], + 'role_id' => $roleId + ]); + } + } + } + + public function update() + { + $params = $this->request->post(); + if (empty($params['userId'])) { + $this->error('参数错误'); + } + $params = convertKeysCamelToSnakeRecursive($params); + if (isset($params['password']) && $params['password'] == '') { + unset($params['password']); + } else if (!empty($params['password'])) { + $params['password'] = shiro_simple_hash_hex_salt('sha256', $params['password'], $params['salt']); + } + $this->updateRoleInfo($params); + unset($params['role_id_list']); + + DatabaseRoute::getDb('sys_user', $params['user_id'], true, true)->where([ + 'user_id' => $params['user_id'] + ])->update($params); + + $this->success(); + } + + public function save() + { + $params = $this->request->post(); + + $params = convertKeysCamelToSnakeRecursive($params); + $params['create_time'] = getNormalDate(); + $params['salt'] = Random::generateRandomPrefixedId(20); + $params['password'] = shiro_simple_hash_hex_salt('sha256', $params['password'], $params['salt']); + $params['user_id'] = Random::generateRandomPrefixedId(); + + $this->updateRoleInfo($params); + + unset($params['role_id_list']); + unset($params['money']); + DatabaseRoute::getDb('sys_user', $params['user_id'], true)->insert($params); + if (!empty($params['is_channel']) && $params['is_channel'] == 1 && empty($params['qd_code'])) { + $params['qd_code'] = InvitationCodeUtil::toRegisteredCode($params['user_id']); + DatabaseRoute::getDb('sys_user', $params['user_id'], true, true)->update($params); + } + + $this->success(); + } + + public function delete() + { + $params = $this->request->post(); + if (empty($params)) { + $this->error('参数有误'); + } + + foreach ($params as $id) { + DatabaseRoute::getDb('sys_user', $id, true, true)->delete(); + } + + $this->success(); + + } + + + public function selectInviteUserList() + { + $params = $this->request->get(); + $params = convertKeysCamelToSnakeRecursive($params); + + // 1. 分页查询被邀请人分组:按 inviter_code 聚合 + $inviteListPageInfo = DatabaseRoute::paginateAllDb('tb_user', function ($query) use ($params) { + if (!empty($params['user_name'])) { + $query->where('user_name', 'like', '%' . $params['user_name'] . '%'); + } + + if (!empty($params['phone'])) { + $query->where('phone', 'like', '%' . $params['phone'] . '%'); + } + + return $query->fieldRaw('ANY_VALUE(inviter_code) AS inviter_code, COUNT(*) AS counts') + ->group('inviter_code') + ->order('counts', 'desc'); + }, $params['page'], $params['limit'], 'counts', null, true); + + $records = $inviteListPageInfo['records']; + if (empty($records)) { + $this->successWithData($inviteListPageInfo); // 无数据 + } + + $inviteCodeList = array_column($records, 'inviter_code'); + $countMap = array_column($records, 'counts', 'inviter_code'); + + // 2. 查询邀请人信息(部分 code 可能查不到 => 被删) + $userInfoList = DatabaseRoute::getAllDbData('tb_user', function ($query) use ($inviteCodeList) { + return $query->whereIn('invitation_code', $inviteCodeList); + })->select()->toArray(); + + // 3. 查询金额信息(注意先判断 user_id 是否存在) + $userIdList = array_column($userInfoList, 'user_id'); + $userMoneyList = []; + if (!empty($userIdList)) { + $userMoneyList = DatabaseRoute::getAllDbData('user_money', function ($query) use ($userIdList) { + return $query->whereIn('user_id', $userIdList); + })->select()->toArray(); + } + + $userMoneyMap = []; + foreach ($userMoneyList as $money) { + $userMoneyMap[$money['user_id']] = $money; + } + + // 4. 构建 inviter_code => user 映射 + $inviterMap = []; + foreach ($userInfoList as $user) { + $code = $user['invitation_code']; + $uid = $user['user_id']; + + $user['money'] = $userMoneyMap[$uid]['invite_income_money'] ?? 0; + $user['counts'] = $countMap[$code] ?? 0; + + $inviterMap[$code] = $user; + } + + // 5. 最终组装记录:保留所有 inviter_code,即使用户不存在 + $finalRecords = []; + foreach ($inviteCodeList as $code) { + if (isset($inviterMap[$code])) { + $finalRecords[] = $inviterMap[$code]; + } else { + // 🛠️ 如果邀请人被删,构造一条匿名信息 + $finalRecords[] = [ + 'user_id' => null, + 'user_name' => '已删除', + 'phone' => '-', + 'money' => 0, + 'counts' => $countMap[$code], + 'invitation_code' => $code, + ]; + } + } + + $inviteListPageInfo['records'] = $finalRecords; + $this->successWithData($inviteListPageInfo); + } + + +} \ No newline at end of file diff --git a/app/czg/user/controller/GroupController.php b/app/czg/user/controller/GroupController.php new file mode 100644 index 0000000..62ddd56 --- /dev/null +++ b/app/czg/user/controller/GroupController.php @@ -0,0 +1,163 @@ +model = new UserGroup(); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('edit')->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + // 读取所有pid,全部从节点数组移除,父级选择状态由子级决定 + $pidArr = UserRule::field('pid') + ->distinct(true) + ->where('id', 'in', $row->rules) + ->select() + ->toArray(); + $rules = $row->rules ? explode(',', $row->rules) : []; + foreach ($pidArr as $item) { + $ruKey = array_search($item['pid'], $rules); + if ($ruKey !== false) { + unset($rules[$ruKey]); + } + } + $row->rules = array_values($rules); + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 权限规则入库前处理 + * @param array $data 接受到的数据 + * @return array + * @throws Throwable + */ + private function handleRules(array &$data): array + { + if (is_array($data['rules']) && $data['rules']) { + $rules = UserRule::select(); + $super = true; + foreach ($rules as $rule) { + if (!in_array($rule['id'], $data['rules'])) { + $super = false; + } + } + + if ($super) { + $data['rules'] = '*'; + } else { + $data['rules'] = implode(',', $data['rules']); + } + } else { + unset($data['rules']); + } + return $data; + } +} \ No newline at end of file diff --git a/app/czg/user/controller/MoneyLogController.php b/app/czg/user/controller/MoneyLogController.php new file mode 100644 index 0000000..acff628 --- /dev/null +++ b/app/czg/user/controller/MoneyLogController.php @@ -0,0 +1,50 @@ +model = new UserMoneyLog(); + } + + /** + * 添加 + * @param int $userId + * @throws Throwable + */ + public function add(int $userId = 0): void + { + if ($this->request->isPost()) { + parent::add(); + } + + $user = User::where('id', $userId)->find(); + if (!$user) { + $this->error(__("The user can't find it")); + } + $this->success('', [ + 'user' => $user + ]); + } +} \ No newline at end of file diff --git a/app/czg/user/controller/RuleController.php b/app/czg/user/controller/RuleController.php new file mode 100644 index 0000000..952eb5a --- /dev/null +++ b/app/czg/user/controller/RuleController.php @@ -0,0 +1,260 @@ + 'desc']; + + protected string|array $quickSearchField = 'title'; + + /** + * 远程select初始化传值 + * @var array + */ + protected array $initValue; + + /** + * 是否组装Tree + * @var bool + */ + protected bool $assembleTree; + + /** + * 搜索关键词 + * @var string + */ + protected string $keyword; + + public function initialize(): void + { +// parent::initialize(); + + // 防止 URL 中的特殊符号被默认的 filter 函数转义 + $this->request->filter('clean_xss'); + + $this->model = new UserRule(); + $this->tree = Tree::instance(); + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get("initValue/a", []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request('quickSearch', ''); + $this->assembleTree = $isTree && !$this->initValue; // 有初始化值时不组装树状(初始化出来的值更好看) + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getRules(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + + if (!empty($data['pid'])) { + $groups = UserGroup::where('rules', '<>', '*')->select(); + foreach ($groups as $group) { + $rules = explode(',', $group->rules); + if (in_array($data['pid'], $rules) && !in_array($this->model->id, $rules)) { + $rules[] = $this->model->id; + $group->rules = implode(',', $rules); + $group->save(); + } + } + } + + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $id = $this->request->param($this->model->getPk()); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + if (isset($data['pid']) && $data['pid'] > 0) { + // 满足意图并消除副作用 + $parent = $this->model->where('id', $data['pid'])->find(); + if ($parent['pid'] == $row['id']) { + $parent->pid = 0; + $parent->save(); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + + // 子级元素检查 + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + parent::del(); + } + + /** + * 远程下拉 + * @throws Throwable + */ + public function select(): void + { + $data = $this->getRules([['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title')); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 获取菜单规则 + * @throws Throwable + */ + private function getRules(array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + $data = $this->model + ->where($where) + ->order($this->queryOrderBuilder()) + ->select() + ->toArray(); + + return $this->assembleTree ? $this->tree->assembleChild($data) : $data; + } + +} \ No newline at end of file diff --git a/app/czg/user/controller/ScoreLogController.php b/app/czg/user/controller/ScoreLogController.php new file mode 100644 index 0000000..023260f --- /dev/null +++ b/app/czg/user/controller/ScoreLogController.php @@ -0,0 +1,50 @@ +model = new UserScoreLog(); + } + + /** + * 添加 + * @param int $userId + * @throws Throwable + */ + public function add(int $userId = 0): void + { + if ($this->request->isPost()) { + parent::add(); + } + + $user = User::where('id', $userId)->find(); + if (!$user) { + $this->error(__("The user can't find it")); + } + $this->success('', [ + 'user' => $user + ]); + } +} \ No newline at end of file diff --git a/app/czg/user/controller/UserController.php b/app/czg/user/controller/UserController.php new file mode 100644 index 0000000..05a74be --- /dev/null +++ b/app/czg/user/controller/UserController.php @@ -0,0 +1,541 @@ +model = new UserModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $result = false; + $passwd = $data['password']; // 密码将被排除不直接入库 + $data = $this->excludeFields($data); + + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + + if (!empty($passwd)) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $password = $this->request->post('password', ''); + if ($password) { + $this->model->resetPassword($id, $password); + } + parent::edit(); + } + + unset($row->salt); + $row->password = ''; + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 重写select + * @throws Throwable + */ + public function select(): void + { + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res as $re) { + $re->nickname_text = $re->username . '(ID:' . $re->id . ')'; + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + // 短剧分析 + public function courseMessage() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + $pageUtils = \app\admin\model\User::queryCourseOrder($get['page'], $get['limit'], $get['type'], completeStartTime($get['date']), $admin['user_id']); + $this->n_success(['data' => $pageUtils]); + } + + // 用户分析 + public function userMessage() + { + $get = $this->request->get(); + $admin = $this->auth->getAdmin(); + // 补全开始时间(调用之前实现的函数) + $date = completeStartTime($get['date']); // 假设已实现该函数 + $qdCode = $admin['qd_code']; + $sumUserCount = \app\admin\model\User::queryUserCount($get['type'], $date, null, $qdCode); + $h5Count = \app\admin\model\User::queryUserCount($get['type'], $date, "h5", $qdCode); + $appCount = \app\admin\model\User::queryUserCount($get['type'], $date, "app", $qdCode); + $wxCount = \app\admin\model\User::queryUserCount($get['type'], $date, "小程序", $qdCode); + $dyCount = \app\admin\model\User::queryUserCount($get['type'], $date, "抖音", $qdCode); + $giveMemberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, 1); + $moneyMemberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, 2); + $memberCount = \app\admin\model\User::userMessage($date, $get['type'], $qdCode, null); + $userCount = $sumUserCount - $memberCount; + $this->n_success(['data' => [ + 'sumUserCount' => $sumUserCount, + 'h5Count' => $h5Count, + 'appCount' => $appCount, + 'wxCount' => $wxCount, + 'dyCount' => $dyCount, + 'memberCount' => $memberCount, + 'giveMemberCount' => $giveMemberCount, + 'moneyMemberCount' => $moneyMemberCount, + 'userCount' => $userCount, + ]]); + } + + // 当前在线人数统计 + public function selectUserOnLineCount() + { + $admin = $this->auth->getAdmin(); + $qdCode = $admin['qd_code']; + $selectUserOnLineCount = DatabaseRoute::getAllDbData('tb_user', function($query)use($qdCode) { + if($query) { + $query->where(['qd_code' => $qdCode]); + } + return $query->where('on_line_time', '>=', Db::raw('DATE_SUB(NOW(), INTERVAL 10 MINUTE)')); + })->count(); + $this->n_success(['data' => $selectUserOnLineCount]); + } + + // 用户统计 + public function homeMessage() + { + $admin = $this->auth->getAdmin(); + $qdCode = $admin['qd_code']; + $data = []; + $data['totalUsers'] = \app\admin\model\User::queryUserCount(0, null, null, $qdCode); + $data['newToday'] = \app\admin\model\User::queryUserCount(1, null, null, $qdCode); + $data['newMonth'] = \app\admin\model\User::queryUserCount(2, null, null, $qdCode); + $data['newYear'] = \app\admin\model\User::queryUserCount(3, null, null, $qdCode); + $data['totalRevenue'] = \app\admin\model\User::queryPayMoney(0, $qdCode); + $data['todayRevenue'] = \app\admin\model\User::queryPayMoney(1, $qdCode); + $data['monthRevenue'] = \app\admin\model\User::queryPayMoney(2, $qdCode); + $data['yearRevenue'] = \app\admin\model\User::queryPayMoney(3, $qdCode); + $map = \app\admin\model\User::queryPayAndExtractInfo(); + $data['todayPayAmount'] = isset($map['payAmount']) + ? round((float)$map['payAmount'], 2, PHP_ROUND_HALF_UP) + : 0.00; + $data['todayPayCount'] = isset($map['payCount']) + ? (int)$map['payCount'] + : 0; + $data['todayExtractAmount'] = isset($map['extractAmount']) + ? round((float)$map['extractAmount'], 2, PHP_ROUND_HALF_UP) + : 0.00; + + $data['todayExtractCount'] = isset($map['extractCount']) + ? (int)$map['extractCount'] + : 0; + $this->n_success(['data' => $data]); + } + + // 用户增长折线图 + public function selectUserCountStatisticsByTime() + { + $get = $this->request->get(); + $startTime = $get['startTime']; + $endTime = $get['endTime']; + + // 初始化结果数组 + $userCountList = []; + $dateList = []; + + // 日期处理 + $currentDate = strtotime($startTime); + $endDate = strtotime($endTime); + + // 循环遍历日期范围 + while ($currentDate <= $endDate) { + $date = date('Y-m-d', $currentDate); + + // 查询当日用户注册数量 + $userCount = \app\admin\model\User::queryUserCount(1, $date, null, null); + + // 记录数据 + $userCountList[] = $userCount; + $dateList[] = $date; + + // 日期加1天 + $currentDate = strtotime('+1 day', $currentDate); + } + + // 构建结果数据 + $result = [ + 'userCountList' => $userCountList, + 'year' => $dateList // 注:原Java代码中使用year变量,但实际存储的是日期列表 + ]; + + $this->n_success(['data' => $result]); + + } + + + + // 查询所有用户列表 + public function selectUserList() + { + $params = $this->request->get(); + $vipType = $params['vipType'] ?? null; + $member = $params['member'] ?? null; + $status = $params['status'] ?? null; + $page = $params['page'] ?? null; + $limit = $params['limit'] ?? null; + $phone = $params['phone'] ?? null; + $sysUserName = $params['sysUserName'] ?? null; + $userName = $params['userName'] ?? null; + $sex = $params['sex'] ?? null; + $platform = $params['platform'] ?? null; + $sysPhone = $params['sysPhone'] ?? null; + $inviterCode = $params['inviterCode'] ?? null; + $invitationCode = $params['invitationCode'] ?? null; + $qdCode = $params['qdCode'] ?? null; + $startTime = $params['startTime'] ?? null; + $endTime = $params['endTime'] ?? null; + $delegate = $params['delegate'] ?? null; + $this->n_success(['data' => \app\admin\model\User::selectUserPage( + $page, $limit, $phone, $sex, $platform, $sysPhone, $status, $member, + $inviterCode, $userName, $invitationCode, $startTime, $endTime, $qdCode, $sysUserName, $vipType, $delegate + )]); + } + + // 修改用户状态 + public function updateUserStatusByUserId() + { + $get = $this->request->get(); + if(empty($get['userId'])) { + $this->error('userId 不能为空'); + } + if(empty($get['status']) && $get['status'] == null) { + $this->error('status 不能为空'); + } + $status = $get['status']; + $userId = $get['userId']; + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId], true)); + // 查询用户是否存在 + $user = $db->name('tb_user')->where(['user_id' => $userId])->find(); + if (is_null($user)) { + $this->error('用户不存在'); + } + + // 根据状态执行不同操作 + switch ($status) { + case 1: + // 状态1:设置状态为1,并调用upUserBlack方法(拉黑) + \app\admin\model\User::upUserBlack($user, 1, $db); + break; + case 2: + // 状态2:直接更新状态为2 + $db->name('tb_user')->where('user_id', $userId) + ->update(['status' => 2]); + break; + case 0: + // 状态0:调用upUserBlack方法(解封) + \app\admin\model\User::upUserBlack($user, 0, $db); + break; + default: + // 无效状态 + $this->error('状态不正确'); + } + $this->success(); + } + + + // 更新用户邀请奖励金额 + public function inviteAmount() + { + $userInviteDTO = $this->request->post(); + // 验证用户ID不能为空 + if (empty($userInviteDTO['userId'])) { + $this->error('用户id不能为空'); + } + + // 验证邀请奖励金额必须大于0 + $inviteAmount = $userInviteDTO['inviteAmount'] ?? null; + if (is_null($inviteAmount) || bccomp($inviteAmount, 0) <= 0) { + $this->error('邀请奖励金额必须大于0'); + } + + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userInviteDTO['userId']], true))->name('tb_user'); + // 查询用户是否存在 + $userEntity = $db->where(['user_id' => $userInviteDTO['userId']])->find($userInviteDTO['userId']); + if (is_null($userEntity)) { + $this->error('用户不存在'); + } + // 更新用户邀请奖励金额 + $db->where(['user_id' => $userInviteDTO['userId']])->update(['invite_amount' => $inviteAmount]); + $this->success(); + } + + + public function updatePwd() + { + $get = $this->request->get(); + if(empty($get['userId']) || empty($get['pwd'])) { + $this->error('参数不完整'); + } + $userId = $get['userId']; + $pwd = $get['pwd']; + $db = Db::connect(DatabaseRoute::getConnection('sys_user', ['user_id' => $userId])); + $user = $db->name('sys_user')->where(['user_id' => $userId])->find(); + if(!$user) { + $this->error('用户不存在'); + } + $db = Db::connect(DatabaseRoute::getConnection('sys_user', ['user_id' => $userId], true)); + $user = $db->name('sys_user')->where(['user_id' => $userId])->update(['password' => shiro_simple_hash_hex_salt('sha256', $pwd, $user['salt'])]); + if($user) { + $this->success(); + } + $this->error(); + } + + public function deleteUserByUserId() + { + $post = $this->request->post(); + if(empty($post['userId'])) { + $this->error('userId 不能为空'); + } + $userId = $post['userId']; + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId], true)); + $user = $db->name('tb_user')->where(['user_id' => $userId])->delete(); + if($user) { + $this->success(); + } + $this->error('操作失败'); + } + + + public function getuserinfo() + { + $userId = $this->request->get('userId'); + if(empty($userId)) { + $this->error('userId 不能为空'); + } + + $db = Db::connect(DatabaseRoute::getConnection('tb_user', ['user_id' => $userId])); + $user = $db->name('tb_user')->where(['user_id' => $userId])->find(); + if(!$user) { + $this->error('用户不存在'); + } + + $inviteMoney = \app\admin\model\User::selectInviteMoneyByUserId($userId, $db); + if(empty($inviteMoney)) { + $inviteMoney = [ + 'user_id' => $userId, + 'money_sum' => 0.00, + 'money' => 0.00, + 'cash_out' => 0.00, + ]; + Db::connect(DatabaseRoute::getConnection('invite_money', ['user_id' => $userId], true), true)->name('invite_money')->insert($inviteMoney); + } + $money = $inviteMoney['money']; + + // 获取当前日期(格式:YYYY-MM-DD HH:mm:ss) + $date = date('Y-m-d H:i:s'); + + // 查询本月充值(复用之前的instantselectSumPay方法) + $consume = \app\admin\model\User::instantselectSumPay(date('Y-m'), $userId, $db); + + // 查询本月提现(假设monthIncome方法已实现) + $income = \app\admin\model\User::monthIncome(date('Y-m'), $userId, $db); + + // 查询邀请人数(复用之前的countUsersByInviterCode方法) + $count = \app\admin\model\User::queryInviterCount($user['invitation_code']); + + // 查询VIP信息 + $userVip = \app\admin\model\User::selectUserVipByUserId($userId); + if ($userVip) { + $user['member'] = $userVip['is_vip']; + $user['end_time'] = $userVip['end_time']; + $user['vip_type'] = $userVip['vip_type']; + } + + // 组装结果数据 + $resultData = [ + 'userEntity' => $user, + 'money' => $money, + 'consume' => $consume, + 'income' => $income, + 'count' => $count + ]; + $this->n_success(['data' => $resultData]); + + } + + public function userListExcel() + { + $get = $this->request->get(); + $startTime = $get['startTime'] ?? null; + $endTime = $get['endTime'] ?? null; + $this->n_success(\app\admin\model\User::userListExcel($startTime, $endTime)); + } + + + + // 获取用户详细信息 + public function selectUserByInvitationCode() + { + $get = $this->request->get(); + if(empty($get['invitationCode'])) { + $this->error('参数不完整'); + } + $invitationCode = $get['invitationCode']; + $userEntity = TbUser::GetByusername($invitationCode, 'invitation_code'); + if(empty($userEntity)) { + $this->error('用户信息不存在'); + } + $userId = $userEntity['user_id']; + + $db = Db::connect(DatabaseRoute::getConnection('invite_money', ['user_id' => $userId])); + // 查询用户钱包 + $inviteMoney = \app\admin\model\User::selectInviteMoneyByUserId($userId, $db); + $money = $inviteMoney['money']; + // 获取当前时间(格式:Y-m-d H:i:s) + $currentDate = date('Y-m-d H:i:s'); + // 查询本月充值总额 + $consume = \app\admin\model\User::instantselectSumPay($currentDate, $userId, $db); + $income = \app\admin\model\User::monthIncome($currentDate, $userId, $db); + //查询邀请人数 + $count = \app\admin\model\User::queryInviterCount($userEntity['invitation_code']); + $userVip = \app\admin\model\User::selectUserVipByUserId($userId); + if ($userVip) { + $userEntity['member'] = $userVip['is_vip']; + $userEntity['end_time'] = $userVip['end_time']; + $userEntity['vip_type'] = $userVip['vip_type']; + } + $data = [ + 'userEntity' => $userEntity, + 'money' => $money, + 'consume' => $consume, + 'income' => $income, + 'count' => $count + ]; + $this->n_success(['data' => $data]); + } + + +} \ No newline at end of file diff --git a/app/functions.php b/app/functions.php index 0fe9f53..74e7f24 100644 --- a/app/functions.php +++ b/app/functions.php @@ -1430,3 +1430,16 @@ function convertUserIdToString(array $data): array { return $result; } +function convertKeysCamelToSnakeRecursive(array $array): array +{ + $converted = []; + foreach ($array as $key => $value) { + $newKey = strtolower(preg_replace('/(?=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webman\\Captcha\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net" + }, + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jeremy Livingston", + "email": "jeremy.j.livingston@gmail.com" + } + ], + "description": "Captcha generator", + "keywords": [ + "bot", + "captcha", + "spam" + ], + "support": { + "source": "https://github.com/webman-php/captcha/tree/v1.0.4" + }, + "time": "2024-05-14T02:56:38+00:00" + }, { "name": "webman/console", "version": "v2.1.3", diff --git a/config/route.php b/config/route.php index 98f3673..9e372d9 100644 --- a/config/route.php +++ b/config/route.php @@ -21,4 +21,42 @@ Route::any('/czg/app/common/type/{num}', [app\czg\app\controller\CommonControlle Route::any('/czg/app/user/realNameAuth/v2', [app\czg\app\controller\UserController::class, 'realNameAuth']); +// 后台 +Route::any('/czg/ext/sys/invite/friend/award/page', [\app\czg\controller\SysController::class, 'invitefriendaward']); +Route::any('/czg/sys/role/select', [\app\czg\sys\controller\RoleController::class, 'selects']); +Route::any('/czg/sys/menu/select', [\app\czg\sys\controller\MenuController::class, 'selectInfo']); +Route::any('/czg/cashOutAudit/alipay/transfer/summary/query', [\app\czg\controller\CashOutAuditController::class, 'alipaytransfersummaryquery']); +Route::any('/czg/sys/user/info/{id}', [\app\czg\sys\controller\UserController::class, 'detail']); +Route::any('/czg/Login/sendMsg/{phone}/{event}', [\app\czg\controller\LoginController::class, 'sendMsg']); +Route::any('/czg/sys/menu/info/{id}', [\app\czg\sys\controller\MenuController::class, 'info']); +Route::any('/czg/sys/menu/delete/{id}', [\app\czg\sys\controller\MenuController::class, 'delete']); + +Route::put('/czg/userInfo', [\app\czg\controller\UserInfoController::class, 'update']); +Route::delete('/czg/userInfo', [\app\czg\controller\UserInfoController::class, 'delete']); + + +Route::any('/czg/user/selectInviteUserList', [\app\czg\sys\controller\UserController::class, 'selectInviteUserList']); +Route::any('/czg/user/courseMessage', [\app\czg\user\controller\UserController::class, 'courseMessage']); +Route::any('/czg/user/userMessage', [\app\czg\user\controller\UserController::class, 'userMessage']); +Route::any('/czg/user/selectUserOnLineCount', [\app\czg\user\controller\UserController::class, 'selectUserOnLineCount']); +Route::any('/czg/user/selectUserByInvitationCode', [\app\czg\user\controller\UserController::class, 'selectUserByInvitationCode']); +Route::any('/czg/user/homeMessage', [\app\czg\user\controller\UserController::class, 'homeMessage']); +Route::any('/czg/user/selectUserCountStatisticsByTime', [\app\czg\user\controller\UserController::class, 'selectUserCountStatisticsByTime']); +Route::any('/czg/user/selectUserList', [\app\czg\user\controller\UserController::class, 'selectUserList']); + + + +Route::any('/czg/user/inviteAmount', [\app\czg\user\controller\UserController::class, 'inviteAmount']); +Route::any('/czg/user/deleteUserByUserId', [\app\czg\user\controller\UserController::class, 'deleteUserByUserId']); +Route::any('/czg/user/userListExcel', [\app\czg\user\controller\UserController::class, 'userListExcel']); +Route::any('/czg/user/updatePwd', [\app\czg\user\controller\UserController::class, 'updatePwd']); +Route::any('/czg/user/selectNewApp', [\app\czg\app\controller\UserController::class, 'selectNewApp']); +Route::any('/czg/user/selectUserById', [\app\czg\app\controller\UserController::class, 'selectUserById']); + +Route::post('/czg/sys/user/delete', [\app\czg\sys\controller\UserController::class, 'delete']); + + + + +Route::any('/czg/user/{id}', [\app\czg\user\controller\UserController::class, 'getuserinfo']); diff --git a/extend/ba/Auth.php b/extend/ba/Auth.php index d88e610..f7de63b 100644 --- a/extend/ba/Auth.php +++ b/extend/ba/Auth.php @@ -1,6 +1,6 @@ getUserMenus($uid); - $file = root_path() . '/jsondata/peion.json'; + $file = BASE_PATH . DIRECTORY_SEPARATOR . '/jsondata/peion.json'; // 检查数组 $par_info = get_file_info($file); $par_info = json_decode($par_info, true); @@ -297,7 +297,7 @@ class Auth return true; } foreach ($par_info as $k => $v) { - if(!empty($v['peion']) && strpos($url, $v['peion']) !== false) { + if(!empty($v['peion']) && strpos($v['peion'], $url) !== false) { if($v['url'] == '*') { return true; } diff --git a/jsondata/peion.json b/jsondata/peion.json new file mode 100644 index 0000000..c120620 --- /dev/null +++ b/jsondata/peion.json @@ -0,0 +1,702 @@ +[ + { + "url": "sys/user", + "name": "管理员列表", + "peion": "" + }, + { + "url": "sys/role", + "name": "角色管理", + "peion": "" + }, + { + "url": "sys/menu", + "name": "菜单管理", + "peion": "" + }, + { + "url": "sys:user:list,sys:user:info", + "name": "查看", + "peion": "" + }, + { + "url": "sys:user:save,sys:role:select", + "name": "新增", + "peion": "sys/role/select" + }, + { + "url": "*", + "name": "用户信息", + "peion": "/sys/user/info" + }, + { + "url": "sys:user:update,sys:role:select", + "name": "修改", + "peion": "sys/role/select" + }, + { + "url": "sys:user:delete", + "name": "删除", + "peion": "" + }, + { + "url": "sys:role:list,sys:role:info", + "name": "查看", + "peion": "sys/role/list|sys/role/info" + }, + { + "url": "sys:role:save,sys:menu:list", + "name": "新增", + "peion": "sys/role/save" + }, + { + "url": "sys:role:update,sys:menu:list", + "name": "修改", + "peion": "" + }, + { + "url": "sys:role:delete", + "name": "删除", + "peion": "" + }, + { + "url": "sys:menu:list,sys:menu:info", + "name": "查看", + "peion": "/sys/menu/nav" + }, + { + "url": "sys:menu:save,sys:menu:select", + "name": "新增", + "peion": "sys/menu/save" + }, + { + "url": "sys:menu:update,sys:menu:select", + "name": "修改", + "peion": "" + }, + { + "url": "sys:menu:delete", + "name": "删除", + "peion": "" + }, + { + "url": "userList", + "name": "用户中心", + "peion": "" + }, + { + "url": "home", + "name": "数据中心", + "peion": "" + }, + { + "url": "financeList", + "name": "财务中心", + "peion": "" + }, + { + "url": "financeList:list", + "name": "查看", + "peion": "" + }, + { + "url": "financeList:transfer", + "name": "转账", + "peion": "" + }, + { + "url": "financeList:refund", + "name": "退款", + "peion": "" + }, + { + "url": "financeList:add", + "name": "退款", + "peion": "" + }, + { + "url": "financeList:update", + "name": "修改", + "peion": "" + }, + { + "url": "financeList:delete", + "name": "删除", + "peion": "" + }, + { + "url": "message", + "name": "消息中心", + "peion": "" + }, + { + "url": "message:list", + "name": "查看", + "peion": "" + }, + { + "url": "message:push", + "name": "消息推送", + "peion": "" + }, + { + "url": "mission", + "name": "资源中心", + "peion": "" + }, + { + "url": "mission:list", + "name": "查看", + "peion": "" + }, + { + "url": "mission:add", + "name": "添加", + "peion": "" + }, + { + "url": "mission:update", + "name": "修改", + "peion": "" + }, + { + "url": "mission:delete", + "name": "删除", + "peion": "" + }, + { + "url": "mission:sold", + "name": "下架", + "peion": "" + }, + { + "url": "bannerList", + "name": "首页装修", + "peion": "" + }, + { + "url": "bannerList:list", + "name": "查看", + "peion": "" + }, + { + "url": "bannerList:add", + "name": "添加", + "peion": "" + }, + { + "url": "bannerList:update", + "name": "修改", + "peion": "" + }, + { + "url": "bannerList:delete", + "name": "删除", + "peion": "" + }, + { + "url": "allocationList", + "name": "系统配置", + "peion": "" + }, + { + "url": "allocationList:list", + "name": "查看", + "peion": "" + }, + { + "url": "allocationList:update", + "name": "修改", + "peion": "" + }, + { + "url": "userList:list", + "name": "查看", + "peion": "" + }, + { + "url": "userList:delete", + "name": "删除", + "peion": "" + }, + { + "url": "orderCenter", + "name": "订单中心", + "peion": "" + }, + { + "url": "orderCenter:list", + "name": "查看", + "peion": "" + }, + { + "url": "orderCenter:delete", + "name": "删除", + "peion": "" + }, + { + "url": "viplist", + "name": "会员列表", + "peion": "" + }, + { + "url": "viplist:list", + "name": "查看", + "peion": "" + }, + { + "url": "message:add", + "name": "添加", + "peion": "" + }, + { + "url": "message:update", + "name": "修改", + "peion": "" + }, + { + "url": "message:delete", + "name": "删除", + "peion": "" + }, + { + "url": "viplist:add", + "name": "添加", + "peion": "" + }, + { + "url": "viplist:update", + "name": "修改", + "peion": "" + }, + { + "url": "viplist:delete", + "name": "删除", + "peion": "" + }, + { + "url": "userList:updatebl", + "name": "修改比例", + "peion": "" + }, + { + "url": "userList:updateVip", + "name": "修改会员", + "peion": "vipDetails/sendVip" + }, + { + "url": "riderTop", + "name": "邀请排行榜", + "peion": "" + }, + { + "url": "riderTop:list", + "name": "查看", + "peion": "" + }, + { + "url": "orderCenter:tuikuan", + "name": "退款", + "peion": "" + }, + { + "url": "userList:update", + "name": "修改信息", + "peion": "" + }, + { + "url": "messageZx", + "name": "注销信息", + "peion": "" + }, + { + "url": "messageZx:list", + "name": "查看", + "peion": "" + }, + { + "url": "messageZx:shenhe", + "name": "注销", + "peion": "" + }, + { + "url": "userList:updateJf", + "name": "修改积分", + "peion": "integral/updateUserIntegral" + }, + { + "url": "userList:updateQb", + "name": "修改钱包", + "peion": "" + }, + { + "url": "app", + "name": "升级配置", + "peion": "" + }, + { + "url": "app:list", + "name": "查看", + "peion": "" + }, + { + "url": "app:add", + "name": "添加", + "peion": "" + }, + { + "url": "app:update", + "name": "修改", + "peion": "" + }, + { + "url": "app:delete", + "name": "删除", + "peion": "" + }, + { + "url": "materialsList", + "name": "帮助中心", + "peion": "" + }, + { + "url": "materialsList:list", + "name": "查看", + "peion": "" + }, + { + "url": "materialsList:add", + "name": "添加", + "peion": "" + }, + { + "url": "materialsList:update", + "name": "修改", + "peion": "" + }, + { + "url": "materialsList:delete", + "name": "删除", + "peion": "" + }, + { + "url": "invite", + "name": "邀请奖励", + "peion": "" + }, + { + "url": "invite:list", + "name": "添加", + "peion": "" + }, + { + "url": "invite:add", + "name": "添加", + "peion": "" + }, + { + "url": "invite:update", + "name": "修改", + "peion": "" + }, + { + "url": "invite:delete", + "name": "删除", + "peion": "" + }, + { + "url": "coupon", + "name": "发卡管理", + "peion": "" + }, + { + "url": "coupon:list", + "name": "查看", + "peion": "" + }, + { + "url": "coupon:add", + "name": "添加", + "peion": "" + }, + { + "url": "coupon:update", + "name": "修改", + "peion": "" + }, + { + "url": "coupon:delete", + "name": "删除", + "peion": "" + }, + { + "url": "missionDy", + "name": "抖音小程序提审", + "peion": "" + }, + { + "url": "missionDy:list", + "name": "查看", + "peion": "" + }, + { + "url": "missionWx", + "name": "微信小程序提审", + "peion": "" + }, + { + "url": "missionWx:list", + "name": "查看", + "peion": "" + }, + { + "url": "missionWx:update", + "name": "设置备案号", + "peion": "" + }, + { + "url": "missionWx:shangchuan", + "name": "上传", + "peion": "" + }, + { + "url": "missionWx:songshen", + "name": "送审", + "peion": "" + }, + { + "url": "missionWx:shangxian", + "name": "上线", + "peion": "" + }, + { + "url": "missionDy:update", + "name": "设置备案号", + "peion": "" + }, + { + "url": "missionDy:shangchuan", + "name": "上传", + "peion": "" + }, + { + "url": "missionDy:songshen", + "name": "送审", + "peion": "" + }, + { + "url": "missionDy:shangxian", + "name": "上线", + "peion": "" + }, + { + "url": "community", + "name": "分销代理管理员", + "peion": "" + }, + { + "url": "community:list", + "name": "查看", + "peion": "" + }, + { + "url": "sys:user:save", + "name": "添加", + "peion": "" + }, + { + "url": "sys:user:update", + "name": "修改", + "peion": "" + }, + { + "url": "sys:user:delete", + "name": "删除", + "peion": "" + }, + { + "url": "managementStoreincome:draw", + "name": "发起提现", + "peion": "" + }, + { + "url": "managementStoreincome:update", + "name": "修改信息", + "peion": "" + }, + { + "url": "domainName", + "name": "分享域名管理", + "peion": "" + }, + { + "url": "domainName:list", + "name": "查看", + "peion": "" + }, + { + "url": "domainName:add", + "name": "添加", + "peion": "" + }, + { + "url": "domainName:update", + "name": "修改", + "peion": "" + }, + { + "url": "domainName:delete", + "name": "删除", + "peion": "" + }, + { + "url": "storeincome", + "name": "代理详情", + "peion": "" + }, + { + "url": "storeincome:list", + "name": "查看", + "peion": "" + }, + { + "url": "communityY", + "name": "员工列表", + "peion": "" + }, + { + "url": "community:list", + "name": "查看", + "peion": "" + }, + { + "url": "sys:user:save", + "name": "添加", + "peion": "" + }, + { + "url": "sys:user:update", + "name": "修改", + "peion": "" + }, + { + "url": "sys:user:delete", + "name": "删除", + "peion": "" + }, + { + "url": "managementStoreincome:draw", + "name": "发起提现", + "peion": "" + }, + { + "url": "managementStoreincome:update", + "name": "修改信息", + "peion": "" + }, + { + "url": "couponQ", + "name": "发卡列表", + "peion": "" + }, + { + "url": "couponQ:list", + "name": "查看", + "peion": "" + }, + { + "url": "campus", + "name": "分享管理", + "peion": "" + }, + { + "url": "campus:list", + "name": "查看", + "peion": "" + }, + { + "url": "IntegralGoods", + "name": "充值配置", + "peion": "" + }, + { + "url": "IntegralGoods:list", + "name": "查看", + "peion": "" + }, + { + "url": "IntegralGoods:add", + "name": "添加", + "peion": "" + }, + { + "url": "IntegralGoods:update", + "name": "修改", + "peion": "" + }, + { + "url": "IntegralGoods:delete", + "name": "删除", + "peion": "" + }, + { + "url": "exchangeList", + "name": "充值记录", + "peion": "" + }, + { + "url": "exchangeList:list", + "name": "查看", + "peion": "" + }, + { + "url": "userList:password", + "name": "修改密码", + "peion": "" + }, + { + "url": "sys/config", + "name": "参数管理", + "peion": "sys/config" + }, + { + "url": "sys/dict", + "name": "字典管理", + "peion": "" + }, + { + "url": "sys/log", + "name": "系统日志", + "peion": "" + }, + { + "url": "oss/oss", + "name": "文件上传", + "peion": "" + }, + { + "url": "job/schedule", + "name": "定时任务", + "peion": "" + }, + { + "url": "renwu", + "name": "任务中心", + "peion": "" + }, + { + "url": "shareFriends", + "name": "邀请好友奖励", + "peion": "/ext/sys/invite/friend" + }, + { + "url": "financeList", + "name": "财务中心", + "peion": "" + }, + { + "url": "lotteryInquiry", + "name": "抽奖查询", + "peion": "lottery" + } +] \ No newline at end of file