瀏覽代碼

Merge branch 'main' of http://192.168.0.80:3000/aexiaoliou/project-manager

文毅 1 年之前
父節點
當前提交
7f5b29bcbd
共有 45 個文件被更改,包括 1725 次插入2030 次删除
  1. 2 1
      api/.gitignore
  2. 14 6
      api/app/admin/controller/Admin.php
  3. 1 3
      api/app/admin/controller/Base.php
  4. 13 2
      api/app/admin/controller/BaseAuthorized.php
  5. 1 1
      api/app/admin/controller/Login.php
  6. 31 3
      api/app/admin/controller/Project.php
  7. 16 14
      api/app/admin/controller/Role.php
  8. 5 0
      api/app/admin/controller/Test.php
  9. 13 4
      api/app/admin/controller/Upload.php
  10. 1 0
      api/app/admin/middleware/CheckPermissionAttr.php
  11. 4 0
      api/app/common.php
  12. 2 1
      api/app/common/model/Contract.php
  13. 11 2
      api/app/common/model/Project.php
  14. 1 0
      api/app/common/model/ProjectSchedule.php
  15. 16 29
      api/app/common/model/Role.php
  16. 27 2
      api/app/common/service/ContractService.php
  17. 31 0
      api/app/common/service/FileService.php
  18. 11 1
      api/app/common/service/ProjectScheduleService.php
  19. 8 5
      api/app/common/service/ProjectService.php
  20. 99 0
      api/app/common/service/RoleService.php
  21. 13 0
      api/app/common/service/Service.php
  22. 26 25
      h5/package.json
  23. 818 568
      h5/pnpm-lock.yaml
  24. 84 69
      h5/src/App.vue
  25. 2 3
      h5/src/api/Urls.ts
  26. 103 0
      h5/src/api/role/index.ts
  27. 0 38
      h5/src/api/role/role.ts
  28. 14 0
      h5/src/components/role/code.tsx
  29. 65 0
      h5/src/components/role/codes.vue
  30. 45 0
      h5/src/components/role/edit.vue
  31. 5 5
      h5/src/router/route.ts
  32. 8 0
      h5/src/types/shime-vue.d.ts
  33. 5 0
      h5/src/utils/component/suspense.tsx
  34. 53 34
      h5/src/utils/net/Http.ts
  35. 0 1
      h5/src/utils/request.ts
  36. 3 0
      h5/src/utils/use/useDialog.ts
  37. 163 0
      h5/src/views/admin/role/index.vue
  38. 0 0
      h5/src/views/admin/role/role.ts
  39. 0 295
      h5/src/views/admin/roleManage/edit.vue
  40. 0 255
      h5/src/views/admin/roleManage/index.vue
  41. 0 295
      h5/src/views/underlying/roleManage/edit.vue
  42. 0 255
      h5/src/views/underlying/roleManage/index.vue
  43. 0 107
      h5/src/views/underlying/roleManage/role.ts
  44. 3 2
      h5/tsconfig.json
  45. 8 4
      h5/vite.config.ts

+ 2 - 1
api/.gitignore

@@ -1,4 +1,5 @@
 /.idea
 /vendor
 *.log
-.env
+.env
+public/storage

+ 14 - 6
api/app/admin/controller/Admin.php

@@ -1,6 +1,8 @@
 <?php
 
 namespace app\admin\controller;
+use app\common\model\Admin as AdminModel;
+use app\common\util\Result;
 
 class Admin extends BaseAuthorized
 {
@@ -13,6 +15,12 @@ class Admin extends BaseAuthorized
         return $this->success($result);
     }
 
+    public function fullList()
+    {
+        $list = (new AdminModel)->select();
+        return Result::rest($list);
+    }
+
     public function list()
     {
         //第1段:校验输入
@@ -22,7 +30,7 @@ class Admin extends BaseAuthorized
         $listRow = input("pageSize", 20);
         $keyword = input("keyword", "");
         //第2段:执行业务
-        $res = \app\common\model\Admin::getList($keyword, $listRow);
+        $res = AdminModel::getList($keyword, $listRow);
         //第3段:格式化输出
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
@@ -44,7 +52,7 @@ class Admin extends BaseAuthorized
         ];
         $this->autoValid($rules, $param);
         //第2段:执行业务
-        $res = \app\common\model\Admin::add($param["name"], $param["password"], $param["phone"], $param["role_id"], $param["valid"]);
+        $res = AdminModel::add($param["name"], $param["password"], $param["phone"], $param["role_id"], $param["valid"]);
         //第3段:格式化输出
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
@@ -65,7 +73,7 @@ class Admin extends BaseAuthorized
         ];
         $this->autoValid($rules, $param);
         //第2段:执行业务
-        $res = \app\common\model\Admin::edit($param["id"], $param["phone"], $param["role_id"], $param["valid"]);
+        $res = AdminModel::edit($param["id"], $param["phone"], $param["role_id"], $param["valid"]);
         //第3段:格式化输出
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
@@ -83,7 +91,7 @@ class Admin extends BaseAuthorized
             'ids|删除项' => 'require',
         ];
         $this->autoValid($rules, $param);
-        $res = \app\common\model\Admin::del($param["ids"]);
+        $res = AdminModel::del($param["ids"]);
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }
@@ -97,7 +105,7 @@ class Admin extends BaseAuthorized
             'id|id' => 'require',
         ];
         $this->autoValid($rules, $param);
-        $admin = \app\common\model\Admin::with(['role'])->find($param["id"]);
+        $admin = AdminModel::with(['role'])->find($param["id"]);
         if (!$admin) {
             $this->error("记录未找到");
         }
@@ -112,7 +120,7 @@ class Admin extends BaseAuthorized
             'password|密码' => 'require',
         ];
         $this->autoValid($rules, $param);
-        $res = \app\common\model\Admin::resetPwd($param["id"], $param["password"]);
+        $res = AdminModel::resetPwd($param["id"], $param["password"]);
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }

+ 1 - 3
api/app/admin/controller/Base.php

@@ -19,8 +19,6 @@ use think\exception\HttpResponseException;
 #[Middleware([WriteLog::class])]
 class Base extends BaseController
 {
-    protected $middleware = [WriteLog::class];
-
     protected $checkTokenOpen = false; //是否校验token
     protected $checkApiSignOpen = false; //是否校验签名
     public $admin; //管理员
@@ -53,7 +51,7 @@ class Base extends BaseController
             //from url
             $token = input("token");
         }
-        return Result::rest($token);
+        return $token;
     }
 
     /**

+ 13 - 2
api/app/admin/controller/BaseAuthorized.php

@@ -3,8 +3,9 @@
 
 namespace app\admin\controller;
 
-use app\middleware\AutoResult;
 use app\common\middleware\WriteLog;
+use app\common\service\FileService;
+use app\common\service\RoleService;
 use app\common\service\ProjectService;
 use app\common\service\ContractService;
 use app\common\exception\CatchException;
@@ -19,7 +20,7 @@ use app\common\service\ProjectScheduleService;
  */
 class BaseAuthorized extends Base
 {
-    protected $middleware = [CheckPermissionAttr::class, AutoResult::class, WriteLog::class];
+    protected $middleware = [CheckPermissionAttr::class, WriteLog::class];
     
     protected $checkTokenOpen = true;
 
@@ -40,4 +41,14 @@ class BaseAuthorized extends Base
     {
         return (new ContractService($this->app))->exceptionClass(CatchException::class);
     }
+
+    protected function FileService(): FileService
+    {
+        return (new FileService($this->app))->exceptionClass(CatchException::class);
+    }
+
+    protected function RoleService(): RoleService
+    {
+        return (new RoleService($this->app))->exceptionClass(CatchException::class);
+    }
 }

+ 1 - 1
api/app/admin/controller/Login.php

@@ -16,7 +16,7 @@ class Login extends Base
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }
-        return $res["data"];
+        return $this->success($res["data"]);
     }
 
 

+ 31 - 3
api/app/admin/controller/Project.php

@@ -10,7 +10,7 @@ use think\annotation\route\Post;
 
 #[Permission('project')]
 #[Group('project')]
-class ProjectController extends BaseAuthorized
+class Project extends BaseAuthorized
 {
     /*
      * 基础接口 
@@ -76,9 +76,30 @@ class ProjectController extends BaseAuthorized
         return Result::rest($res);
     }
 
+    #[Post('schedule/update')]
+    public function updateSchedule()
+    {
+        $res = $this->ProjectScheduleService()->update();
+        return Result::rest($res);
+    }
+
+    #[Post('schedule/delete')]
+    public function deleteSchedule()
+    {
+        $res = $this->ProjectScheduleService()->delete();
+        return Result::rest($res);
+    }
+
+
     /*
-    * 合同相关接口
-    */
+     * 合同相关接口
+     */
+    #[Post('contract/page')]
+    public function pageContranct()
+    {
+        $res = $this->ContractService()->page();
+        return Result::rest($res);        
+    }
 
     #[Post('contract/create')]
     public function createContract()
@@ -94,4 +115,11 @@ class ProjectController extends BaseAuthorized
         return Result::rest($res);
     }
 
+    #[Post('contract/delete')]
+    public function deleteContract()
+    {
+        $res = $this->ContractService()->delete();
+        return Result::rest($res);
+    }
+
 }

+ 16 - 14
api/app/admin/controller/Role.php

@@ -2,25 +2,27 @@
 
 namespace app\admin\controller;
 use app\admin\attr\Permission;
+use app\common\util\Result;
 
 #[Permission('role')]
 class Role extends BaseAuthorized
 {
-    public function getList()
+    public function list()
     {
-        //第1段:校验输入
-        $param = request()->param();
-        $rules = [];
-        $this->autoValid($rules, $param);
-        $listRow = input("pageSize", 20);
-        $keyword = input("keyword", "");
-        //第2段:执行业务
-        $res = \app\common\model\Role::getList($keyword, $listRow);
-        //第3段:格式化输出
-        if ($res["code"] != 0) {
-            $this->error($res['msg'], $res["code"]);
-        }
-        return $res["data"];
+        $res = $this->RoleService()->list();
+        return Result::rest($res);
+    }
+
+    public function update()
+    {
+        $res = $this->RoleService()->update();
+        return Result::rest($res);
+    }
+
+    public function codes()
+    {
+        $res = $this->RoleService()->codes();
+        return Result::rest($res);
     }
 
 }

+ 5 - 0
api/app/admin/controller/Test.php

@@ -16,4 +16,9 @@ class Test extends Base
         return Db::execute('SELECT 1');
     }
 
+    public function vir()
+    {
+        return getVirRootDir();
+    }
+
 }

+ 13 - 4
api/app/admin/controller/Upload.php

@@ -2,16 +2,25 @@
 
 namespace app\admin\controller;
 
-use app\common\exception\CatchException;
-use app\common\service\FileService;
+use app\common\util\Result;
 
