zory 3 weeks ago
parent
commit
0845ee03b5

+ 11 - 1
README.md

@@ -1 +1,11 @@
-## 洗衣Saas系统API
+## 洗衣Saas系统API
+
+#### 验证码修改
+```
+
+\vendor\hzdad\codecheck\src\Codecheck.php
+
+namespace Hzdad\Codecheck;
+use support\think\Cache;
+
+```

+ 66 - 0
app/controller/admin/Config.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace app\controller\admin;
+
+use app\extra\basic\Base;
+use app\middleware\AuthMiddleware;
+use app\model\system\SystemConfig;
+use LinFly\Annotation\Route\Controller;
+use LinFly\Annotation\Route\Route;
+use support\Request;
+use support\Response;
+use Webman\Annotation\Middleware;
+
+
+#[Controller(prefix: "/api/config"),Middleware(AuthMiddleware::class)]
+class Config extends Base
+{
+
+
+    /**
+     * 获取配置信息
+     */
+    #[Route(path: "list",methods: "get")]
+    public function getConfigList(Request $request): Response
+    {
+        try {
+            $type = $request->get("type","service");
+            $data = (new SystemConfig)->where("type",$type)->where("status",1)->field("name,value")->select()->toArray();
+            $result = [];
+            foreach ($data as $item) {
+                $result[$item['name']] = $item['value'];
+            }
+            if ($type == "sms") {
+                $result['channel'] = $this->getSmsChannel();
+                $result['login_sms'] = '您的验证码为:${code},请勿泄露于他人!';
+            }
+            return successTrans("success.data",$result);
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+
+    /**
+     * 保存通用配置
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "save",methods: "post")]
+    public function setConfigData(Request $request): Response
+    {
+        try {
+            $param = $request->post();
+            if (isset($param['data']['channel'])) unset($param['data']['channel']);
+            foreach ($param['data'] as $k => $v){
+                if(is_array($v)) $v = implode(",",$v);
+                sConf($param['type'].'.'.$k, $v);
+            }
+            return successTrans("success.data",[]);
+        } catch (\Throwable $exception){
+            return error($exception->getMessage());
+        }
+
+    }
+
+}

+ 96 - 1
app/controller/common/Login.php

@@ -3,11 +3,18 @@
 namespace app\controller\common;
 
 use app\extra\basic\Base;
+use app\extra\service\basic\SmsService;
+use app\middleware\AuthMiddleware;
+use app\model\system\SystemUser;
+use Hzdad\Codecheck\Codecheck;
 use LinFly\Annotation\Route\Controller;
 use LinFly\Annotation\Route\Route;
+use Shopwwi\WebmanAuth\Auth;
 use support\Request;
 use support\Response;
+use think\facade\Db;
 use Tinywan\Captcha\Captcha;
+use Webman\Annotation\Middleware;
 
 
 #[Controller(prefix: "/api/login")]
@@ -31,7 +38,10 @@ class Login extends Base
             ],"post");
             if (!is_array($param)) return error($param);
             if (Captcha::check($param['code'],$param['key']) === false) return errorTrans("error.captcha");
-
+            $map = ["is_deleted" => 0,"username" => $param['username']];
+            [$state,$msg,$user] = $this->checkLogin($map,2,$param);
+            if (!$state) return error($msg);
+            return successTrans("success.login",get_object_vars((new Auth)->guard("admin")->login($user)));
         } catch (\Throwable $throwable) {
             return error($throwable->getMessage());
         }
@@ -49,9 +59,94 @@ class Login extends Base
             $param = $this->_valid([
                 "mobile.require"    => trans("empty.mobile"),
                 "code.require"      => trans("empty.code"),
+                "scene.require"     => trans("empty.data"),
             ],"post");
             if (!is_array($param)) return error($param);
+            $code = (new Codecheck)->mobile($param['mobile'])->scene($param['scene'])->code($param['code'])->delafterok(true)->check();
+            print_r((new Codecheck)->getErrorMsg());
+            if (!$code) return errorTrans("error.captcha");
+            $map = ["is_deleted" => 0,"mobile" => $param['mobile']];
+            [$state,$msg,$user] = $this->checkLogin($map);
+            if (!$state) return error($msg);
+            return successTrans("success.login",get_object_vars((new Auth)->guard("admin")->login($user)));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+
+    /**
+     * 登录验证处理
+     * @param array $map
+     * @param int $type
+     * @param array $param
+     * @return array
+     */
+    protected function checkLogin(array $map = [],int $type = 1,array $param = []): array
+    {
+        $user = (new SystemUser)->where($map)->findOrEmpty();
+        if ($user->isEmpty()) return [0,trans("error.user-empty"),[]];
+        if ($user['status'] <> 1) return [0,trans("error.user-status"),[]];
+        if ($type == 2) {
+            if (md5($param['password'].$user['salt']) <> $user['password']) return [0,trans("error.passwd"),[]];
+        }
+        $user->login_at = getDateFull();
+        $user->login_ip = request()->getRealIp();
+        $user->login_num = Db::raw("login_num+1");
+        $user->save();
+        return [1,'success',$user->toArray()];
+    }
 
+
+    /**
+     * @return Response
+     */
+    #[Route(path: "profile",methods: "get"),Middleware(AuthMiddleware::class)]
+    public function getLoginUser(): Response
+    {
+        try {
+            $userData = (new Auth)->guard("admin")->user()->toArray();
+            if (isset($userData['password'])) unset($userData['password']);
+            if (empty($userData['vip_at']))
+            {
+                $userData['vip_at'] = 0;
+            } else {
+                $userData['vip_at'] = strtotime($userData['vip_at']);
+            }
+            return successTrans("success.data",[
+                "username"  => $userData['username'],
+                "truename"  => $userData['truename'],
+                "vip_at"    => $userData['vip_at'],
+                "super"     => $userData['is_super'],
+                "type"      => $userData['type']
+            ]);
+        } catch (\Throwable $exception){
+            return error($exception->getMessage());
+        }
+    }
+
+
+    /**
+     * 发送登录/注册验证码
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "sms",methods: "post")]
+    public function getLoginSms(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "mobile.require"    => trans("empty.mobile"),
+                "mobile.mobile"     => trans("error.mobile"),
+                "code.require"      => trans("empty.code"),
+                "key.require"       => trans("empty.data"),
+                "scene.require"     => trans("empty.data"),
+            ],"post");
+            if (!is_array($param)) return error($param);
+            if (Captcha::check($param['code'],$param['key']) === false) return errorTrans("error.captcha");
+            [$state,$msg] = (new SmsService)->sendSceneSms($param['mobile'],$param['scene']);
+            if (!$state) return error($msg);
+            return success($msg);
         } catch (\Throwable $throwable) {
             return error($throwable->getMessage());
         }

+ 74 - 0
app/controller/common/Menu.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace app\controller\common;
+
+use app\extra\basic\Base;
+use app\extra\service\system\MenuService;
+use app\extra\tools\DataExtend;
+use app\middleware\AuthMiddleware;
+use app\model\system\SystemMenu;
+use DI\Attribute\Inject;
+use LinFly\Annotation\Route\Controller;
+use LinFly\Annotation\Route\Route;
+use support\Request;
+use support\Response;
+use Webman\Annotation\Middleware;
+
+
+#[Controller(prefix: "/api/menu"),Middleware(AuthMiddleware::class)]
+class Menu extends Base
+{
+
+    #[Inject]
+    protected MenuService $service;
+
+    /**
+     * 获取菜单
+     */
+    #[Route(path: "list",methods: "get")]
+    public function getMenuList(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "form.default"  => $request->user['type'],
+                "type.default"  => 1
+            ]);
+            $menu = $this->service->getMenuList($request->user['is_super'],$param['form']);
+            $permissionsData = [];
+            foreach ($menu as $val) {
+                if ($val['type'] == 'button') {
+                    $permissionsData[] = $val['name'];
+                }
+            }
+            $menu = $this->filterMenu(DataExtend::arr2tree($menu),$param['type']);
+            if($param['type'] == 1) {
+                $permissions = $permissionsData;
+                $dashboardGrid = [];
+                return successTrans("success.data",compact('menu','permissions','dashboardGrid'));
+            }
+            return successTrans("success.data",$menu);
+        } catch (\Throwable $throwable) {
+            echo $throwable->getFile()."\n";
+            echo $throwable->getLine()."\n";
+            return error($throwable->getMessage());
+        }
+    }
+
+
+    /**
+     * 更新
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "save",methods: "post")]
+    public function saveMenuData(Request $request): Response
+    {
+        try {
+            $state = (new SystemMenu)->setAutoData($request->post());
+            if(!$state) return errorTrans("error.data");
+            return successTrans("success.data");
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+}

+ 28 - 0
app/controller/common/Test.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace app\controller\common;
+
+use app\extra\basic\Base;
+use app\extra\tools\CodeExtend;
+use LinFly\Annotation\Route\Controller;
+use LinFly\Annotation\Route\Route;
+
+
+#[Controller(prefix: "/test")]
+class Test extends Base
+{
+
+
+    #[Route(path: "index",methods: "get")]
+    public function test()
+    {
+        try {
+            $code = strtoupper(CodeExtend::random(12,3));
+            $passwd = md5(md5("111111").$code);
+            return success("ok",compact("code",'passwd'));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+}

+ 2 - 4
app/extra/basic/Base.php

@@ -8,8 +8,6 @@ use think\Validate;
 class Base
 {
 
-    protected array $mobileWhite = ["18665619195","18665619196","18665619198","18665619199"];
-
     protected function getParent(array $data)
     {
         if ($data['parent_id'] > 0) {
@@ -120,6 +118,7 @@ class Base
      * 菜单信息格式化
      * @param array $menus
      * @param int $type
+     * @param int $mch
      * @return array
      */
     protected function filterMenu(array $menus,int $type,int $mch = 0): array