-class Upload extends Base
+class Upload extends BaseAuthorized
 {
     /**
      * 图片上传
      */
     public function img()
     {
-        return (new FileService($this->app))->exceptionClass(CatchException::class)->uploadImage('admin');
+        $res = $this->FileService()->uploadImage('adminImg');
+        return Result::rest($res);
+    }
+
+    /**
+     * 附件上传
+     */
+    public function attachment()
+    {
+        $res = $this->FileService()->uploadAttachment('adminContractAttachment');
+        return Result::rest($res);
     }
 }

+ 1 - 0
api/app/admin/middleware/CheckPermissionAttr.php

@@ -11,6 +11,7 @@ class CheckPermissionAttr
 {
     public function handle(Request $request, \Closure $next)
     {
+        return $next($request);
         // 通过依赖注入获取admin
         $admin = app(Admin::class);
         $role = $admin->role;

+ 4 - 0
api/app/common.php

@@ -43,6 +43,10 @@ if (!function_exists('getVirRootDir')) {
      */
     function getVirRootDir()
     {
+        if (isset($_SERVER['HTTP_X_ORIGINAL_URI'])) {
+            $url = $_SERVER['HTTP_X_ORIGINAL_URI'];
+            return preg_replace('/index\.php.*/m', '', $url);
+        }
         $url = $_SERVER['SCRIPT_NAME'];
         $url = substr($url, 0, strripos($url, "/"));
         return $url;

+ 2 - 1
api/app/common/model/Contract.php

@@ -16,6 +16,7 @@ class Contract extends Base
         'date'   => 'date',      // 合同签署日期
         'start_date'     => 'date',      // 合同开始日期
         'end_date'       => 'date',      // 合同结束日期
-        'amout'  => 'int',       // 合同金额,单位为分
+        'amount'  => 'int',       // 合同金额,单位为分
+        'attachment' => 'varchar', //附件
     ];
 }

+ 11 - 2
api/app/common/model/Project.php

@@ -30,7 +30,11 @@ class Project extends Base
         'maintain_start_date'    => 'date',      // 维护开始时间
         'maintain_end_date'      => 'date',      // 维护结束时间
         'pre_maintain_time'      => 'int',       // 约定维护周期,单位为天
-        'participants'   => 'json',      // 项目参与人员
+        'participants_id'   => 'json',      // 项目参与人员
+    ];
+
+    protected $type = [
+        'participants_id' => 'array'
     ];
 
     public function responsibilityPersonName()
@@ -45,6 +49,11 @@ class Project extends Base
 
     public function schedules()
     {
-        return $this->hasMany(ProjectSchedule::class);
+        return $this->hasMany(ProjectSchedule::class)
+            ->field('s.*')
+            ->field('a.real_name as updater')
+            ->alias('s')
+            ->order('s.start_date asc')
+            ->join('admin a', 'a.id = s.updater_id', 'LEFT');
     }
 }

+ 1 - 0
api/app/common/model/ProjectSchedule.php

@@ -39,5 +39,6 @@ class ProjectSchedule extends Base
         'going_project_status'   => 'varchar',   // 进行中项目状态
         'finish_project_status'  => 'varchar',   // 结束项目状态(如果勾选更新项目状态为必填)
         'status'         => 'varchar',   // "NOT_START"未开始 "GOING"进行中 "FINISH"完成 "SKIP"跳过
+        'updater_id'     => 'int'   // 更新人id
     ];
 }

+ 16 - 29
api/app/common/model/Role.php

@@ -2,37 +2,24 @@
 
 namespace app\common\model;
 
-/**
- * @property array $codes
- */
 class Role extends Base
 {
-    /**
-     * 获取分页列表
-     * @param $keyword
-     * @param $valid
-     * @param $listRow
-     * @param $field
-     * @return array|mixed
-     * @throws \think\db\exception\DbException
-     */
-    public static function getList($keyword = "", $valid = -1, $listRow = 20, $field = "*")
-    {
-        $where = [];
-        if ($keyword) {
-            $where[] = ["name", "like", "%" . $keyword . "%"];
-        }
-        if ($valid != -1) {
-            $where[] = ["valid", "=", $valid];
-        }
+    const CODE_SUPER_ADMIN = 'super_admin';
 
-        $list = Role::field($field)->where($where)->paginate($listRow);
-        return returnFormat(0, '', $list);
-    }
-
-    public function getCodesAttr($value, $data)
-    {
-        return explode(',', $data['codes']);
-    }
+    protected $schema = [
+        'id'     => 'int',       // id
+        'name'   => 'varchar',   // 名字
+        'codes'  => 'text',      // 权限代码集合
+        'codes_cn'       => 'text',      // 权限代码集合(中文)
+        'create_time'    => 'datetime',  // create_time
+        'update_time'    => 'datetime',  // update_time
+        'delete_time'    => 'datetime',  // delete_time
+        'valid'  => 'tinyint',   // 状态
+        'remark'         => 'varchar',   // 备注
+    ];
 
+    protected $type = [
+        'codes' => 'array',
+        'codes_cn' => 'array'
+    ];
 }

+ 27 - 2
api/app/common/service/ContractService.php

@@ -2,20 +2,45 @@
 
 namespace app\common\service;
 use app\common\model\Contract;
+use app\common\util\WhereBuilder;
 
 class ContractService extends Service
 {
-    public function create($param = [])
+    public function page($param = [])
     {
         $this->autoParams($param);
 
+        $project_id = $this->pg('project_id');
+
+        $where = WhereBuilder::builder()
+            ->eq('project_id', $project_id)
+            ->build();
+
+        return (new Contract)
+            ->where($where)
+            ->paginate($this->tp6Page());
+    }
+
+    public function create($param = [])
+    {
+        $param = $this->autoParams($param);
+
         return Contract::create($param);
     }
 
     public function update($param = [])
     {
-        $this->autoParams($param);
+        $param = $this->autoParams($param);
 
         return Contract::update($param);
     }
+
+    public function delete($param = [])
+    {
+        $this->autoParams($param);
+
+        $contract = $this->one(Contract::class);
+
+        return $contract->delete();
+    }
 }

+ 31 - 0
api/app/common/service/FileService.php

@@ -39,6 +39,37 @@ class FileService extends Service
     }
 
     /**
+     * 上传附件
+     * 本地运行如果无法写入图片可能是没有给public目录写权限
+     * 
+     * @param string $path 上传路径,默认为'default'
+     * @return array 上传后的图片路径
+     */
+    public function uploadAttachment($path = 'default')
+    {
+        // 获取表单上传文件
+        $files = request()->file();
+        // 验证上传文件格式和大小
+        $this->validate($files, Validate::rule(['file' => 'fileExt:pdf,doc,docx']));
+        $file = request()->file('file');
+        try {
+            // 保存上传文件到public目录下的$path目录中
+            $path = Filesystem::disk('public')->putFile($path, $file);
+        } catch (\Exception $e) {
+            throw $this->warpException($e, '上传图片失败:\n');
+        }
+
+        // 获取图片的url地址
+        $path = Request::domain() . getVirRootDir() . '/storage/' . $path;
+
+        return [
+            'path' => $path
+        ];
+    }
+
+
+
+    /**
      * 获取当前网站的域名地址
      * 
      * @return string 域名地址

+ 11 - 1
api/app/common/service/ProjectScheduleService.php

@@ -15,6 +15,16 @@ class ProjectScheduleService extends Service
 
     public function update($param = [])
     {
-        
+        $param = $this->autoParams($param);
+
+        return ProjectSchedule::update($param);
+    }
+
+    public function delete($param = [])
+    {
+        $param = $this->autoParams($param);
+        $schedule = $this->one(ProjectSchedule::class);
+
+        return $schedule->delete();
     }
 }

+ 8 - 5
api/app/common/service/ProjectService.php

@@ -12,16 +12,19 @@ class ProjectService extends Service
     {
         $this->autoParams($param);
 
-        $status = $this->pg('status');
+        $status = $this->array('status');
         $keyword = $this->pg('keyword');
         
         $where = WhereBuilder::builder()
-            ->like('keyword', $keyword)
-            ->in('status', $status)
+            ->like('p.name', $keyword)
+            ->in('p.status', $status)
             ->build();
 
-        return (new Project)
-            ->with(['contracts', 'schedules'])
+        return (new Project)->alias('p')
+            ->with(['schedules'])
+            ->field('p.*')
+            ->field('a.real_name as responsibility_person')
+            ->join('admin a', 'a.id = p.responsibility_person_id', 'LEFT')
             ->where($where)
             ->paginate($this->tp6Page());
     }

+ 99 - 0
api/app/common/service/RoleService.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace app\common\service;
+
+use app\common\model\Role;
+use app\common\service\Service;
+use think\facade\Cache;
+
+class RoleService extends Service
+{
+    public function list()
+    {
+        return (new Role)->select();
+    }
+
+    public function update($param = [])
+    {
+        $param = $this->autoParams($param);
+
+        return Role::update($param);
+    }
+
+    const CODE_CACHE_KEY = 'ROLE_CODE_CACHE';
+
+    public function codes()
+    {
+        // 从缓存获取之前生成好的值
+        $cache = Cache::get(self::CODE_CACHE_KEY);
+        if ($cache) {
+            return $cache;
+        }
+
+        $crud = function($parent, $name, $create = true, $read = true, $update = true, $delete = true) {
+            $codes = [];
+            if ($create) {
+                $codes[] = [
+                    'id' => "$parent.create",
+                    'lable' => "创建-$name"
+                ];
+            }
+            if ($read) {
+                $codes[] = [
+                    'id' => "$parent.read",
+                    'lable' => "读取-$name"
+                ];
+            }
+            if ($update) {
+                $codes[] = [
+                    'id' => "$parent.update",
+                    'lable' => "编辑-$name"
+                ];
+            }
+            if ($delete) {
+                $codes[] = [
+                    'id' => "$parent.delete",
+                    'lable' => "删除-$name"
+                ];
+            }
+
+            return $codes;
+        };
+
+        $codes = [
+            [
+                'id' => Role::CODE_SUPER_ADMIN,
+                'lable' => '超级管理员(所有权限)',
+            ],
+            [
+                'id' => 'admin',
+                'lable' => '人员管理',
+                'children' => $crud('admin', '人员管理')
+            ],
+            [
+                'id' => 'project',
+                'lable' => '项目',
+                'children' => [
+                    ...$crud('project', '项目'),
+                    [
+                        'id' => 'project.schedule',
+                        'lable' => '进程',
+                        'children' => $crud('project.schedule', '进程')
+                    ],
+                    [
+                        'id' => 'project.status',
+                        'lable' => '状态',
+                        'children' => $crud('project.status', '状态', delete: false)
+                    ],
+                    [
+                        'id' => 'project.contract',
+                        'lable' => '合同',
+                        'children' => $crud('project.contract', '合同')
+                    ]
+                ]
+            ]
+        ];
+        Cache::set(self::CODE_CACHE_KEY, $codes, 600);
+        return $codes;
+    }
+}

+ 13 - 0
api/app/common/service/Service.php

@@ -85,6 +85,19 @@ class Service extends ThinkService
         throw $this->exception("缺少参数 $desc");
     }
 
+    protected function array(...$index)
+    {
+        $arg = $this->pg(...$index);
+        if (is_null($arg)) {
+            $arg = [];
+        }
+        if (!is_array($arg)) {
+            $desc = implode('或', $index);
+            throw $this->exception("参数 $desc 必须为数组");
+        }
+        return $arg;
+    }
+
     /**
      * 获取主键
      *

+ 26 - 25
h5/package.json

@@ -14,53 +14,54 @@
 		"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
 	},
 	"dependencies": {
-		"@element-plus/icons-vue": "^2.0.10",
+		"@element-plus/icons-vue": "^2.1.0",
 		"@wangeditor/editor": "^5.1.23",
 		"@wangeditor/editor-for-vue": "^5.1.12",
 		"await-to-js": "^3.0.0",
-		"axios": "^1.2.1",
-		"countup.js": "^2.3.2",
+		"axios": "^1.4.0",
+		"countup.js": "^2.6.2",
 		"cropperjs": "^1.5.13",
-		"echarts": "^5.4.1",
+		"echarts": "^5.4.2",
 		"echarts-gl": "^2.0.9",
 		"echarts-wordcloud": "^2.1.0",
-		"element-plus": "^2.2.26",
-		"js-cookie": "^3.0.1",
+		"element-plus": "^2.3.7",
+		"js-cookie": "^3.0.5",
 		"js-md5": "^0.7.3",
-		"js-table2excel": "^1.0.3",
+		"js-table2excel": "^1.1.2",
 		"jsplumb": "^2.15.6",
+		"lodash": "^4.17.21",
 		"mitt": "^3.0.0",
 		"nprogress": "^0.2.0",
-		"pinia": "^2.0.28",
+		"pinia": "^2.1.4",
 		"print-js": "^1.6.0",
 		"qrcodejs2-fixes": "^0.0.2",
-		"qs": "^6.11.0",
+		"qs": "^6.11.2",
 		"screenfull": "^6.0.2",
 		"sortablejs": "^1.15.0",
 		"splitpanes": "^3.1.5",
-		"vue": "^3.2.45",
+		"vue": "^3.3.4",
 		"vue-clipboard3": "^2.0.0",
-		"vue-grid-layout": "^3.0.0-beta1",
+		"vue-grid-layout": "3.0.0-beta1",
 		"vue-i18n": "^9.2.2",
-		"vue-router": "^4.1.6",
+		"vue-router": "^4.2.2",
 		"vue-vuecmf-dialog": "^1.4.8"
 	},
 	"devDependencies": {
-		"@types/node": "^18.11.13",
+		"@types/lodash": "^4.14.195",
+		"@types/node": "^18.16.18",
 		"@types/nprogress": "^0.2.0",
-		"@types/sortablejs": "^1.15.0",
-		"@typescript-eslint/eslint-plugin": "^5.46.0",
-		"@typescript-eslint/parser": "^5.46.0",
-		"@vitejs/plugin-vue": "^4.0.0",
-		"@vue/compiler-sfc": "^3.2.45",
-		"eslint": "^8.29.0",
-		"eslint-plugin-vue": "^9.8.0",
-		"prettier": "^2.8.1",
-		"sass": "^1.56.2",
-		"typescript": "^4.9.4",
-		"vite": "^4.0.0",
+		"@types/sortablejs": "^1.15.1",
+		"@typescript-eslint/eslint-plugin": "^5.60.1",
+		"@typescript-eslint/parser": "^5.60.1",
+		"@vitejs/plugin-vue": "^4.2.3",
+		"@vitejs/plugin-vue-jsx": "^3.0.1",
+		"@vue/compiler-sfc": "^3.3.4",
+		"prettier": "^2.8.8",
+		"sass": "^1.63.6",
+		"typescript": "^4.9.5",
+		"vite": "^4.3.9",
 		"vite-plugin-vue-setup-extend": "^0.4.0",
-		"vue-eslint-parser": "^9.1.0"
+		"vue-eslint-parser": "^9.3.1"
 	},
 	"browserslist": [
 		"> 1%",

文件差異過大導致無法顯示
+ 818 - 568
h5/pnpm-lock.yaml


+ 84 - 69
h5/src/App.vue

@@ -1,93 +1,108 @@
 <template>
-	<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
-		<router-view v-show="themeConfig.lockScreenTime > 1" />
-		<LockScreen v-if="themeConfig.isLockScreen" />
-		<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
-		<CloseFull v-if="!themeConfig.isLockScreen" />
-		<!-- <Upgrade v-if="getVersion" /> -->
-	</el-config-provider>
+    <el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
+        <router-view v-show="themeConfig.lockScreenTime > 1" v-slot="{ Component }">
+            <template v-if="Component">
+                <Transition mode="out-in">
+                    <KeepAlive>
+                        <Suspense>
+                            <!-- 主要内容 -->
+                            <component :is="Component"></component>
+                            <!-- 加载中状态 -->
+                            <template #fallback>
+                                正在加载...
+                            </template>
+                        </Suspense>
+                    </KeepAlive>
+                </Transition>
+            </template>
+        </router-view>
+        <LockScreen v-if="themeConfig.isLockScreen" />
+        <Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
+        <CloseFull v-if="!themeConfig.isLockScreen" />
+        <!-- <Upgrade v-if="getVersion" /> -->
+    </el-config-provider>
 </template>
 
 <script setup lang="ts" name="app">
-import { defineAsyncComponent, computed, ref, onBeforeMount, onMounted, onUnmounted, nextTick, watch } from 'vue';
-import { useRoute } from 'vue-router';
-import { useI18n } from 'vue-i18n';
-import { storeToRefs } from 'pinia';
-import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
-import { useThemeConfig } from '/@/stores/themeConfig';
-import other from '/@/utils/other';
-import { Local, Session } from '/@/utils/storage';
-import mittBus from '/@/utils/mitt';
-import setIntroduction from '/@/utils/setIconfont';
+import { defineAsyncComponent, computed, ref, onBeforeMount, onMounted, onUnmounted, nextTick, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { useI18n } from 'vue-i18n'
+import { storeToRefs } from 'pinia'
+import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'
+import { useThemeConfig } from '/@/stores/themeConfig'
+import other from '/@/utils/other'
+import { Local, Session } from '/@/utils/storage'
+import mittBus from '/@/utils/mitt'
+import setIntroduction from '/@/utils/setIconfont'
 
 // 引入组件
-const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
-const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
-const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
-const Upgrade = defineAsyncComponent(() => import('/@/layout/upgrade/index.vue'));
+const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'))
+const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'))
+const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'))
+const Upgrade = defineAsyncComponent(() => import('/@/layout/upgrade/index.vue'))
 
 // 定义变量内容
-const { messages, locale } = useI18n();
-const setingsRef = ref();
-const route = useRoute();
-const stores = useTagsViewRoutes();
-const storesThemeConfig = useThemeConfig();
-const { themeConfig } = storeToRefs(storesThemeConfig);
+const { messages, locale } = useI18n()
+const setingsRef = ref()
+const route = useRoute()
+const stores = useTagsViewRoutes()
+const storesThemeConfig = useThemeConfig()
+const { themeConfig } = storeToRefs(storesThemeConfig)
 
 // 获取版本号
 const getVersion = computed(() => {
-	let isVersion = false;
-	if (route.path !== '/login') {
-		// @ts-ignore
-		if ((Local.get('version') && Local.get('version') !== __VERSION__) || !Local.get('version')) isVersion = true;
-	}
-	return isVersion;
-});
+    let isVersion = false
+    if (route.path !== '/login') {
+        // @ts-ignore
+        if ((Local.get('version') && Local.get('version') !== __VERSION__) || !Local.get('version')) isVersion = true
+    }
+    return isVersion
+})
 // 获取全局组件大小
 const getGlobalComponentSize = computed(() => {
-	return other.globalComponentSize();
-});
+    return other.globalComponentSize()
+})
 // 获取全局 i18n
 const getGlobalI18n = computed(() => {
-	return messages.value[locale.value];
-});
+    return messages.value[locale.value]
+})
 // 设置初始化,防止刷新时恢复默认
 onBeforeMount(() => {
-	// 设置批量第三方 icon 图标
-	setIntroduction.cssCdn();
-	// 设置批量第三方 js
-	setIntroduction.jsCdn();
-});
+    // 设置批量第三方 icon 图标
+    setIntroduction.cssCdn()
+    // 设置批量第三方 js
+    setIntroduction.jsCdn()
+})
 // 页面加载时
 onMounted(() => {
-	nextTick(() => {
-		// 监听布局配'置弹窗点击打开
-		mittBus.on('openSetingsDrawer', () => {
-			setingsRef.value.openDrawer();
-		});
-		// 获取缓存中的布局配置
-		if (Local.get('themeConfig')) {
-			storesThemeConfig.setThemeConfig({ themeConfig: Local.get('themeConfig') });
-			document.documentElement.style.cssText = Local.get('themeConfigStyle');
-		}
-		// 获取缓存中的全屏配置
-		if (Session.get('isTagsViewCurrenFull')) {
-			stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'));
-		}
-	});
-});
+    nextTick(() => {
+        // 监听布局配'置弹窗点击打开
+        mittBus.on('openSetingsDrawer', () => {
+            setingsRef.value.openDrawer()
+        })
+        // 获取缓存中的布局配置
+        if (Local.get('themeConfig')) {
+            storesThemeConfig.setThemeConfig({ themeConfig: Local.get('themeConfig') })
+            document.documentElement.style.cssText = Local.get('themeConfigStyle')
+        }
+        // 获取缓存中的全屏配置
+        if (Session.get('isTagsViewCurrenFull')) {
+            stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'))
+        }
+    })
+})
 // 页面销毁时,关闭监听布局配置/i18n监听
 onUnmounted(() => {
-	mittBus.off('openSetingsDrawer', () => {});
-});
+    mittBus.off('openSetingsDrawer', () => { })
+})
 // 监听路由的变化,设置网站标题
 watch(
-	() => route.path,
-	() => {
-		other.useTitle();
-	},
-	{
-		deep: true,
-	}
-);
+    () => route.path,
+    () => {
+        other.useTitle()
+    },
+    {
+        deep: true,
+    }
+)
 </script>

+ 2 - 3
h5/src/api/Urls.ts

@@ -100,10 +100,9 @@ const Urls = {
 	},
 	// 角色权限
 	role: {
-		init: 'admin/role/init', //初始化
 		list: 'admin/role/list', //列表
-		detail: 'admin/role/detail', //详情
-		edit: 'admin/role/edit', //更新
+        codes: '/admin/role/codes', // 权限列表
+		update: 'admin/role/update', //更新
 		add: 'admin/role/add', //添加
 		del: 'admin/role/del', //删除/批量删除
 	},

+ 103 - 0
h5/src/api/role/index.ts

@@ -0,0 +1,103 @@
+import Http from '../../utils/net/Http'
+import Urls from '../Urls'
+import { ElMessage } from 'element-plus'
+import { ref } from 'vue'
+
+const role = Urls.role
+/**
+ * role,角色表
+ */
+export interface Role {
+    /**
+     * 权限代码集合
+     */
+    codes?: string
+    /**
+     * 权限代码集合(中文)
+     */
+    codes_cn?: string
+    /**
+     * 主键
+     */
+    id: number
+    /**
+     * 名字
+     */
+    name: string
+    /**
+     * 备注
+     */
+    remark: string
+    /**
+     * 状态
+     */
+    valid: number
+    create_time?: Date | string
+    update_time?: Date | string
+    delete_time?: Date | string
+}
+
+export const newRole = (): Role => {
+    return {
+        id: 0,
+        name: '',
+        remark: '',
+        valid: 1
+    }
+}
+
+export interface CodeTree {
+    code: string
+    cn: string
+    children?: CodeTree[]
+}
+/**
+ * 角色
+ * @returns 角色列表
+ */
+export const list = async () => {
+    const res = await Http.get(role.list)
+    return res
+}
+/**
+ * 异步组件初始化
+ * @returns vue ref role
+ */
+export const init = async () => {
+    const roles = ref(null)
+    const res = await list()
+    roles.value = res.data
+    return roles
+}
+/**
+ * 创建角色
+ * @param param 创建参数
+ * @returns 创建后对象
+ */
+export const create = async (param: object) => {
+    const res = await Http.post(role.add, param)
+    return res
+}
+/**
+ * 更新角色
+ * @param param 更新对象
+ * @returns 更新后对象
+ */
+export const update = async (param: any) => {
+    const res = await Http.post(role.update, param)
+    return res
+}
+/**
+ * 删除
+ * @param id id
+ * @returns res
+ */
+export const del = async (id: number[]) => {
+    const res = await Http.post(role.del, { id })
+    return res
+}
+
+export const codes = async () => {
+    const res = await Http.get(role.codes)
+    return res
+}