@@ -128,8 +127,7 @@ class Base
             $menu['meta'] = [
                 "title"     => $menu['title'],
                 "icon"      => $menu['icon']??'',
-                "type"      => $menu['type'],
-                "desc"      => $menu['descs'],
+                "type"      => $menu['type']
             ];
             if (!empty($menu['children'])) {
                 $menu['children'] = $this->filterMenu($menu['children'],$type,$mch);

+ 40 - 0
app/extra/basic/Service.php

@@ -2,6 +2,9 @@
 
 namespace app\extra\basic;
 
+use app\model\system\SystemConfig;
+use Overtrue\EasySms\Strategies\OrderStrategy;
+
 class Service
 {
 
@@ -11,6 +14,43 @@ class Service
     protected $mode = null;
 
 
+    /**
+     * 白名单
+     * @var array|string[]
+     */
+    protected array $mobileWhite = ["18665619195","18665619196","18665619198","18665619199"];
+
+
+    /**
+     * 短信配置
+     * @param int $type 1 系统配置 2 代理配置
+     * @return array
+     */
+    protected function smsConfig(int $type = 1): array
+    {
+        $sms = (new SystemConfig)->where("type","sms")->column("value","name");
+        return [
+            "config" => [
+                'enable' => true,
+                'timeout' => 5.0,
+                "default"   => [
+                    "strategy"  => OrderStrategy::class,
+                    "gateways"  => [$sms['sms_type']]
+                ],
+                "gateways"  => [
+                    'errorlog' => [
+                        'file' => runtime_path().'/tmp/easy-sms.log',
+                    ],
+                    'aliyun' => [
+                        'access_key_id' => $sms['AccessKeyId'],
+                        'access_key_secret' => $sms['AccessKeySecret'],
+                        'sign_name' => trim($sms['sign']),
+                    ],
+                ]
+            ],
+            "template"  => $sms['login']
+        ];
+    }
     /**
      * 默认排序筛选
      * @param array $param

+ 13 - 0
app/extra/service/basic/KeyService.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace app\extra\service\basic;
+
+class KeyService
+{
+
+    public static function smsKey(int $mobile): string
+    {
+        return "sms_{$mobile}";
+    }
+
+}

+ 50 - 0
app/extra/service/basic/SmsService.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\extra\service\basic;
+
+use app\extra\basic\Service;
+use app\model\system\SystemUser;
+use Hzdad\Codecheck\Codecheck;
+use Overtrue\EasySms\EasySms;
+use support\think\Cache;
+
+class SmsService extends Service
+{
+
+    /**
+     * 发送短信
+     * @param int $mobile
+     * @param string $scene
+     * @param bool $empty true 验证手机号是否注册
+     * @return array
+     */
+    public function sendSceneSms(int $mobile,string $scene = "login",bool $empty = false): array
+    {
+        try {
+            $mobileUser =(new SystemUser)->where("mobile",$mobile)->findOrEmpty();
+            if (!$empty && $mobileUser->isEmpty()) return [0,trans("error.mobile-empty")];
+            if ($empty && !$mobileUser->isEmpty()) return [0,trans("error.mobile-exist")];
+            $cacheCode = Cache::get(KeyService::smsKey($mobile));
+            if (!empty($cacheCode)) return [0,trans("error.sms-repeat")];
+            $code = (new Codecheck)->mobile($mobile)->scene($scene)->create();
+            if (!in_array($mobile,$this->mobileWhite)) {
+                $smsConfig = $this->smsConfig();
+                $resp = (new EasySms($smsConfig['config']))->send($mobile,[
+                    "template"  => $smsConfig['template'],
+                    "data"      => [
+                        "code"  => $code
+                    ]
+                ]);
+                if (!isset($resp[$smsConfig['config']['default']['gateways']]['status'])) return [0,trans("error.sms")];
+                $msg = trans("success.sms",['%mobile%' => hide_mobile($mobile)]);
+            } else {
+                $msg = "当前号码为测试号码,验证码为{$code}";
+            }
+            Cache::set(KeyService::smsKey($mobile),$code,60);
+            return [1,$msg];
+        } catch (\Throwable $throwable) {
+            return [0,$throwable->getMessage()];
+        }
+    }
+
+}

+ 97 - 0
app/extra/service/basic/UploadService.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace app\extra\service\basic;
+
+use app\model\system\SystemConfig;
+use Tinywan\Storage\Adapter\CosAdapter;
+use Tinywan\Storage\Adapter\LocalAdapter;
+use Tinywan\Storage\Adapter\QiniuAdapter;
+
+class UploadService
+{
+    /**
+     * 配置
+     * @return array
+     */
+    public function setConfigVal(): array
+    {
+        $data = (new SystemConfig)->where("storage","service")->column("value","name");
+        $config = [];
+        $config['storage']['default'] = $data['type'];
+        $config['storage']['include'] = !empty($data['allow_exts']) ? explode(",",$data['allow_exts']) : [];
+        $config['storage']['exclude'] = !empty($data['noallow_exts']) ? explode(",",$data['noallow_exts']) : [];
+        $config['storage']['nums'] = 10;
+        $config['storage']['single_limit'] = 1024 * 1024 * 200;
+        $config['storage']['total_limit'] = 1024 * 1024 * 200;
+        switch ($data['type'])
+        {
+            case "local":
+                $config['storage']['local'] = [
+                    'adapter' => LocalAdapter::class,
+                    'root' => public_path().'/uploads/storage/',
+                    'dirname' => function () {
+                        return date('Ymd');
+                    },
+                    'domain' => '//'.request()->host(),
+                    'uri' => '/uploads/storage/', // 如果 domain + uri 不在 public 目录下,请做好软链接,否则生成的url无法访问
+                    'algo' => 'sha1',
+                ];
+                break;
+            case "qiniu":
+                $config['storage']['qiniu'] = [
+                    'adapter' => QiniuAdapter::class,
+                    'accessKey' => $data['qiniu_access_key'],
+                    'secretKey' => $data['qiniu_secret_key'],
+                    'bucket' => $data['qiniu_bucket'],
+                    'dirname' => 'storage',
+                    'domain' => $this->setDomain($data['oss_http_protocol'],$data['qiniu_http_domain']),
+                ];
+                break;
+            case "oss":
+                $config['storage']['oss'] = [
+                    'adapter' => \Tinywan\Storage\Adapter\OssAdapter::class,
+                    'accessKeyId' => $data['oss_access_key'],
+                    'accessKeySecret' => $data['oss_secret_key'],
+                    'bucket' => $data['oss_bucket'],
+                    'dirname' => function () {
+                        return 'storage';
+                    },
+                    'domain' => $this->setDomain($data['oss_http_protocol'],$data['oss_http_domain']),
+                    'endpoint' => $data['oss_region'],
+                    'algo' => 'sha1',
+
+                ];
+                break;
+            case "cos":
+                $config['storage']['cos'] = [
+                    'adapter' => CosAdapter::class,
+                    'secretId' => $data['cos_access_key'],
+                    'secretKey' => $data['cos_secret_key'],
+                    'bucket' => $data['cos_bucket'],
+                    'dirname' => 'storage',
+                    'domain' => $this->setDomain($data['oss_http_protocol'],$data['cos_http_domain']),
+                    'region' => $data['cos_region'],
+                ];
+                break;
+            default:
+                break;
+        }
+        return $config;
+    }
+
+    /**
+     * 协议域名
+     * @param string $type
+     * @param string $domain
+     * @return string
+     */
+    protected function setDomain(string $type,string $domain): string
+    {
+        if ($type == "auto") {
+            return "//".$domain;
+        }
+        return $type."://".$domain;
+    }
+
+
+}

+ 27 - 0
app/extra/service/system/MenuService.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace app\extra\service\system;
+
+use app\extra\basic\Service;
+use app\model\system\SystemMenu;
+
+class MenuService extends Service
+{
+
+    /**
+     * @param int $super
+     * @param int $type
+     * @return array
+     */
+    public function getMenuList(int $super = 0,int $type = 1): array
+    {
+        $model = new SystemMenu();
+        try {
+            $data = $model->where("status",1)->where("from",$type)->order("sort","asc")->select();
+        } catch (\Throwable $throwable) {
+            return [];
+        }
+        return $data->isEmpty()?[]:$data->toArray();
+    }
+
+}

+ 183 - 0
app/extra/service/system/SystemService.php

@@ -0,0 +1,183 @@
+<?php
+
+namespace app\extra\service\system;
+
+use app\extra\basic\Service;
+use app\model\system\SystemConfig;
+use app\model\system\SystemData;
+use app\model\system\SystemOplog;
+use support\think\Cache;
+
+class SystemService extends Service
+{
+
+    /**
+     * 配置缓存数据
+     * @var array
+     */
+    private static array $config = [];
+
+
+    public static function get(string $name = '', string $default = '')
+    {
+        try {
+            $cacheConfig = Cache::get("SystemConfig");
+            if (empty($cacheConfig))
+            {
+                $config = (new SystemConfig)->select();
+                self::setConfig($config);
+                Cache::set("SystemConfig",json_encode($config));
+            } else {
+                $config = json_decode($cacheConfig,true);
+                self::setConfig($config);
+            }
+
+            [$type, $field, $outer] = static::_parse($name);
+            if (empty($name)) {
+                return static::$config;
+            } elseif (isset(static::$config[$type])) {
+                $group = static::$config[$type];
+                if ($outer !== 'raw') foreach ($group as $kk => $vo) {
+                    $group[$kk] = htmlspecialchars(strval($vo));
+                }
+                return $field ? ($group[$field] ?? $default) : $group;
+            } else {
+                return $default;
+            }
+
+        } catch (\Exception $exception)
+        {
+            return false;
+        }
+
+    }
+
+    protected static function setConfig($data)
+    {
+        foreach($data as $item)
+        {
+            static::$config[$item['type']][$item['name']] = $item['value'];
+        }
+    }
+
+    public static function set(string $name, $value = '')
+    {
+        static::$config = [];
+        [$type, $field] = static::_parse($name);
+        if (is_array($value)) {
+            $count = 0;
+            foreach ($value as $kk => $vv) {
+                $count += static::set("{$field}.{$kk}", $vv);
+            }
+            return $count;
+        } else try {
+            Cache::delete("SystemConfig");
+            $map = ['type' => $type, 'name' => $field];
+            $data = array_merge($map, ['value' => $value]);
+            $query = (new SystemConfig)->where($map);
+            return (clone $query)->count() > 0 ? $query->update($data) : $query->insert($data);
+        } catch (\Throwable $exception) {
+            return false;
+        }
+    }
+
+    /**
+     * 解析缓存名称
+     * @param string $rule 配置名称
+     * @return array
+     */
+    private static function _parse(string $rule): array
+    {
+        $type = 'base';
+        if (stripos($rule, '.') !== false) {
+            [$type, $rule] = explode('.', $rule, 2);
+        }
+        [$field, $outer] = explode('|', "{$rule}|");
+        return [$type, $field, strtolower($outer)];
+    }
+
+
+    /**
+     * 读取数据内容
+     * @param string $name
+     * @param array $default
+     * @return array|mixed
+     */
+    public static function getData(string $name, array $default = [])
+    {
+        try {
+            $value = (new SystemData)->where("name",$name)->value("content");
+            if (!empty($value)) return json_decode($value,true);
+            return $default;
+        } catch (\Throwable $exception)
+        {
+            return $default;
+        }
+    }
+
+    /**
+     * 保存数据内容
+     * @param string $name 数据名称
+     * @param mixed $value 数据内容
+     * @return bool
+     */
+    public static function setData(string $name, $value)
+    {
+        try {
+            $data = ['name' => $name, 'content' => json_encode($value, 64 | 256)];
+            return (new SystemData)->setAutoData($data,"name");
+        } catch (\Throwable $exception) {
+            echo $exception->getFile()."\n";
+            echo $exception->getLine()."\n";
+            echo $exception->getMessage()."\n";
+            return false;
+        }
+    }
+
+
+    /**
+     * 写入系统日志内容
+     * @param string $action
+     * @param string $content
+     * @param string $userName
+     * @return boolean
+     */
+    public static function setOplog(string $action, string $content, string $userName): bool
+    {
+        return (new SystemOplog)->insert(static::getOplog($action, $content,$userName)) !== false;
+    }
+
+    /**
+     * 获取系统日志内容
+     * @param string $action
+     * @param string $content
+     * @param string $userName
+     * @return array
+     */
+    public static function getUserOplog(string $action, string $content, string $userName): array
+    {
+        return [
+            'username'  => $userName,
+            'action'    => $action, 'content' => $content,
+            'geoip'     => request()->getRealIp() ?: '127.0.0.1',
+        ];
+    }
+
+    /**
+     * 获取系统日志内容
+     * @param string $action
+     * @param string $content
+     * @param string $userName
+     * @return array
+     */
+    public static function getOplog(string $action, string $content, string $userName): array
+    {
+        return [
+            'node'      => request()->uri(),
+            'action'    => $action, 'content' => $content,
+            'geoip'     => request()->getRealIp() ?: '127.0.0.1',
+            'username'  => $userName ?: '-'
+        ];
+    }
+
+}

+ 135 - 0
app/extra/tools/CodeExtend.php

@@ -0,0 +1,135 @@
+<?php
+
+namespace app\extra\tools;
+
+class CodeExtend
+{
+    /**
+     * 生成随机编码
+     * @param integer $size 编码长度
+     * @param integer $type 编码类型(1纯数字,2纯字母,3数字字母)
+     * @param string $prefix 编码前缀
+     * @return string
+     */
+    public static function random(int $size = 10, int $type = 1, string $prefix = ''): string
+    {
+        $numbs = '0123456789';
+        $chars = 'abcdefghijklmnopqrstuvwxyz';
+        if ($type === 1) $chars = $numbs;
+        if ($type === 3) $chars = "{$numbs}{$chars}";
+        $code = $prefix . $chars[rand(1, strlen($chars) - 1)];
+        while (strlen($code) < $size) $code .= $chars[rand(0, strlen($chars) - 1)];
+        return $code;
+    }
+
+    /**
+     * 生成日期编码
+     * @param integer $size 编码长度
+     * @param string $prefix 编码前缀
+     * @return string
+     */
+    public static function uniqidDate(int $size = 16, string $prefix = ''): string
+    {
+        if ($size < 14) $size = 14;
+        $code = $prefix . date('Ymd') . (date('H') + date('i')) . date('s');
+        while (strlen($code) < $size) $code .= rand(0, 9);
+        return $code;
+    }
+
+    /**
+     * 生成数字编码
+     * @param integer $size 编码长度
+     * @param string $prefix 编码前缀
+     * @return string
+     */
+    public static function uniqidNumber(int $size = 12, string $prefix = ''): string
+    {
+        $time = strval(time());
+        if ($size < 10) $size = 10;
+        $code = $prefix . (intval($time[0]) + intval($time[1])) . substr($time, 2) . rand(0, 9);
+        while (strlen($code) < $size) $code .= rand(0, 9);
+        return $code;
+    }
+
+    /**
+     * 文本转码
+     * @param string $text 文本内容
+     * @param string $target 目标编码
+     * @return string
+     */
+    public static function text2utf8(string $text, string $target = 'UTF-8'): string
+    {
+        [$first2, $first4] = [substr($text, 0, 2), substr($text, 0, 4)];
+        if ($first4 === chr(0x00) . chr(0x00) . chr(0xFE) . chr(0xFF)) $ft = 'UTF-32BE';
+        elseif ($first4 === chr(0xFF) . chr(0xFE) . chr(0x00) . chr(0x00)) $ft = 'UTF-32LE';
+        elseif ($first2 === chr(0xFE) . chr(0xFF)) $ft = 'UTF-16BE';
+        elseif ($first2 === chr(0xFF) . chr(0xFE)) $ft = 'UTF-16LE';
+        return mb_convert_encoding($text, $target, $ft ?? mb_detect_encoding($text));
+    }
+
+    /**
+     * 数据解密处理
+     * @param mixed $data 加密数据
+     * @param string $skey 安全密钥
+     * @return string
+     */
+    public static function encrypt($data, string $skey): string
+    {
+        $iv = static::random(16, 3);
+        $value = openssl_encrypt(serialize($data), 'AES-256-CBC', $skey, 0, $iv);
+        return static::enSafe64(json_encode(['iv' => $iv, 'value' => $value]));
+    }
+
+    /**
+     * 数据加密处理
+     * @param string $data 解密数据
+     * @param string $skey 安全密钥
+     * @return mixed
+     */
+    public static function decrypt(string $data, string $skey)
+    {
+        $attr = json_decode(static::deSafe64($data), true);
+        return unserialize(openssl_decrypt($attr['value'], 'AES-256-CBC', $skey, 0, $attr['iv']));
+    }
+
+    /**
+     * Base64Url 安全编码
+     * @param string $text 待加密文本
+     * @return string
+     */
+    public static function enSafe64(string $text): string
+    {
+        return rtrim(strtr(base64_encode($text), '+/', '-_'), '=');
+    }
+
+    /**
+     * Base64Url 安全解码
+     * @param string $text 待解密文本
+     * @return string
+     */
+    public static function deSafe64(string $text): string
+    {
+        return base64_decode(str_pad(strtr($text, '-_', '+/'), strlen($text) % 4, '='));
+    }
+
+    /**
+     * 压缩数据对象
+     * @param mixed $data
+     * @return string
+     */
+    public static function enzip($data): string
+    {
+        return static::enSafe64(gzcompress(serialize($data)));
+    }
+
+    /**
+     * 解压数据对象
+     * @param string $string
+     * @return mixed
+     */
+    public static function dezip(string $string)
+    {
+        return unserialize(gzuncompress(static::deSafe64($string)));
+    }
+
+}

+ 73 - 0
app/extra/tools/DataExtend.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace app\extra\tools;
+
+
+class DataExtend
+{
+
+    /**
+     * 一维数组转多维数据树
+     * @param array $its 待处理数据
+     * @param string $cid 自己的主键
+     * @param string $pid 上级的主键
+     * @param string $sub 子数组名称
+     * @return array
+     */
+    public static function arr2tree(array $its, string $cid = 'id', string $pid = 'pid', string $sub = 'children'): array
+    {
+        [$tree, $its] = [[], array_column($its, null, $cid)];
+        foreach ($its as $it) isset($its[$it[$pid]]) ? $its[$it[$pid]][$sub][] = &$its[$it[$cid]] : $tree[] = &$its[$it[$cid]];
+        return $tree;
+    }
+
+    /**
+     * 一维数组转数据树表
+     * @param array $its 待处理数据
+     * @param string $cid 自己的主键
+     * @param string $pid 上级的主键
+     * @param string $path 当前 PATH
+     * @return array
+     */
+    public static function arr2table(array $its, string $cid = 'id', string $pid = 'pid', string $path = 'path'): array
+    {
+        $call = function (array $its, callable $call, array &$data = [], string $parent = '') use ($cid, $pid, $path) {
+            foreach ($its as $it) {
+                $ts = $it['sub'] ?? [];
+                unset($it['sub']);
+                $it[$path] = "{$parent}-{$it[$cid]}";
+                $it['spc'] = count($ts);
+                $it['spt'] = substr_count($parent, '-');
+                $it['spl'] = str_repeat('ㅤ├ㅤ', $it['spt']);
+                $it['sps'] = ",{$it[$cid]},";
+                array_walk_recursive($ts, function ($val, $key) use ($cid, &$it) {
+                    if ($key === $cid) $it['sps'] .= "{$val},";
+                });
+                $it['spp'] = arr2str(str2arr(strtr($parent . $it['sps'], '-', ',')));
+                $data[] = $it;
+                if (empty($ts)) continue;
+                $call($ts, $call, $data, $it[$path]);
+            }
+            return $data;
+        };
+        return $call(static::arr2tree($its, $cid, $pid), $call);
+    }
+
+    /**
+     * 获取数据树子ID集合
+     * @param array $list 数据列表
+     * @param mixed $value 起始有效ID值
+     * @param string $ckey 当前主键ID名称
+     * @param string $pkey 上级主键ID名称
+     * @return array
+     */
+    public static function getArrSubIds(array $list, $value = 0, string $ckey = 'id', string $pkey = 'pid'): array
+    {
+        $ids = [intval($value)];
+        foreach ($list as $vo) if (intval($vo[$pkey]) > 0 && intval($vo[$pkey]) === intval($value)) {
+            $ids = array_merge($ids, static::getArrSubIds($list, intval($vo[$ckey]), $ckey, $pkey));
+        }
+        return $ids;
+    }
+
+}

+ 122 - 0
app/extra/tools/UploadExtend.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace app\extra\tools;
+
+use app\extra\service\basic\UploadService;
+use Tinywan\Storage\Storage;
+
+/**
+ * @see Storage
+ * @mixin Storage
+ *
+ * @method static array uploadFile(array $config = [])  上传文件
+ * @method static array uploadBase64(string $base64, string $extension = 'png') 上传Base64文件
+ * @method static array uploadServerFile(string $file_path)  上传服务端文件
+ */
+class UploadExtend
+{
+    /**
+     * 本地对象存储.
+     */
+    public const MODE_LOCAL = 'local';
+
+    /**
+     * 阿里云对象存储.
+     */
+    public const MODE_OSS = 'oss';
+
+    /**
+     * 腾讯云对象存储.
+     */
+    public const MODE_COS = 'cos';
+
+    /**
+     * 七牛云对象存储.
+     */
+    public const MODE_QINIU = 'qiniu';
+
+    /**
+     * S3对象存储.
+     */
+    public const MODE_S3 = 's3';
+
+
+    protected array $config = [];
+
+    /**
+     * Support Storage
+     */
+    static $allowStorage = [
+        self::MODE_LOCAL,
+        self::MODE_OSS,
+        self::MODE_COS,
+        self::MODE_QINIU,
+        self::MODE_S3
+    ];
+
+    /**
+     * 存储磁盘
+     * @param string|null $name
+     * @param bool $_is_file_upload
+     * @return mixed
+     * @author Tinywan(ShaoBo Wan)
+     */
+    public static function disk(string $name = null, bool $_is_file_upload = true)
+    {
+        $storage = $name ?? self::getDefaultStorage();
+        $config = self::getConfig($storage);
+        return new $config['adapter'](array_merge(
+            $config, ['_is_file_upload' => $_is_file_upload]
+        ));
+    }
+
+    /**
+     * 默认存储
+     * @return mixed
+     * @author Tinywan(ShaoBo Wan)
+     */
+    public static function getDefaultStorage()
+    {
+        return self::getConfig('default');
+    }
+
+    /**
+     * 获取存储配置
+     * @param string|null $name 名称
+     * @return mixed
+     * @author Tinywan(ShaoBo Wan)
+     */
+    public static function getConfig(string $name = null)
+    {
+        $config = (new UploadService)->setConfigVal();
+        if (!is_null($name)) {
+            return $config['storage'][$name];
+//            return config('plugin.tinywan.storage.app.storage.' . $name, self::MODE_LOCAL);
+        }
+        return $config['storage']["default"];
+//        return config('plugin.tinywan.storage.app.storage.default');
+    }
+
+
+    /**
+     * 配置信息
+     * @param array $config
+     */
+    public function config(array $config)
+    {
+        $this->$config = $config;
+        return $this;
+    }
+
+    /**
+     * @param $name
+     * @param $arguments
+     * @return mixed
+     * @author Tinywan(ShaoBo Wan)
+     */
+    public static function __callStatic($name, $arguments)
+    {
+        return static::disk()->{$name}(...$arguments);
+    }
+
+}

+ 67 - 0
app/functions.php

@@ -1,6 +1,7 @@
 <?php
 
 
+use app\extra\service\system\SystemService;
 use support\Response;
 use Webman\Event\Event;
 
@@ -39,6 +40,21 @@ if (!function_exists("str2date"))
         return strtotime($date);
     }
 }
+
+if(!function_exists("hide_mobile")){
+
+    /**
+     * 手机号码脱敏
+     * @param string $mobile
+     * @param int $len 4 末尾4位 6 末尾2位
+     * @return string
+     */
+    function hide_mobile(string $mobile,int $len = 6): string
+    {
+        return substr_replace($mobile, ($len==4 ? '****' : '******'), 3, $len);
+    }
+}
+
 if (!function_exists('hide_str')) {
     /**
      * 将一个字符串部分字符用*替代隐藏
@@ -326,4 +342,55 @@ if (!function_exists("pageFormat")) {
             'rows'      => $data->items()
         ];
     }
+}
+
+
+
+if (!function_exists('sConf')) {
+
+    /**
+     * 获取或配置系统参数
+     * @param string $name 参数名称
+     * @param string|null $value 参数内容
+     */
+    function sConf(string $name = '', string $value = null)
+    {
+        if (is_null($value) && is_string($name)) {
+            return SystemService::get($name);
+        } else {
+            return SystemService::set($name, $value);
+        }
+    }
+}
+
+if (!function_exists('sData')) {
+
+    /**
+     * JSON 数据读取与存储
+     * @param string $name 数据名称
+     * @param mixed $value 数据内容
+     */
+    function sData(string $name,string $value = null)
+    {
+        if (is_null($value)) {
+            return SystemService::getData($name);
+        } else {
+            return SystemService::setData($name, $value);
+        }
+    }
+}
+
+
+if (!function_exists('sOplog')) {
+    /**
+     * 写入系统日志
+     * @param string $action 日志行为
+     * @param string $content 日志内容
+     * @param string $userName
+     * @return boolean
+     */
+    function sOplog(string $action, string $content, string $userName): bool
+    {
+        return SystemService::setOplog($action, $content,$userName);
+    }
 }