+ 0 - 38
h5/src/api/role/role.ts

@@ -1,38 +0,0 @@
-import Http from "../../utils/net/Http";
-import Urls from "../Urls";
-const Role = {
-    async init() {
-        let url = Urls.role.init;
-        let param: object = {};
-        let res = await Http.post(url, param);
-        return res;
-    },
-    async list(param: object) {
-        let url = Urls.role.list;
-        let res = await Http.post(url, param);
-        return res;
-    },
-    async add(param: object) {
-        let url = Urls.role.add;
-        let res = await Http.post(url, param);
-        return res;
-    },
-    async edit(param: object) {
-        let url = Urls.role.edit;
-        let res = await Http.post(url, param);
-        return res;
-    },
-    async del(ids: number | string | object) {
-        let url = Urls.role.del;
-        let param: object = { ids };
-        let res = await Http.post(url, param);
-        return res;
-    },
-    async detail(id: number | string | object) {
-        let url = Urls.role.detail;
-        let param: object = { id };
-        let res = await Http.post(url, param);
-        return res;
-    },
-};
-export default Role;

+ 14 - 0
h5/src/components/role/code.tsx

@@ -0,0 +1,14 @@
+import { update } from '/@/api/role'
+import type { Role } from '/@/api/role'
+import { defineProps } from 'vue';
+
+const props = defineProps<{
+    role: Role
+}>();
+
+export default {
+    props: props,
+    setup() {
+        
+    }
+}

+ 65 - 0
h5/src/components/role/codes.vue

@@ -0,0 +1,65 @@
+<template>
+    <el-dialog :modelValue="modelValue" @close="$emit('update:modelValue', false)" title="编辑权限">
+        <el-tree-v2 ref="tree" :data="codes" :props="treeProps" :default-checked-keys="role?.codes" show-checkbox :height="500">
+            <template #default="{ node }">
+                <span>{{ node.data.lable }}</span>
+            </template>
+        </el-tree-v2>
+        <template #footer>
+            <el-button type="default" @click="$emit('update:modelValue', false)">取消</el-button>
+            <el-button v-loading="submitLoading" type="primary" @click="submitForm()">提交</el-button>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { update, codes as getCodes } from '/@/api/role'
+import type { Role } from '/@/api/role'
+import { ref, onMounted } from 'vue'
+import type { ElTreeV2 } from 'element-plus'
+import { clone } from 'lodash'
+import { ElMessage } from 'element-plus'
+
+const { modelValue, role } = defineProps<{
+    modelValue: boolean,
+    role?: Role
+}>()
+const emit = defineEmits(['update:modelValue'])
+
+const codes = ref()
+
+const tree = ref()
+
+const submitLoading = ref(false)
+
+const treeProps = {
+    value: 'id',
+    label: 'label',
+    children: 'children',
+}
+
+onMounted(async () => {
+    codes.value = (await getCodes()).data
+})
+
+const submitForm = async () => {
+    const checkedCodes = tree.value?.getCheckedNodes(true).map(node => node.lable)
+    console.log("🚀 ~ file: edit.vue:43 ~ submitForm ~ checkedCodes:", checkedCodes)
+    const checkedKeys = tree.value?.getCheckedKeys()
+
+    const updateRole = clone(role) as Role
+    updateRole.codes = checkedKeys
+    updateRole.codes_cn = checkedCodes
+
+    submitLoading.value = true
+    const result = await update(updateRole)
+    if (result.code != 0) {
+        return
+    }
+    submitLoading.value = false
+    ElMessage({ message: '更新成功' })
+
+    emit('update:modelValue', false)
+}
+
+</script>

+ 45 - 0
h5/src/components/role/edit.vue

@@ -0,0 +1,45 @@
+<template>
+    <el-dialog :modelValue="modelValue" @close="$emit('update:modelValue', false)" title="编辑权限">
+        <el-form :model="role" lable-width="120px">
+            <el-form-item lable="名字">
+                <el-input v-model="role.name" />
+            </el-form-item>
+            <el-form-item lable="是否启用">
+                <el-switch v-model="role.valid" :active-value="1" :inactive-value="0" />
+            </el-form-item>
+            <el-form-item lable="备注">
+                <el-input v-model="role.remark" type="textarea" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button type="default" @click="$emit('update:modelValue', false)">取消</el-button>
+            <el-button v-loading="submitLoading" type="primary" @click="submitForm()">提交</el-button>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { update } from '/@/api/role'
+import type { Role } from '/@/api/role'
+import { ElMessage } from 'element-plus'
+
+const { modelValue, role } = defineProps<{
+    modelValue: boolean,
+    role: Role
+}>()
+const emit = defineEmits(['update:modelValue'])
+const submitLoading = ref(false)
+
+const submitForm = async () => {
+    submitLoading.value = true
+    const result = await update(role)
+    if (result.code != 0) {
+        return
+    }
+    submitLoading.value = false
+    ElMessage({ message: '更新成功' })
+
+    emit('update:modelValue', false)
+}
+</script>

+ 5 - 5
h5/src/router/route.ts

@@ -1,4 +1,4 @@
-import { RouteRecordRaw } from 'vue-router';
+import { RouteRecordRaw } from 'vue-router'
 
 /**
  * 建议:路由 path 路径与文件夹名称相同,找文件可浏览器地址找,方便定位文件位置
@@ -95,11 +95,11 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
 						},
 					},
 					{
-						path: '/admin/adminrole',
-						name: 'adminRole',
-						component: () => import('/@/views/admin/admin/index.vue'),
+						path: '/admin/role',
+						name: 'role',
+						component: () => import('/@/views/admin/role/index.vue'),
 						meta: {
-							title: 'message.router.adminRole', //角色管理
+                            title: '角色管理', // 角色管理
 							isLink: '',
 							isHide: false,
 							isKeepAlive: true,

+ 8 - 0
h5/src/types/shime-vue.d.ts

@@ -0,0 +1,8 @@
+/**
+ * JSX支持
+ */
+declare module '*.vue' {
+	import { ComponentOptions } from 'vue';
+	const component: ComponentOptions;
+	export default component;
+}

+ 5 - 0
h5/src/utils/component/suspense.tsx

@@ -0,0 +1,5 @@
+import { Suspense } from "vue"
+
+export const withSuspense = (component) => {
+    return () => <Suspense>{component}</Suspense>
+}

+ 53 - 34
h5/src/utils/net/Http.ts

@@ -1,37 +1,56 @@
-import Sign from './Sign.js';
-const tagInfo = '/utils/net/Http.ts';
-import to from 'await-to-js';
-import request from '../request.ts';
-import { Session } from '/@/utils/storage';
+import Sign from './Sign.js'
+const tagInfo = '/utils/net/Http'
+import to from 'await-to-js'
+import request from '../request'
+import { Session } from '/@/utils/storage'
+import { AxiosRequestConfig } from 'axios'
+import { ElMessage } from 'element-plus'
+
+
 const Http = {
-	async post(url: string, param: object = {}): Promise<any> {
-		console.log(tagInfo, 'get param', param);
+    async post(url: string, param: object = {}, axiosConfig: AxiosRequestConfig = {}, { useNotZeroCodeCheck = true } = {}): Promise<any> {
+        axiosConfig.headers = { ...axiosConfig.headers, token: Session.get('token') }
+
+        // 检查http错误
+        let result = await request.post(url, param, axiosConfig)
+            .catch((err) => {
+                return { code: 999, data: err, msg: '请求失败' }
+            })
+
+        // 检查业务错误
+        if (useNotZeroCodeCheck && result?.code != 0) {
+            ElMessage({
+                message: result?.msg,
+            })
+        }
+        return result
+    },
+    async get(url: string, param: object = {}, { useNotZeroCodeCheck = true } = {}): Promise<any> {
+        //param = sign(param);
+        let [err, result] = await to(request.get(url, { params: this.combineData(param) }))
+        // 检查http错误
+        if (err) {
+            console.log('err', err)
+            return { code: 999, data: err, msg: '请求失败' }
+        }
 
-		let response = await request.post(url, param, { headers: { token: Session.get('token') } }).catch((err) => {
-			return { code: 999, data: err, msg: '请求失败' };
-		});
-		return response;
-	},
-	async get(url: string, param: object = {}): Promise<any> {
-		//param = sign(param);
-		let [err, res] = await to(request.get(url, { params: this.combineData(param) }));
-		if (err) {
-			console.log('err', err);
-			return { code: 999, data: err, msg: '请求失败' };
-		}
-		return res;
-	},
-	combineData(param: any = {}): any {
-		// 在请求发送之前做一些处理
-		// 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
-		// config.headers['X-Token'] = token;
-		if (Session.get('token')) {
-			param.token = `${Session.get('token')}`;
-		}
-		// param = Sign(param);
-		console.log(tagInfo, 'http:param', param);
-		return param;
-	},
-};
+        // 检查业务错误
+        if (useNotZeroCodeCheck && result?.code != 0) {
+            ElMessage({
+                message: result?.msg,
+            })
+        }
+        return result
+    },
+    combineData(param: any = {}): any {
+        // 在请求发送之前做一些处理
+        // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
+        // config.headers['X-Token'] = token;
+        if (Session.get('token')) {
+            param.token = `${Session.get('token')}`
+        }
+        return param
+    },
+}
 
-export default Http;
+export default Http

+ 0 - 1
h5/src/utils/request.ts

@@ -42,7 +42,6 @@ service.interceptors.response.use(
 	(response) => {
 		// 对响应数据做点什么
 		const res = response.data;
-		console.log('axios res:', response)
 		//console.log("service.interceptors.response", response, res);
 		if (res.code && res.code !== 0) {
 			// 刷新页面

+ 3 - 0
h5/src/utils/use/useDialog.ts

@@ -0,0 +1,3 @@
+export const useDialog = () => {
+    
+}

+ 163 - 0
h5/src/views/admin/role/index.vue

@@ -0,0 +1,163 @@
+<template>
+    <Codes v-model="showCodesEditForm" :role="editRole" />
+    <Edit v-model="showRoleEditForm" :role="editRole" />
+    <div>
+        <el-card class="box-card" v-loading="wholeLoading" element-loading-text="Loading..." style="height: 600px">
+            <template #header>
+                <div class="card-header">
+                    <span>权限管理</span>
+                    <div>
+                        <el-button type="default" @click="reflush()">刷新列表</el-button>
+                        <el-button type="primary" @click="create()">新增角色</el-button>
+                    </div>
+                </div>
+            </template>
+            <el-auto-resizer>
+                <template #default="{ height, width }">
+                    <el-table-v2 :data="data" :columns="columns" :width="width" :height="600" fixed />
+                </template>
+            </el-auto-resizer>
+        </el-card>
+    </div>
+</template>
+
+<script lang="ts" setup name="underlyingRoleManage">
+import { ref, reactive, onMounted, h } from 'vue'
+import { ElSwitch, ElTag, ElMessage, ElMessageBox, ElButton, TableV2FixedDir, roleTypes } from 'element-plus'
+import type { Column } from 'element-plus'
+import { throttle } from 'lodash'
+import { init, update, newRole } from '/@/api/role'
+import type { Role } from '/@/api/role'
+import Codes from '/@/components/role/codes.vue'
+import Edit from '/@/components/role/edit.vue'
+
+/**
+ * 表格数据
+ */
+const data = await init()
+/**
+ * 整个页面的loading
+ */
+const wholeLoading = ref(false)
+/**
+ * 编辑权限表单的显示控制
+ */
+const showCodesEditForm = ref(false)
+/**
+ * 编辑角色表单的显示控制
+ */
+const showRoleEditForm = ref(false)
+/**
+ * 需要编辑的角色
+ */
+const editRole = ref<Role>(newRole())
+
+/**
+ * 虚拟表格列信息
+ */
+const columns: Column<any>[] = [
+    {
+        key: 'name',
+        title: '角色名',
+        dataKey: 'name',
+        width: 150,
+    },
+    {
+        key: 'codes_cn',
+        title: '权限值',
+        dataKey: 'codes_cn',
+        width: 400,
+        cellRenderer: ({ cellData: codes_cn }) => h(
+            'div',
+            codes_cn?.map(cn => h(ElTag, { style: { 'margin-right': '5px' } }, cn))
+        ),
+    },
+    {
+        key: 'remark',
+        title: '备注',
+        dataKey: 'remark',
+        width: 300,
+    },
+    {
+        key: 'valid',
+        title: '是否启用',
+        dataKey: 'valid',
+        width: 100,
+        cellRenderer: ({ cellData: valid }) => h(
+            ElTag,
+            { effect: valid ? 'dark' : 'plain' }, valid ? '已启用' : '已禁用'
+        ),
+    },
+    {
+        key: 'op',
+        title: '操作',
+        width: 400,
+        fixed: TableV2FixedDir.RIGHT,
+        flexGrow: 1,
+        cellRenderer: ({ rowData: row }) =>
+            h('div', [
+                // 启用禁用
+                h(
+                    ElButton,
+                    {
+                        type: row.valid ? 'danger' : 'success',
+                        onClick: throttle(() => {
+                            row.valid = !row.valid
+                            update(row)
+                        }),
+                    },
+                    row.valid ? '禁用' : '启用'
+                ),
+                // 打开权限表单
+                h(
+                    ElButton,
+                    {
+                        type: 'primary',
+                        onClick: throttle(() => {
+                            showCodesEditForm.value = true
+                            editRole.value = row
+                        }),
+                    },
+                    '权限'
+                ),
+                h(
+                    ElButton,
+                    {
+                        type: 'primary',
+                        onClick: throttle(() => {
+                            showRoleEditForm.value = true
+                            editRole.value = row
+                        }),
+                    },
+                    '编辑'
+                ),
+            ]),
+    },
+]
+
+/**
+ * 创建
+ */
+const create = throttle(() => {
+    showRoleEditForm.value = true
+    editRole.value = newRole()
+})
+/**
+ * 刷新
+ */
+const reflush = () => { }
+
+</script>
+
+<style lang="scss" scoped>
+.box-card {
+    margin: 10px;
+}
+
+.card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    overflow-x: auto;
+}
+</style>

h5/src/views/admin/roleManage/role.ts → h5/src/views/admin/role/role.ts


+ 0 - 295
h5/src/views/admin/roleManage/edit.vue

@@ -1,295 +0,0 @@
-<template>
-	<div class="system-dept-dialog-container">
-		<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
-			<el-form ref="deptDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
-				<el-row :gutter="35">
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="权限名称">
-							<el-input v-model="state.ruleForm.name" placeholder="请输入权限名称" clearable></el-input>
-						</el-form-item>
-					</el-col>
-
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="备注说明">
-							<el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" clearable></el-input>
-						</el-form-item>
-					</el-col>
-
-					<!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="角色状态">
-							<el-switch v-model="state.status" inline-prompt active-text="启用" inactive-text="禁用"></el-switch>
-						</el-form-item>
-					</el-col> -->
-
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="权限状态" :rules="[{ required: true, message: '权限状态不能为空' }]">
-							<el-radio-group v-model="state.ruleForm.valid">
-								<el-radio :label="1">启用</el-radio>
-								<el-radio :label="0">禁用</el-radio>
-							</el-radio-group>
-						</el-form-item>
-					</el-col>
-
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
-						<el-form-item label="菜单权限">
-							<!-- :default-expanded-keys="state.ruleForm.codes" -->
-							<el-tree
-								show-checkbox
-							 	ref="treeRef"
-								node-key="id"
-								:data="state.role_list"
-								:props="state.menuProps"
-								:default-checked-keys="state.ruleForm.code"
-								@check-change="getCheckedNodes()"
-								class="menu-data-tree"
-							/>
-						</el-form-item>
-					</el-col>
-				</el-row>
-			</el-form>
-			<template #footer>
-				<span class="dialog-footer">
-					<el-button @click="onCancel" size="default">取 消</el-button>
-					<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
-				</span>
-			</template>
-		</el-dialog>
-	</div>
-</template>
-
-<script setup lang="ts" name="underlyingProductManageEdit">
-import { reactive, ref } from 'vue';
-import { ElMessage, ElTree } from 'element-plus';
-import type Node from 'element-plus/es/components/tree/src/model/node';
-import { Plus } from '@element-plus/icons-vue';
-import type { UploadProps } from 'element-plus';
-import config from '/@/config.ts';
-import Role from '/@/api/role/role.ts';
-import ruleReg from '/@/utils/ruleReg.ts';
-import Data from './role.ts';
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['refresh']);
-
-// 定义变量内容
-const deptDialogFormRef = ref();
-const state = reactive({
-	ruleForm: {
-		id: 0,
-		name: '',
-		remark: '',
-		valid: 1,
-		code:<any> [],
-		codes:<any> [],
-		codes_cn:<any> [],
-	},
-	code:<any> [],
-	codes:<any> [],
-	codes_cn:<any> [],
-	status: true,
-	options: [], // 单位类型
-	dialog: {
-		isShowDialog: false,
-		type: '',
-		title: '',
-		submitTxt: '',
-	},
-	action: config.host + '/admin/upload/file',
-	menuData: [] as TreeType[],
-	menuProps: {
-		children: 'children',
-		label: 'label',
-	},
-	role_list: [],//Data.role_list
-});
-
-const handleCheckChange = (
-  data: TreeType,
-  checked: boolean,
-  indeterminate: boolean
-) => {
-  	let getCheckedNodes = treeRef.value!.getCheckedNodes(false, true);
-	console.log('getCheckedNodes', getCheckedNodes);
-	treeFormat(getCheckedNodes);
-}
-
-const treeRef = ref<InstanceType<typeof ElTree>>()
-const getCheckedNodes = () => {
-	let getCheckedNodes = treeRef.value!.getCheckedNodes(false, true);
-	console.log('getCheckedNodes', getCheckedNodes);
-	treeFormat(getCheckedNodes);
-}
-// 树状列表处理
-const treeFormat = (tree_list:any) => {
-	state.code = [];
-	state.codes = [];
-	state.codes_cn = [];
-	let ids:any = [];
-	tree_list.forEach((item:any)=>{
-		state.codes.push(item.id);
-		state.codes_cn.push(item.label);
-	})
-	for(let i=0;i<tree_list.length;i++){
-		for(let j=0;j<tree_list.length;j++){
-			if(tree_list[i].id==tree_list[j].pId){
-				ids.push(tree_list[i].id);
-			}
-		}
-	}
-	for(let k=0;k<tree_list.length;k++){
-		for(let l=0;l<ids.length;l++){
-			if(tree_list[k].id==ids[l]){
-				tree_list.splice(k,1);
-			}
-		}
-	}
-	tree_list.forEach((item:any)=>{
-		state.code.push(item.id);
-	})
-	console.log('state.code',state.code);
-	console.log('state.codes',state.codes);
-	console.log('state.codes_cn',state.codes_cn);
-}
-
-// 打开弹窗
-const openDialog = (type: string, row: any) => {
-	state.dialog.type = type;
-	if (type === 'edit') {
-		state.ruleForm = {
-            id: row.id,
-			name: row.name,
-			remark: row.remark,
-			valid: row.valid,
-			code: row.code,
-			codes: row.codes,
-			codes_cn: row.codes_cn,
-        };
-		state.dialog.title = '编辑权限022';
-		state.dialog.submitTxt = '修 改';
-		state.code = row.code;
-		state.codes = row.codes;
-		state.codes_cn = row.codes_cn;
-		console.log('state.ruleForm.codes->',state.ruleForm.code);
-		console.log('state.ruleForm.codes->',state.ruleForm.codes);
-		console.log('state.ruleForm.codes_cn->',state.ruleForm.codes_cn);
-	} else {
-        state.ruleForm = {
-            id: 0,
-			name: '',
-			remark: '',
-			valid: 1,
-			code: [],
-			codes: [],
-			codes_cn: [],
-        };
-		state.status = true;
-		state.dialog.title = '新增权限021';
-		state.dialog.submitTxt = '保 存';
-		// 清空表单,此项需加表单验证才能使用
-		// nextTick(() => {
-		// 	deptDialogFormRef.value.resetFields();
-		// });
-	}
-	state.dialog.isShowDialog = true;
-	getMenuData();
-};
-// 关闭弹窗
-const closeDialog = () => {
-	state.dialog.isShowDialog = false;
-};
-// 取消
-const onCancel = () => {
-	closeDialog();
-};
-// 提交
-const onSubmit = async() => {
-	if(!ruleReg.emptyReg(state.ruleForm.name)){
-		return ElMessage.warning("请输入权限名称");
-	}
-	if(!ruleReg.emptyReg(state.ruleForm.remark)){
-		return ElMessage.warning("请输入备注说明");
-	}
-	if(state.code[0]!=='home'&&state.codes[0]!=='home'&&state.codes_cn[0]!=='首页'){
-		state.code.unshift('home');
-		state.codes.unshift('home');
-		state.codes_cn.unshift('首页');
-	}
-	state.ruleForm.code = state.code;
-	state.ruleForm.codes = state.codes;
-	state.ruleForm.codes_cn = state.codes_cn;
-	// state.ruleForm.code.push([]);
-	// state.ruleForm.codes.push([]);
-	// state.ruleForm.codes_cn.push([]);
-	// state.ruleForm.code.splice(-1,1);
-	// state.ruleForm.codes.splice(-1,1);
-	// state.ruleForm.codes_cn.splice(-1,1);
-	let res: any = null;
-	if(state.dialog.type=='edit' || state.ruleForm.id!=0){
-		res = await Role.edit(state.ruleForm);
-		if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-	}else{
-		res = await Role.add(state.ruleForm);
-		if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-	}
-	ElMessage.success(res.msg);
-	closeDialog();
-	emit('refresh');
-};
-
-// 初始化权限菜单
-const init = async() => {
-	let res = await Role.init();
-	if(res.code != 0){
-		return ElMessage.error(res.msg);
-	}
-	state.role_list = res.data;
-};
-
-// 获取菜单结构数据
-const getMenuData = () => {
-	init();
-};
-
-// 暴露变量
-defineExpose({
-	openDialog,
-});
-</script>
-
-<style lang="scss" scoped>
-	.avatar-uploader .avatar {
-		width: 178px;
-		height: 178px;
-		display: block;
-	}
-	.avatar-uploader .el-upload {
-		border: 1px dashed var(--el-border-color);
-		border-radius: 6px;
-		cursor: pointer;
-		position: relative;
-		overflow: hidden;
-		transition: var(--el-transition-duration-fast);
-	}
-	.avatar-uploader .el-upload:hover {
-		border-color: var(--el-color-primary);
-	}
-	.el-icon.avatar-uploader-icon {
-		font-size: 28px;
-		color: #8c939d;
-		width: 178px;
-		height: 178px;
-		text-align: center;
-	}
-	.system-role-dialog-container {
-		.menu-data-tree {
-			width: 100%;
-			border: 1px solid var(--el-border-color);
-			border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
-			padding: 5px;
-		}
-	}
-</style>

+ 0 - 255
h5/src/views/admin/roleManage/index.vue

@@ -1,255 +0,0 @@
-<template>
-	<div>
-		<el-card class="box-card" v-loading="state.loading" element-loading-text="Loading...">
-            <template #header>
-                <div class="card-header">
-                    <span>权限管理</span>
-                    <div>
-                        <el-button type="default" @click="reFlush()">刷新列表</el-button>
-                        <el-button type="primary" @click="onOpenAddDept('add')">新增权限</el-button>
-                        <el-button type="danger" @click="del()">批量删除</el-button>
-                    </div>
-                </div>
-            </template>
-
-			<el-table ref="multipleTableRef" :data="state.tableData" style="width: 100%" @selection-change="handleSelectionChange">
-				<el-table-column type="selection" width="55" />
-				<el-table-column type="index" label="序号" width="90" />
-				<el-table-column property="name" label="权限名称" />
-
-                <el-table-column property="codes_cn" label="权限">
-                    <template #default="scope">
-                        <div v-if="scope.row.codes_cn">
-                            <span v-if="scope.row.codes_cn.length>1">{{scope.row.codes_cn[0]}},{{scope.row.codes_cn[1]}},等{{scope.row.codes_cn.length}}项权限</span>
-                            <span v-else v-for="(item,index) in scope.row.codes_cn" :key="index">
-                                <span>{{item}}</span>
-                            </span>
-                        </div>
-                    </template>
-                </el-table-column>
-
-				<!-- <el-table-column property="company.personnel_size" label="人数" width="90" /> -->
-				<el-table-column property="update_time" label="最后修改时间" width="240" />
-
-                <el-table-column property="valid" label="状态" width="90">
-                    <template #default="scope">
-                        <el-button link type="danger" size="default" v-if="scope.row.valid == 0">禁用</el-button>
-                        <el-button link type="primary" size="default" v-if="scope.row.valid == 1">启用</el-button>
-                    </template>
-                </el-table-column>
-
-				<el-table-column property="remark" label="备注" />
-
-				<el-table-column fixed="right" label="操作" width="120">
-					<template #default="scope">
-						<div class="disflex">
-							<el-button link type="primary" size="small" @click="onOpenEditDept('edit',scope.row)">编辑</el-button>
-							<el-button link type="danger" size="small" @click="handleClick_del(scope.row)">删除</el-button>
-						</div>
-					</template>
-				</el-table-column>
-			</el-table>
-
-            <el-pagination
-				@size-change="onHandleSizeChange"
-				@current-change="onHandleCurrentChange"
-				class="mt15"
-				:pager-count="5"
-				:page-sizes="[10, 20, 30]"
-				v-model:current-page="state.param.page"
-				background
-				v-model:page-size="state.param.list_rows"
-				layout="total, sizes, prev, pager, next, jumper"
-				:total="state.total"
-			>
-			</el-pagination>
-		</el-card>
-        <DeptDialog ref="deptDialogRef" @refresh="getTableData()" />
-	</div>
-</template>
-
-<script lang="ts" setup name="underlyingRoleManage">
-    import { ref, reactive, onMounted, defineAsyncComponent } from 'vue';
-    import { ElTable, ElMessage, ElMessageBox } from 'element-plus';
-    import Role from '/@/api/role/role.ts';
-    import ruleReg from '/@/utils/ruleReg';
-
-    const DeptDialog = defineAsyncComponent(() => import('/@/views/underlying/roleManage/edit.vue'));
-    const deptDialogRef = ref();
-    // 打开新增菜单弹窗
-    const onOpenAddDept = (type: string) => {
-        deptDialogRef.value.openDialog(type);
-    };
-    // 打开编辑菜单弹窗
-    const onOpenEditDept = (type: string, row: any) => {
-        row = JSON.parse(JSON.stringify(row));
-        console.log('row',row);
-        deptDialogRef.value.openDialog(type, row);
-    };
-
-    interface User {
-        id: number
-        name: string
-        gender: number
-        img_url: string
-        company_id: number
-        department_id: number
-        id_card: string
-        age: number
-        phone: string
-        password: string
-        role_id: number
-        is_root: number
-        valid: number
-        create_time: string
-        update_time: string
-        is_pass: number
-        pass_time: string
-        remark: string
-    }
-    const multipleTableRef = ref<InstanceType<typeof ElTable>>()
-    const multipleSelection = ref<User[]>([])
-    const toggleSelection = (rows?: User[]) => {
-        if (rows) {
-            rows.forEach((row) => {
-                // TODO: improvement typing when refactor table
-                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-                // @ts-expect-error
-                multipleTableRef.value!.toggleRowSelection(row, undefined)
-            })
-        } else {
-            multipleTableRef.value!.clearSelection()
-        }
-    }
-    const handleSelectionChange = (val: User[]) => {
-        multipleSelection.value = val;
-        console.log('multipleSelection',multipleSelection.value);
-    }
-    const handleCommand = (command: string | number | object) => {
-        console.log('command',command);
-    }
-    const handleClick_edit = () => {
-        ElMessage(`click on 编辑`);
-    }
-    const handleClick_del = (row: any) => {
-        row = JSON.parse(JSON.stringify(row));
-        console.log('row',row);
-        ElMessageBox.confirm(`此操作将永久删除角色:“${row.name}”,是否继续?`, '提示', {
-            confirmButtonText: '确认',
-            cancelButtonText: '取消',
-            type: 'warning',
-        })
-        .then(() => {
-            delOnce(row.id);
-            // getTableData();
-            // ElMessage.success('删除成功');
-        })
-        .catch(() => {});
-    }
-    const del = () => {
-        console.log('multipleSelection.value',multipleSelection.value.length);
-        if(multipleSelection.value.length==0){
-            return ElMessage.warning("请选择要操作的列表");
-        }
-        let name = [];
-        state.ids = [];
-        for(let i=0;i<multipleSelection.value.length;i++){
-            name.push(multipleSelection.value[i].name);
-            state.ids.push(multipleSelection.value[i].id);
-        }
-        ElMessageBox.confirm(`此操作将永久删除角色:“${name}”,是否继续?`, '提示', {
-            confirmButtonText: '确认',
-            cancelButtonText: '取消',
-            type: 'warning',
-        })
-        .then(() => {
-            console.log('ids',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
-            delOnce(JSON.stringify(state.ids).split('[')[1].split(']')[0]);
-            // getTableData();
-            // ElMessage.success('删除成功');
-        })
-        .catch(() => {});
-    }
-    const delOnce = async(ids: number | string) => {
-        let res = await Role.del(ids);
-        if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-        getTableData();
-        ElMessage.success(res.msg);
-    }
-
-    const state = reactive({
-        tableData: [],
-        total: 0,
-        loading: false,
-        param: {
-            keyword: '',
-            page: 1,
-            list_rows: 10,
-        },
-        ids: [],
-    });
-    const getList = async() => {
-        let res = await Role.list(state.param);
-        if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-        res.data.data.forEach((item:any)=>{
-            // console.log('item.codes_cn1',item.codes_cn);
-            // console.log('item.codes1',item.codes);
-            // console.log('item.code1',item.code);
-            if(!ruleReg.emptyReg(item.codes_cn)){
-                item.codes_cn = [];
-                item.codes = [];
-                item.code = [];
-            }else{
-                item.codes_cn = (item.codes_cn || '').split(',');
-                item.codes = (item.codes || '').split(',');
-                item.code = (item.code || '').split(',');
-            }
-            // console.log('item.codes_cn2',item.codes_cn.length);
-            // console.log('item.codes2',item.codes.length);
-            // console.log('item.code2',item.code.length);
-        });
-        state.tableData = res.data.data;
-        state.total = res.data.total;
-    }
-    const reFlush = () => {
-        getTableData();
-        state.loading = true;
-        setTimeout(() => {
-            state.loading = false;
-            ElMessage.success("刷新列表成功");
-        }, 500);
-    }
-    // 初始化表格数据
-    const getTableData = () => {
-        getList();
-    };
-    // 分页改变
-    const onHandleSizeChange = (val: number) => {
-        state.param.list_rows = val;
-        getTableData();
-    };
-    // 分页改变
-    const onHandleCurrentChange = (val: number) => {
-        state.param.page = val;
-        getTableData();
-    };
-    // 页面加载时
-    onMounted(() => {
-        getTableData();
-    });
-</script>
-
-<style lang="scss" scoped>
-    .box-card {
-        margin: 10px;
-    }
-    .card-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-    }
-</style>

+ 0 - 295
h5/src/views/underlying/roleManage/edit.vue

@@ -1,295 +0,0 @@
-<template>
-	<div class="system-dept-dialog-container">
-		<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
-			<el-form ref="deptDialogFormRef" :model="state.ruleForm" size="default" label-width="90px">
-				<el-row :gutter="35">
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="权限名称">
-							<el-input v-model="state.ruleForm.name" placeholder="请输入权限名称" clearable></el-input>
-						</el-form-item>
-					</el-col>
-
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="备注说明">
-							<el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" clearable></el-input>
-						</el-form-item>
-					</el-col>
-
-					<!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="角色状态">
-							<el-switch v-model="state.status" inline-prompt active-text="启用" inactive-text="禁用"></el-switch>
-						</el-form-item>
-					</el-col> -->
-
-					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
-						<el-form-item label="权限状态" :rules="[{ required: true, message: '权限状态不能为空' }]">
-							<el-radio-group v-model="state.ruleForm.valid">
-								<el-radio :label="1">启用</el-radio>
-								<el-radio :label="0">禁用</el-radio>
-							</el-radio-group>
-						</el-form-item>
-					</el-col>
-
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
-						<el-form-item label="菜单权限">
-							<!-- :default-expanded-keys="state.ruleForm.codes" -->
-							<el-tree
-								show-checkbox
-							 	ref="treeRef"
-								node-key="id"
-								:data="state.role_list"
-								:props="state.menuProps"
-								:default-checked-keys="state.ruleForm.code"
-								@check-change="getCheckedNodes()"
-								class="menu-data-tree"
-							/>
-						</el-form-item>
-					</el-col>
-				</el-row>
-			</el-form>
-			<template #footer>
-				<span class="dialog-footer">
-					<el-button @click="onCancel" size="default">取 消</el-button>
-					<el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
-				</span>
-			</template>
-		</el-dialog>
-	</div>
-</template>
-
-<script setup lang="ts" name="underlyingProductManageEdit">
-import { reactive, ref } from 'vue';
-import { ElMessage, ElTree } from 'element-plus';
-import type Node from 'element-plus/es/components/tree/src/model/node';
-import { Plus } from '@element-plus/icons-vue';
-import type { UploadProps } from 'element-plus';
-import config from '/@/config.ts';
-import Role from '/@/api/role/role.ts';
-import ruleReg from '/@/utils/ruleReg.ts';
-import Data from './role.ts';
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['refresh']);
-
-// 定义变量内容
-const deptDialogFormRef = ref();
-const state = reactive({
-	ruleForm: {
-		id: 0,
-		name: '',
-		remark: '',
-		valid: 1,
-		code:<any> [],
-		codes:<any> [],
-		codes_cn:<any> [],
-	},
-	code:<any> [],
-	codes:<any> [],
-	codes_cn:<any> [],
-	status: true,
-	options: [], // 单位类型
-	dialog: {
-		isShowDialog: false,
-		type: '',
-		title: '',
-		submitTxt: '',
-	},
-	action: config.host + '/admin/upload/file',
-	menuData: [] as TreeType[],
-	menuProps: {
-		children: 'children',
-		label: 'label',
-	},
-	role_list: [],//Data.role_list
-});
-
-const handleCheckChange = (
-  data: TreeType,
-  checked: boolean,
-  indeterminate: boolean
-) => {
-  	let getCheckedNodes = treeRef.value!.getCheckedNodes(false, true);
-	console.log('getCheckedNodes', getCheckedNodes);
-	treeFormat(getCheckedNodes);
-}
-
-const treeRef = ref<InstanceType<typeof ElTree>>()
-const getCheckedNodes = () => {
-	let getCheckedNodes = treeRef.value!.getCheckedNodes(false, true);
-	console.log('getCheckedNodes', getCheckedNodes);
-	treeFormat(getCheckedNodes);
-}
-// 树状列表处理
-const treeFormat = (tree_list:any) => {
-	state.code = [];
-	state.codes = [];
-	state.codes_cn = [];
-	let ids:any = [];
-	tree_list.forEach((item:any)=>{
-		state.codes.push(item.id);
-		state.codes_cn.push(item.label);
-	})
-	for(let i=0;i<tree_list.length;i++){
-		for(let j=0;j<tree_list.length;j++){
-			if(tree_list[i].id==tree_list[j].pId){
-				ids.push(tree_list[i].id);
-			}
-		}
-	}
-	for(let k=0;k<tree_list.length;k++){
-		for(let l=0;l<ids.length;l++){
-			if(tree_list[k].id==ids[l]){
-				tree_list.splice(k,1);
-			}
-		}
-	}
-	tree_list.forEach((item:any)=>{
-		state.code.push(item.id);
-	})
-	console.log('state.code',state.code);
-	console.log('state.codes',state.codes);
-	console.log('state.codes_cn',state.codes_cn);
-}
-
-// 打开弹窗
-const openDialog = (type: string, row: any) => {
-	state.dialog.type = type;
-	if (type === 'edit') {
-		state.ruleForm = {
-            id: row.id,
-			name: row.name,
-			remark: row.remark,
-			valid: row.valid,
-			code: row.code,
-			codes: row.codes,
-			codes_cn: row.codes_cn,
-        };
-		state.dialog.title = '编辑权限022';
-		state.dialog.submitTxt = '修 改';
-		state.code = row.code;
-		state.codes = row.codes;
-		state.codes_cn = row.codes_cn;
-		console.log('state.ruleForm.codes->',state.ruleForm.code);
-		console.log('state.ruleForm.codes->',state.ruleForm.codes);
-		console.log('state.ruleForm.codes_cn->',state.ruleForm.codes_cn);
-	} else {
-        state.ruleForm = {
-            id: 0,
-			name: '',
-			remark: '',
-			valid: 1,
-			code: [],
-			codes: [],
-			codes_cn: [],
-        };
-		state.status = true;
-		state.dialog.title = '新增权限021';
-		state.dialog.submitTxt = '保 存';
-		// 清空表单,此项需加表单验证才能使用
-		// nextTick(() => {
-		// 	deptDialogFormRef.value.resetFields();
-		// });
-	}
-	state.dialog.isShowDialog = true;
-	getMenuData();
-};
-// 关闭弹窗
-const closeDialog = () => {
-	state.dialog.isShowDialog = false;
-};
-// 取消
-const onCancel = () => {
-	closeDialog();
-};
-// 提交
-const onSubmit = async() => {
-	if(!ruleReg.emptyReg(state.ruleForm.name)){
-		return ElMessage.warning("请输入权限名称");
-	}
-	if(!ruleReg.emptyReg(state.ruleForm.remark)){
-		return ElMessage.warning("请输入备注说明");
-	}
-	if(state.code[0]!=='home'&&state.codes[0]!=='home'&&state.codes_cn[0]!=='首页'){
-		state.code.unshift('home');
-		state.codes.unshift('home');
-		state.codes_cn.unshift('首页');
-	}
-	state.ruleForm.code = state.code;
-	state.ruleForm.codes = state.codes;
-	state.ruleForm.codes_cn = state.codes_cn;
-	// state.ruleForm.code.push([]);
-	// state.ruleForm.codes.push([]);
-	// state.ruleForm.codes_cn.push([]);
-	// state.ruleForm.code.splice(-1,1);
-	// state.ruleForm.codes.splice(-1,1);
-	// state.ruleForm.codes_cn.splice(-1,1);
-	let res: any = null;
-	if(state.dialog.type=='edit' || state.ruleForm.id!=0){
-		res = await Role.edit(state.ruleForm);
-		if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-	}else{
-		res = await Role.add(state.ruleForm);
-		if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-	}
-	ElMessage.success(res.msg);
-	closeDialog();
-	emit('refresh');
-};
-
-// 初始化权限菜单
-const init = async() => {
-	let res = await Role.init();
-	if(res.code != 0){
-		return ElMessage.error(res.msg);
-	}
-	state.role_list = res.data;
-};
-
-// 获取菜单结构数据
-const getMenuData = () => {
-	init();
-};
-
-// 暴露变量
-defineExpose({
-	openDialog,
-});
-</script>
-
-<style lang="scss" scoped>
-	.avatar-uploader .avatar {
-		width: 178px;
-		height: 178px;
-		display: block;
-	}
-	.avatar-uploader .el-upload {
-		border: 1px dashed var(--el-border-color);
-		border-radius: 6px;
-		cursor: pointer;
-		position: relative;
-		overflow: hidden;
-		transition: var(--el-transition-duration-fast);
-	}
-	.avatar-uploader .el-upload:hover {
-		border-color: var(--el-color-primary);
-	}
-	.el-icon.avatar-uploader-icon {
-		font-size: 28px;
-		color: #8c939d;
-		width: 178px;
-		height: 178px;
-		text-align: center;
-	}
-	.system-role-dialog-container {
-		.menu-data-tree {
-			width: 100%;
-			border: 1px solid var(--el-border-color);
-			border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
-			padding: 5px;
-		}
-	}
-</style>