+ 45 - 0
app/middleware/AuthMiddleware.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace app\middleware;
+
+use Shopwwi\WebmanAuth\Auth;
+use Shopwwi\WebmanAuth\JWT;
+use Webman\Http\Request;
+use Webman\Http\Response;
+use Webman\MiddlewareInterface;
+
+class AuthMiddleware implements MiddlewareInterface
+{
+
+
+    public function process(Request $request, callable $handler): Response
+    {
+        try {
+            $controller = new \ReflectionClass($request->controller);
+            $noNeedLogin = $controller->getDefaultProperties()['noNeedLogin']??[];
+            if (empty($noNeedLogin) || !in_array($request->action, $noNeedLogin)) {
+                $type = $request->header('api-type','');
+                if (empty($type)) return json(['code'=> 0,'msg'=> trans("error.param")]);
+                $token =  $request->header("Authorization","");
+                if (empty($token)) return json(['code'=> 0,'msg'=> trans("error.request")]);
+                (new JWT)->guard("admin")->verify();
+                $user = (new Auth)->guard("admin")->user();
+                if (empty($user)) return json(['code'=>401,'msg'=> trans("error.login")]);
+                $request->user = $user->toArray();
+            }
+        } catch (\ReflectionException $exception) {
+            return json(['code'=> 500,'msg'=> $exception->getMessage()]);
+        }
+        $response = $request->method() == 'OPTIONS' ? response('',204) : $handler($request);
+        // 给响应添加跨域相关的http头
+        $response->withHeaders([
+            'Access-Control-Allow-Credentials' => 'true',
+            'Access-Control-Allow-Origin' => $request->header('origin', '*'),
+            'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'),
+            'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'),
+        ]);
+        return $response;
+    }
+
+
+}