+ 0 - 255
h5/src/views/underlying/roleManage/index.vue

@@ -1,255 +0,0 @@
-<template>
-	<div>
-		<el-card class="box-card" v-loading="state.loading" element-loading-text="Loading...">
-            <template #header>
-                <div class="card-header">
-                    <span>权限管理</span>
-                    <div>
-                        <el-button type="default" @click="reFlush()">刷新列表</el-button>
-                        <el-button type="primary" @click="onOpenAddDept('add')">新增权限</el-button>
-                        <el-button type="danger" @click="del()">批量删除</el-button>
-                    </div>
-                </div>
-            </template>
-
-			<el-table ref="multipleTableRef" :data="state.tableData" style="width: 100%" @selection-change="handleSelectionChange">
-				<el-table-column type="selection" width="55" />
-				<el-table-column type="index" label="序号" width="90" />
-				<el-table-column property="name" label="权限名称" />
-
-                <el-table-column property="codes_cn" label="权限">
-                    <template #default="scope">
-                        <div v-if="scope.row.codes_cn">
-                            <span v-if="scope.row.codes_cn.length>1">{{scope.row.codes_cn[0]}},{{scope.row.codes_cn[1]}},等{{scope.row.codes_cn.length}}项权限</span>
-                            <span v-else v-for="(item,index) in scope.row.codes_cn" :key="index">
-                                <span>{{item}}</span>
-                            </span>
-                        </div>
-                    </template>
-                </el-table-column>
-
-				<!-- <el-table-column property="company.personnel_size" label="人数" width="90" /> -->
-				<el-table-column property="update_time" label="最后修改时间" width="240" />
-
-                <el-table-column property="valid" label="状态" width="90">
-                    <template #default="scope">
-                        <el-button link type="danger" size="default" v-if="scope.row.valid == 0">禁用</el-button>
-                        <el-button link type="primary" size="default" v-if="scope.row.valid == 1">启用</el-button>
-                    </template>
-                </el-table-column>
-
-				<el-table-column property="remark" label="备注" />
-
-				<el-table-column fixed="right" label="操作" width="120">
-					<template #default="scope">
-						<div class="disflex">
-							<el-button link type="primary" size="small" @click="onOpenEditDept('edit',scope.row)">编辑</el-button>
-							<el-button link type="danger" size="small" @click="handleClick_del(scope.row)">删除</el-button>
-						</div>
-					</template>
-				</el-table-column>
-			</el-table>
-
-            <el-pagination
-				@size-change="onHandleSizeChange"
-				@current-change="onHandleCurrentChange"
-				class="mt15"
-				:pager-count="5"
-				:page-sizes="[10, 20, 30]"
-				v-model:current-page="state.param.page"
-				background
-				v-model:page-size="state.param.list_rows"
-				layout="total, sizes, prev, pager, next, jumper"
-				:total="state.total"
-			>
-			</el-pagination>
-		</el-card>
-        <DeptDialog ref="deptDialogRef" @refresh="getTableData()" />
-	</div>
-</template>
-
-<script lang="ts" setup name="underlyingRoleManage">
-    import { ref, reactive, onMounted, defineAsyncComponent } from 'vue';
-    import { ElTable, ElMessage, ElMessageBox } from 'element-plus';
-    import Role from '/@/api/role/role.ts';
-    import ruleReg from '/@/utils/ruleReg';
-
-    const DeptDialog = defineAsyncComponent(() => import('/@/views/underlying/roleManage/edit.vue'));
-    const deptDialogRef = ref();
-    // 打开新增菜单弹窗
-    const onOpenAddDept = (type: string) => {
-        deptDialogRef.value.openDialog(type);
-    };
-    // 打开编辑菜单弹窗
-    const onOpenEditDept = (type: string, row: any) => {
-        row = JSON.parse(JSON.stringify(row));
-        console.log('row',row);
-        deptDialogRef.value.openDialog(type, row);
-    };
-
-    interface User {
-        id: number
-        name: string
-        gender: number
-        img_url: string
-        company_id: number
-        department_id: number
-        id_card: string
-        age: number
-        phone: string
-        password: string
-        role_id: number
-        is_root: number
-        valid: number
-        create_time: string
-        update_time: string
-        is_pass: number
-        pass_time: string
-        remark: string
-    }
-    const multipleTableRef = ref<InstanceType<typeof ElTable>>()
-    const multipleSelection = ref<User[]>([])
-    const toggleSelection = (rows?: User[]) => {
-        if (rows) {
-            rows.forEach((row) => {
-                // TODO: improvement typing when refactor table
-                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-                // @ts-expect-error
-                multipleTableRef.value!.toggleRowSelection(row, undefined)
-            })
-        } else {
-            multipleTableRef.value!.clearSelection()
-        }
-    }
-    const handleSelectionChange = (val: User[]) => {
-        multipleSelection.value = val;
-        console.log('multipleSelection',multipleSelection.value);
-    }
-    const handleCommand = (command: string | number | object) => {
-        console.log('command',command);
-    }
-    const handleClick_edit = () => {
-        ElMessage(`click on 编辑`);
-    }
-    const handleClick_del = (row: any) => {
-        row = JSON.parse(JSON.stringify(row));
-        console.log('row',row);
-        ElMessageBox.confirm(`此操作将永久删除角色:“${row.name}”,是否继续?`, '提示', {
-            confirmButtonText: '确认',
-            cancelButtonText: '取消',
-            type: 'warning',
-        })
-        .then(() => {
-            delOnce(row.id);
-            // getTableData();
-            // ElMessage.success('删除成功');
-        })
-        .catch(() => {});
-    }
-    const del = () => {
-        console.log('multipleSelection.value',multipleSelection.value.length);
-        if(multipleSelection.value.length==0){
-            return ElMessage.warning("请选择要操作的列表");
-        }
-        let name = [];
-        state.ids = [];
-        for(let i=0;i<multipleSelection.value.length;i++){
-            name.push(multipleSelection.value[i].name);
-            state.ids.push(multipleSelection.value[i].id);
-        }
-        ElMessageBox.confirm(`此操作将永久删除角色:“${name}”,是否继续?`, '提示', {
-            confirmButtonText: '确认',
-            cancelButtonText: '取消',
-            type: 'warning',
-        })
-        .then(() => {
-            console.log('ids',JSON.stringify(state.ids).split('[')[1].split(']')[0]);
-            delOnce(JSON.stringify(state.ids).split('[')[1].split(']')[0]);
-            // getTableData();
-            // ElMessage.success('删除成功');
-        })
-        .catch(() => {});
-    }
-    const delOnce = async(ids: number | string) => {
-        let res = await Role.del(ids);
-        if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-        getTableData();
-        ElMessage.success(res.msg);
-    }
-
-    const state = reactive({
-        tableData: [],
-        total: 0,
-        loading: false,
-        param: {
-            keyword: '',
-            page: 1,
-            list_rows: 10,
-        },
-        ids: [],
-    });
-    const getList = async() => {
-        let res = await Role.list(state.param);
-        if(res.code != 0){
-            return ElMessage.error(res.msg);
-        }
-        res.data.data.forEach((item:any)=>{
-            // console.log('item.codes_cn1',item.codes_cn);
-            // console.log('item.codes1',item.codes);
-            // console.log('item.code1',item.code);
-            if(!ruleReg.emptyReg(item.codes_cn)){
-                item.codes_cn = [];
-                item.codes = [];
-                item.code = [];
-            }else{
-                item.codes_cn = (item.codes_cn || '').split(',');
-                item.codes = (item.codes || '').split(',');
-                item.code = (item.code || '').split(',');
-            }
-            // console.log('item.codes_cn2',item.codes_cn.length);
-            // console.log('item.codes2',item.codes.length);
-            // console.log('item.code2',item.code.length);
-        });
-        state.tableData = res.data.data;
-        state.total = res.data.total;
-    }
-    const reFlush = () => {
-        getTableData();
-        state.loading = true;
-        setTimeout(() => {
-            state.loading = false;
-            ElMessage.success("刷新列表成功");
-        }, 500);
-    }
-    // 初始化表格数据
-    const getTableData = () => {
-        getList();
-    };
-    // 分页改变
-    const onHandleSizeChange = (val: number) => {
-        state.param.list_rows = val;
-        getTableData();
-    };
-    // 分页改变
-    const onHandleCurrentChange = (val: number) => {
-        state.param.page = val;
-        getTableData();
-    };
-    // 页面加载时
-    onMounted(() => {
-        getTableData();
-    });
-</script>
-
-<style lang="scss" scoped>
-    .box-card {
-        margin: 10px;
-    }
-    .card-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-    }
-</style>