+ 54 - 0
app/model/system/SystemMenu.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace app\model\system;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property integer $from 1管理后台2代理
+ * @property integer $pid 
+ * @property string $name 
+ * @property string $path 
+ * @property string $title 
+ * @property string $type 
+ * @property string $descs 
+ * @property string $icon 
+ * @property integer $status 
+ * @property integer $sort 
+ * @property integer $is_used 
+ * @property integer $is_mch 1代理2门店
+ */
+class SystemMenu extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "system_menu";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 3 - 1
composer.json

@@ -51,7 +51,9 @@
     "tinywan/storage": "^1.1",
     "aliyuncs/oss-sdk-php": "^2.7",
     "qcloud/cos-sdk-v5": "^2.6",
-    "topthink/think-validate": "^3.0"
+    "topthink/think-validate": "^3.0",
+    "hzdad/codecheck": "^1.0",
+    "php-di/php-di": "7.0"
   },
   "suggest": {
     "ext-event": "For better performance. "

+ 183 - 3
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "4b880fa3dfb7d1cea01d84bd973bde12",
+    "content-hash": "2ead91c6e9a163acf92581803d2a67f8",
     "packages": [
         {
             "name": "aliyuncs/oss-sdk-php",
@@ -1146,6 +1146,31 @@
             },
             "time": "2022-09-07T08:00:40+00:00"
         },
+        {
+            "name": "hzdad/codecheck",
+            "version": "v1.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/hzdad/codecheck/v1.0/hzdad-codecheck-v1.0.zip",
+                "reference": "929c7119824e9c82534ddaccdcce4971258044e3",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Hzdad\\Codecheck\\": "src"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "Webman plugin hzdad/codecheck",
+            "support": {
+                "issues": "https://github.com/hzdad/codecheck/issues",
+                "source": "https://github.com/hzdad/codecheck/tree/v1.0"
+            },
+            "time": "2022-06-02T03:29:02+00:00"
+        },
         {
             "name": "illuminate/bus",
             "version": "v12.39.0",
@@ -1783,6 +1808,61 @@
             },
             "time": "2025-10-22T09:02:34+00:00"
         },
+        {
+            "name": "laravel/serializable-closure",
+            "version": "v1.3.7",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/laravel/serializable-closure/v1.3.7/laravel-serializable-closure-v1.3.7.zip",
+                "reference": "4f48ade902b94323ca3be7646db16209ec76be3d",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.3|^8.0"
+            },
+            "require-dev": {
+                "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
+                "nesbot/carbon": "^2.61|^3.0",
+                "pestphp/pest": "^1.21.3",
+                "phpstan/phpstan": "^1.8.2",
+                "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Laravel\\SerializableClosure\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                },
+                {
+                    "name": "Nuno Maduro",
+                    "email": "nuno@laravel.com"
+                }
+            ],
+            "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.",
+            "keywords": [
+                "closure",
+                "laravel",
+                "serializable"
+            ],
+            "support": {
+                "issues": "https://github.com/laravel/serializable-closure/issues",
+                "source": "https://github.com/laravel/serializable-closure"
+            },
+            "time": "2024-11-14T18:34:49+00:00"
+        },
         {
             "name": "linfly/annotation",
             "version": "1.0.12",
@@ -2263,6 +2343,106 @@
             },
             "time": "2025-07-17T07:07:58+00:00"
         },
+        {
+            "name": "php-di/invoker",
+            "version": "2.3.7",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/php-di/invoker/2.3.7/php-di-invoker-2.3.7.zip",
+                "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "psr/container": "^1.0|^2.0"
+            },
+            "require-dev": {
+                "athletic/athletic": "~0.1.8",
+                "mnapoli/hard-mode": "~0.3.0",
+                "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Invoker\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "Generic and extensible callable invoker",
+            "homepage": "https://github.com/PHP-DI/Invoker",
+            "keywords": [
+                "callable",
+                "dependency",
+                "dependency-injection",
+                "injection",
+                "invoke",
+                "invoker"
+            ],
+            "support": {
+                "issues": "https://github.com/PHP-DI/Invoker/issues",
+                "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7"
+            },
+            "time": "2025-08-30T10:22:22+00:00"
+        },
+        {
+            "name": "php-di/php-di",
+            "version": "7.0.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/php-di/php-di/7.0.0/php-di-php-di-7.0.0.zip",
+                "reference": "f0ca9a0e0fb800974fcaf7b2f896ca1e840fd15b",
+                "shasum": ""
+            },
+            "require": {
+                "laravel/serializable-closure": "^1.0",
+                "php": ">=8.0",
+                "php-di/invoker": "^2.0",
+                "psr/container": "^1.1 || ^2.0"
+            },
+            "provide": {
+                "psr/container-implementation": "^1.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3",
+                "mnapoli/phpunit-easymock": "^1.3",
+                "ocramius/proxy-manager": "^2.11.2",
+                "phpunit/phpunit": "^9.5",
+                "vimeo/psalm": "^4.6"
+            },
+            "suggest": {
+                "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ^2.3)"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/functions.php"
+                ],
+                "psr-4": {
+                    "DI\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "The dependency injection container for humans",
+            "homepage": "https://php-di.org/",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interop",
+                "dependency injection",
+                "di",
+                "ioc",
+                "psr11"
+            ],
+            "support": {
+                "issues": "https://github.com/PHP-DI/PHP-DI/issues",
+                "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.0"
+            },
+            "time": "2023-01-12T14:08:11+00:00"
+        },
         {
             "name": "phpoffice/phpspreadsheet",
             "version": "5.2.0",
@@ -4872,12 +5052,12 @@
     "packages-dev": [],
     "aliases": [],
     "minimum-stability": "dev",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
         "php": ">=8.1"
     },
-    "platform-dev": [],
+    "platform-dev": {},
     "plugin-api-version": "2.6.0"
 }

+ 5 - 14
config/container.php

@@ -1,15 +1,6 @@
 <?php
-/**
- * This file is part of webman.
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the MIT-LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @author    walkor<walkor@workerman.net>
- * @copyright walkor<walkor@workerman.net>
- * @link      http://www.workerman.net/
- * @license   http://www.opensource.org/licenses/mit-license.php MIT License
- */
-
-return new Webman\Container;
+$builder = new \DI\ContainerBuilder();
+$builder->addDefinitions(config('dependence', []));
+$builder->useAutowiring(true);
+$builder->useAttributes(true);
+return $builder->build();

+ 8 - 0
config/plugin/hzdad/codecheck/app.php

@@ -0,0 +1,8 @@
+<?php
+return [
+    'enable' => true,
+    'expire' => 300,
+    'length' => 6,
+    'chcktimes' => 3,//最多可以尝试次数
+    'delafterok' => true,//验证后删除
+];

+ 3 - 3
config/plugin/shopwwi/auth/app.php

@@ -4,11 +4,11 @@
      'enable' => true,
      'app_key' => 'base64:N721v3Gt2I58HH7oiU7a70PQ+i8ekPWRqwI+JSnM1wo=',
      'guard' => [
-         'user' => [
+         'admin' => [
              'key' => 'id',
-             'field' => ['id','name','email','mobile'], //设置允许写入扩展中的字段
+             'field' => ['id','username'], //设置允许写入扩展中的字段
              'num' => 0, //-1为不限制终端数量 0为只支持一个终端在线 大于0为同一账号同终端支持数量 建议设置为1 则同一账号同终端在线1个
-             'model'=> app\model\Test::class // 当为数组时 [app\model\Test::class,'thinkphp'] 来说明模型归属
+             'model'=> [\app\model\system\SystemUser::class,'thinkphp'] // 当为数组时 [app\model\Test::class,'thinkphp'] 来说明模型归属
          ]
      ],
      'jwt' => [

+ 4 - 3
config/plugin/tinywan/captcha/app.php

@@ -5,7 +5,8 @@ return [
         // 验证码存储key前缀
         'prefix'  => 'captcha',
         // 验证码字符集合
-        'codeSet'  => 'ABCDEFGHJKLMNPQRTUVWXY2345678abcdefhijkmnpqrstuvwxyz',
+        'codeSet'  => '0123456789',
+//        'codeSet'  => 'ABCDEFGHJKLMNPQRTUVWXY2345678abcdefhijkmnpqrstuvwxyz',
         // 是否使用中文验证码
         'useZh'  => false,
         // 中文验证码字符串
@@ -15,13 +16,13 @@ return [
         // 是否使用混淆曲线
         'useCurve' => false,
         // 是否添加杂点
-        'useNoise' => false,
+        'useNoise' => true,
         // 验证码图片高度
         'imageH'   => 0,
         // 验证码图片宽度
         'imageW'   => 0,
         // 验证码位数
-        'length'   => 5,
+        'length'   => 4,
         // 验证码字符大小
         'fontSize' => 25,
         // 验证码过期时间 不设置默认60秒

+ 18 - 2
resource/translations/zh_CN/messages.php

@@ -10,7 +10,23 @@ return [
         "data"      => "数据不存在"
     ],
     "error"     => [
-        "captcha"  => "验证码输入错误"
+        "data"          => "操作失败",
+        "captcha"       => "验证码输入错误",
+        "mobile"        => "手机号码格式错误",
+        "sms-repeat"    => "请勿重复获取",
+        "sms"           => "获取验证码失败,请联系管理员",
+        "mobile-empty"  => "手机号未注册,请开通后再重试",
+        "mobile-exist"  => "手机号已被注册",
+        "user-empty"    => "登录账号不存在",
+        "user-status"   => "该账号已被冻结,请联系管理员",
+        "passwd"        => "登录密码错误",
+        "param"         => "不合法的参数",
+        "request"       => "不合法的请求格式",
+        "login"         => "登录已过期,请重新登录"
+    ],
+    "success"   => [
+        "data"  => "操作成功",
+        "sms"   => "验证码已成功发送至%mobile%,请注意查收",
+        "login" => "登录成功"
     ],
-    "success"   => "操作成功",
 ];

+ 0 - 2
runtime/logs/.gitignore

@@ -1,2 +0,0 @@
-*
-!.gitignore

+ 0 - 2
runtime/views/.gitignore

@@ -1,2 +0,0 @@
-*
-!.gitignore

+ 1 - 0
support/Request.php

@@ -21,4 +21,5 @@ namespace support;
 class Request extends \Webman\Http\Request
 {
 
+    public mixed $user;
 }

+ 1 - 4
vendor/autoload.php

@@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
             echo $err;
         }
     }
-    trigger_error(
-        $err,
-        E_USER_ERROR
-    );
+    throw new RuntimeException($err);
 }
 
 require_once __DIR__ . '/composer/autoload_real.php';

+ 41 - 4
vendor/composer/InstalledVersions.php