+ 0 - 107
h5/src/views/underlying/roleManage/role.ts

@@ -1,107 +0,0 @@
-const Data = {
-    role_list: [
-		{
-			id: 1,
-			label: '系统管理',
-			children: [
-				{
-					id: 11,
-					label: '菜单管理',
-					children: [
-						{
-							id: 111,
-							label: '菜单新增',
-						},
-						{
-							id: 112,
-							label: '菜单修改',
-						},
-						{
-							id: 113,
-							label: '菜单删除',
-						},
-						{
-							id: 114,
-							label: '菜单查询',
-						},
-					],
-				},
-				{
-					id: 12,
-					label: '角色管理',
-					children: [
-						{
-							id: 121,
-							label: '角色新增',
-						},
-						{
-							id: 122,
-							label: '角色修改',
-						},
-						{
-							id: 123,
-							label: '角色删除',
-						},
-						{
-							id: 124,
-							label: '角色查询',
-						},
-					],
-				},
-				{
-					id: 13,
-					label: '用户管理',
-					children: [
-						{
-							id: 131,
-							label: '用户新增',
-						},
-						{
-							id: 132,
-							label: '用户修改',
-						},
-						{
-							id: 133,
-							label: '用户删除',
-						},
-						{
-							id: 134,
-							label: '用户查询',
-						},
-					],
-				},
-			],
-		},
-		{
-			id: 2,
-			label: '权限管理',
-			children: [
-				{
-					id: 21,
-					label: '前端控制',
-					children: [
-						{
-							id: 211,
-							label: '页面权限',
-						},
-						{
-							id: 212,
-							label: '页面权限',
-						},
-					],
-				},
-				{
-					id: 22,
-					label: '后端控制',
-					children: [
-						{
-							id: 221,
-							label: '页面权限',
-						},
-					],
-				},
-			],
-		},
-	],
-}
-export default Data;