@@ -26,12 +26,23 @@ use Composer\Semver\VersionParser;
  */
 class InstalledVersions
 {
+    /**
+     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
+     * @internal
+     */
+    private static $selfDir = null;
+
     /**
      * @var mixed[]|null
      * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
      */
     private static $installed;
 
+    /**
+     * @var bool
+     */
+    private static $installedIsLocalDir;
+
     /**
      * @var bool|null
      */
@@ -309,6 +320,24 @@ class InstalledVersions
     {
         self::$installed = $data;
         self::$installedByVendor = array();
+
+        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
+        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
+        // so we have to assume it does not, and that may result in duplicate data being returned when listing
+        // all installed packages for example
+        self::$installedIsLocalDir = false;
+    }
+
+    /**
+     * @return string
+     */
+    private static function getSelfDir()
+    {
+        if (self::$selfDir === null) {
+            self::$selfDir = strtr(__DIR__, '\\', '/');
+        }
+
+        return self::$selfDir;
     }
 
     /**
@@ -322,19 +351,27 @@ class InstalledVersions
         }
 
         $installed = array();
+        $copiedLocalDir = false;
 
         if (self::$canGetVendors) {
+            $selfDir = self::getSelfDir();
             foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+                $vendorDir = strtr($vendorDir, '\\', '/');
                 if (isset(self::$installedByVendor[$vendorDir])) {
                     $installed[] = self::$installedByVendor[$vendorDir];
                 } elseif (is_file($vendorDir.'/composer/installed.php')) {
                     /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                     $required = require $vendorDir.'/composer/installed.php';
-                    $installed[] = self::$installedByVendor[$vendorDir] = $required;
-                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
-                        self::$installed = $installed[count($installed) - 1];
+                    self::$installedByVendor[$vendorDir] = $required;
+                    $installed[] = $required;
+                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
+                        self::$installed = $required;
+                        self::$installedIsLocalDir = true;
                     }
                 }
+                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
+                    $copiedLocalDir = true;
+                }
             }
         }
 
@@ -350,7 +387,7 @@ class InstalledVersions
             }
         }
 
-        if (self::$installed !== array()) {
+        if (self::$installed !== array() && !$copiedLocalDir) {
             $installed[] = self::$installed;
         }
 

+ 1 - 0
vendor/composer/autoload_files.php

@@ -34,5 +34,6 @@ return array(
     '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
     'ef65a1626449d89d0811cf9befce46f0' => $vendorDir . '/illuminate/events/functions.php',
     '45c103288aaada066086e997f1d1c6dd' => $vendorDir . '/kkokk/poster/src/helpers.php',
+    'b33e3d135e5d9e47d845c576147bda89' => $vendorDir . '/php-di/php-di/src/functions.php',
     'cd5441689b14144e5573bf989ee47b34' => $vendorDir . '/qcloud/cos-sdk-v5/src/Common.php',
 );

+ 8 - 4
vendor/composer/autoload_psr4.php

@@ -8,8 +8,8 @@ $baseDir = dirname($vendorDir);
 return array(
     'yzh52521\\EasyHttp\\' => array($vendorDir . '/yzh52521/easyhttp/src'),
     'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),
-    'think\\' => array($vendorDir . '/topthink/think-container/src', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-validate/src'),
-    'support\\' => array($vendorDir . '/webman/redis/src/support', $vendorDir . '/webman/think-cache/src/support', $vendorDir . '/webman/think-orm/src/support', $vendorDir . '/workerman/webman-framework/src/support'),
+    'think\\' => array($vendorDir . '/topthink/think-template/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-validate/src', $vendorDir . '/topthink/think-container/src', $vendorDir . '/topthink/think-helper/src'),
+    'support\\' => array($vendorDir . '/webman/think-orm/src/support', $vendorDir . '/webman/think-cache/src/support', $vendorDir . '/webman/redis/src/support', $vendorDir . '/workerman/webman-framework/src/support'),
     'app\\View\\Components\\' => array($baseDir . '/app/view/components'),
     'app\\' => array($baseDir . '/app'),
     'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
@@ -18,7 +18,7 @@ return array(
     'Workerman\\RedisQueue\\' => array($vendorDir . '/workerman/redis-queue/src'),
     'Workerman\\Crontab\\' => array($vendorDir . '/workerman/crontab/src'),
     'Workerman\\Coroutine\\' => array($vendorDir . '/workerman/coroutine/src'),
-    'Workerman\\' => array($vendorDir . '/workerman/coroutine/src', $vendorDir . '/workerman/workerman/src'),
+    'Workerman\\' => array($vendorDir . '/workerman/workerman/src', $vendorDir . '/workerman/coroutine/src'),
     'Webman\\ThinkOrm\\' => array($vendorDir . '/webman/think-orm/src'),
     'Webman\\ThinkCache\\' => array($vendorDir . '/webman/think-cache/src'),
     'Webman\\Redis\\' => array($vendorDir . '/webman/redis/src'),
@@ -65,16 +65,19 @@ return array(
     'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
     'LinFly\\Annotation\\' => array($vendorDir . '/linfly/annotation/src'),
     'LinFly\\' => array($vendorDir . '/linfly/container/src'),
+    'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'),
     'Kkokk\\Poster\\' => array($vendorDir . '/kkokk/poster/src'),
+    'Invoker\\' => array($vendorDir . '/php-di/invoker/src'),
     'Intervention\\Image\\' => array($vendorDir . '/intervention/image/src'),
     'Intervention\\Gif\\' => array($vendorDir . '/intervention/gif/src'),
-    'Illuminate\\Support\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'),
+    'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable'),
     'Illuminate\\Redis\\' => array($vendorDir . '/illuminate/redis'),
     'Illuminate\\Pipeline\\' => array($vendorDir . '/illuminate/pipeline'),
     'Illuminate\\Events\\' => array($vendorDir . '/illuminate/events'),
     'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
     'Illuminate\\Container\\' => array($vendorDir . '/illuminate/container'),
     'Illuminate\\Bus\\' => array($vendorDir . '/illuminate/bus'),
+    'Hzdad\\Codecheck\\' => array($vendorDir . '/hzdad/codecheck/src'),
     'Hhink\\WebmanSms\\' => array($vendorDir . '/hhink/webman-sms/src'),
     'GuzzleHttp\\UriTemplate\\' => array($vendorDir . '/guzzlehttp/uri-template/src'),
     'GuzzleHttp\\Stream\\' => array($vendorDir . '/ezimuel/guzzlestreams/src'),
@@ -93,6 +96,7 @@ return array(
     'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/src'),
     'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'),
     'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
+    'DI\\' => array($vendorDir . '/php-di/php-di/src'),
     'Composer\\Pcre\\' => array($vendorDir . '/composer/pcre/src'),
     'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
     'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),

+ 34 - 13
vendor/composer/autoload_static.php

@@ -35,6 +35,7 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
         'ef65a1626449d89d0811cf9befce46f0' => __DIR__ . '/..' . '/illuminate/events/functions.php',
         '45c103288aaada066086e997f1d1c6dd' => __DIR__ . '/..' . '/kkokk/poster/src/helpers.php',
+        'b33e3d135e5d9e47d845c576147bda89' => __DIR__ . '/..' . '/php-di/php-di/src/functions.php',
         'cd5441689b14144e5573bf989ee47b34' => __DIR__ . '/..' . '/qcloud/cos-sdk-v5/src/Common.php',
     );
 
@@ -145,6 +146,7 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         array (
             'LinFly\\Annotation\\' => 18,
             'LinFly\\' => 7,
+            'Laravel\\SerializableClosure\\' => 28,
         ),
         'K' => 
         array (
@@ -152,6 +154,7 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         ),
         'I' => 
         array (
+            'Invoker\\' => 8,
             'Intervention\\Image\\' => 19,
             'Intervention\\Gif\\' => 17,
             'Illuminate\\Support\\' => 19,
@@ -164,6 +167,7 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         ),
         'H' => 
         array (
+            'Hzdad\\Codecheck\\' => 16,
             'Hhink\\WebmanSms\\' => 16,
         ),
         'G' => 
@@ -194,6 +198,7 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
             'Doctrine\\Deprecations\\' => 22,
             'Doctrine\\Common\\Lexer\\' => 22,
             'Doctrine\\Common\\Annotations\\' => 28,
+            'DI\\' => 3,
         ),
         'C' => 
         array (
@@ -219,17 +224,17 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         ),
         'think\\' => 
         array (
-            0 => __DIR__ . '/..' . '/topthink/think-container/src',
-            1 => __DIR__ . '/..' . '/topthink/think-helper/src',
-            2 => __DIR__ . '/..' . '/topthink/think-orm/src',
-            3 => __DIR__ . '/..' . '/topthink/think-template/src',
-            4 => __DIR__ . '/..' . '/topthink/think-validate/src',
+            0 => __DIR__ . '/..' . '/topthink/think-template/src',
+            1 => __DIR__ . '/..' . '/topthink/think-orm/src',
+            2 => __DIR__ . '/..' . '/topthink/think-validate/src',
+            3 => __DIR__ . '/..' . '/topthink/think-container/src',
+            4 => __DIR__ . '/..' . '/topthink/think-helper/src',
         ),
         'support\\' => 
         array (
-            0 => __DIR__ . '/..' . '/webman/redis/src/support',
+            0 => __DIR__ . '/..' . '/webman/think-orm/src/support',
             1 => __DIR__ . '/..' . '/webman/think-cache/src/support',
-            2 => __DIR__ . '/..' . '/webman/think-orm/src/support',
+            2 => __DIR__ . '/..' . '/webman/redis/src/support',
             3 => __DIR__ . '/..' . '/workerman/webman-framework/src/support',
         ),
         'app\\View\\Components\\' => 
@@ -266,8 +271,8 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         ),
         'Workerman\\' => 
         array (
-            0 => __DIR__ . '/..' . '/workerman/coroutine/src',
-            1 => __DIR__ . '/..' . '/workerman/workerman/src',
+            0 => __DIR__ . '/..' . '/workerman/workerman/src',
+            1 => __DIR__ . '/..' . '/workerman/coroutine/src',
         ),
         'Webman\\ThinkOrm\\' => 
         array (
@@ -454,10 +459,18 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         array (
             0 => __DIR__ . '/..' . '/linfly/container/src',
         ),
+        'Laravel\\SerializableClosure\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/laravel/serializable-closure/src',
+        ),
         'Kkokk\\Poster\\' => 
         array (
             0 => __DIR__ . '/..' . '/kkokk/poster/src',
         ),
+        'Invoker\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/php-di/invoker/src',
+        ),
         'Intervention\\Image\\' => 
         array (
             0 => __DIR__ . '/..' . '/intervention/image/src',
@@ -468,10 +481,10 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         ),
         'Illuminate\\Support\\' => 
         array (
-            0 => __DIR__ . '/..' . '/illuminate/macroable',
-            1 => __DIR__ . '/..' . '/illuminate/conditionable',
-            2 => __DIR__ . '/..' . '/illuminate/collections',
-            3 => __DIR__ . '/..' . '/illuminate/support',
+            0 => __DIR__ . '/..' . '/illuminate/support',
+            1 => __DIR__ . '/..' . '/illuminate/collections',
+            2 => __DIR__ . '/..' . '/illuminate/conditionable',
+            3 => __DIR__ . '/..' . '/illuminate/macroable',
         ),
         'Illuminate\\Redis\\' => 
         array (
@@ -497,6 +510,10 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         array (
             0 => __DIR__ . '/..' . '/illuminate/bus',
         ),
+        'Hzdad\\Codecheck\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/hzdad/codecheck/src',
+        ),
         'Hhink\\WebmanSms\\' => 
         array (
             0 => __DIR__ . '/..' . '/hhink/webman-sms/src',
@@ -569,6 +586,10 @@ class ComposerStaticInit691f538563ac6695008ddc51b7722c80
         array (
             0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
         ),
+        'DI\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/php-di/php-di/src',
+        ),
         'Composer\\Pcre\\' => 
         array (
             0 => __DIR__ . '/..' . '/composer/pcre/src',

+ 192 - 0
vendor/composer/installed.json

@@ -1197,6 +1197,34 @@
             },
             "install-path": "../hhink/webman-sms"
         },
+        {
+            "name": "hzdad/codecheck",
+            "version": "v1.0",
+            "version_normalized": "1.0.0.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/hzdad/codecheck/v1.0/hzdad-codecheck-v1.0.zip",
+                "reference": "929c7119824e9c82534ddaccdcce4971258044e3",
+                "shasum": ""
+            },
+            "time": "2022-06-02T03:29:02+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Hzdad\\Codecheck\\": "src"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "Webman plugin hzdad/codecheck",
+            "support": {
+                "issues": "https://github.com/hzdad/codecheck/issues",
+                "source": "https://github.com/hzdad/codecheck/tree/v1.0"
+            },
+            "install-path": "../hzdad/codecheck"
+        },
         {
             "name": "illuminate/bus",
             "version": "v12.39.0",
@@ -1873,6 +1901,64 @@
             },
             "install-path": "../kkokk/poster"
         },
+        {
+            "name": "laravel/serializable-closure",
+            "version": "v1.3.7",
+            "version_normalized": "1.3.7.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/laravel/serializable-closure/v1.3.7/laravel-serializable-closure-v1.3.7.zip",
+                "reference": "4f48ade902b94323ca3be7646db16209ec76be3d",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.3|^8.0"
+            },
+            "require-dev": {
+                "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
+                "nesbot/carbon": "^2.61|^3.0",
+                "pestphp/pest": "^1.21.3",
+                "phpstan/phpstan": "^1.8.2",
+                "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0"
+            },
+            "time": "2024-11-14T18:34:49+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Laravel\\SerializableClosure\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                },
+                {
+                    "name": "Nuno Maduro",
+                    "email": "nuno@laravel.com"
+                }
+            ],
+            "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.",
+            "keywords": [
+                "closure",
+                "laravel",
+                "serializable"
+            ],
+            "support": {
+                "issues": "https://github.com/laravel/serializable-closure/issues",
+                "source": "https://github.com/laravel/serializable-closure"
+            },
+            "install-path": "../laravel/serializable-closure"
+        },
         {
             "name": "linfly/annotation",
             "version": "1.0.12",
@@ -2380,6 +2466,112 @@
             },
             "install-path": "../overtrue/easy-sms"
         },
+        {
+            "name": "php-di/invoker",
+            "version": "2.3.7",
+            "version_normalized": "2.3.7.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/php-di/invoker/2.3.7/php-di-invoker-2.3.7.zip",
+                "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "psr/container": "^1.0|^2.0"
+            },
+            "require-dev": {
+                "athletic/athletic": "~0.1.8",
+                "mnapoli/hard-mode": "~0.3.0",
+                "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12"
+            },
+            "time": "2025-08-30T10:22:22+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Invoker\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "Generic and extensible callable invoker",
+            "homepage": "https://github.com/PHP-DI/Invoker",
+            "keywords": [
+                "callable",
+                "dependency",
+                "dependency-injection",
+                "injection",
+                "invoke",
+                "invoker"
+            ],
+            "support": {
+                "issues": "https://github.com/PHP-DI/Invoker/issues",
+                "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7"
+            },
+            "install-path": "../php-di/invoker"
+        },
+        {
+            "name": "php-di/php-di",
+            "version": "7.0.0",
+            "version_normalized": "7.0.0.0",
+            "dist": {
+                "type": "zip",
+                "url": "https://mirrors.cloud.tencent.com/repository/composer/php-di/php-di/7.0.0/php-di-php-di-7.0.0.zip",
+                "reference": "f0ca9a0e0fb800974fcaf7b2f896ca1e840fd15b",
+                "shasum": ""
+            },
+            "require": {
+                "laravel/serializable-closure": "^1.0",
+                "php": ">=8.0",
+                "php-di/invoker": "^2.0",
+                "psr/container": "^1.1 || ^2.0"
+            },
+            "provide": {
+                "psr/container-implementation": "^1.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3",
+                "mnapoli/phpunit-easymock": "^1.3",
+                "ocramius/proxy-manager": "^2.11.2",
+                "phpunit/phpunit": "^9.5",
+                "vimeo/psalm": "^4.6"
+            },
+            "suggest": {
+                "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ^2.3)"
+            },
+            "time": "2023-01-12T14:08:11+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "src/functions.php"
+                ],
+                "psr-4": {
+                    "DI\\": "src/"
+                }
+            },
+            "license": [
+                "MIT"
+            ],
+            "description": "The dependency injection container for humans",
+            "homepage": "https://php-di.org/",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interop",
+                "dependency injection",
+                "di",
+                "ioc",
+                "psr11"
+            ],
+            "support": {
+                "issues": "https://github.com/PHP-DI/PHP-DI/issues",
+                "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.0"
+            },
+            "install-path": "../php-di/php-di"
+        },
         {
             "name": "phpoffice/phpspreadsheet",
             "version": "5.2.0",

+ 39 - 2
vendor/composer/installed.php

@@ -3,7 +3,7 @@
         'name' => 'workerman/webman',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '30c96d0f94751c8e0c1e1703781aee519213b2f4',
+        'reference' => 'e8bf7c27fd47cc24b0cd339dcd51e296dae18ef2',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -187,6 +187,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'hzdad/codecheck' => array(
+            'pretty_version' => 'v1.0',
+            'version' => '1.0.0.0',
+            'reference' => '929c7119824e9c82534ddaccdcce4971258044e3',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../hzdad/codecheck',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'illuminate/bus' => array(
             'pretty_version' => 'v12.39.0',
             'version' => '12.39.0.0',
@@ -304,6 +313,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'laravel/serializable-closure' => array(
+            'pretty_version' => 'v1.3.7',
+            'version' => '1.3.7.0',
+            'reference' => '4f48ade902b94323ca3be7646db16209ec76be3d',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../laravel/serializable-closure',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'linfly/annotation' => array(
             'pretty_version' => '1.0.12',
             'version' => '1.0.12.0',
@@ -385,6 +403,24 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'php-di/invoker' => array(
+            'pretty_version' => '2.3.7',
+            'version' => '2.3.7.0',
+            'reference' => '3c1ddfdef181431fbc4be83378f6d036d59e81e1',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../php-di/invoker',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'php-di/php-di' => array(
+            'pretty_version' => '7.0.0',
+            'version' => '7.0.0.0',
+            'reference' => 'f0ca9a0e0fb800974fcaf7b2f896ca1e840fd15b',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../php-di/php-di',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'phpoffice/phpspreadsheet' => array(
             'pretty_version' => '5.2.0',
             'version' => '5.2.0.0',
@@ -440,6 +476,7 @@
             'dev_requirement' => false,
             'provided' => array(
                 0 => '1.1|2.0',
+                1 => '^1.0',
             ),
         ),
         'psr/http-client' => array(
@@ -878,7 +915,7 @@
         'workerman/webman' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '30c96d0f94751c8e0c1e1703781aee519213b2f4',
+            'reference' => 'e8bf7c27fd47cc24b0cd339dcd51e296dae18ef2',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),