+ 3 - 2
h5/tsconfig.json

@@ -7,7 +7,7 @@
 		"target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
 		"module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
 		"lib": ["esnext", "dom", "dom.iterable", "scripthost"] /* Specify library files to be included in the compilation. */,
-		// "allowJs": true,                       /* Allow javascript files to be compiled. */
+		"allowJs": true,                       /* Allow javascript files to be compiled. */
 		// "checkJs": true,                       /* Report errors in .js files. */
 		"jsx": "preserve" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
 		// "declaration": true /* Generates corresponding '.d.ts' file. */,
@@ -68,7 +68,8 @@
 		/* Advanced Options */
 		"skipLibCheck": true /* Skip type checking of declaration files. */,
 		"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
-		"suppressImplicitAnyIndexErrors": true
+		"noImplicitAny": false,
+        "noEmit": true
 	},
 	"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "src/utils/request.ts"], // **Represents any directory, and * represents any file. Indicates that all files in the src directory will be compiled
 	"exclude": ["node_modules", "dist"] // Indicates the file directory that does not need to be compiled

+ 8 - 4
h5/vite.config.ts

@@ -2,7 +2,7 @@ import vue from '@vitejs/plugin-vue';
 import { resolve } from 'path';
 import { defineConfig, loadEnv, ConfigEnv } from 'vite';
 import vueSetupExtend from 'vite-plugin-vue-setup-extend';
-
+import vueJsx from '@vitejs/plugin-vue-jsx';
 const pathResolve = (dir: string) => {
 	return resolve(__dirname, '.', dir);
 };
@@ -14,9 +14,13 @@ const alias: Record<string, string> = {
 
 const viteConfig = defineConfig((mode: ConfigEnv) => {
 	const env = loadEnv(mode.mode, process.cwd());
-	console.log("process.env.VITE_OUTPUT_DIR", env.VITE_OUTPUT_DIR);
+	console.log('process.env.VITE_OUTPUT_DIR', env.VITE_OUTPUT_DIR);
 	return {
-		plugins: [vue(), vueSetupExtend()],
+		plugins: [
+			vue(),
+			vueSetupExtend(),
+			vueJsx(),
+		],
 		root: process.cwd(),
 		resolve: { alias },
 		base: mode.command === 'serve' ? './' : env.VITE_PUBLIC_PATH,
@@ -52,7 +56,7 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
 					},
 				},
 			},
-            sourcemap: true
+			sourcemap: true,
 		},
 		css: { preprocessorOptions: { css: { charset: false } } },
 		define: {