Преглед на файлове

feat: 新增代理管理和商户管理

叶静 преди 3 седмици
родител
ревизия
e1f4f570a9
променени са 45 файла, в които са добавени 3324 реда и са изтрити 5885 реда
  1. 2 2
      .env
  2. 1 1
      .env.development
  3. 0 94
      doc/1.md
  4. 0 460
      doc/10.md
  5. 0 169
      doc/11.md
  6. 0 186
      doc/12.md
  7. 0 161
      doc/13.md
  8. 0 197
      doc/14.md
  9. 0 204
      doc/15.md
  10. 0 151
      doc/16.md
  11. 0 121
      doc/17.md
  12. 0 86
      doc/18.md
  13. 0 198
      doc/19.md
  14. 0 108
      doc/2.md
  15. 0 257
      doc/20.md
  16. 0 167
      doc/21.md
  17. 0 199
      doc/22.md
  18. 0 197
      doc/23.md
  19. 0 83
      doc/24.md
  20. 0 479
      doc/25.md
  21. 0 340
      doc/26.md
  22. 0 692
      doc/27.md
  23. 0 260
      doc/3.md
  24. 0 240
      doc/4.md
  25. 0 128
      doc/5.md
  26. 0 177
      doc/6.md
  27. 0 255
      doc/7.md
  28. 0 107
      doc/8.md
  29. 0 164
      doc/9.md
  30. 778 0
      doc/daili.json
  31. 1051 0
      doc/shanghu.json
  32. 47 0
      src/api/agent/agentUser.ts
  33. 54 0
      src/api/merchant/merchantUser.ts
  34. 78 0
      src/i18n/pages/agent/en.ts
  35. 78 0
      src/i18n/pages/agent/zh-cn.ts
  36. 73 0
      src/i18n/pages/merchant/en.ts
  37. 73 0
      src/i18n/pages/merchant/zh-cn.ts
  38. 2 2
      src/views/admin/audit/index.vue
  39. 93 0
      src/views/agent/flow/index.vue
  40. 96 0
      src/views/agent/list/changePwd.vue
  41. 251 0
      src/views/agent/list/form.vue
  42. 166 0
      src/views/agent/list/index.vue
  43. 96 0
      src/views/merchant/list/changePwd.vue
  44. 245 0
      src/views/merchant/list/form.vue
  45. 140 0
      src/views/merchant/list/index.vue

+ 2 - 2
.env

@@ -1,5 +1,5 @@
 # 网站主标题
-VITE_GLOBAL_TITLE= 'PIGX ADMIN'
+VITE_GLOBAL_TITLE= '运营端'
 
 # footer
 VITE_FOOTER_TITLE= '©2025 pig4cloud.com'
@@ -14,7 +14,7 @@ VITE_PUBLIC_PATH = /
 VITE_API_URL = /api
 
 # ADMIN 服务地址
-VITE_ADMIN_PROXY_PATH = http://192.168.0.106:9999
+VITE_ADMIN_PROXY_PATH = http://192.168.0.103:9999
 
 # 前端加密密钥
 VITE_PWD_ENC_KEY='pigxpigxpigxpigx'

+ 1 - 1
.env.development

@@ -8,4 +8,4 @@ VITE_OPEN = true
 ENV = 'development'
 
 # ADMIN 服务地址
-VITE_ADMIN_PROXY_PATH = http://192.168.0.106:9999
+VITE_ADMIN_PROXY_PATH = http://192.168.0.103:9999

+ 0 - 94
doc/1.md

@@ -1,94 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端参数工具使用
-========
-
-[](#1-useparam-函数)1\. useParam 函数
----------------------------------
-
-| 入参 | 出参 |
-| --- | --- |
-| 
-
-sys\_public\_param 表中 publicKey 字段
-
- | 
-
-sys\_public\_param 表中 publicValue 字段
-
- |
-
-```
-
-
-`import  {useParam}  from  '/@/hooks/param';  
-const param =  useParam('GEN_TABLE_PREFIX')`
-
-
-
-
-```
-
-[](#2-页面使用)2\. 页面使用
--------------------
-
-```
-
-
-`{{useParam('GEN_TABLE_PREFIX')}}`
-
-
-
-
-```
-
-### 本页导航
-
-1\. useParam 函数
-
-2\. 页面使用

+ 0 - 460
doc/10.md

@@ -1,460 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端上传组件
-======
-
-[](#普通文件上传)普通文件上传
------------------
-
-![](https://minio.pigx.top/oss/202304/1681632734.png)
-
-```
-
-
-`<upload-file  @change="success"  />`
-
-
-
-
-```
-
-### [](#属性说明)属性说明
-
-| 属性名称 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| 
-
-modelValue
-
- | 
-
-组件的值
-
- | 
-
-string
-
- | 
-
-Array
-
- |
-| 
-
-limit
-
- | 
-
-数量限制
-
- | 
-
-number (非必传)
-
- | 
-
-5
-
- |
-| 
-
-fileSize
-
- | 
-
-文件大小限制
-
- | 
-
-number (非必传)
-
- | 
-
-5MB
-
- |
-| 
-
-fileType
-
- | 
-
-文件类型限制
-
- | 
-
-Array (非必传)
-
- | 
-
-\['png', 'jpg', 'jpeg', 'doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'pptx'\]
-
- |
-| 
-
-isShowTip
-
- | 
-
-是否显示提示
-
- | 
-
-boolean (非必传)
-
- | 
-
-true
-
- |
-| 
-
-uploadFileUrl
-
- | 
-
-上传文件的 API 方法
-
- | 
-
-string (非必传)
-
- | 
-
-'/admin/sys-file/upload'
-
- |
-| 
-
-type
-
- | 
-
-组件类型
-
- | 
-
-string (非必传)
-
- | 
-
-'default'
-
- |
-| 
-
-data
-
- | 
-
-需要额外传递给 API 的数据
-
- | 
-
-Object (非必传)
-
- | 
-
- |
-| 
-
-dir
-
- | 
-
-子目录名称
-
- | 
-
-String (非必传)
-
- | 
-
-a/b 格式, v5.3+
-
- |
-| 
-
-autoUpload
-
- | 
-
-是否自动上传文件
-
- | 
-
-boolean (非必传)
-
- | 
-
-true
-
- |
-
-[](#图片上传)图片上传
--------------
-
-![](https://minio.pigx.top/oss/202304/1681632840.png)
-
-```
-
-
-`<upload-img  v-model:imageUrl="formData.avatar"  borderRadius="50%">   <template  #empty>   <el-icon><Avatar  /></el-icon>   <span>请上传头像</span>   </template>  </upload-img>`
-
-
-
-
-```
-
-### [](#属性说明-1)属性说明
-
-| 属性名称 | 描述 | 类型 |
-| --- | --- | --- |
-| 
-
-imageUrl
-
- | 
-
-图片地址 (双向绑定,上传会更新返回此字段)
-
- | 
-
-string (必传)
-
- |
-| 
-
-uploadFileUrl
-
- | 
-
-上传图片的 API 方法
-
- | 
-
-string (非必传)
-
- |
-| 
-
-dir
-
- | 
-
-子目录名称
-
- | 
-
-String (非必传)
-
- |
-| 
-
-drag
-
- | 
-
-是否支持拖拽上传
-
- | 
-
-boolean (非必传,默认为 true)
-
- |
-| 
-
-disabled
-
- | 
-
-是否禁用上传组件
-
- | 
-
-boolean (非必传,默认为 false)
-
- |
-| 
-
-fileSize
-
- | 
-
-图片大小限制
-
- | 
-
-number (非必传,默认为 5M)
-
- |
-| 
-
-fileType
-
- | 
-
-图片类型限制
-
- | 
-
-File.ImageMimeType\[\] (非必传,默认为 \["image/jpeg", "image/png", "image/gif"\])
-
- |
-| 
-
-height
-
- | 
-
-组件高度
-
- | 
-
-string (非必传,默认为 150px)
-
- |
-| 
-
-width
-
- | 
-
-组件宽度
-
- | 
-
-string (非必传,默认为 150px)
-
- |
-| 
-
-borderRadius
-
- | 
-
-组件边框圆角
-
- | 
-
-string (非必传,默认为 8px)
-
- |
-
-[](#excel-文件上传)excel 文件上传
--------------------------
-
-![](https://minio.pigx.top/oss/202304/1681632946.png)
-
-```
-
-
-`<upload-excel   ref="excelUploadRef"   :title="$t('sysuser.importUserTip')"   temp-url="/admin/sys-file/local/file/user.xlsx"   url="/admin/user/import"   @refreshDataList="getDataList"  />`
-
-
-
-
-```
-
-### [](#属性说明-2)属性说明
-
-| 属性名称 | 描述 | 类型 |
-| --- | --- | --- |
-| 
-
-url
-
- | 
-
-导入文件后台接口
-
- | 
-
-String
-
- |
-| 
-
-title
-
- | 
-
-弹出框标题
-
- | 
-
-String
-
- |
-| 
-
-tempUrl
-
- | 
-
-获取当前导如 excel 模板地址
-
- | 
-
-String
-
- |
-
-### 本页导航
-
-普通文件上传
-
-属性说明
-
-图片上传
-
-属性说明
-
-excel 文件上传
-
-属性说明

+ 0 - 169
doc/11.md

@@ -1,169 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/9UFEBWm9yghqfP2A3Ri7GzEqF8ccpKj2J0fHzhS7.png)
-](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)
-
-[电商项目必备!Java 开源商城系统 SpringBoot+Vue 框架,功能齐全,全源码交付,可二开](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端表格工具栏组件
-=========
-
-[](#分页组件使用)分页组件使用
------------------
-
-*   工具栏组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
-
-```
-
-
-`<right-toolbar   v-model:showSearch="showSearch"   :export="'sys_user_export'"   @exportExcel="exportExcel"   @queryTable="getDataList"  />`
-
-
-
-
-```
-
-```
-
-
-`const  { getDataList }  =  useTable(state);`
-
-
-
-
-```
-
-[](#卡槽扩展)卡槽扩展
--------------
-
-```
-
-
-`<query-tree>   <template  #default="{ node, data }">  </template>  </query-tree>`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性 | 类型 | 默认值 | 说明 |
-| --- | --- | --- | --- |
-| 
-
-`showSearch`
-
- | 
-
-`Boolean`
-
- | 
-
-`true`
-
- | 
-
-是否显示搜索框。
-
- |
-| 
-
-`export`
-
- | 
-
-`String or Boolean`
-
- | 
-
-`当设置为true的显示,如设置为权限字符串则根据当前用户权限动态控制`
-
- | 
-
-是否导出下载按钮。
-
- |
-| 
-
-`search`
-
- | 
-
-`Boolean`
-
- | 
-
-`true`
-
- | 
-
-是否显示搜索框。
-
- |
-| 
-
-`gutter`
-
- | 
-
-`Number`
-
- | 
-
-`10`
-
- | 
-
-列表项之间的间距。
-
- |
-
-### 本页导航
-
-分页组件使用
-
-卡槽扩展
-
-属性说明

+ 0 - 186
doc/12.md

@@ -1,186 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/HYKVsnrmfPfixKqkTmAG9VrkVFraIps5tqkbEE8n.jpg)
-](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)
-
-[注册亚马逊云服务免费套餐🆓可享高达200美元抵扣金🚀包括免费使用精选服务🎉](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端表格分页组件
-========
-
-[](#分页组件使用)分页组件使用
------------------
-
-*   分页组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
-
-```
-
-
-`<pagination   v-bind="state.pagination"   @current-change="currentChangeHandle"   @size-change="sizeChangeHandle"  ></pagination>`
-
-
-
-
-```
-
-```
-
-
-`const  { currentChangeHandle, sizeChangeHandle }  =  useTable(state);`
-
-
-
-
-```
-
-[](#卡槽扩展)卡槽扩展
--------------
-
-```
-
-
-`<query-tree>   <template  #default="{ node, data }">  </template>  </query-tree>`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性 | 类型 | 默认值 | 说明 |
-| --- | --- | --- | --- |
-| 
-
-`current`
-
- | 
-
-`Number`
-
- | 
-
-`1`
-
- | 
-
-当前页码。
-
- |
-| 
-
-`size`
-
- | 
-
-`Number`
-
- | 
-
-`10`
-
- | 
-
-每页展示的条数。
-
- |
-| 
-
-`total`
-
- | 
-
-`Number`
-
- | 
-
-`0`
-
- | 
-
-数据总数。
-
- |
-| 
-
-`pageSizes`
-
- | 
-
-`Array`
-
- | 
-
-`[1, 10, 20, 50, 100, 200]`
-
- | 
-
-每页展示的条数可选项。
-
- |
-| 
-
-`layout`
-
- | 
-
-`String`
-
- | 
-
-`'total, sizes, prev, pager, next, jumper'`
-
- | 
-
-分页组件的布局。
-
- |
-
-### 本页导航
-
-分页组件使用
-
-卡槽扩展
-
-属性说明

+ 0 - 161
doc/13.md

@@ -1,161 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/HYKVsnrmfPfixKqkTmAG9VrkVFraIps5tqkbEE8n.jpg)
-](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)
-
-[注册亚马逊云服务免费套餐🆓可享高达200美元抵扣金🚀包括免费使用精选服务🎉](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端表格组件
-======
-
-[](#1-usetable-函数是什么)1\. useTable 函数是什么
----------------------------------------
-
-官方对自定义 hook 定义:在 Vue 应用的概念中,“组合式函数” (Composables) 是一个利用 Vue 组合式 API 来封装和复用有状态逻辑的函数。Hooks 在前端领域并没有明确定义,借用知乎大佬的定义:在 JS 里是 callback,事件驱动,集成定义一些可复用的方法。
-
-**useTable 函数的名称就能清晰地表达其作用,它是集成了前端 element-plus 表格的一些通用函数。** 
-
-| 方法名 | 描述 |
-| --- | --- |
-| 
-
-`tableStyle`
-
- | 
-
-返回包含表格样式的对象,其中包含 `cellStyle` 和 `headerCellStyle` 两个属性,分别用于设置表格单元格和表头单元格的样式
-
- |
-| 
-
-`getDataList(refresh?: any)`
-
- | 
-
-获取数据列表,并可选择是否刷新当前页码。如果需要刷新,则将 `state.pagination.current` 重置为 1
-
- |
-| 
-
-`sizeChangeHandle(val: number)`
-
- | 
-
-分页大小改变时触发的事件处理函数。会修改 `state.pagination` 中的 `size` 属性,并再次调用 `query()` 方法进行查询
-
- |
-| 
-
-`currentChangeHandle(val: number)`
-
- | 
-
-当前页码改变时触发的事件处理函数。会修改 `state.pagination` 中的 `current` 属性,并再次调用 `query()` 方法进行查询
-
- |
-| 
-
-`sortChangeHandle(column: any)`
-
- | 
-
-排序方式改变时触发的事件处理函数。根据 `column` 的内容,修改 `state.descs` 和 `state.ascs` 中的排序字段,并再次调用 `query()` 方法进行查询
-
- |
-| 
-
-`downBlobFile(url: string, query: any, fileName: string)`
-
- | 
-
-用于下载文件的方法。接收三个参数:文件下载地址 `url`、请求参数 `query` 和文件名 `fileName`。调用了 `other.downBlobFile()` 方法来执行文件下载。返回一个 Promise 对象,用于异步处理结果
-
- |
-
-[](#2-页面中如何使用)2\. 页面中如何使用
--------------------------
-
-```
-
-
-`// 使用 useTable 自动生成表格一些通用方法  const  {  getDataList,  currentChangeHandle,  sizeChangeHandle,  downBlobFile,  tableStyle,  }  =  useTable(state);`
-
-
-
-
-```
-
-[](#3-usetable-初始化-state-如何构建)3\. useTable 初始化 state 如何构建
----------------------------------------------------------
-
-如果你想通过 useTable 生成一些通用的表格方法,那么就需要向它提供一些初始值,比如查询的URL和分页大小等参数。
-
-```
-
-
-`const state:  BasicTableProps  =  reactive<BasicTableProps>({   queryForm:  {    },   pageList: pageList,  });`
-
-
-
-
-```
-
-*   完整的 BasicTable 定义属性如下
-
-```
-
-
-`export  interface  BasicTableProps  {    // 是否在创建页面时即调用数据列表接口,默认为true   createdIsNeed?:  boolean;    // 是否需要分页,默认为true   isPage?:  boolean;    // 查询条件表单对象,类型为any   queryForm?:  any;    // 数据列表数组   dataList?:  any[];    // 分页属性对象   pagination?:  Pagination;    // 数据列表,loading状态标志,默认为false   dataListLoading?:  boolean;    // 数据列表多选项数组   dataListSelections?:  any[];    // 数据列表查询接口api方法,接收任意数量参数,返回Promise   pageList?:  (...arg:  any)  =>  Promise<any>;    // loading标志,默认为false   loading?:  Boolean;    // 多选结果数组   selectObjs?:  any[];    // 排序字段数组   descs?:  string[];    // 排序方式数组   ascs?:  string[];    // props属性对象,类型为any   props?:  any;  }`
-
-
-
-
-```
-
-### 本页导航
-
-1\. useTable 函数是什么
-
-2\. 页面中如何使用
-
-3\. useTable 初始化 state 如何构建

+ 0 - 197
doc/14.md

@@ -1,197 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/UPQhl7yG06tksqj5rkpXaQj3eAO6yA02XkpyhkoX.jpg)
-](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)
-
-[🚀 支持40+常用图表,20+主流数据源,拖拉拽制作数据大屏。**开源免费,支持二开**。](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端富文本组件
-=======
-
-Wangeditor 是一款基于 Web 的所见即所得富文本编辑器,它提供了丰富的富文本编辑功能,支持插入图片、音视频等多媒体内容,并且可以通过自定义插件扩展其功能。Wangeditor 支持跨浏览器和跨平台,同时具有良好的兼容性和性能表现,易于集成和使用。
-
-Wangeditor 采用 HTML5 和 JavaScript 技术实现,可以直接嵌入到网页中使用,也可以作为独立的编辑器使用。在使用过程中,Wangeditor 提供了简洁的 API 接口和详细的文档,方便开发人员进行二次开发和扩展。
-
-[](#页面使用)页面使用
--------------
-
-```
-
-
-`<editor  v-model:get-html="form.content"  />`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性名称 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| 
-
-disable
-
- | 
-
-是否禁用编辑器
-
- | 
-
-Boolean
-
- | 
-
-false
-
- |
-| 
-
-placeholder
-
- | 
-
-编辑器默认占位符
-
- | 
-
-String
-
- | 
-
-"请输入内容..."
-
- |
-| 
-
-mode
-
- | 
-
-编辑器模式,可选值为 default 或 simple
-
- | 
-
-String
-
- | 
-
-default
-
- |
-| 
-
-height
-
- | 
-
-编辑器高度
-
- | 
-
-String
-
- | 
-
-"310px"
-
- |
-| 
-
-getHtml
-
- | 
-
-双向绑定的属性,用于获取编辑器中 HTML 内容
-
- | 
-
-String
-
- | 
-
-\-
-
- |
-| 
-
-getText
-
- | 
-
-双向绑定的属性,用于获取编辑器中纯文本内容
-
- | 
-
-String
-
- | 
-
-\-
-
- |
-| 
-
-uploadFileUrl
-
- | 
-
-上传文件的接口地址
-
- | 
-
-String
-
- | 
-
-"/admin/sys-file/upload"
-
- |
-
-### 本页导航
-
-页面使用
-
-属性说明

+ 0 - 204
doc/15.md

@@ -1,204 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/9UFEBWm9yghqfP2A3Ri7GzEqF8ccpKj2J0fHzhS7.png)
-](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)
-
-[电商项目必备!Java 开源商城系统 SpringBoot+Vue 框架,功能齐全,全源码交付,可二开](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端代码编辑组件
-========
-
-[](#引入组件)引入组件
--------------
-
-![](https://minio.pigx.top/oss/202308/1690987106.png)
-
-```
-
-
-`const  CodeEditor  =  defineAsyncComponent(   ()  =>  import("/@/components/CodeEditor/index.vue")  );`
-
-
-
-
-```
-
-[](#使用方法)使用方法
--------------
-
-```
-
-
-`<template>
-  <div>
-    <CodeEditor
-      v-model="code"
-      mode="go"
-      theme="idea"
-      :readOnly="false"
-      :height="300"
-    />
-  </div>
-</template>` 
-
-
-
-
-```
-
-### [](#props)Props
-
-| 属性 | 类型 | 默认值 | 说明 |
-| --- | --- | --- | --- |
-| 
-
-`modelValue`
-
- | 
-
-String
-
- | 
-
-''
-
- | 
-
-绑定的代码内容
-
- |
-| 
-
-`mode`
-
- | 
-
-String
-
- | 
-
-'go'
-
- | 
-
-代码语言
-
- |
-| 
-
-`theme`
-
- | 
-
-String
-
- | 
-
-'idea'
-
- | 
-
-代码编辑器的主题
-
- |
-| 
-
-`height`
-
- | 
-
-\[String, Number\]
-
- | 
-
-300
-
- | 
-
-代码编辑器的高度
-
- |
-| 
-
-`options`
-
- | 
-
-Object
-
- | 
-
-{}
-
- | 
-
-CodeMirror 的配置选项
-
- |
-| 
-
-`readOnly`
-
- | 
-
-Boolean
-
- | 
-
-false
-
- | 
-
-是否只读
-
- |
-
-### 本页导航
-
-引入组件
-
-使用方法
-
-Props

+ 0 - 151
doc/16.md

@@ -1,151 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/9UFEBWm9yghqfP2A3Ri7GzEqF8ccpKj2J0fHzhS7.png)
-](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)
-
-[电商项目必备!Java 开源商城系统 SpringBoot+Vue 框架,功能齐全,全源码交付,可二开](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-省市区街四级联动组件
-==========
-
-![](https://minio.pigx.top/oss/202305/1684049377.png)
-
-[](#省市区三级联动)省市区三级联动
--------------------
-
-```
-
-
-`const  ChinaArea  =  defineAsyncComponent(   ()  =>  import("/@/components/ChinaArea/index.vue")  );`
-
-
-
-
-```
-
-```
-
-
-`<china-area v-model="data"  @change="handleChange"/>;  
-// 双向绑定数据 自动回显: 北京市/市辖区/东城区  const data =  ref("11,1101,110101");  
-// 可选 输出: 11,1101,110101  const  handleChange  =  (val:  String)  =>  {  }` 
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性名称 | 描述 | 类型 |
-| --- | --- | --- |
-| 
-
-v-model
-
- | 
-
-双向绑定
-
- | 
-
-String
-
- |
-| 
-
-type
-
- | 
-
-省级 1 市 2 区 3 街道 4
-
- | 
-
-Number
-
- |
-| 
-
-plus
-
- | 
-
-默认 false, 不用选择某级
-
- | 
-
-Boolean
-
- |
-| 
-
-@change
-
- | 
-
-选中回调事件
-
- | 
-
-Function
-
- |
-
-[](#完整区划数据)完整区划数据
------------------
-
-下载 [👉🏻 省市街区详细 SQL](https://minio.pigx.top/oss/202402/1708152046.sql),导入至 sys\_area 表即可。
-
-如果此数据(来自民政部 2023 年的数据)中不存在对应地区,您可以根据规则自行新增。请注意,编码需保持唯一。
-
-### 本页导航
-
-省市区三级联动
-
-属性说明
-
-完整区划数据

+ 0 - 121
doc/17.md

@@ -1,121 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端通用工具函数
-========
-
-[](#点击复制文本)点击复制文本
------------------
-
-```
-
-
-`<button  @click="copyText('文案内容')">复制</button>`
-
-
-
-
-```
-
-```
-
-
-`const  { copyText }  =  commonFunction();`
-
-
-
-
-```
-
-[](#格式化时间)格式化时间
----------------
-
-*   html 代码中直接使用 parseDate parseTime 进行格式化
-
-```
-
-
-`<el-table-column   :label="t('tenant.startTime')"   prop="startTime"   show-overflow-tooltip  >   <template  #default="scope">   <span>{{ parseDate(scope.row.startTime) }}</span>   </template>  </el-table-column>  <el-table-column   :label="t('tenant.endTime')"   prop="endTime"   show-overflow-tooltip  >   <template  #default="scope">   <span>{{ parseTime(scope.row.endTime) }}</span>   </template>  </el-table-column>`
-
-
-
-
-```
-
-*   ts 中需要手动导入
-
-```
-
-
-`import  { formatDate, parseDate }  from  "/@/utils/formatTime";`
-
-
-
-
-```
-
-[](#获取后端参数)获取后端参数
------------------
-
-```
-
-
-`import  params  from  "/@/utils/params";  
-let result =  await params.get("参数管理中的KEY")`
-
-
-
-
-```
-
-### 本页导航
-
-点击复制文本
-
-格式化时间
-
-获取后端参数

+ 0 - 86
doc/18.md

@@ -1,86 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端字典工具使用
-========
-
-[](#1-usedict-函数)1\. useDict 函数
--------------------------------
-
-*   字典类型对应 sys\_dict 表中字典数据
-
-```
-
-
-`import  {useDict}  from  '/@/hooks/dict';  
-const  {字典类型A, 字典类型B}  =  useDict('字典类型A','字典类型B'  )  ;`
-
-
-
-
-```
-
-注意:element-plus 的 radio 和 select 等类型组件对 value 字段有强制的数据类型要求。实体字段应该使用字符串而不是数字类型来对应字典功能使用。
-
-[](#2-页面使用-dict-tag)2\. 页面使用 dict-tag
--------------------------------------
-
-```
-
-
- `<el-table-column>   <template  #default="scope">   <dict-tag  :options="字典类型"  :value="scope.row.xx"></dict-tag>   </template>  </el-table-column>`
-
-
-
-
-```
-
-### 本页导航
-
-1\. useDict 函数
-
-2\. 页面使用 dict-tag

+ 0 - 198
doc/19.md

@@ -1,198 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/UPQhl7yG06tksqj5rkpXaQj3eAO6yA02XkpyhkoX.jpg)
-](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)
-
-[🚀 支持40+常用图表,20+主流数据源,拖拉拽制作数据大屏。**开源免费,支持二开**。](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端标签页管理
-=======
-
-[](#1指定标签页名称)1.指定标签页名称
-----------------------
-
-跳转函数中指定路由参数 `tagsViewName`。
-
-```
-
-
-`const router =  useRouter();  router.push({ path:  '/xxx', query:  { tagsViewName:  '标签名称'  }  });`
-
-
-
-
-```
-
-[](#2刷新当前页面)2.刷新当前页面
---------------------
-
-```
-
-
-`import  { useRoute }  from  "vue-router";  import  mittBus  from  "/@/utils/mitt";  
-const route =  useRoute();  
-// 刷新当前页面  const  refreshPage  =  ()  =>  {  mittBus.emit("onCurrentContextmenuClick",  {  contextMenuClickId:  0,   ...route
-  });  };`
-
-
-
-
-```
-
-[](#3关闭当前页面)3.关闭当前页面
---------------------
-
-```
-
-
-`// 关闭当前页面  const  closePage  =  ()  =>  {  mittBus.emit("onCurrentContextmenuClick",  {  contextMenuClickId:  1,   ...route
-  });  };`
-
-
-
-
-```
-
-[](#4关闭其它页面)4.关闭其它页面
---------------------
-
-```
-
-
-`// 关闭除当前页外的其它页面  const  closeOthers  =  ()  =>  {  mittBus.emit("onCurrentContextmenuClick",  {  contextMenuClickId:  2,   ...route
-  });  };`
-
-
-
-
-```
-
-[](#5关闭全部页面)5.关闭全部页面
---------------------
-
-```
-
-
-`// 关闭所有页面  const  closeAll  =  ()  =>  {  mittBus.emit("onCurrentContextmenuClick",  {  contextMenuClickId:  3,   ...route
-  });  };`
-
-
-
-
-```
-
-[](#6全屏显示)6.全屏显示
-----------------
-
-```
-
-
-`// 当前页面全屏显示  const  fullscreen  =  ()  =>  {  mittBus.emit("onCurrentContextmenuClick",  {  contextMenuClickId:  4,   ...route
-  });  };`
-
-
-
-
-```
-
-| 操作ID | 功能说明 |
-| --- | --- |
-| 
-
-0
-
- | 
-
-刷新当前页面
-
- |
-| 
-
-1
-
- | 
-
-关闭当前页面
-
- |
-| 
-
-2
-
- | 
-
-关闭其它页面
-
- |
-| 
-
-3
-
- | 
-
-关闭全部页面
-
- |
-| 
-
-4
-
- | 
-
-当前页全屏显示
-
- |
-
-### 本页导航
-
-1.指定标签页名称
-
-2.刷新当前页面
-
-3.关闭当前页面
-
-4.关闭其它页面
-
-5.关闭全部页面
-
-6.全屏显示

+ 0 - 108
doc/2.md

@@ -1,108 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/tCsMFF956EX0JzAB8kkMuGpAUwWcW7KoJnzN1fY5.jpg)
-](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)
-
-[🛒 B2B2C商家入驻平台系统java版 **Java+vue+uniapp** 功能强大 稳定 支持diy 方便二开](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端图表功能
-======
-
-![](https://minio.pigx.top/oss/202311/1700887610.png)
-
-Vue Echarts 是一个 Vue.js 的 ECharts 图表组件,对 EChart 进行了封装,简化了 Echart 图表的使用。
-
-pigx-ui 默认引入了 vue-echarts ,业务代码中可以非常方便地使用相关的 EChart 图表组件【例如:日志管理】。
-
-[](#1-快速使用)1\. 快速使用
--------------------
-
-*   访问 [ECharts 官网](https://echarts.apache.org/examples/zh/index.html#chart-type-bar),选择目标类型的图表组件,获取图表的 option 配置 JSON。
-
-![](https://minio.pigx.top/oss/202311/1700888098.png)
-
-*   访问 [vue-echarts 代码生成器](https://vue-echarts.dev/#codegen)。
-
-![](https://minio.pigx.top/oss/202311/1700888283.png)
-
-[](#2-业务页面使用-vue-echarts)2\. 业务页面使用 vue-echarts
------------------------------------------------
-
-```
-
-
-`<template>
-  <v-chart class="h-80 w-full" :option="option"/>
-</template>
-<script setup lang="ts" name="demo-chart">
-// 直接复制 vue-echart codegen 生成的 vue 代码部分
-import { use, reactive } from 'echarts/core'
-import {
-  BarChart
-} from 'echarts/charts'
-import {
-  GridComponent
-} from 'echarts/components'
-import {
-  CanvasRenderer
-} from 'echarts/renderers'
-
-use([
-  GridComponent,
-  BarChart,
-  CanvasRenderer
-])
-
-// 定义 JSON
-const option = reactive(复制 EChart option JSON)`
-
-
-
-
-```
-
-### 本页导航
-
-1\. 快速使用
-
-2\. 业务页面使用 vue-echarts

+ 0 - 257
doc/20.md

@@ -1,257 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/tCsMFF956EX0JzAB8kkMuGpAUwWcW7KoJnzN1fY5.jpg)
-](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)
-
-[🛒 B2B2C商家入驻平台系统java版 **Java+vue+uniapp** 功能强大 稳定 支持diy 方便二开](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端组件路由管理
-========
-
-[](#静态路由)静态路由
--------------
-
-静态路由是指直接在前端代码中配置的路由,不需要通过后端接口动态获取。这些路由在项目编译时就已确定,适用于固定不变的页面导航结构。
-
-在 PIGX-UI 中使用静态路由的主要原因: 适合配置系统级别的页面(如登录、404等),可以独立于后端菜单权限系统 (不需要鉴权等配置)
-
-### [](#路由配置位置)路由配置位置
-
-```
-
-
-`src/
-  └── router/
-     └── route.ts          # 路由配置文件`
-
-
-
-
-```
-
-![](https://minio.pigx.top/oss/202411/1730690892.png)
-
-### [](#属性配置说明)属性配置说明
-
-| 配置项 | 说明 |
-| --- | --- |
-| 
-
-title
-
- | 
-
-菜单栏及 tagsView 栏、菜单搜索名称(国际化)
-
- |
-| 
-
-isLink
-
- | 
-
-是否超链接菜单,开启外链条件:1. isLink: 链接地址不为空 2. isIframe: false
-
- |
-| 
-
-isHide
-
- | 
-
-是否隐藏此路由
-
- |
-| 
-
-isKeepAlive
-
- | 
-
-是否缓存组件状态
-
- |
-| 
-
-isAuth
-
- | 
-
-是否需要认证才能进入的页面
-
- |
-| 
-
-isAffix
-
- | 
-
-是否固定在 tagsView 栏上
-
- |
-| 
-
-isIframe
-
- | 
-
-是否内嵌窗口,开启条件:1. isIframe: true 2. isLink:链接地址不为空
-
- |
-| 
-
-icon
-
- | 
-
-菜单、tagsView 图标,阿里:加 `iconfont xxx`,fontawesome:加 `fa xxx`
-
- |
-
-[](#动态路由)动态路由
--------------
-
-点击页面上的按钮可以打开新的 Tagsview 标签页,同时也可以传递参数。
-
-以下是一个适用场景的例子,当点击“新增文章”按钮时,会打开一个新的发布文章页面,方便进行操作。
-
-![](https://minio.pigx.top/oss/202308/1692178174.png)
-
-[](#代码实现方式)代码实现方式
------------------
-
-### [](#-菜单管理中定义隐藏菜单)① 菜单管理中定义隐藏菜单
-
-警告
-
-注意为角色分配该菜单的权限。
-
-![](https://minio.pigx.top/oss/202308/1692178433.png)
-
-### [](#-点击目标按钮触发路由跳转)② 点击目标按钮触发路由跳转
-
-```
-
-
-`const  click  =  ()  =>  {  router.push({   path:  "/app/appArticle/form",   query:  {  tagsViewName:  "动态路由测试",  param1:  "123"  },   });  };`
-
-
-
-
-```
-
-### [](#-在跳转的页面获取请求参数)③ 在跳转的页面获取请求参数
-
-```
-
-
-`const route =  useRoute();  
-onMounted(()  =>  {   console.log(route.query.tagsViewName);   console.log(route.query.param1);  });`
-
-
-
-
-```
-
-[](#菜单参数方式)菜单参数方式
------------------
-
-在多个菜单中引用同一个路由下的组件,通过路由进行区分。
-
-![](https://minio.pigx.top/oss/202402/1709135366.png)
-
-### [](#-配置菜单-带参)① 配置菜单 (带参)
-
-指向 /admin/test/index 组件
-
-```
-
-
-`AAA /admin/test/1  
-BBB /admin/test/2`
-
-
-
-
-```
-
-![](https://minio.pigx.top/oss/202402/1709182037.png)
-
-### [](#-页面获取参数)② 页面获取参数
-
-*   admin/test/index.vue
-
-```
-
-
-`const route =  useRoute();  
-onMounted(()  =>  {   // test/index/参数   const parts = route.path.split("/");   const lastParam = parts[parts.length  -  1];   console.log(lastParam);  });`
-
-
-
-
-```
-
-### 本页导航
-
-静态路由
-
-路由配置位置
-
-属性配置说明
-
-动态路由
-
-代码实现方式
-
-① 菜单管理中定义隐藏菜单
-
-② 点击目标按钮触发路由跳转
-
-③ 在跳转的页面获取请求参数
-
-菜单参数方式
-
-① 配置菜单 (带参)
-
-② 页面获取参数

+ 0 - 167
doc/21.md

@@ -1,167 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/UPQhl7yG06tksqj5rkpXaQj3eAO6yA02XkpyhkoX.jpg)
-](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)
-
-[🚀 支持40+常用图表,20+主流数据源,拖拉拽制作数据大屏。**开源免费,支持二开**。](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端数据状态管理
-========
-
-框架中数据状态使用 vuex Module 模块化进行管理,您可能需要了解 [vuex 核心概念 Module](https://next.vuex.vuejs.org/zh/guide/modules.html)
-
-[](#pinia)pinia
----------------
-
-代码位置:[/src/stores](#)
-
-相关文档:[pinia 官网](https://pinia.vuejs.org/)
-
-相关文档:[vuex 3.x 官网](https://v3.vuex.vuejs.org/zh/)
-
-[](#全局引入)全局引入
--------------
-
-页面模块已做全局自动引入,代码位置:`/@/store/index.ts`。[import.meta.globEager](https://vitejs.cn/guide/features.html#glob-import)
-
-```
-
-
-`const modulesFiles =  import.meta.globEager("./modules/*.ts");  const pathList:  string[]  =  [];  
-for  (const path in modulesFiles)  {  pathList.push(path);  }  
-const modules = pathList.reduce(   (modules:  {  [x:  string]:  any  }, modulePath:  string)  =>  {   const moduleName = modulePath.replace(/^./modules/(.*).w+$/,  "$1");   const value = modulesFiles[modulePath];  modules[moduleName]  = value.default;   return modules;   },   {}  );`
-
-
-
-
-```
-
-[](#定义接口)定义接口
--------------
-
-### [](#1-interface-定义)1\. interface 定义
-
-`/@/store/interface/index.ts`,如:路由缓存列表 `KeepAliveNamesState`
-
-```
-
-
-`// 路由缓存列表  export  interface  KeepAliveNamesState  {  keepAliveNames:  Array<string>;  }`
-
-
-
-
-```
-
-### [](#2-interface-使用)2\. interface 使用
-
-在 `/@/store/modules/` 新增 `keepAliveNames.ts`,界面写入如下代码:注意需要开启 `namespaced: true` 文件名称即模块名称。([vuex Module 命名空间](https://next.vuex.vuejs.org/zh/guide/modules.html#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4))
-
-```
-
-
-``import  {  Module  }  from  "vuex";  // 此处加上 `.ts` 后缀报错,具体原因不详  import  {  KeepAliveNamesState,  RootStateTypes  }  from  "/@/store/interface/index";  
-const keepAliveNamesModule:  Module<KeepAliveNamesState,  RootStateTypes>  =  {  namespaced:  true,  state:  {  keepAliveNames:  [],   },  mutations:  {   // 设置路由缓存(name字段)   getCacheKeepAlive(state:  any, data:  Array<string>)  {  state.keepAliveNames  = data;   },   },  actions:  {   // 设置路由缓存(name字段)   async  setCacheKeepAlive({ commit }, data:  Array<string>)  {   commit("getCacheKeepAlive", data);   },   },  };  
-export  default keepAliveNamesModule;``
-
-
-
-
-```
-
-[](#定义模块)定义模块
--------------
-
-如上所示,我们在 `/@/store/modules/` 下新增了 `keepAliveNames.ts` 文件,并定义了方法 `mutations`、`actions`
-
-[](#使用模块)使用模块
--------------
-
-### [](#1-在-ts-中使用)1\. 在 .ts 中使用
-
-```
-
-
-`import  { store }  from  "/@/store/index.ts";  
-// dispatch  store.dispatch("keepAliveNames/setCacheKeepAlive", cacheList);  
-// 或者 commit  // store.commit("keepAliveNames/getCacheKeepAlive", cacheList);`
-
-
-
-
-```
-
-### [](#2-在-vue-中使用)2\. 在 .vue 中使用
-
-```
-
-
-`<template>   <div  v-if="getThemeConfig.isLockScreen">在 .vue 中使用</div>  </template>  
-<script  lang="ts">   import  { computed, defineComponent }  from  "vue";   import  { useStore }  from  "/@/store/index";   export  default  defineComponent({   name:  "app",   setup()  {   const store =  useStore();   // 获取布局配置信息   const getThemeConfig =  computed(()  =>  {   return store.state.themeConfig.themeConfig;   });   },   });  </script>`
-
-
-
-
-```
-
-### 本页导航
-
-pinia
-
-全局引入
-
-定义接口
-
-1\. interface 定义
-
-2\. interface 使用
-
-定义模块
-
-使用模块
-
-1\. 在 .ts 中使用
-
-2\. 在 .vue 中使用

+ 0 - 199
doc/22.md

@@ -1,199 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/9/22
-
-切换主题
-
-前端权限管理
-======
-
-### [](#1-组件方式)1\. 组件方式
-
-组件位置:[/@/components/auth](#/src/components/auth),您可能需要了解 [插槽 slot](https://v3.cn.vuejs.org/guide/component-slots.html)
-
-#### [](#单个权限验证valuexxx)单个权限验证(:value="xxx")
-
-*   组件代码,注意看 `some` 高亮处判断,根据需求适当时候需要自行修改
-
-```
-
-
-`<template>   <slot  v-if="getUserAuthBtnList"  />  </template>  
-<script  setup  lang="ts"  name="auth">   import  { computed }  from  "vue";   import  { storeToRefs }  from  "pinia";   import  { useUserInfo }  from  "/@/stores/userInfo";     // 定义父组件传过来的值   const props =  defineProps({   value:  {   type:  String,   default:  ()  =>  "",   },   });     // 定义变量内容   const stores =  useUserInfo();   const  { userInfos }  =  storeToRefs(stores);     // 获取 pinia 中的用户权限   const getUserAuthBtnList =  computed(()  =>  {   return userInfos.value.authBtnList.some((v: string)  => v === props.value);   });  </script>`
-
-
-
-
-```
-
-*   页面中使用
-
-```
-
-
-`<template>   <!-- 使用 -->   <Auth  :value="'btn.add'"  />  </template>  
-<script  setup  lang="ts"  name="xxx">   // 局部引入   import  Auth  from  "/@/components/auth/auth.vue";  </script>`
-
-
-
-
-```
-
-#### [](#多个权限验证满足一个则显示valuexxxxxx)多个权限验证,满足一个则显示(:value="\[xxx,xxx\]")
-
-```
-
-
-`<template>   <!-- 使用 -->   <Auths  :value="['btn.addsss', 'btn.edit', 'btn.delsss', 'btn.linksss']"  />  </template>  
-<script  lang="ts">   import  { defineComponent }  from  "vue";   // 局部引入   import  Auths  from  "/@/components/auth/auths.vue";     export  default  defineComponent({   name:  "xxxx",   // 局部注册   components:  {  Auths  },   });  </script>`
-
-
-
-
-```
-
-#### [](#多个权限验证全部满足则显示valuexxxxxx)多个权限验证,全部满足则显示(:value="\[xxx,xxx\]")
-
-```
-
-
-`<template>   <!-- 使用 -->   <AuthAll  :value="['btn.add', 'btn.edit', 'btn.del', 'btn.link']"  />  </template>  
-<script  lang="ts">   import  { defineComponent }  from  "vue";   // 局部引入   import  AuthAll  from  "/@/components/auth/authAll.vue";     export  default  defineComponent({   name:  "xxxx",   // 局部注册   components:  {  AuthAll  },   });  </script>`
-
-
-
-
-```
-
-### [](#2-指令方式)2\. 指令方式
-
-指令位置:[/@/directive/authDirective.ts](#/src/directive),您可能需要了解 [自定义指令 directive](https://v3.cn.vuejs.org/guide/custom-directive.html)
-
-#### [](#单个权限验证v-authxxx)单个权限验证(v-auth="xxx")
-
-```
-
-
-`<div  v-auth="'btn.add'">   <el-button>新增</el-button>  </div>  
-<div  v-auth="'btn.edit'">   <el-button>编辑</el-button>  </div>  
-<div  v-auth="'btn.del'">   <el-button>删除</el-button>  </div>  
-<div  v-auth="'btn.link'">   <el-button>跳转</el-button>  </div>`
-
-
-
-
-```
-
-#### [](#多个权限验证满足一个则显示v-authsxxxxxx)多个权限验证,满足一个则显示(v-auths="\[xxx,xxx\]")
-
-```
-
-
-`<div  v-auths="['btn.addsss', 'btn.edit', 'btn.delsss', 'btn.linksss']">   <el-button>新增</el-button>  </div>  
-<div  v-auths="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">   <el-button>编辑</el-button>  </div>`
-
-
-
-
-```
-
-#### [](#多个权限验证全部满足则显示v-auth-allxxxxxx)多个权限验证,全部满足则显示(v-auth-all="\[xxx,xxx\]")
-
-```
-
-
-`<div  v-auth-all="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">   <el-button>新增</el-button>  </div>  
-<div  v-auth-all="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">   <el-button>编辑</el-button>  </div>`
-
-
-
-
-```
-
-### [](#3-函数方式)3\. 函数方式
-
-方法位置:[/@/utils/authFunction.ts](#/src/utils/authFunction.ts),用于方法中的判断,使用方法如下
-
-```
-
-
-`<script lang="ts" setup>  import  {  ElMessage  }  from  'element-plus';  import  { auth, auths, authAll }  from  '/@/utils/authFunction';  
-// 单个权限验证  const  onAuthClick  =  ()  =>  {   if  (!auth('btn.add'))  ElMessage.error('抱歉,您没有权限!');   else  ElMessage.success('恭喜,您有权限!');  };  // 多个权限验证,满足一个则为 true  const  onAuthsClick  =  ()  =>  {   if  (!auths(['btn.add',  'btn.edit']))  ElMessage.error('抱歉,您没有权限!');   else  ElMessage.success('恭喜,您有权限!');  };  // 多个权限验证,全部满足则为 true  const  onAuthAllClick  =  ()  =>  {   if  (!authAll(['btn.add',  'btn.edit'))  ElMessage.error('抱歉,您没有权限!');   else  ElMessage.success('恭喜,您有权限!');  };  </script>`
-
-
-
-
-```
-
-或
-
-```
-
-
-`import { auth } from '/@/utils/authFunction'; <div v-if="auth('sys_file_del')">...</div>`
-
-
-
-
-```
-
-### 本页导航
-
-1\. 组件方式
-
-单个权限验证(:value="xxx")
-
-多个权限验证,满足一个则显示(:value="\[xxx,xxx\]")
-
-多个权限验证,全部满足则显示(:value="\[xxx,xxx\]")
-
-2\. 指令方式
-
-单个权限验证(v-auth="xxx")
-
-多个权限验证,满足一个则显示(v-auths="\[xxx,xxx\]")
-
-多个权限验证,全部满足则显示(v-auth-all="\[xxx,xxx\]")
-
-3\. 函数方式

+ 0 - 197
doc/23.md

@@ -1,197 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/9UFEBWm9yghqfP2A3Ri7GzEqF8ccpKj2J0fHzhS7.png)
-](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)
-
-[电商项目必备!Java 开源商城系统 SpringBoot+Vue 框架,功能齐全,全源码交付,可二开](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/10/23
-
-切换主题
-
-前端国际化配置
-=======
-
-框架内置 `中文简体`、`英文`
-
-### [](#1-多国语言配置)1\. 多国语言配置
-
-##### [](#前端配置国际化)前端配置国际化
-
-注意:页面国际化数据最好放 `同级的目录中 i18n` 里。`/@/i18n` 为框架内置,为了更好的升级,最好别添加到里面
-
-![](https://minio.pigx.top/oss/202304/1681629726.png)
-
-##### [](#后端配置国际化)后端配置国际化
-
-与前端 i18n 配置 ts 文件格式相同,i18n 可以通过后台进行国际化管理的配置和使用。
-
-![](https://minio.pigx.top/oss/202304/1682143507.png)
-
-### [](#2-国际化使用)2\. 国际化使用
-
-#### [](#页面上使用-vuetxxxxxx)页面上使用 `.vue`,`$t('xxx.xxx')`
-
-```
-
-
-`<el-button>   <span>{{ $t('message.account.accountBtnText') }}</span>  </el-button>  
-<el-divider  content-position="left">   {{ $t('message.layout.oneTitle') }}
-</el-divider>`
-
-
-
-
-```
-
-#### [](#ts-上使用-tsi18nglobaltxxx)ts 上使用 `.ts`,`i18n.global.t(xxx)`
-
-```
-
-
-`import  { i18n }  from  "/@/i18n/index";  
-const webTitle = i18n.global.t(router.currentRoute.value.meta.title  as  any);`
-
-
-
-
-```
-
-#### [](#setup-里使用-txxx)setup 里使用 ,`t(xxx)`
-
-```
-
-
-`<script lang="ts">  import  { defineComponent }  from  'vue';  import  { useI18n }  from  'vue-i18n';  
-export  default  defineComponent({  name:  'xxx',   setup()  {   const  { t }  =  useI18n();  
-  // 使用,xxx 为变量   t(xxx)   }  })  </script>`
-
-
-
-
-```
-
-[](#框架其它国际化)框架其它国际化
--------------------
-
-### [](#1-菜单)1\. 菜单
-
-![](https://minio.pigx.vip/oss/202510/FC7lef.png)
-
-[/@/layout/navMenu](#/src/layout/navMenu),取 [/@/router/route.ts](#/src/router/route.ts) 中的 `meta.title` 字段(`message.router.xxx` 需提前在 PC 后台 【国际化管理】中维护,中文菜单和英文的对应关系。
-
-### [](#2-浏览器标题)2\. 浏览器标题
-
-> [/@/utils/other.ts](#/src/utils/other.ts#L28) useTitle 方法,使用时:`other.useTitle()`
-
-```
-
-
-``/**
- * 设置浏览器标题国际化 * @method const title = useTitle(); ==> title() */  export  function  useTitle()  {   const stores =  useThemeConfig(pinia);   const  { themeConfig }  =  storeToRefs(stores);   nextTick(()  =>  {   let webTitle =  "";   let globalTitle:  string  = themeConfig.value.globalTitle;   const  { path, meta }  = router.currentRoute.value;   if  (path ===  "/login")  {  webTitle =  <string>meta.title;   }  else  {  webTitle =  setTagsViewNameI18n(router.currentRoute.value);   }   document.title  =  `${webTitle} - ${globalTitle}`  || globalTitle;   });  }``
-
-
-
-
-```
-
-### [](#3-顶栏)3\. 顶栏
-
-[/@/layout/navBars/breadcrumb](#/src/layout/navBars/breadcrumb),面包屑、组件大小、语言切换、菜单搜索、布局配置、消息、开/关全屏、用户下拉菜单(鼠标放入 `icon 图标` 上会显示图标说明)。
-
-基本都使用 `$t(xxx.xxx.xxx)` 语法。
-
-```
-
-
-`<div>{{ $t(v.meta.title) }}</div>`
-
-
-
-
-```
-
-### [](#4-布局配置)4\. 布局配置
-
-[/@/layout/navBars/breadcrumb/setings.vue](#/src/layout/navBars/breadcrumb/setings.vue),国际化数据在 [/@/i18n/lang](#/src/i18n/lang) 中的 `layout` 对象。基本上使用 `$t('message.layout.xxx')` 语法
-
-```
-
-
-`<div  class="layout-breadcrumb-seting-bar-flex-label">   {{ $t('message.layout.twoMenuBar') }}
-</div>`
-
-
-
-
-```
-
-### [](#5-页面)5\. 页面
-
-基本上使用 `$t('message.xxx.xxx')` 语法
-
-### 本页导航
-
-1\. 多国语言配置
-
-前端配置国际化
-
-后端配置国际化
-
-2\. 国际化使用
-
-页面上使用 .vue,$t('xxx.xxx')
-
-ts 上使用 .ts,i18n.global.t(xxx)
-
-setup 里使用 ,t(xxx)
-
-框架其它国际化
-
-1\. 菜单
-
-2\. 浏览器标题
-
-3\. 顶栏
-
-4\. 布局配置
-
-5\. 页面

+ 0 - 83
doc/24.md

@@ -1,83 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/tCsMFF956EX0JzAB8kkMuGpAUwWcW7KoJnzN1fY5.jpg)
-](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)
-
-[🛒 B2B2C商家入驻平台系统java版 **Java+vue+uniapp** 功能强大 稳定 支持diy 方便二开](https://wwads.cn/click/bundle?code=9jhZ2FXcnCRpk9xUn1XCDu9dgxbnga)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端首页组件开发
-========
-
-![](https://minio.pigx.top/oss/202403/1711008130.png)
-
-[](#开发组件)开发组件
--------------
-
-*   在 src/views/home/widgets/components 目录下创建组件
-
-![](https://minio.pigx.top/oss/202403/1711008491.png)
-
-[](#挂载组件)挂载组件
--------------
-
-*   在 src/views/home/widgets/index.vue 中挂载组件,将 myGrid 数组增加上一步创建的组件文件名称
-
-```
-
-
- `const myGrid =  [    'test-demo',    ];`
-
-
-
-
-```
-
-![](https://minio.pigx.top/oss/202403/1711008679.png)
-
-### 本页导航
-
-开发组件
-
-挂载组件

+ 0 - 479
doc/25.md

@@ -1,479 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/U3n343DCMimUvbTZX1xnbYkOoPlTBBVBjzP4bqjf.jpg)
-](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)
-
-[🔥**码云GVP开源项目 16k star** Uniapp + ElementUI 功能强大 支持多语言、二开方便](https://wwads.cn/click/bundle?code=ajZTgGgWudQ8jFBWxiOCY1T5Qly4mg)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/22
-
-切换主题
-
-前端目录结构
-======
-
-```
-
-
-`├── src/ # 源代码目录  │   ├── api/ # API 接口定义  │   ├── assets/ # 静态资源  │   ├── components/ # 公共组件  │   ├── directive/ # Vue 自定义指令  │   ├── hooks/ # Vue Composition API hooks  │   ├── i18n/ # 国际化相关  │   ├── layout/ # 布局组件  │   ├── locales/ # 语言包  │   ├── router/ # Vue Router 配置  │   ├── stores/ # Pinia 状态管理  │   ├── theme/ # 主题相关  │   ├── types/ # TypeScript 类型定义  │   ├── utils/ # 工具函数  │   ├── views/ # 页面组件  │   ├── App.vue # 根组件  │   └── main.ts # 应用入口文件  ├── public/ # 公共静态资源  ├── docker/ # Docker 相关配置  ├── index.html # HTML 入口文件  ├── vite.config.ts # Vite 配置  ├── tsconfig.json # TypeScript 配置  ├── tailwind.config.js # Tailwind CSS 配置  ├── postcss.config.js # PostCSS 配置  ├── package.json # 项目依赖配置  ├── .env # 环境变量  ├── .env.development # 开发环境变量  ├── .env.development.local # 本地开发环境变量  ├── .env.local # 本地环境变量  ├── .eslintrc.js # ESLint 配置  └── .prettierrc.js                     Prettier 配置`
-
-
-
-
-```
-
-警告
-
-清空浏览器永久缓存或者点击 `布局配置 -> 一键恢复默认`,前提是修改了 [/src/stores/themeConfig.ts](#/src/stores/themeConfig.ts) 配置文件内容。添加或者修改功能,请前往 [/@/layout/navBars/breadcrumb/setings.vue](#/src/layout/navBars/breadcrumb/setings.vue) 组件位置修改
-
-[](#布局说明)布局说明
--------------
-
-警告
-
-可视化操作:左上角 `icon` 图标点击打开布局配置,所有配置功能都在这个里面 代码操作:[/src/stores/themeConfig.ts](#/src/stores/themeConfig.ts)
-
-包含:`菜单栏`、`顶栏`、`tagsView 标签页`、`主内容区`。
-
-[](#全局主题)全局主题
--------------
-
-### [](#1-目录结构)1\. 目录结构
-
-```
-
-
-`├── theme  (页面样式)   ├── common  (基础样式)   │	├── transition.scss  (页面过渡动画)   │	└── var.scss  (全局主题样式,用于全局改变样式)  	│
- ├── media  (媒体查询)   │	├── chart.scss  (大数据图表)   │	├── cityLinkage.scss  (Cascader 级联选择器城市选择)   │	├── dialog.scss  (弹窗)   │	├── error.scss  (404、401界面)   │	├── form.scss  (表单)   │	├── home.scss  (首页)   │	├── index.scss  (媒体查询定义主样式)   │	├── layout.scss  (框架布局)   │	├── login.scss  (登录界面)   │	├── media.scss  (媒体查询主出口)   │	├── pagination.scss  (分页)   │	├── personal.scss  (个人中心)   │	├── scrollbar.scss  (页面滚动条)   │	└── tagsView.scss  (tagsView 标签页)  	│
- ├── mixins  (scss混入)   │	├── element-mixins.scss  (定义重置的element plus混入复用样式)   │	├── function.scs  (全局主题颜色调用混入函数)   │	└── mixins.scss  (定义一些常用的全局混入样式)  	│
- ├── app.scss  (页面主样式,用于重置浏览器默认样式)   ├── base.scss  (基础样式、过渡动画引入等)   ├── dark.scss  (深色主题)   ├── element.scss  (重置的element plus样式,用于改变主题)   ├── iconSelector.scss  (图标选择器)   ├── index.scss  (页面样式主出口)   ├── loading.scss  (loading样式)   ├── other.scss  (其它样式)   └── waves.scss  (按钮波浪样式)`
-
-
-
-
-```
-
-### [](#2-scss-部分函数说明)2\. scss 部分函数说明
-
-一、scss @mixin
-
-*   定义:[scss 官方中文文档](https://www.sass.hk/docs/),具体请查阅官方文档。使用方法:
-
-```
-
-
-`/* Button 按钮 ------------------------------- */  @mixin  Button($main,  $c1,  $c2)  {   color:  set-color($main);   background:  set-color($c1);   border-color:  set-color($c2);  }`
-
-
-
-
-```
-
-*   页面中使用,先引入,然后在 `css` 类中通过 `@include` 使用
-
-```
-
-
-`@import  "mixins/element-mixins.scss";  
-// default  .el-button--default:hover, .el-button--default:focus {   @include  Button(primary, primary-light-8, primary-light-6);  }`
-
-
-
-
-```
-
-二、scss @function
-
-*   定义函数
-
-```
-
-
-`/* 颜色调用函数 ------------------------------- */  @function  set-color($key)  {   @return  var(--color-#{$key});  }`
-
-
-
-
-```
-
-*   不理解?请看这个 `css3 :root` [CSS var() 函数](https://www.runoob.com/cssref/func-var.html)
-
-```
-
-
-`/* 定义一个名为 "--main-bg-color" 的属性,然后使用 var() 函数调用该属性: */  :root {   --main-bg-color:  red;  }  
-#div1 {   background-color:  var(--main-bg-color);  }  
-#div2 {   background-color:  var(--main-bg-color);  }`
-
-
-
-
-```
-
-三、为什么不使用这种写法放进 :root 中?
-
-警告
-
-因为 scss 不支持这种嵌套 `mix(var(--color-primary), var(--color-success), 10%)`,lighten / darken / saturate / desaturate 等,从而无法用 `document.documentElement.style.setProperty('--color-primary', 'blue');` 改变样式
-
-```
-
-
-`$colors:  (    primary:  #409eff,    success:  #67c23a,    info:  #909399,    warning:  #e6a23c,    danger:  #f56c6c  )  
-:root {    @each  $key, $value in $colors  {    --color-#{$key}:  #{$value};    }  }`
-
-
-
-
-```
-
-### [](#3-自定义全局主题)3\. 自定义全局主题
-
-一、实现方法,以下方法不晓得会不会影响页面渲染性能:
-
-*   1、定义全局 :root 初始变量,路径:`src/theme/common/var.scss`
-*   2、编写覆盖 element plus 的样式:路径:`src/theme/element.scss`
-*   3、页面通过 `document.documentElement.style.setProperty` 方法改变 `:root` 中的值
-
-二、具体实现
-
-警告
-
-第 1 第 2 步就不介绍了,直接去路径去看就懂了。接下来我们讲讲第 3 步:
-
-*   通过 `document.documentElement.style.setProperty` 改变颜色值 [setProperty 文档](https://developer.mozilla.org/zh-CN/docs/Web/API/CSSStyleDeclaration/setProperty)
-
-```
-
-
-`<script  setup>   import  { reactive }  from  "vue";     // 定义变量内容   const state =  reactive({   color:  "",   });     // 改变主题颜色   const  onColorChange  =  ()  =>  {   // 设置颜色   document.documentElement.style.setProperty("--color-primary", state.color);   // 设置颜色变浅   document.documentElement.style.setProperty(   "--color-primary-light-1",   getLightColor(state.color1,  0.1)   );   };  </script>`
-
-
-
-
-```
-
-*   getLightColor 颜色变浅方法,路径在:[src/utils/theme.ts](#)
-
-```
-
-
-`// 变浅颜色值,level为加深的程度,限0-1之间  export  function  getLightColor(color:  any, level:  number)  {   let reg =  /^#?[0-9A-Fa-f]{6}$/;   if  (!reg.test(color))  return  ElMessage.warning("输入错误的hex颜色值");   let rgb =  hexToRgb(color);   for  (let i =  0; i <  3; i++)  rgb[i]  =  Math.floor((255  - rgb[i])  * level + rgb[i]);   return  rgbToHex(rgb[0], rgb[1], rgb[2]);  }`
-
-
-
-
-```
-
-*   到此就完成了主题的全局变色了
-
-tip 还有疑问?总的来说,就是通过重新定义 `css` 样式,用来覆盖 [element-plus](https://element-plus.gitee.io/#/zh-CN/component/changelog) 默认的样式,从而实现全局主题变色。其它方法实现全局主题,请自行 [百度一下:https://www.baidu.com/](https://www.baidu.com/)
-
-### [](#4-框架中实现例子)4\. 框架中实现例子
-
-一、全局主题改变时
-
-*   主题改变时,会调用 `onColorPickerChange` 方法进行重新的覆盖 css `:root` 定义的变量的值
-
-```
-
-
-`const  onColorPickerChange  =  (color:  string)  =>  {   document.documentElement.style.setProperty(  color,  getThemeConfig.value[color]   );  };`
-
-
-
-
-```
-
-*   拿到的值会赋值给根节点上 `html`,`document.documentElement.style`。刷新的时再设置 `document.documentElement.style.cssText = Local.get('themeConfigStyle');`,防止数据丢失
-
-二、更改主题配置文件路径
-
-修改后不生效,请注意看下列文件顶部文字注释。
-
-[vue3.x:/src/stores/themeConfig.ts](#),
-
-警告
-
-1、需要每次都清理 `window.localStorage` 浏览器永久缓存 2、或者点击布局配置最底部 `一键恢复默认` 按钮即可看到效果
-
-[](#菜单--顶栏)菜单 / 顶栏
-------------------
-
-### [](#1-顶栏)1\. 顶栏
-
-文件路径:[/@/layout/navBars/breadcrumb](#)
-
-一、顶栏背景、顶栏默认字体颜色、顶栏背景渐变
-
-功能说明:`设置顶栏的背景颜色、字体颜色、背景渐变`
-
-### [](#2-菜单)2\. 菜单
-
-文件路径:[/@/layout/navMenu](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/navMenu)
-
-一、菜单背景、菜单默认字体颜色、菜单背景渐变、菜单字体背景高亮
-
-功能说明:`设置菜单的背景颜色、字体颜色、背景渐变、字体高亮背景色(颜色跟随全局主题(primary))`
-
-### [](#3-分栏)3\. 分栏
-
-文件路径:[/@/layout/component/columnsAside.vue](#/src/layout/component/columnsAside.vue)
-
-一、分栏菜单背景、分栏菜单默认字体颜色、分栏菜单背景渐变
-
-功能说明:`设置分栏菜单的背景颜色、字体颜色、背景渐变`
-
-[](#界面设置)界面设置
--------------
-
-### [](#1-菜单设置)1\. 菜单设置
-
-文件路径:[/@/layout/navMenu](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/navMenu)
-
-一、菜单水平折叠、菜单手风琴、经典布局分割菜单
-
-功能说明:`菜单水平折叠、手风琴(开启一个展开)、经典布局分割菜单(顶级在顶栏处,子级在菜单栏)`
-
-二、效果图
-
-### [](#2-固定-header)2\. 固定 Header
-
-文件路径:[/@/layout/main](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/main)
-
-一、固定 Header
-
-功能说明:`固定 Header(主内容区滚动,顶栏不跟随滚动)`
-
-### [](#3-锁屏)3\. 锁屏
-
-文件路径:[/@/layout/lockScreen](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/lockScreen)
-
-一、开启锁屏、自动锁屏(s/秒)
-
-功能说明:`开启锁屏(类似于电脑屏保)、自动锁屏(s/秒)`
-
-[](#界面显示)界面显示
--------------
-
-### [](#1-侧边栏-logo)1\. 侧边栏 Logo
-
-文件路径:[/@/layout/logo](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/logo)
-
-一、侧边栏 Logo
-
-功能说明:`显示/隐藏侧边栏 Logo`
-
-### [](#2-breadcrumb-面包屑)2\. Breadcrumb 面包屑
-
-文件路径:[/@/layout/navBars/Breadcrumb/breadcrumb.vue](#/src/layout/navBars/breadcrumb/breadcrumb.vue)
-
-一、开启 Breadcrumb、开启 Breadcrumb 图标
-
-功能说明:`开启 Breadcrumb、Breadcrumb 图标`
-
-### [](#3-tagsview-标签页)3\. Tagsview 标签页
-
-文件路径:[/@/layout/navBars/tagsView](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/navBars/tagsView)
-
-一、开启 Tagsview、开启 Tagsview 图标、开启 TagsView 缓存、开启 TagsView 拖拽、开启 TagsView 共用
-
-功能说明:`开启 Tagsview、Tagsview 图标、TagsView 缓存、TagsView 拖拽、TagsView 共用(共用详情界面:tagsView只会出现一个;非共用详情界面:tagsView会出现多个)`
-
-### [](#4-footer-版权)4\. Footer 版权
-
-文件路径:[/@/layout/footer](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/footer)
-
-一、开启 Footer 版权
-
-功能说明:`显示/隐藏底部版权`
-
-### [](#5-颜色模式)5\. 颜色模式
-
-文件路径:[/@/layout/navBars/breadcrumb/setings.vue](#/src/layout/navBars/breadcrumb/setings.vue)
-
-一、灰色模式、色弱模式、深色模式
-
-功能说明:`开启灰色模式、色弱模式、深色模式`
-
-### [](#6-前端水印)6\. 前端水印
-
-文件路径:[/@/utils/wartermark.ts](#/src/utils/watermark.ts)
-
-一、开启水印、水印文案
-
-功能说明:`开启开启水印、设置水印文案` ,可通过 [👉🏻修改前端配置项解决](https://pig4cloud.com/data/doc/pigx/front-end/pigx-front-config-setting.html)
-
-[](#其它设置)其它设置
--------------
-
-警告
-
-可使用 el-option 的 `value` 值去对应的 `文件路径` 里搜索查看
-
-### [](#1-tagsview-风格)1\. Tagsview 风格
-
-文件路径:[/@/layout/navBars/tagsView](https://gitee.com/lyt-top/vue-next-admin/tree/master/src/layout/navBars/tagsView)
-
-需注意 `value` 值需与定义的 `css 类名` 一致
-
-```
-
-
-`<el-select  v-model="getThemeConfig.tagsStyle">   <el-option  label="风格1"  value="tags-style-one"></el-option>   <el-option  label="风格2"  value="tags-style-two"></el-option>   <el-option  label="风格3"  value="tags-style-three"></el-option>   <el-option  label="风格4"  value="tags-style-four"></el-option>   <!-- 新增的风格 -->   <el-option  label="风格xx"  value="tags-style-xxx"></el-option>   <!-- 继续添加 -->   ...
-</el-select>`
-
-
-
-
-```
-
-### [](#2-主页面切换动画)2\. 主页面切换动画
-
-文件路径:[/@/theme/common/transition.scss](#/src/theme/common/transition.scss),内置 `slide-right`、`slide-left`、`opacitys` 切换风格。
-
-你可能需要了解 [进入过渡 & 离开过渡](https://v3.cn.vuejs.org/guide/transitions-enterleave.html)。新增动画时,需要在 [/@/layout/navBars/breadcrumb/setings.vue](#/src/layout/navBars/breadcrumb/setings.vue) 其它设置中添加如下:
-
-```
-
-
-`<el-select  v-model="getThemeConfig.animation">   <el-option  label="slide-right"  value="slide-right"></el-option>   <el-option  label="slide-left"  value="slide-left"></el-option>   <el-option  label="opacitys"  value="opacitys"></el-option>   <!-- 新增的动画名 -->   <el-option  label="xxx"  value="xxx"></el-option>   <!-- 继续添加 -->   ...
-</el-select>`
-
-
-
-
-```
-
-### [](#3-分栏高亮风格)3\. 分栏高亮风格
-
-文件路径:[/@/layout/component/columnsAside.vue](#/src/layout/component/columnsAside.vue)。
-
-需注意 `value` 值需与定义的 `css 类名` 一致
-
-```
-
-
-`<el-select  v-model="getThemeConfig.columnsAsideStyle">   <el-option  label="圆角"  value="columns-round"></el-option>   <el-option  label="卡片"  value="columns-card"></el-option>   <!-- 新增的高亮风格 -->   <el-option  label="xxx"  value="xxx"></el-option>   <!-- 继续添加 -->   ...
-</el-select>`
-
-
-
-
-```
-
-### [](#4-分栏布局风格)4\. 分栏布局风格
-
-文件路径:[/@/layout/component/columnsAside.vue](#/src/layout/component/columnsAside.vue)。
-
-需注意 `value` 值需与定义的 `css 类名` 一致
-
-```
-
-
-`<el-select  v-model="getThemeConfig.columnsAsideLayout">   <el-option  label="水平"  value="columns-horizontal"></el-option>   <el-option  label="垂直"  value="columns-vertical"></el-option>   <!-- 新增的分栏布局风格 -->   <el-option  label="xxx"  value="xxx"></el-option>   <!-- 继续添加 -->   ...
-</el-select>`
-
-
-
-
-```
-
-[](#布局切换)布局切换
--------------
-
-此项目包含四个布局:默认、经典、横向、分栏。
-
-### 本页导航
-
-布局说明
-
-全局主题
-
-1\. 目录结构
-
-2\. scss 部分函数说明
-
-3\. 自定义全局主题
-
-4\. 框架中实现例子
-
-菜单 / 顶栏
-
-1\. 顶栏
-
-2\. 菜单
-
-3\. 分栏
-
-界面设置
-
-1\. 菜单设置
-
-2\. 固定 Header
-
-3\. 锁屏
-
-界面显示
-
-1\. 侧边栏 Logo
-
-2\. Breadcrumb 面包屑
-
-3\. Tagsview 标签页
-
-4\. Footer 版权
-
-5\. 颜色模式
-
-6\. 前端水印
-
-其它设置
-
-1\. Tagsview 风格
-
-2\. 主页面切换动画
-
-3\. 分栏高亮风格
-
-4\. 分栏布局风格
-
-布局切换

+ 0 - 340
doc/26.md

@@ -1,340 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/nq9iSbnLOnks56yd7kgp0mkIMOE0r2L5Tfoh2Xsl.jpg)
-](https://wwads.cn/click/bundle?code=HjZ6abOaWJEGLWeayArlJsVuAiVWpI)
-
-[U-Mail邮件群发平台-众多优质通道-送达率超90%-全面技术提升发送效果-免费测试](https://wwads.cn/click/bundle?code=HjZ6abOaWJEGLWeayArlJsVuAiVWpI)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端ENV环境配置
-=========
-
-| 配置项 | 值 | 描述 |
-| --- | --- | --- |
-| 
-
-**VITE\_IS\_MICRO**
-
- | 
-
-`true`
-
- | 
-
-是否是微服务架构(重要),因为单体和微服务版本共用一套前端
-
- |
-| 
-
-**VITE\_GLOBAL\_TITLE**
-
- | 
-
-`'PIGX ADMIN'`
-
- | 
-
-网站主标题 (修改需要清空 localstore)
-
- |
-| 
-
-**VITE\_FOOTER\_TITLE**
-
- | 
-
-`'©2024 pig4cloud.com'`
-
- | 
-
-网站页脚信息 (修改需要清空 localstore)
-
- |
-| 
-
-**VITE\_PUBLIC\_PATH**
-
- | 
-
-`/`
-
- | 
-
-前端访问前缀
-
- |
-| 
-
-**VITE\_API\_URL**
-
- | 
-
-`/api`
-
- | 
-
-后端请求前缀
-
- |
-| 
-
-**VITE\_ADMIN\_PROXY\_PATH**
-
- | 
-
-`http://localhost:9999`
-
- | 
-
-ADMIN 服务地址
-
- |
-| 
-
-**VITE\_PWD\_ENC\_KEY**
-
- | 
-
-`'pigxpigxpigxpigx'`
-
- | 
-
-前端加密密钥 (16位,具体参考文���前端报文加密)
-
- |
-| 
-
-**VITE\_OAUTH2\_PASSWORD\_CLIENT**
-
- | 
-
-`'pig:pig'`
-
- | 
-
-OAUTH2 密码模式客户端信息
-
- |
-| 
-
-**VITE\_OAUTH2\_MOBILE\_CLIENT**
-
- | 
-
-`'app:app'`
-
- | 
-
-OAUTH2 短信客户端信息
-
- |
-| 
-
-**VITE\_OAUTH2\_SOCIAL\_CLIENT**
-
- | 
-
-`'social:social'`
-
- | 
-
-OAUTH2 社交登录客户端信息
-
- |
-| 
-
-**VITE\_VERIFY\_ENABLE**
-
- | 
-
-`true`
-
- | 
-
-是否开启前端滑块验证码
-
- |
-| 
-
-**VITE\_VERIFY\_IMAGE\_ENABLE**
-
- | 
-
-`false`
-
- | 
-
-是否开启前端图形验证码 (具体参考验证码章节)
-
- |
-| 
-
-**VITE\_WEBSOCKET\_ENABLE**
-
- | 
-
-`false`
-
- | 
-
-是否开启 WebSocket 消息接收
-
- |
-| 
-
-**VITE\_REGISTER\_ENABLE**
-
- | 
-
-`true`
-
- | 
-
-是否开启注册
-
- |
-| 
-
-**VITE\_AUTO\_TENANT**
-
- | 
-
-`false`
-
- | 
-
-是否开启租户自动选择(根据租户域名)
-
- |
-| 
-
-**VITE\_I18N\_ENABLE**
-
- | 
-
-`true`
-
- | 
-
-登录页是否开启多语言切换
-
- |
-| 
-
-**VITE\_DARK\_MODE\_ENABLE**
-
- | 
-
-`true`
-
- | 
-
-登录页是否开启暗黑模式切换
-
- |
-| 
-
-**VITE\_ENABLE\_ANTI\_DEBUG**
-
- | 
-
-`false`
-
- | 
-
-是否启用禁用浏览器调试功能(反爬)
-
- |
-| 
-
-**VITE\_ANTI\_DEBUG\_KEY**
-
- | 
-
-`pig`
-
- | 
-
-绕过反爬参数值(URL中 `?ddtk=参数值`)
-
- |
-| 
-
-**VITE\_GRAY\_VERSION**
-
- | 
-
-无
-
- | 
-
-对应灰度路由的header Version
-
- |
-| 
-
-**VITE\_API\_ENC\_ENABLED**
-
- | 
-
-false
-
- | 
-
-是否开启请求加解密
-
- |
-| 
-
-**VITE\_TENANT\_ENABLE**
-
- | 
-
-true
-
- | 
-
-是否开启租户功能 (v5.9)
-
- |
-
-### 本页导航

+ 0 - 692
doc/27.md

@@ -1,692 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/HYKVsnrmfPfixKqkTmAG9VrkVFraIps5tqkbEE8n.jpg)
-](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)
-
-[注册亚马逊云服务免费套餐🆓可享高达200美元抵扣金🚀包括免费使用精选服务🎉](https://wwads.cn/click/bundle?code=9jV4U87gm2l5qP0HxzCu8wLpUQUQrP)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-浏览器兼容性前端配置项说明前端ENV环境配置前端目录结构前端首页组件开发前端国际化配置前端字体图标配置前端图表功能前端权限管理前端数据状态管理前端组件路由管理前端标签页管理前端字典工具使用前端参数工具使用前端通用工具函数省市区街四级联动组件前端代码编辑组件前端富文本组件前端表格组件前端表格分页组件前端表格工具栏组件前端上传组件前端左侧查询树前端文字提示组件前端悬浮输入组件前端组织架构组件前端标签列表组件前端表单校验
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端配置项说明
-=======
-
-配置文件:src/stores/themeConfig.ts
-
-*   1、需要每次都清理 `window.localStorage` 浏览器永久缓存
-*   2、或者点击布局配置最底部 `一键恢复默认` 按钮即可看到效果
-
-| 配置项 | 默认值 | 描述 |
-| --- | --- | --- |
-| 
-
-isDrawer
-
- | 
-
-false
-
- | 
-
-是否开启布局配置抽屉
-
- |
-| 
-
-primary
-
- | 
-
-#2E5CF6
-
- | 
-
-全局主题默认 primary 主题颜色
-
- |
-| 
-
-isDark
-
- | 
-
-false
-
- | 
-
-是否开启深色模式
-
- |
-| 
-
-topBar
-
- | 
-
-#ffffff
-
- | 
-
-顶栏设置默认顶栏导航背景颜色
-
- |
-| 
-
-topBarColor
-
- | 
-
-#606266
-
- | 
-
-顶栏设置默认顶栏导航字体颜色
-
- |
-| 
-
-isTopBarColorGradual
-
- | 
-
-false
-
- | 
-
-顶栏设置是否开启顶栏背景颜色渐变
-
- |
-| 
-
-menuBar
-
- | 
-
-#FFFFFF
-
- | 
-
-菜单设置默认菜单导航背景颜色
-
- |
-| 
-
-menuBarColor
-
- | 
-
-#505968
-
- | 
-
-菜单设置默认菜单导航字体颜色
-
- |
-| 
-
-menuBarActiveColor
-
- | 
-
-rgba(242...
-
- | 
-
-菜单设置默认菜单高亮背景色
-
- |
-| 
-
-isMenuBarColorGradual
-
- | 
-
-false
-
- | 
-
-菜单设置是否开启菜单背景颜色渐变
-
- |
-| 
-
-columnsMenuBar
-
- | 
-
-#545c64
-
- | 
-
-分栏设置默认分栏菜单背景颜色
-
- |
-| 
-
-columnsMenuBarColor
-
- | 
-
-#e6e6e6
-
- | 
-
-分栏设置默认分栏菜单字体颜色
-
- |
-| 
-
-isColumnsMenuBarColorGradual
-
- | 
-
-false
-
- | 
-
-分栏设置是否开启分栏菜单背景颜色渐变
-
- |
-| 
-
-isColumnsMenuHoverPreload
-
- | 
-
-false
-
- | 
-
-分栏设置是否开启分栏菜单鼠标悬停预加载(预览菜单)
-
- |
-| 
-
-isCollapse
-
- | 
-
-false
-
- | 
-
-界面设置是否开启菜单水平折叠效果
-
- |
-| 
-
-isUniqueOpened
-
- | 
-
-true
-
- | 
-
-界面设置是否开启菜单手风琴效果
-
- |
-| 
-
-isFixedHeader
-
- | 
-
-false
-
- | 
-
-界面设置是否开启固定 Header
-
- |
-| 
-
-isFixedHeaderChange
-
- | 
-
-false
-
- | 
-
-初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
-
- |
-| 
-
-isClassicSplitMenu
-
- | 
-
-false
-
- | 
-
-界面设置是否开启经典布局分割菜单(仅经典布局生效)
-
- |
-| 
-
-isLockScreen
-
- | 
-
-false
-
- | 
-
-界面设置是否开启自动锁屏
-
- |
-| 
-
-lockScreenTime
-
- | 
-
-30
-
- | 
-
-界面设置开启自动锁屏倒计时(s/秒)
-
- |
-| 
-
-isShowLogo
-
- | 
-
-true
-
- | 
-
-界面显示是否开启侧边栏 Logo
-
- |
-| 
-
-isShowLogoChange
-
- | 
-
-false
-
- | 
-
-初始化变量,用于 el-scrollbar 的高度更新,请勿删除
-
- |
-| 
-
-isBreadcrumb
-
- | 
-
-true
-
- | 
-
-界面显示是否开启 Breadcrumb,强制经典、横向布局不显示
-
- |
-| 
-
-isTagsview
-
- | 
-
-true
-
- | 
-
-界面显示是否开启 Tagsview
-
- |
-| 
-
-isBreadcrumbIcon
-
- | 
-
-false
-
- | 
-
-界面显示是否开启 Breadcrumb 图标
-
- |
-| 
-
-isTagsviewIcon
-
- | 
-
-false
-
- | 
-
-界面显示是否开启 Tagsview 图标
-
- |
-| 
-
-isCacheTagsView
-
- | 
-
-true
-
- | 
-
-界面显示是否开启 TagsView 缓存
-
- |
-| 
-
-isSortableTagsView
-
- | 
-
-true
-
- | 
-
-界面显示是否开启 TagsView 拖拽
-
- |
-| 
-
-isShareTagsView
-
- | 
-
-false
-
- | 
-
-界面显示是否开启 TagsView 共用
-
- |
-| 
-
-isFooter
-
- | 
-
-true
-
- | 
-
-界面显示是否开启 Footer 底部版权信息
-
- |
-| 
-
-isGrayscale
-
- | 
-
-false
-
- | 
-
-界面显示是否开启灰色模式
-
- |
-| 
-
-isInvert
-
- | 
-
-false
-
- | 
-
-界面显示是否开启色弱模式
-
- |
-| 
-
-isWartermark
-
- | 
-
-true
-
- | 
-
-界面显示是否开启水印
-
- |
-| 
-
-wartermarkText
-
- | 
-
-PigX
-
- | 
-
-界面显示水印文案
-
- |
-| 
-
-quickLinkNum
-
- | 
-
-12
-
- | 
-
-首页快捷导航数量上限
-
- |
-| 
-
-tagsStyle
-
- | 
-
-tags-style-five
-
- | 
-
-其它设置 Tagsview 风格,默认 tags-style-five
-
- |
-| 
-
-animation
-
- | 
-
-slide-right
-
- | 
-
-其它设置主页面切换动画,默认 slide-right
-
- |
-| 
-
-columnsAsideStyle
-
- | 
-
-columns-round
-
- | 
-
-其它设置分栏高亮风格,默认 columns-round
-
- |
-| 
-
-columnsAsideLayout
-
- | 
-
-columns-vertical
-
- | 
-
-其它设置分栏布局风格,默认 columns-horizontal
-
- |
-| 
-
-layout
-
- | 
-
-defaults
-
- | 
-
-布局设置,默认 defaults
-
- |
-| 
-
-isRequestRoutes
-
- | 
-
-true
-
- | 
-
-后端控制路由是否开启
-
- |
-| 
-
-globalTitle
-
- | 
-
-PIGX ADMIN
-
- | 
-
-全局网站标题 / 副标题-网站主标题(菜单导航、浏览器当前网页标题、登录 form 顶部右侧)
-
- |
-| 
-
-globalViceTitle
-
- | 
-
-PigX 快速开发框架
-
- | 
-
-全局网站标题 / 副标题-网站副标题(登录左侧底部页顶部文字)
-
- |
-| 
-
-globalViceTitleMsg
-
- | 
-
-专注、免费、开源、维护、解疑
-
- | 
-
-全局网站标题 / 副标题-网站副标题(登录页顶部文字)
-
- |
-| 
-
-globalI18n
-
- | 
-
-zh-cn
-
- | 
-
-全局网站标题 / 副标题-默认初始语言,可选值"<zh-cn
-
- |
-| 
-
-globalComponentSize
-
- | 
-
-'default'
-
- | 
-
-全局网站标题 / 副标题-默认全局组件大小,可选值"<large
-
- |
-| 
-
-footerAuthor
-
- | 
-
-©2023 pig4cloud.com
-
- | 
-
-全局网站标题 / 副标题-footer 页面作者
-
- |
-
-[](#图形化配置)图形化配置
----------------
-
-![](https://minio.pigx.top/oss/202304/1681738432.png)
-
-### 本页导航
-
-图形化配置

+ 0 - 260
doc/3.md

@@ -1,260 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/9UFEBWm9yghqfP2A3Ri7GzEqF8ccpKj2J0fHzhS7.png)
-](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)
-
-[电商项目必备!Java 开源商城系统 SpringBoot+Vue 框架,功能齐全,全源码交付,可二开](https://wwads.cn/click/bundle?code=4jQpSYno5LBbz49BkpNUvNEIyc5l09)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端字体图标配置
-========
-
-[](#一-elementplus-图标)一、 ElementPlus 图标
---------------------------------------
-
-使用 element plus 的图标,可去 [https://element-plus.org/zh-CN/component/icon.html](https://element-plus.org/zh-CN/component/icon.html) 复制粘贴
-
-`<el-icon></el-icon>` 包裹着
-
-```
-
-
-`<el-input   type="text"   :placeholder="$t('message.account.accountPlaceholder1')"   v-model="ruleForm.userName"   clearable   autocomplete="off"  >   <template  #prefix>   <el-icon  class="el-input__icon"><ele-User  /></el-icon>   </template>  </el-input>`
-
-
-
-
-```
-
-[](#二-阿里巴巴在线图标)二、 阿里巴巴在线图标
---------------------------
-
-### [](#1-创建图标项目)1\. 创建图标项目
-
-1.  访问 [iconfont 官网](https://www.iconfont.cn/) 并登录
-2.  创建新项目 -> 设置`FontClass/Symbol 前缀`为 `icon`,`Font Family` 为 `iconfont`
-3.  添加所需图标到项目 -> 生成在线链接
-
-### [](#2-设置在线链接)2\. 设置在线链接
-
-代码位置:[/@/utils/setIconfont.ts](#/src/utils/setIconfont.ts)
-
-```
-
-
-``// `/@/utils/setIconfont.ts` cssCdnUrlList 方法中添加在线链接  // 字体图标 url (新增)  const cssCdnUrlList:  Array<string>  =  [   "//at.alicdn.com/t/font_2298093_y6u00apwst.css",   "//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css",  ];``
-
-
-
-
-```
-
-### [](#3-界面中使用)3\. 界面中使用
-
-警告
-
-*   iconfont(阿里巴巴素材库):需要添加 `iconfont` 前缀,如:`iconfont xitongshezhi`
-*   font-awesome:需要添加 `fa` 前缀,如:`fa xitongshezhi`
-
-```
-
-
-`<!-- 项目使用 -->  <i  class="iconfont xitongshezhi"></i>  <!-- <i class="fa xitongshezhi"></i> -->  
-<!-- 或者 -->  <SvgIcon  name="iconfont xitongshezhi"></SvgIcon>  <!-- <SvgIcon name="fa xitongshezhi"></SvgIcon> -->`
-
-
-
-
-```
-
-[](#三本地图标)三、本地图标
-----------------
-
-支持下载 svg ,放在前端的 icons 目录
-
-![](https://minio.pigx.top/oss/202306/1685929608.png)
-
-前端可通过 local-文件名的形式加载
-
-```
-
-
-`<SvgIcon  name="local-gitee"  :size="30"  />`
-
-
-
-
-```
-
-[](#svgicon-标签使用)`<SvgIcon/>` 标签使用
-----------------------------------
-
-### [](#2-局部注册--全局注册-svg-组件)2\. 局部注册 & 全局注册 svg 组件
-
-*   局部注册
-
-```
-
-
-`<!-- 页面上使用 -->  <SvgIcon  :name="item.meta.icon"  />  
-<script  setup  lang="ts"  name="xxx">   import  SvgIcon  from  "/@/components/svgIcon/index.vue";  </script>`
-
-
-
-
-```
-
-*   全局注册(框架中使用全局注册)
-
-[/@/utils/other.ts](#/src/utils/other.ts) 中的 `elSvg` 方法
-
-```
-
-
-`// 全局注册  import  SvgIcon  from  '/@/components/svgIcon/index.vue';  app.component("SvgIcon",  SvgIcon);  
-// 页面上使用  <SvgIcon  :name="item.meta.icon"  />  
-// 或者  <SvgIcon name="ele-Aim"  :size="14" color="#333333"/>`
-
-
-
-
-```
-
-[](#自定义引入本地图标)自定义引入本地图标
------------------------
-
-```
-
-
-`<!-- 项目使用 -->  <i  class="iconfont xitongshezhi"></i>  
-<!-- 或者 -->  <SvgIcon  name="iconfont xitongshezhi"></SvgIcon>`
-
-
-
-
-```
-
-[](#进阶阿里巴巴图标库离线)进阶:阿里巴巴图标库离线
-----------------------------
-
-为了提高系统的稳定性和加载速度,我们可以将原本使用的阿里巴巴在线图标库转换为本地离线使用。
-
-#### [](#1-下载图标资源包)1\. 下载图标资源包
-
-[点击下载 PIGX-UI 都有依赖的阿里巴巴图标](https://minio.pigx.vip/oss/202501/1737972483.zip)
-
-#### [](#2-创建本地图标目录)2\. 创建本地图标目录
-
-```
-
-
-`mkdir -p pigx-ui/public/assets/iconfont`
-
-
-
-
-```
-
-#### [](#3-复制资源文件)3\. 复制资源文件
-
-将下载的资源包中的以下文件复制到 `public/assets/iconfont/` 目录:
-
-*   iconfont.css
-*   iconfont.ttf
-*   iconfont.woff
-*   iconfont.woff2
-
-#### [](#4-修改配置文件)4\. 修改配置文件
-
-修改 `src/utils/setIconfont.ts` 文件中的图标引用路径:
-
-```
-
-
-`const cssCdnUrlList:  Array<string>  =  [   '/assets/iconfont/iconfont.css',  // 本地图标文件   '/assets/styles/font-awesome.min.css',  ];`
-
-
-
-
-```
-
-#### [](#验证)验证
-
-1.  启动项目
-2.  检查图标是否正常显示
-3.  在断网情况下验证图标是否仍然可用
-
-警告
-
-确保复制的文件名与代码中引用的路径完全一致 如果后续需要添加新图标,重复以上步骤即可更新本地图标文件
-
-### 本页导航
-
-一、 ElementPlus 图标
-
-二、 阿里巴巴在线图标
-
-1\. 创建图标项目
-
-2\. 设置在线链接
-
-3\. 界面中使用
-
-三、本地图标
-
-<SvgIcon/> 标签使用
-
-2\. 局部注册 & 全局注册 svg 组件
-
-自定义引入本地图标
-
-进阶:阿里巴巴图标库离线
-
-1\. 下载图标资源包
-
-2\. 创建本地图标目录
-
-3\. 复制资源文件
-
-4\. 修改配置文件
-
-验证

+ 0 - 240
doc/4.md

@@ -1,240 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/nq9iSbnLOnks56yd7kgp0mkIMOE0r2L5Tfoh2Xsl.jpg)
-](https://wwads.cn/click/bundle?code=HjZ6abOaWJEGLWeayArlJsVuAiVWpI)
-
-[U-Mail邮件群发平台-众多优质通道-送达率超90%-全面技术提升发送效果-免费测试](https://wwads.cn/click/bundle?code=HjZ6abOaWJEGLWeayArlJsVuAiVWpI)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端表单校验
-======
-
-[](#表单校验使用)表单校验使用
------------------
-
-Form 组件允许你验证用户的输入是否符合规范,来帮助你找到和纠正错误。
-
-Form 组件提供了表单验证的功能,只需为 rules 属性传入约定的验证规则,并将 form-Item 的 prop 属性设置为需要验证的特殊键值即可。 校验规则参见 [https://element-plus.org](https://element-plus.org/zh-CN/component/form.html)
-
-```
-
-
-`const rule =  ref({   字段名称:  [   // 校验用户输入的长度避免超长 0-255个字符 超长   {  validator: rule.overLength,  trigger:  "blur"  },   // 根据字段自动查询后台是否重复   {   validator:  (rule: any,  value: any,  callback: any)  =>  {   validateExist(rule, value, callback, form.id  !==  "");   },   trigger:  "blur",   },   ],  });`
-
-
-
-
-```
-
-[](#内置规则)内置规则
--------------
-
-| 函数名称 | 函数作用 |
-| --- | --- |
-| 
-
-validateExist
-
- | 
-
-根据字段自动查询后台是否重复
-
- |
-| 
-
-overLength
-
- | 
-
-校验用户输入的长度避免超长,范围为 0-255 个字符
-
- |
-| 
-
-validatorNameCn
-
- | 
-
-校验用户输入是否为中文、英文、数字包括下划线
-
- |
-| 
-
-validatorCapital
-
- | 
-
-校验用户输入是否为大写英文、下划线
-
- |
-| 
-
-validatorLowercase
-
- | 
-
-校验用户输入是否为小写英文、下划线
-
- |
-| 
-
-validatorLower
-
- | 
-
-校验用户输入是否为小写英文
-
- |
-| 
-
-checkSpace
-
- | 
-
-校验输入是否包含首尾空白字符
-
- |
-| 
-
-validatePhone
-
- | 
-
-校验手机号的合法性
-
- |
-| 
-
-number
-
- | 
-
-校验输入是否为数字
-
- |
-| 
-
-letter
-
- | 
-
-校验输入是否为字母
-
- |
-| 
-
-letterAndNumber
-
- | 
-
-校验输入是否为字母和数字
-
- |
-| 
-
-mobilePhone
-
- | 
-
-校验输入是否为正确格式的手机号码
-
- |
-| 
-
-letterStartNumberIncluded
-
- | 
-
-校验输入是否以字母开头,可包含数字
-
- |
-| 
-
-noChinese
-
- | 
-
-校验输入是否包含中文字符
-
- |
-| 
-
-chinese
-
- | 
-
-校验输入是否为中文字符
-
- |
-| 
-
-email
-
- | 
-
-校验输入是否为正确格式的电子邮箱
-
- |
-| 
-
-url
-
- | 
-
-校验输入是否为正确格式的 URL
-
- |
-| 
-
-regExp
-
- | 
-
-校验输入是否符合给定的正则表达式
-
- |
-
-### 本页导航
-
-表单校验使用
-
-内置规则

+ 0 - 128
doc/5.md

@@ -1,128 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/7U1lK1OhuTHyblDBlklblPMLDASL04CY2LWZppnD.jpg)
-](https://wwads.cn/click/bundle?code=sj7Ny736XRcFfkxA7ZZ2xd4g0QXaBc)
-
-[立即注册亚马逊云服务免费套餐🆓享高达200美元抵扣金🚀开始您的云计算之旅🎉](https://wwads.cn/click/bundle?code=sj7Ny736XRcFfkxA7ZZ2xd4g0QXaBc)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端标签列表组件
-========
-
-![](https://minio.pigx.top/oss/202407/1721358361.png)
-
-[](#使用方法)使用方法
--------------
-
-![](https://minio.pigx.top/oss/202308/1690987106.png)
-
-```
-
-
-`<tag-list buttonText="+手机号" v-model="phoneList"  />;  
-const phoneList =  ref([]);`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性 | 类型 | 默认值 | 说明 |
-| --- | --- | --- | --- |
-| 
-
-`modelValue`
-
- | 
-
-Array\[String\]
-
- | 
-
-`[]`
-
- | 
-
-双向绑定绑定的标签数组
-
- |
-| 
-
-`buttonText`
-
- | 
-
-String
-
- | 
-
-`+ New Tag`
-
- | 
-
-按钮显示的文本
-
- |
-| 
-
-`tagType`
-
- | 
-
-'success', 'info', 'warning', 'danger'
-
- | 
-
- | 
-
-按钮显示类型
-
- |
-
-### 本页导航
-
-使用方法
-
-属性说明

+ 0 - 177
doc/6.md

@@ -1,177 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/GPfb3fTMCC7MNI9G44pKV791miZNKE2REPWfwcD4.jpg)
-](https://wwads.cn/click/bundle?code=ZjHRzsttiShllTKioSc21ytNdis6pa)
-
-[🔥**2核2G ARM架构云服务器 每月750小时免费试用**🆓 灵活弹性又可靠💪早用早省~](https://wwads.cn/click/bundle?code=ZjHRzsttiShllTKioSc21ytNdis6pa)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/9/16
-
-切换主题
-
-前端组织架构组件
-========
-
-![](https://minio.pigx.top/oss/202310/1696317433.jpg)
-
-[](#页面使用)页面使用
--------------
-
-```
-
-
-`import orgSelector from '/@/components/OrgSelector/index.vue'; 
-<org-selector  v-model:orgList="userList"  type="user"  :multiple="false"  />`
-
-
-
-
-```
-
-[](#数据格式)数据格式
--------------
-
-```
-
-
-`[   {   "type":  "user",   "id":  "1",   "name":  "admin",   "avatar":  "xx.png"   }  ]`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性名 | 类型 | 默认值 | 描述 |
-| --- | --- | --- | --- |
-| 
-
-orgList
-
- | 
-
-Array
-
- | 
-
-\[\]\`
-
- | 
-
-组织列表,用于显示可选的组织。
-
- |
-| 
-
-type
-
- | 
-
-String
-
- | 
-
-user
-
- | 
-
-类型,可选值为 user、 dept、 org (部门、用户 同时可选) 、role、post
-
- |
-| 
-
-multiple
-
- | 
-
-Boolean
-
- | 
-
-true
-
- | 
-
-是否允许多选。如果为 `true`,则可以选择多个组织或用户;如果为 `false`,则只能选择一个组织或用户。默认为 `true`。
-
- |
-| 
-
-disabled
-
- | 
-
-Boolean
-
- | 
-
-`false`
-
- | 
-
-是否禁用组件。如果为 `true`,则组件将不可用,用户无法进行选择。默认为 `false`。
-
- |
-| 
-
-selectSelf
-
- | 
-
-Boolean
-
- | 
-
-`true`
-
- | 
-
-是否包含自身。如果为 `true`,则在可选项中包含当前用户自身;如果为 `false`,则不包含当前用户自身。默认为 `true`。
-
- |
-
-### 本页导航
-
-页面使用
-
-数据格式
-
-属性说明

+ 0 - 255
doc/7.md

@@ -1,255 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/GPfb3fTMCC7MNI9G44pKV791miZNKE2REPWfwcD4.jpg)
-](https://wwads.cn/click/bundle?code=ZjHRzsttiShllTKioSc21ytNdis6pa)
-
-[🔥**2核2G ARM架构云服务器 每月750小时免费试用**🆓 灵活弹性又可靠💪早用早省~](https://wwads.cn/click/bundle?code=ZjHRzsttiShllTKioSc21ytNdis6pa)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端悬浮输入组件
-========
-
-[](#普通文件上传)普通文件上传
------------------
-
-![](https://minio.pigx.top/oss/202306/1687530763.png)
-
-```
-
-
-`const  PopoverInput  =  defineAsyncComponent(   ()  =>  import("/@/components/PopoverInput/index.vue")  );`
-
-
-
-
-```
-
-```
-
-
-`<popover-input  @confirm="onConfirm">   <template  #default>   <el-button> 点击输入 </el-button>   </template>  </popover-input>`
-
-
-
-
-```
-
-### [](#属性说明)属性说明
-
-| 属性名称 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| 
-
-value
-
- | 
-
-值
-
- | 
-
-String
-
- | 
-
-\-
-
- |
-| 
-
-type
-
- | 
-
-类型
-
- | 
-
-String
-
- | 
-
-'text'
-
- |
-| 
-
-width
-
- | 
-
-宽度
-
- | 
-
-Number
-
- | 
-
-String
-
- |
-| 
-
-placeholder
-
- | 
-
-提示文字
-
- | 
-
-String
-
- | 
-
-\-
-
- |
-| 
-
-disabled
-
- | 
-
-是否禁用
-
- | 
-
-Boolean
-
- | 
-
-false
-
- |
-| 
-
-options
-
- | 
-
-选项列表
-
- | 
-
-Array<any\[\]>
-
- | 
-
-\[\]
-
- |
-| 
-
-size
-
- | 
-
-大小
-
- | 
-
-'default'
-
- | 
-
-'small'
-
- |
-| 
-
-limit
-
- | 
-
-字符限制
-
- | 
-
-Number
-
- | 
-
-200
-
- |
-| 
-
-showLimit
-
- | 
-
-是否显示字符限制
-
- | 
-
-Boolean
-
- | 
-
-false
-
- |
-| 
-
-teleported
-
- | 
-
-是否使用传送门(teleport)进行渲染
-
- | 
-
-Boolean
-
- | 
-
-true
-
- |
-
-### 本页导航
-
-普通文件上传
-
-属性说明

+ 0 - 107
doc/8.md

@@ -1,107 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/7U1lK1OhuTHyblDBlklblPMLDASL04CY2LWZppnD.jpg)
-](https://wwads.cn/click/bundle?code=sj7Ny736XRcFfkxA7ZZ2xd4g0QXaBc)
-
-[立即注册亚马逊云服务免费套餐🆓享高达200美元抵扣金🚀开始您的云计算之旅🎉](https://wwads.cn/click/bundle?code=sj7Ny736XRcFfkxA7ZZ2xd4g0QXaBc)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端文字提示组件
-========
-
-[](#提示组件)提示组件
--------------
-
-```
-
-
-`<el-form-item  label="初始浏览量"  prop="visit">   <template  #label> 浏览量<tip  content="初始值"  />  </template>  </el-form-item>`
-
-
-
-
-```
-
-### [](#属性说明)属性说明
-
-| 属性名称 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| 
-
-content
-
- | 
-
-内容
-
- | 
-
-String
-
- | 
-
-\-
-
- |
-| 
-
-placement
-
- | 
-
-放置位置
-
- | 
-
-String
-
- | 
-
-'top-start'
-
- |
-
-### 本页导航
-
-提示组件
-
-属性说明

+ 0 - 164
doc/9.md

@@ -1,164 +0,0 @@
-技术文档
-
-打开导航菜单
-
-PIG AI Guide
-============
-
-切换主题搜索
-
-[](https://wwads.cn/click/bait)[![](https://cdn.wwads.cn/creatives/UPQhl7yG06tksqj5rkpXaQj3eAO6yA02XkpyhkoX.jpg)
-](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)
-
-[🚀 支持40+常用图表,20+主流数据源,拖拉拽制作数据大屏。**开源免费,支持二开**。](https://wwads.cn/click/bundle?code=rj1sGC1a4OL9EZHJYkOcZnZecLZrnV)[广告](https://wwads.cn/?utm_source=property-270&utm_medium=footer "点击了解万维广告联盟")
-
-PIGX 技术指南
-=========
-
-适配 5.0 以上单体和微服务版本
-
-PIGX 技术指南PIG
-
-⌘K
-
-参与开发
-
-快速上手
-
-前端部分
-
-功能使用
-
-后端部分
-
-扩展必看
-
-生产部署
-
-社区分享
-
-更新日志
-
-更新日期: 2025-10-23
-
-最后更新: 2025/8/19
-
-切换主题
-
-前端左侧查询树
-=======
-
-![](https://minio.pigx.top/oss/202304/1681633931.png)
-
-```
-
-
-`<query-tree  :query="state.queryList"  @node-click="handleNodeClick">  </query-tree>`
-
-
-
-
-```
-
-```
-
-
-`const  QueryTree  =  defineAsyncComponent(   ()  =>  import("/@/components/QueryTree/index.vue")  );  
-const state =  reactive({   queryList:  (name:  String)  =>  {   return  api({  name: name,   });   },  });  
-const  handleNodeClick  =  (e:  any)  =>  {};`
-
-
-
-
-```
-
-[](#卡槽扩展)卡槽扩展
--------------
-
-```
-
-
-`<query-tree>   <template  #default="{ node, data }">  </template>  </query-tree>`
-
-
-
-
-```
-
-[](#属性说明)属性说明
--------------
-
-| 属性 | 类型 | 默认值 | 说明 |
-| --- | --- | --- | --- |
-| 
-
-`props`
-
- | 
-
-`Object`
-
- | 
-
-`{ label: 'name', children: 'children', value: 'id' }`
-
- | 
-
-树形结构的属性配置。
-
- |
-| 
-
-`placeholder`
-
- | 
-
-`String`
-
- | 
-
-`''`
-
- | 
-
-输入框的占位符。
-
- |
-| 
-
-`loading`
-
- | 
-
-`Boolean`
-
- | 
-
-`false`
-
- | 
-
-是否显示加载状态。
-
- |
-| 
-
-`query`
-
- | 
-
-`Function`
-
- | 
-
- | 
-
-包含查询方法的函数,必须返回 Promise 类型的数据,并在组件中被调用。
-
- |
-
-### 本页导航
-
-卡槽扩展
-
-属性说明

+ 778 - 0
doc/daili.json

@@ -0,0 +1,778 @@
+{
+	"openapi": "3.0.1",
+	"info": {
+		"title": "默认模块",
+		"description": "",
+		"version": "1.0.0"
+	},
+	"tags": [],
+	"paths": {
+		"/agentUser/page": {
+			"get": {
+				"summary": "分页",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [
+					{
+						"name": "records[0].key",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": ""
+						}
+					},
+					{
+						"name": "total",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "integer",
+							"format": "int64"
+						}
+					},
+					{
+						"name": "size",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "integer",
+							"format": "int64"
+						}
+					},
+					{
+						"name": "current",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "integer",
+							"format": "int64"
+						}
+					},
+					{
+						"name": "orders[0].column",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "string"
+						}
+					},
+					{
+						"name": "orders[0].asc",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "boolean"
+						}
+					},
+					{
+						"name": "optimizeCountSql",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "boolean"
+						}
+					},
+					{
+						"name": "searchCount",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "boolean"
+						}
+					},
+					{
+						"name": "optimizeJoinOfCountSql",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "boolean"
+						}
+					},
+					{
+						"name": "maxLimit",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "integer",
+							"format": "int64"
+						}
+					},
+					{
+						"name": "countId",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "string"
+						}
+					},
+					{
+						"name": "query",
+						"in": "query",
+						"description": "",
+						"required": false,
+						"schema": {
+							"type": "string"
+						}
+					}
+				],
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/RPageAgentUserPageDTO"
+								},
+								"example": {
+									"code": 0,
+									"msg": "",
+									"data": {
+										"records": [
+											{
+												"userId": 0,
+												"status": false,
+												"agentName": ""
+											}
+										],
+										"total": 0,
+										"size": 0,
+										"current": 0,
+										"orders": [
+											{
+												"column": "",
+												"asc": false
+											}
+										],
+										"optimizeCountSql": false,
+										"searchCount": false,
+										"optimizeJoinOfCountSql": false,
+										"maxLimit": 0,
+										"countId": ""
+									}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		},
+		"/agentUser/save": {
+			"post": {
+				"summary": "新增",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [],
+				"requestBody": {
+					"content": {
+						"application/json": {
+							"schema": {
+								"$ref": "#/components/schemas/AgentUserROAdd",
+								"description": ""
+							}
+						}
+					}
+				},
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/R",
+									"description": "响应信息主体"
+								},
+								"example": {
+									"ok": false,
+									"code": null,
+									"msg": "",
+									"data": {}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		},
+		"/agentUser/changePwd/{id:^\\d+$}": {
+			"patch": {
+				"summary": "修改密码",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [
+					{
+						"name": "id",
+						"in": "path",
+						"description": "",
+						"required": true,
+						"schema": {
+							"type": "integer"
+						}
+					}
+				],
+				"requestBody": {
+					"content": {
+						"application/json": {
+							"schema": {
+								"$ref": "#/components/schemas/AgentUserROChangePwd",
+								"description": ""
+							}
+						}
+					}
+				},
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/R",
+									"description": "响应信息主体"
+								},
+								"example": {
+									"ok": false,
+									"code": null,
+									"msg": "",
+									"data": {}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		},
+		"/agentUser/changeStatus/{id:^\\d+$}": {
+			"patch": {
+				"summary": "启用禁用",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [
+					{
+						"name": "id",
+						"in": "path",
+						"description": "",
+						"required": true,
+						"schema": {
+							"type": "integer"
+						}
+					}
+				],
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/R",
+									"description": "响应信息主体"
+								},
+								"example": {
+									"ok": false,
+									"code": null,
+									"msg": "",
+									"data": {}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		},
+		"/agentUser/info/{id:^\\d+$}": {
+			"get": {
+				"summary": "详情",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [
+					{
+						"name": "id",
+						"in": "path",
+						"description": "",
+						"required": true,
+						"schema": {
+							"type": "integer"
+						}
+					}
+				],
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/R",
+									"description": "响应信息主体"
+								},
+								"example": {
+									"ok": false,
+									"code": null,
+									"msg": "",
+									"data": {}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		},
+		"/agentUser/edit/{id:^\\d+$}": {
+			"patch": {
+				"summary": "修改",
+				"deprecated": false,
+				"description": "",
+				"tags": [],
+				"parameters": [
+					{
+						"name": "id",
+						"in": "path",
+						"description": "",
+						"required": true,
+						"schema": {
+							"type": "integer"
+						}
+					}
+				],
+				"requestBody": {
+					"content": {
+						"application/json": {
+							"schema": {
+								"$ref": "#/components/schemas/AgentUserROUpdate",
+								"description": ""
+							}
+						}
+					}
+				},
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"$ref": "#/components/schemas/R",
+									"description": "响应信息主体"
+								},
+								"example": {
+									"ok": false,
+									"code": null,
+									"msg": "",
+									"data": {}
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": [
+					{
+						"bearer": []
+					}
+				]
+			}
+		}
+	},
+	"components": {
+		"schemas": {
+			"R": {
+				"type": "object",
+				"properties": {
+					"ok": {
+						"type": "boolean"
+					},
+					"code": {
+						"description": "返回标记:成功标记=0,失败标记=1",
+						"type": "null"
+					},
+					"msg": {
+						"type": "string",
+						"description": "返回信息"
+					},
+					"data": {
+						"type": "object",
+						"properties": {},
+						"description": "数据"
+					}
+				}
+			},
+			"AgentUserPageDTO": {
+				"type": "object",
+				"properties": {
+					"userId": {
+						"type": "integer",
+						"description": "用户ID",
+						"format": "int64"
+					},
+					"status": {
+						"type": "boolean",
+						"description": "启用状态"
+					},
+					"agentName": {
+						"type": "string",
+						"description": "代理商名称"
+					}
+				}
+			},
+			"AgentUserROAdd": {
+				"type": "object",
+				"properties": {
+					"username": {
+						"type": "string",
+						"description": "用户名"
+					},
+					"agentName": {
+						"type": "string",
+						"description": "代理商名称"
+					},
+					"realname": {
+						"type": "string",
+						"description": "真实姓名"
+					},
+					"phone": {
+						"type": "string",
+						"description": "手机号码"
+					},
+					"idcard": {
+						"type": "string",
+						"description": "身份证号"
+					},
+					"address": {
+						"type": "string",
+						"description": "通讯地址"
+					},
+					"email": {
+						"type": "string",
+						"description": "邮箱地址"
+					},
+					"offlineRechargeRate": {
+						"type": "number",
+						"description": "线下充值费率"
+					},
+					"status": {
+						"type": "boolean",
+						"description": "启用状态"
+					},
+					"bankName": {
+						"type": "string",
+						"description": "开户行名称"
+					},
+					"bankBranch": {
+						"type": "string",
+						"description": "开户网点"
+					},
+					"accountName": {
+						"type": "string",
+						"description": "账户名"
+					},
+					"accountNum": {
+						"type": "string",
+						"description": "账户号"
+					},
+					"bankProvince": {
+						"type": "string",
+						"description": "开户省"
+					},
+					"bankCity": {
+						"type": "string",
+						"description": "开户市"
+					},
+					"newPwd": {
+						"type": "string",
+						"description": "新密码"
+					},
+					"oldPwd": {
+						"type": "string",
+						"description": "旧密码"
+					}
+				},
+				"required": ["username", "agentName", "realname", "phone", "email"]
+			},
+			"OrderItem": {
+				"type": "object",
+				"properties": {
+					"column": {
+						"type": "string",
+						"description": ""
+					},
+					"asc": {
+						"type": "boolean",
+						"description": ""
+					}
+				}
+			},
+			"PageAgentUserPageDTO": {
+				"type": "object",
+				"properties": {
+					"records": {
+						"type": "array",
+						"items": {
+							"$ref": "#/components/schemas/AgentUserPageDTO",
+							"description": ""
+						},
+						"description": ""
+					},
+					"total": {
+						"type": "integer",
+						"description": "",
+						"format": "int64"
+					},
+					"size": {
+						"type": "integer",
+						"description": "",
+						"format": "int64"
+					},
+					"current": {
+						"type": "integer",
+						"description": "",
+						"format": "int64"
+					},
+					"orders": {
+						"type": "array",
+						"items": {
+							"$ref": "#/components/schemas/OrderItem",
+							"description": "com.baomidou.mybatisplus.core.metadata.OrderItem"
+						},
+						"description": ""
+					},
+					"optimizeCountSql": {
+						"type": "boolean",
+						"description": ""
+					},
+					"searchCount": {
+						"type": "boolean",
+						"description": ""
+					},
+					"optimizeJoinOfCountSql": {
+						"type": "boolean",
+						"description": ""
+					},
+					"maxLimit": {
+						"type": "integer",
+						"description": "",
+						"format": "int64"
+					},
+					"countId": {
+						"type": "string",
+						"description": ""
+					}
+				}
+			},
+			"RPageAgentUserPageDTO": {
+				"type": "object",
+				"properties": {
+					"code": {
+						"type": "integer",
+						"description": "返回标记:成功标记=0,失败标记=1"
+					},
+					"msg": {
+						"type": "string",
+						"description": "返回信息"
+					},
+					"data": {
+						"$ref": "#/components/schemas/PageAgentUserPageDTO",
+						"description": "数据"
+					}
+				}
+			},
+			"AgentUserROUpdate": {
+				"type": "object",
+				"properties": {
+					"username": {
+						"type": "string",
+						"description": "用户名"
+					},
+					"agentName": {
+						"type": "string",
+						"description": "代理商名称"
+					},
+					"realname": {
+						"type": "string",
+						"description": "真实姓名"
+					},
+					"phone": {
+						"type": "string",
+						"description": "手机号码"
+					},
+					"idcard": {
+						"type": "string",
+						"description": "身份证号"
+					},
+					"address": {
+						"type": "string",
+						"description": "通讯地址"
+					},
+					"email": {
+						"type": "string",
+						"description": "邮箱地址"
+					},
+					"offlineRechargeRate": {
+						"type": "number",
+						"description": "线下充值费率"
+					},
+					"status": {
+						"type": "boolean",
+						"description": "启用状态"
+					},
+					"bankName": {
+						"type": "string",
+						"description": "开户行名称"
+					},
+					"bankBranch": {
+						"type": "string",
+						"description": "开户网点"
+					},
+					"accountName": {
+						"type": "string",
+						"description": "账户名"
+					},
+					"accountNum": {
+						"type": "string",
+						"description": "账户号"
+					},
+					"bankProvince": {
+						"type": "string",
+						"description": "开户省"
+					},
+					"bankCity": {
+						"type": "string",
+						"description": "开户市"
+					},
+					"newPwd": {
+						"type": "string",
+						"description": "新密码"
+					},
+					"oldPwd": {
+						"type": "string",
+						"description": "旧密码"
+					}
+				},
+				"required": ["username", "agentName", "realname", "phone", "email"]
+			},
+			"AgentUserROChangePwd": {
+				"type": "object",
+				"properties": {
+					"username": {
+						"type": "string",
+						"description": "用户名"
+					},
+					"agentName": {
+						"type": "string",
+						"description": "代理商名称"
+					},
+					"realname": {
+						"type": "string",
+						"description": "真实姓名"
+					},
+					"phone": {
+						"type": "string",
+						"description": "手机号码"
+					},
+					"idcard": {
+						"type": "string",
+						"description": "身份证号"
+					},
+					"address": {
+						"type": "string",
+						"description": "通讯地址"
+					},
+					"email": {
+						"type": "string",
+						"description": "邮箱地址"
+					},
+					"offlineRechargeRate": {
+						"type": "number",
+						"description": "线下充值费率"
+					},
+					"status": {
+						"type": "boolean",
+						"description": "启用状态"
+					},
+					"bankName": {
+						"type": "string",
+						"description": "开户行名称"
+					},
+					"bankBranch": {
+						"type": "string",
+						"description": "开户网点"
+					},
+					"accountName": {
+						"type": "string",
+						"description": "账户名"
+					},
+					"accountNum": {
+						"type": "string",
+						"description": "账户号"
+					},
+					"bankProvince": {
+						"type": "string",
+						"description": "开户省"
+					},
+					"bankCity": {
+						"type": "string",
+						"description": "开户市"
+					},
+					"newPwd": {
+						"type": "string",
+						"description": "新密码"
+					},
+					"oldPwd": {
+						"type": "string",
+						"description": "旧密码"
+					}
+				},
+				"required": ["newPwd", "oldPwd"]
+			}
+		},
+		"securitySchemes": {
+			"bearer": {
+				"type": "http",
+				"scheme": "bearer"
+			}
+		}
+	},
+	"servers": [],
+	"security": []
+}

+ 1051 - 0
doc/shanghu.json

@@ -0,0 +1,1051 @@
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "默认模块",
+    "description": "",
+    "version": "1.0.0"
+  },
+  "tags": [],
+  "paths": {
+    "/merchantUser/page": {
+      "get": {
+        "summary": "分页",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "records[0].key",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": ""
+            }
+          },
+          {
+            "name": "total",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          },
+          {
+            "name": "size",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          },
+          {
+            "name": "current",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          },
+          {
+            "name": "orders[0].column",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "name": "orders[0].asc",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "boolean"
+            }
+          },
+          {
+            "name": "optimizeCountSql",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "boolean"
+            }
+          },
+          {
+            "name": "searchCount",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "boolean"
+            }
+          },
+          {
+            "name": "optimizeJoinOfCountSql",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "boolean"
+            }
+          },
+          {
+            "name": "maxLimit",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          },
+          {
+            "name": "countId",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "name": "query",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RPageMerchantUserPageDTO"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": {
+                    "records": [
+                      {
+                        "userId": 0,
+                        "nickname": "",
+                        "agentId": "",
+                        "agentName": "",
+                        "status": false
+                      }
+                    ],
+                    "total": 0,
+                    "size": 0,
+                    "current": 0,
+                    "orders": [
+                      {
+                        "column": "",
+                        "asc": false
+                      }
+                    ],
+                    "optimizeCountSql": false,
+                    "searchCount": false,
+                    "optimizeJoinOfCountSql": false,
+                    "maxLimit": 0,
+                    "countId": ""
+                  }
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/agentList/{id:^\\d+$}": {
+      "get": {
+        "summary": "所属代理商列表",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RListAgentUser"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": [
+                    {
+                      "userId": 0,
+                      "username": "",
+                      "agentName": "",
+                      "password": "",
+                      "realname": "",
+                      "phone": "",
+                      "idcard": "",
+                      "address": "",
+                      "email": "",
+                      "offlineRechargeRate": 0,
+                      "status": false,
+                      "bankName": "",
+                      "bankBranch": "",
+                      "accountName": "",
+                      "accountNum": "",
+                      "bankProvince": "",
+                      "bankCity": "",
+                      "createBy": "",
+                      "updateBy": "",
+                      "createTime": "",
+                      "updateTime": "",
+                      "tenantId": 0
+                    }
+                  ]
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/save": {
+      "post": {
+        "summary": "新增",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/MerchantUserROAdd",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": null,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/changePwd/{id:^\\d+$}": {
+      "patch": {
+        "summary": "修改密码",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/MerchantUserROChangePwd",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": null,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/changeStatus/{id:^\\d+$}": {
+      "patch": {
+        "summary": "启用禁用",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": null,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/info/{id:^\\d+$}": {
+      "get": {
+        "summary": "详情",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RMerchantUserInfoVO"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": {
+                    "userId": 0,
+                    "username": "",
+                    "merchantName": "",
+                    "phone": "",
+                    "email": "",
+                    "websiteName": "",
+                    "websiteAddress": "",
+                    "appId": "",
+                    "idcard": "",
+                    "realname": "",
+                    "contactAddress": "",
+                    "offlineRechargeRate": 0,
+                    "status": false,
+                    "agentId": 0,
+                    "agentName": ""
+                  }
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchantUser/edit/{id:^\\d+$}": {
+      "patch": {
+        "summary": "修改",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/MerchantUserROUpdate",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": null,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "R": {
+        "type": "object",
+        "properties": {
+          "ok": {
+            "type": "boolean"
+          },
+          "code": {
+            "description": "返回标记:成功标记=0,失败标记=1",
+            "type": "null"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "object",
+            "properties": {},
+            "description": "数据"
+          }
+        }
+      },
+      "MerchantUserPageDTO": {
+        "type": "object",
+        "properties": {
+          "userId": {
+            "type": "integer",
+            "description": "用户ID",
+            "format": "int64"
+          },
+          "nickname": {
+            "type": "string",
+            "description": "昵称"
+          },
+          "agentId": {
+            "type": "string",
+            "description": "代理商id"
+          },
+          "agentName": {
+            "type": "string",
+            "description": "代理商名称"
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          }
+        }
+      },
+      "OrderItem": {
+        "type": "object",
+        "properties": {
+          "column": {
+            "type": "string",
+            "description": ""
+          },
+          "asc": {
+            "type": "boolean",
+            "description": ""
+          }
+        }
+      },
+      "PageMerchantUserPageDTO": {
+        "type": "object",
+        "properties": {
+          "records": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/MerchantUserPageDTO",
+              "description": ""
+            },
+            "description": ""
+          },
+          "total": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "size": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "current": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "orders": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/OrderItem",
+              "description": "com.baomidou.mybatisplus.core.metadata.OrderItem"
+            },
+            "description": ""
+          },
+          "optimizeCountSql": {
+            "type": "boolean",
+            "description": ""
+          },
+          "searchCount": {
+            "type": "boolean",
+            "description": ""
+          },
+          "optimizeJoinOfCountSql": {
+            "type": "boolean",
+            "description": ""
+          },
+          "maxLimit": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "countId": {
+            "type": "string",
+            "description": ""
+          }
+        }
+      },
+      "RPageMerchantUserPageDTO": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/PageMerchantUserPageDTO",
+            "description": "数据"
+          }
+        }
+      },
+      "RListAgentUser": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/AgentUser",
+              "description": ""
+            },
+            "description": "数据"
+          }
+        }
+      },
+      "AgentUser": {
+        "type": "object",
+        "properties": {
+          "userId": {
+            "type": "integer",
+            "description": "用户ID",
+            "format": "int64"
+          },
+          "username": {
+            "type": "string",
+            "description": "用户名"
+          },
+          "agentName": {
+            "type": "string",
+            "description": "代理商名称"
+          },
+          "password": {
+            "type": "string",
+            "description": "密码"
+          },
+          "realname": {
+            "type": "string",
+            "description": "真实姓名"
+          },
+          "phone": {
+            "type": "string",
+            "description": "手机号"
+          },
+          "idcard": {
+            "type": "string",
+            "description": "身份证号"
+          },
+          "address": {
+            "type": "string",
+            "description": "通讯地址"
+          },
+          "email": {
+            "type": "string",
+            "description": "邮箱地址"
+          },
+          "offlineRechargeRate": {
+            "type": "number",
+            "description": "线下充值费率"
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          },
+          "bankName": {
+            "type": "string",
+            "description": "开户行名称"
+          },
+          "bankBranch": {
+            "type": "string",
+            "description": "开户网点"
+          },
+          "accountName": {
+            "type": "string",
+            "description": "账户名"
+          },
+          "accountNum": {
+            "type": "string",
+            "description": "账户号"
+          },
+          "bankProvince": {
+            "type": "string",
+            "description": "开户省"
+          },
+          "bankCity": {
+            "type": "string",
+            "description": "开户市"
+          },
+          "createBy": {
+            "type": "string",
+            "description": "创建人"
+          },
+          "updateBy": {
+            "type": "string",
+            "description": "修改人"
+          },
+          "createTime": {
+            "type": "string",
+            "description": "创建时间"
+          },
+          "updateTime": {
+            "type": "string",
+            "description": "修改时间"
+          },
+          "tenantId": {
+            "type": "integer",
+            "description": "所属租户ID",
+            "format": "int64"
+          }
+        }
+      },
+      "MerchantUserROAdd": {
+        "type": "object",
+        "properties": {
+          "username": {
+            "type": "string",
+            "description": "用户名"
+          },
+          "merchantName": {
+            "type": "string",
+            "description": "商户名称"
+          },
+          "phone": {
+            "type": "string",
+            "description": "电话号码"
+          },
+          "email": {
+            "type": "string",
+            "description": "邮箱地址"
+          },
+          "websiteName": {
+            "type": "string",
+            "description": "网站名称"
+          },
+          "websiteAddress": {
+            "type": "string",
+            "description": "网站地址"
+          },
+          "idcard": {
+            "type": "string",
+            "description": "身份证号"
+          },
+          "realname": {
+            "type": "string",
+            "description": "真实姓名"
+          },
+          "contactAddress": {
+            "type": "string",
+            "description": "通讯地址"
+          },
+          "offlineRechargeRate": {
+            "type": "number",
+            "description": "线下充值费率",
+            "minimum": 0,
+            "maximum": 100,
+            "exclusiveMinimum": true,
+            "exclusiveMaximum": true
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          },
+          "agentId": {
+            "type": "integer",
+            "description": "所属商户ID",
+            "format": "int64"
+          },
+          "newPwd": {
+            "type": "string",
+            "description": "新密码"
+          },
+          "oldPwd": {
+            "type": "string",
+            "description": "旧密码"
+          }
+        },
+        "required": [
+          "username",
+          "merchantName",
+          "phone",
+          "email"
+        ]
+      },
+      "MerchantUserROChangePwd": {
+        "type": "object",
+        "properties": {
+          "username": {
+            "type": "string",
+            "description": "用户名"
+          },
+          "merchantName": {
+            "type": "string",
+            "description": "商户名称"
+          },
+          "phone": {
+            "type": "string",
+            "description": "电话号码"
+          },
+          "email": {
+            "type": "string",
+            "description": "邮箱地址"
+          },
+          "websiteName": {
+            "type": "string",
+            "description": "网站名称"
+          },
+          "websiteAddress": {
+            "type": "string",
+            "description": "网站地址"
+          },
+          "idcard": {
+            "type": "string",
+            "description": "身份证号"
+          },
+          "realname": {
+            "type": "string",
+            "description": "真实姓名"
+          },
+          "contactAddress": {
+            "type": "string",
+            "description": "通讯地址"
+          },
+          "offlineRechargeRate": {
+            "type": "number",
+            "description": "线下充值费率"
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          },
+          "agentId": {
+            "type": "integer",
+            "description": "所属商户ID",
+            "format": "int64"
+          },
+          "newPwd": {
+            "type": "string",
+            "description": "新密码"
+          },
+          "oldPwd": {
+            "type": "string",
+            "description": "旧密码"
+          }
+        },
+        "required": [
+          "newPwd",
+          "oldPwd"
+        ]
+      },
+      "MerchantUserInfoVO": {
+        "type": "object",
+        "properties": {
+          "userId": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "username": {
+            "type": "string",
+            "description": "用户名"
+          },
+          "merchantName": {
+            "type": "string",
+            "description": "昵称"
+          },
+          "phone": {
+            "type": "string",
+            "description": "电话号码"
+          },
+          "email": {
+            "type": "string",
+            "description": "邮箱地址"
+          },
+          "websiteName": {
+            "type": "string",
+            "description": "网站名称"
+          },
+          "websiteAddress": {
+            "type": "string",
+            "description": "网站地址"
+          },
+          "appId": {
+            "type": "string",
+            "description": "appId"
+          },
+          "idcard": {
+            "type": "string",
+            "description": "身份证号"
+          },
+          "realname": {
+            "type": "string",
+            "description": "真实姓名"
+          },
+          "contactAddress": {
+            "type": "string",
+            "description": "通讯地址"
+          },
+          "offlineRechargeRate": {
+            "type": "number",
+            "description": "线下充值费率"
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          },
+          "agentId": {
+            "type": "integer",
+            "description": "所属商户ID",
+            "format": "int64"
+          },
+          "agentName": {
+            "type": "string",
+            "description": "所属商户名称"
+          }
+        }
+      },
+      "RMerchantUserInfoVO": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/MerchantUserInfoVO",
+            "description": "数据"
+          }
+        }
+      },
+      "MerchantUserROUpdate": {
+        "type": "object",
+        "properties": {
+          "username": {
+            "type": "string",
+            "description": "用户名"
+          },
+          "merchantName": {
+            "type": "string",
+            "description": "商户名称"
+          },
+          "phone": {
+            "type": "string",
+            "description": "电话号码"
+          },
+          "email": {
+            "type": "string",
+            "description": "邮箱地址"
+          },
+          "websiteName": {
+            "type": "string",
+            "description": "网站名称"
+          },
+          "websiteAddress": {
+            "type": "string",
+            "description": "网站地址"
+          },
+          "idcard": {
+            "type": "string",
+            "description": "身份证号"
+          },
+          "realname": {
+            "type": "string",
+            "description": "真实姓名"
+          },
+          "contactAddress": {
+            "type": "string",
+            "description": "通讯地址"
+          },
+          "offlineRechargeRate": {
+            "type": "number",
+            "description": "线下充值费率",
+            "minimum": 0,
+            "maximum": 100,
+            "exclusiveMinimum": true,
+            "exclusiveMaximum": true
+          },
+          "status": {
+            "type": "boolean",
+            "description": "启用状态"
+          },
+          "agentId": {
+            "type": "integer",
+            "description": "所属商户ID",
+            "format": "int64"
+          },
+          "newPwd": {
+            "type": "string",
+            "description": "新密码"
+          },
+          "oldPwd": {
+            "type": "string",
+            "description": "旧密码"
+          }
+        }
+      }
+    },
+    "securitySchemes": {
+      "bearer": {
+        "type": "http",
+        "scheme": "bearer"
+      }
+    }
+  },
+  "servers": [],
+  "security": []
+}

+ 47 - 0
src/api/agent/agentUser.ts

@@ -0,0 +1,47 @@
+import request from '/@/utils/request';
+
+export function fetchList(query?: Object) {
+	return request({
+		url: 'admin/agentUser/page',
+		method: 'get',
+		params: query,
+	});
+}
+
+export function addObj(obj?: Object) {
+	return request({
+		url: 'admin/agentUser/save',
+		method: 'post',
+		data: obj,
+	});
+}
+
+export function getObj(id?: string) {
+	return request({
+		url: `admin/agentUser/info/${id}`,
+		method: 'get',
+	});
+}
+
+export function putObj(id: string, obj?: Object) {
+	return request({
+		url: `admin/agentUser/edit/${id}`,
+		method: 'patch',
+		data: obj,
+	});
+}
+
+export function changeStatus(id: string) {
+	return request({
+		url: `/admin/agentUser/changeStatus/${id}`,
+		method: 'patch',
+	});
+}
+
+export function changePwd(id: string, data?: Object) {
+	return request({
+		url: `/admin/agentUser/changePwd/${id}`,
+		method: 'patch',
+		data: data,
+	});
+}

+ 54 - 0
src/api/merchant/merchantUser.ts

@@ -0,0 +1,54 @@
+import request from '/@/utils/request';
+
+export function fetchList(query?: Object) {
+	return request({
+		url: 'admin/merchantUser/page',
+		method: 'get',
+		params: query,
+	});
+}
+
+export function addObj(obj?: Object) {
+	return request({
+		url: 'admin/merchantUser/save',
+		method: 'post',
+		data: obj,
+	});
+}
+
+export function getObj(id?: string) {
+	return request({
+		url: `admin/merchantUser/info/${id}`,
+		method: 'get',
+	});
+}
+
+export function putObj(id: string, obj?: Object) {
+	return request({
+		url: `admin/merchantUser/edit/${id}`,
+		method: 'patch',
+		data: obj,
+	});
+}
+
+export function changeStatus(id: string) {
+	return request({
+		url: `/admin/merchantUser/changeStatus/${id}`,
+		method: 'patch',
+	});
+}
+
+export function changePwd(id: string, data?: Object) {
+	return request({
+		url: `/admin/merchantUser/changePwd/${id}`,
+		method: 'patch',
+		data: data,
+	});
+}
+
+export function getAgentList(id: string) {
+	return request({
+		url: `/admin/merchantUser/agentList/${id}`,
+		method: 'get',
+	});
+}

+ 78 - 0
src/i18n/pages/agent/en.ts

@@ -0,0 +1,78 @@
+export default {
+	agentUser: {
+		index: '#',
+		agentId: 'Agent ID',
+		agentName: 'Agent Name',
+		username: 'Username',
+		realname: 'Real Name',
+		phone: 'Phone',
+		email: 'Email',
+		idcard: 'ID Card',
+		address: 'Address',
+		offlineRechargeRate: 'Offline Recharge Rate (%)',
+		status: 'Status',
+		bankName: 'Bank Name',
+		bankBranch: 'Bank Branch',
+		bankProvince: 'Bank Province',
+		bankCity: 'Bank City',
+		accountName: 'Account Name',
+		accountNum: 'Account Number',
+		createTime: 'Create Time',
+		updateTime: 'Update Time',
+		operation: 'Operation',
+		
+		// Tips
+		inputAgentNameTip: 'Please enter agent name',
+		inputUsernameTip: 'Please enter username',
+		inputRealnameTip: 'Please enter real name',
+		inputPhoneTip: 'Please enter phone',
+		inputEmailTip: 'Please enter email',
+		inputIdcardTip: 'Please enter ID card',
+		inputAddressTip: 'Please enter address',
+		inputOfflineRechargeRateTip: 'Please enter rate',
+		inputBankNameTip: 'Please enter bank name',
+		inputBankBranchTip: 'Please enter bank branch',
+		inputBankProvinceTip: 'Please enter bank province',
+		inputBankCityTip: 'Please enter bank city',
+		inputAccountNameTip: 'Please enter account name',
+		inputAccountNumTip: 'Please enter account number',
+		
+		// Search
+		searchAgentAccount: 'Please enter agent account',
+		
+		// Buttons
+		viewBtn: 'View',
+		changePwdBtn: 'Change Password',
+		
+		// Status
+		statusEnable: 'Enable',
+		statusDisable: 'Disable',
+		statusChangeSuccess: 'Status changed successfully',
+		
+		// Group titles
+		basicInfo: 'Basic Information',
+		bankInfo: 'Bank Information',
+		
+		// Tips
+		defaultPasswordTip: 'Tip: Default password for new agent is qwe123QWE!',
+		
+		// Validation
+		usernameRequired: 'Username cannot be empty',
+		agentNameRequired: 'Agent name cannot be empty',
+		realnameRequired: 'Real name cannot be empty',
+		phoneRequired: 'Phone cannot be empty',
+		emailRequired: 'Email cannot be empty',
+		
+		// Change password
+		changePwdTitle: 'Change Password',
+		newPassword: 'New Password',
+		confirmPassword: 'Confirm Password',
+		inputNewPasswordTip: 'Please enter new password',
+		inputConfirmPasswordTip: 'Please enter new password again',
+		newPasswordRequired: 'New password cannot be empty',
+		passwordLengthTip: 'Password length should be 6 to 20 characters',
+		confirmPasswordRequired: 'Please enter new password again',
+		passwordNotMatch: 'Passwords do not match',
+		changePwdSuccess: 'Password changed successfully',
+	},
+};

+ 78 - 0
src/i18n/pages/agent/zh-cn.ts

@@ -0,0 +1,78 @@
+export default {
+	agentUser: {
+		index: '#',
+		agentId: '代理ID',
+		agentName: '代理名称',
+		username: '用户名',
+		realname: '真实姓名',
+		phone: '手机号码',
+		email: '邮箱地址',
+		idcard: '身份证号',
+		address: '通讯地址',
+		offlineRechargeRate: '线下充值费率(%)',
+		status: '状态',
+		bankName: '开户行名称',
+		bankBranch: '开户网点',
+		bankProvince: '开户省',
+		bankCity: '开户市',
+		accountName: '账户名',
+		accountNum: '账户号',
+		createTime: '创建时间',
+		updateTime: '更新时间',
+		operation: '操作',
+		
+		// 提示信息
+		inputAgentNameTip: '请输入代理商名称',
+		inputUsernameTip: '请输入用户名',
+		inputRealnameTip: '请输入真实姓名',
+		inputPhoneTip: '请输入手机号码',
+		inputEmailTip: '请输入邮箱地址',
+		inputIdcardTip: '请输入身份证号',
+		inputAddressTip: '请输入通讯地址',
+		inputOfflineRechargeRateTip: '请输入费率',
+		inputBankNameTip: '请输入开户行名称',
+		inputBankBranchTip: '请输入开户网点',
+		inputBankProvinceTip: '请输入开户省',
+		inputBankCityTip: '请输入开户市',
+		inputAccountNameTip: '请输入账户名',
+		inputAccountNumTip: '请输入账户号',
+		
+		// 搜索
+		searchAgentAccount: '请输入代理账号',
+		
+		// 按钮
+		viewBtn: '查看',
+		changePwdBtn: '改密',
+		
+		// 状态
+		statusEnable: '启用',
+		statusDisable: '禁用',
+		statusChangeSuccess: '状态修改成功',
+		
+		// 分组标题
+		basicInfo: '基本信息',
+		bankInfo: '银行信息',
+		
+		// 提示
+		defaultPasswordTip: '提示:新增代理的默认密码为 qwe123QWE!',
+		
+		// 校验
+		usernameRequired: '用户名不能为空',
+		agentNameRequired: '代理商名称不能为空',
+		realnameRequired: '真实姓名不能为空',
+		phoneRequired: '手机号码不能为空',
+		emailRequired: '邮箱地址不能为空',
+		
+		// 修改密码
+		changePwdTitle: '修改密码',
+		newPassword: '新密码',
+		confirmPassword: '确认密码',
+		inputNewPasswordTip: '请输入新密码',
+		inputConfirmPasswordTip: '请再次输入新密码',
+		newPasswordRequired: '新密码不能为空',
+		passwordLengthTip: '密码长度在 6 到 20 个字符',
+		confirmPasswordRequired: '请再次输入新密码',
+		passwordNotMatch: '两次输入的密码不一致',
+		changePwdSuccess: '密码修改成功',
+	},
+};

+ 73 - 0
src/i18n/pages/merchant/en.ts

@@ -0,0 +1,73 @@
+export default {
+	merchantUser: {
+		index: '#',
+		merchantId: 'Merchant ID',
+		merchantName: 'Merchant Name',
+		username: 'Username',
+		realname: 'Real Name',
+		phone: 'Phone',
+		email: 'Email',
+		idcard: 'ID Card',
+		contactAddress: 'Contact Address',
+		websiteName: 'Website Name',
+		websiteAddress: 'Website Address',
+		appId: 'AppId',
+		offlineRechargeRate: 'Offline Recharge Rate (%)',
+		status: 'Status',
+		agentId: 'Agent',
+		agentName: 'Agent',
+		createTime: 'Create Time',
+		updateTime: 'Update Time',
+		operation: 'Operation',
+		
+		// Tips
+		inputMerchantNameTip: 'Please enter merchant name',
+		inputUsernameTip: 'Please enter username',
+		inputRealnameTip: 'Please enter real name',
+		inputPhoneTip: 'Please enter phone',
+		inputEmailTip: 'Please enter email',
+		inputIdcardTip: 'Please enter ID card',
+		inputContactAddressTip: 'Please enter contact address',
+		inputWebsiteNameTip: 'Please enter website name',
+		inputWebsiteAddressTip: 'Please enter website address',
+		inputOfflineRechargeRateTip: 'Please enter rate',
+		selectAgentTip: 'Please select agent',
+		
+		// Search
+		searchMerchantAccount: 'Please enter merchant account',
+		
+		// Buttons
+		viewBtn: 'View',
+		changePwdBtn: 'Change Password',
+		
+		// Status
+		statusEnable: 'Enable',
+		statusDisable: 'Disable',
+		statusChangeSuccess: 'Status changed successfully',
+		
+		// Group titles
+		basicInfo: 'Basic Information',
+		websiteInfo: 'Website Information',
+		
+		// Tips
+		defaultPasswordTip: 'Tip: Default password for new merchant is qwe123QWE!',
+		
+		// Validation
+		usernameRequired: 'Username cannot be empty',
+		merchantNameRequired: 'Merchant name cannot be empty',
+		phoneRequired: 'Phone cannot be empty',
+		emailRequired: 'Email cannot be empty',
+		
+		// Change password
+		changePwdTitle: 'Change Password',
+		newPassword: 'New Password',
+		confirmPassword: 'Confirm Password',
+		inputNewPasswordTip: 'Please enter new password',
+		inputConfirmPasswordTip: 'Please enter new password again',
+		newPasswordRequired: 'New password cannot be empty',
+		passwordLengthTip: 'Password length should be 6 to 20 characters',
+		confirmPasswordRequired: 'Please enter new password again',
+		passwordNotMatch: 'Passwords do not match',
+		changePwdSuccess: 'Password changed successfully',
+	},
+};

+ 73 - 0
src/i18n/pages/merchant/zh-cn.ts

@@ -0,0 +1,73 @@
+export default {
+	merchantUser: {
+		index: '#',
+		merchantId: '商户ID',
+		merchantName: '商户名称',
+		username: '用户名',
+		realname: '真实姓名',
+		phone: '手机号码',
+		email: '邮箱地址',
+		idcard: '身份证号',
+		contactAddress: '通讯地址',
+		websiteName: '网站名称',
+		websiteAddress: '网站地址',
+		appId: 'AppId',
+		offlineRechargeRate: '线下充值费率(%)',
+		status: '状态',
+		agentId: '所属代理商',
+		agentName: '所属代理',
+		createTime: '创建时间',
+		updateTime: '更新时间',
+		operation: '操作',
+		
+		// 提示信息
+		inputMerchantNameTip: '请输入商户名称',
+		inputUsernameTip: '请输入用户名',
+		inputRealnameTip: '请输入真实姓名',
+		inputPhoneTip: '请输入手机号码',
+		inputEmailTip: '请输入邮箱地址',
+		inputIdcardTip: '请输入身份证号',
+		inputContactAddressTip: '请输入通讯地址',
+		inputWebsiteNameTip: '请输入网站名称',
+		inputWebsiteAddressTip: '请输入网站地址',
+		inputOfflineRechargeRateTip: '请输入费率',
+		selectAgentTip: '请选择所属代理商',
+		
+		// 搜索
+		searchMerchantAccount: '请输入商户账号',
+		
+		// 按钮
+		viewBtn: '查看',
+		changePwdBtn: '改密',
+		
+		// 状态
+		statusEnable: '启用',
+		statusDisable: '禁用',
+		statusChangeSuccess: '状态修改成功',
+		
+		// 分组标题
+		basicInfo: '基本信息',
+		websiteInfo: '网站信息',
+		
+		// 提示
+		defaultPasswordTip: '提示:新增商户的默认密码为 qwe123QWE!',
+		
+		// 校验
+		usernameRequired: '用户名不能为空',
+		merchantNameRequired: '商户名称不能为空',
+		phoneRequired: '手机号码不能为空',
+		emailRequired: '邮箱地址不能为空',
+		
+		// 修改密码
+		changePwdTitle: '修改密码',
+		newPassword: '新密码',
+		confirmPassword: '确认密码',
+		inputNewPasswordTip: '请输入新密码',
+		inputConfirmPasswordTip: '请再次输入新密码',
+		newPasswordRequired: '新密码不能为空',
+		passwordLengthTip: '密码长度在 6 到 20 个字符',
+		confirmPasswordRequired: '请再次输入新密码',
+		passwordNotMatch: '两次输入的密码不一致',
+		changePwdSuccess: '密码修改成功',
+	},
+};

+ 2 - 2
src/views/admin/audit/index.vue

@@ -48,7 +48,7 @@
 				:data="state.dataList"
 				v-loading="state.loading"
 				style="width: 100%"
-        row-key="id"
+				row-key="id"
 				@selection-change="handleSelectionChange"
 				@sort-change="sortChangeHandle"
 				border
@@ -109,7 +109,7 @@ const resetQuery = () => {
 
 // 导出excel
 const exportExcel = () => {
-	downBlobFile('/admin/audit/export', Object.assign(state.queryForm,{ids:selectObjs}), 'audit.xlsx');
+	downBlobFile('/admin/audit/export', Object.assign(state.queryForm, { ids: selectObjs }), 'audit.xlsx');
 };
 
 // 多选事件

+ 93 - 0
src/views/agent/flow/index.vue

@@ -0,0 +1,93 @@
+<template>
+	<div class="layout-padding">
+		<div class="layout-padding-auto layout-padding-view">
+			<el-row class="ml10" v-show="showSearch">
+				<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
+					<el-form-item label="代理账号" prop="userId">
+						<el-input placeholder="请输入代理账号" style="max-width: 180px" v-model="state.queryForm.userId" />
+					</el-form-item>
+					<el-form-item label="流水类型" prop="flowType">
+						<el-select v-model="state.queryForm.flowType" placeholder="请选择流水类型">
+							<el-option label="全部" value=""></el-option>
+							<el-option label="充值" value="1"></el-option>
+							<el-option label="提现" value="2"></el-option>
+							<el-option label="消费" value="3"></el-option>
+						</el-select>
+					</el-form-item>
+					<el-form-item>
+						<el-button @click="getDataList" icon="search" type="primary">
+							{{ $t('common.queryBtn') }}
+						</el-button>
+						<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
+					</el-form-item>
+				</el-form>
+			</el-row>
+			<el-row>
+				<div class="mb8" style="width: 100%">
+					<right-toolbar
+						@queryTable="getDataList"
+						class="ml10"
+						style="float: right; margin-right: 20px"
+						v-model:showSearch="showSearch"
+					></right-toolbar>
+				</div>
+			</el-row>
+			<el-table
+				:data="state.dataList"
+				@sort-change="sortChangeHandle"
+				style="width: 100%"
+				v-loading="state.loading"
+				border
+				:cell-style="tableStyle.cellStyle"
+				:header-cell-style="tableStyle.headerCellStyle"
+			>
+				<el-table-column label="序号" fixed type="index" width="60" />
+				<el-table-column label="代理账号" prop="userId" show-overflow-tooltip width="120" />
+				<el-table-column label="代理商名称" prop="agentName" show-overflow-tooltip width="150" />
+				<el-table-column label="流水类型" prop="flowType" show-overflow-tooltip width="100" />
+				<el-table-column label="金额" prop="amount" show-overflow-tooltip width="120" />
+				<el-table-column label="余额" prop="balance" show-overflow-tooltip width="120" />
+				<el-table-column label="备注" prop="remark" show-overflow-tooltip width="200" />
+				<el-table-column label="创建时间" prop="createTime" show-overflow-tooltip width="180" />
+			</el-table>
+			<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
+		</div>
+	</div>
+</template>
+
+<script lang="ts" name="systemAgentFlow" setup>
+import { BasicTableProps, useTable } from '/@/hooks/table';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+// 搜索变量
+const queryRef = ref();
+const showSearch = ref(true);
+
+// 临时的空数据列表函数
+const fetchList = () => {
+	return Promise.resolve({
+		data: {
+			records: [],
+			total: 0,
+		},
+	});
+};
+
+const state: BasicTableProps = reactive<BasicTableProps>({
+	queryForm: {},
+	pageList: fetchList,
+	descs: ['create_time'],
+});
+
+//  table hook
+const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle } = useTable(state);
+
+// 清空搜索条件
+const resetQuery = () => {
+	// 清空搜索条件
+	queryRef.value.resetFields();
+	getDataList();
+};
+</script>

+ 96 - 0
src/views/agent/list/changePwd.vue

@@ -0,0 +1,96 @@
+<template>
+	<el-dialog :close-on-click-modal="false" :title="$t('agentUser.changePwdTitle')" draggable v-model="visible" width="500px">
+		<el-form :model="form" :rules="dataRules" label-width="100px" ref="dataFormRef" v-loading="loading">
+			<el-form-item :label="$t('agentUser.newPassword')" prop="newPwd">
+				<el-input :placeholder="$t('agentUser.inputNewPasswordTip')" type="password" v-model="form.newPwd" show-password />
+			</el-form-item>
+
+			<el-form-item :label="$t('agentUser.confirmPassword')" prop="confirmPwd">
+				<el-input :placeholder="$t('agentUser.inputConfirmPasswordTip')" type="password" v-model="form.confirmPwd" show-password />
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
+				<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" name="ChangePwdDialog" setup>
+import { useMessage } from '/@/hooks/message';
+import { changePwd } from '/@/api/agent/agentUser';
+import { useI18n } from 'vue-i18n';
+
+const emit = defineEmits(['refresh']);
+
+const { t } = useI18n();
+// 定义变量内容
+const dataFormRef = ref();
+const visible = ref(false);
+const loading = ref(false);
+const userId = ref('');
+
+// 提交表单数据
+const form = reactive({
+	newPwd: '',
+	confirmPwd: '',
+});
+
+// 自定义校验规则
+const validateConfirmPwd = (rule: any, value: any, callback: any) => {
+	if (value === '') {
+		callback(new Error(t('agentUser.confirmPasswordRequired')));
+	} else if (value !== form.newPwd) {
+		callback(new Error(t('agentUser.passwordNotMatch')));
+	} else {
+		callback();
+	}
+};
+
+// 定义校验规则
+const dataRules = ref({
+	newPwd: [
+		{ required: true, message: t('agentUser.newPasswordRequired'), trigger: 'blur' },
+		{ min: 6, max: 20, message: t('agentUser.passwordLengthTip'), trigger: 'blur' },
+	],
+	confirmPwd: [{ required: true, validator: validateConfirmPwd, trigger: 'blur' }],
+});
+
+// 打开弹窗
+const openDialog = (id: string) => {
+	visible.value = true;
+	userId.value = id;
+
+	// 重置表单数据
+	nextTick(() => {
+		dataFormRef.value?.resetFields();
+	});
+};
+
+// 提交
+const onSubmit = async () => {
+	const valid = await dataFormRef.value.validate().catch(() => {});
+	if (!valid) return false;
+
+	try {
+		loading.value = true;
+		await changePwd(userId.value, {
+			newPwd: form.newPwd,
+		});
+		useMessage().success(t('agentUser.changePwdSuccess'));
+		visible.value = false;
+		emit('refresh');
+	} catch (err: any) {
+		useMessage().error(err.msg);
+	} finally {
+		loading.value = false;
+	}
+};
+
+// 暴露变量
+defineExpose({
+	openDialog,
+});
+</script>

+ 251 - 0
src/views/agent/list/form.vue

@@ -0,0 +1,251 @@
+<template>
+	<el-dialog
+		:close-on-click-modal="false"
+		:title="form.userId ? (readonly ? '查看详情' : $t('common.editBtn')) : $t('common.addBtn')"
+		draggable
+		v-model="visible"
+		width="920px"
+	>
+		<el-alert v-if="!form.userId" :title="$t('agentUser.defaultPasswordTip')" type="warning" :closable="false" style="margin-bottom: 15px" />
+		<el-form :model="form" :rules="dataRules" label-width="140px" ref="dataFormRef" v-loading="loading">
+			<!-- 基本信息 -->
+			<el-divider content-position="left">{{ $t('agentUser.basicInfo') }}</el-divider>
+			<el-row :gutter="24">
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.agentName')" prop="agentName">
+						<el-input :placeholder="$t('agentUser.inputAgentNameTip')" v-model="form.agentName" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.username')" prop="username">
+						<el-input :placeholder="$t('agentUser.inputUsernameTip')" v-model="form.username" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.realname')" prop="realname">
+						<el-input :placeholder="$t('agentUser.inputRealnameTip')" v-model="form.realname" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.phone')" prop="phone">
+						<el-input :placeholder="$t('agentUser.inputPhoneTip')" v-model="form.phone" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.email')" prop="email">
+						<el-input :placeholder="$t('agentUser.inputEmailTip')" v-model="form.email" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.idcard')" prop="idcard">
+						<el-input :placeholder="$t('agentUser.inputIdcardTip')" v-model="form.idcard" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.address')" prop="address">
+						<el-input :placeholder="$t('agentUser.inputAddressTip')" v-model="form.address" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.offlineRechargeRate')" prop="offlineRechargeRate">
+						<el-input-number
+							:placeholder="$t('agentUser.inputOfflineRechargeRateTip')"
+							v-model="form.offlineRechargeRate"
+							:min="0"
+							:max="100"
+							:precision="2"
+							:disabled="readonly"
+							style="width: 100%"
+						/>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.status')" prop="status">
+						<el-radio-group v-model="form.status" :disabled="readonly || !!form.userId">
+							<el-radio :label="true">{{ $t('agentUser.statusEnable') }}</el-radio>
+							<el-radio :label="false">{{ $t('agentUser.statusDisable') }}</el-radio>
+						</el-radio-group>
+					</el-form-item>
+				</el-col>
+			</el-row>
+
+			<!-- 银行信息 -->
+			<el-divider content-position="left">{{ $t('agentUser.bankInfo') }}</el-divider>
+			<el-row :gutter="24">
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.bankName')" prop="bankName">
+						<el-input :placeholder="$t('agentUser.inputBankNameTip')" v-model="form.bankName" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.bankBranch')" prop="bankBranch">
+						<el-input :placeholder="$t('agentUser.inputBankBranchTip')" v-model="form.bankBranch" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.bankProvince')" prop="bankProvince">
+						<el-input :placeholder="$t('agentUser.inputBankProvinceTip')" v-model="form.bankProvince" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.bankCity')" prop="bankCity">
+						<el-input :placeholder="$t('agentUser.inputBankCityTip')" v-model="form.bankCity" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.accountName')" prop="accountName">
+						<el-input :placeholder="$t('agentUser.inputAccountNameTip')" v-model="form.accountName" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('agentUser.accountNum')" prop="accountNum">
+						<el-input :placeholder="$t('agentUser.inputAccountNumTip')" v-model="form.accountNum" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="visible = false">{{ readonly ? $t('common.closeBtn') : $t('common.cancelButtonText') }}</el-button>
+				<el-button @click="onSubmit" type="primary" :disabled="loading" v-if="!readonly">{{ $t('common.confirmButtonText') }}</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" name="AgentUserDialog" setup>
+// 定义子组件向父组件传值/事件
+import { useMessage } from '/@/hooks/message';
+import { addObj, getObj, putObj } from '/@/api/agent/agentUser';
+import { useI18n } from 'vue-i18n';
+import { rule } from '/@/utils/validate';
+
+const emit = defineEmits(['refresh']);
+
+const { t } = useI18n();
+// 定义变量内容
+const dataFormRef = ref();
+const visible = ref(false);
+const loading = ref(false);
+const readonly = ref(false);
+
+// 提交表单数据(严格按照接口文档字段)
+const form = reactive({
+	userId: '',
+	username: '',
+	agentName: '',
+	realname: '',
+	phone: '',
+	idcard: '',
+	address: '',
+	email: '',
+	offlineRechargeRate: 0,
+	status: true,
+	bankName: '',
+	bankBranch: '',
+	accountName: '',
+	accountNum: '',
+	bankProvince: '',
+	bankCity: '',
+});
+
+// 定义校验规则(根据接口文档,必填字段:username, agentName, realname, phone, email)
+const dataRules = ref({
+	username: [
+		{ required: true, message: t('agentUser.usernameRequired'), trigger: 'blur' },
+		{ validator: rule.overLength, trigger: 'blur' },
+	],
+	agentName: [
+		{ required: true, message: t('agentUser.agentNameRequired'), trigger: 'blur' },
+		{ validator: rule.overLength, trigger: 'blur' },
+	],
+	realname: [
+		{ required: true, message: t('agentUser.realnameRequired'), trigger: 'blur' },
+		{ validator: rule.overLength, trigger: 'blur' },
+	],
+	phone: [
+		{ required: true, message: t('agentUser.phoneRequired'), trigger: 'blur' },
+		{ validator: rule.validatePhone, trigger: 'blur' },
+	],
+	email: [
+		{ required: true, message: t('agentUser.emailRequired'), trigger: 'blur' },
+		{ validator: rule.email, trigger: 'blur' },
+	],
+});
+
+// 打开弹窗
+const openDialog = (id: string, isReadonly = false) => {
+	visible.value = true;
+	readonly.value = isReadonly;
+	form.userId = '';
+
+	// 重置表单数据
+	nextTick(() => {
+		dataFormRef.value?.resetFields();
+	});
+
+	// 获取代理用户信息
+	if (id) {
+		form.userId = id;
+		getAgentUserData(id);
+	}
+};
+
+// 提交
+const onSubmit = async () => {
+	const valid = await dataFormRef.value.validate().catch(() => {});
+	if (!valid) return false;
+
+	try {
+		loading.value = true;
+		if (form.userId) {
+			await putObj(form.userId, form);
+		} else {
+			await addObj(form);
+		}
+		useMessage().success(t(form.userId ? 'common.editSuccessText' : 'common.addSuccessText'));
+		visible.value = false;
+		emit('refresh');
+	} catch (err: any) {
+		useMessage().error(err.msg);
+	} finally {
+		loading.value = false;
+	}
+};
+
+/**
+ * 根据 ID 获取代理用户数据并初始化表单。
+ * @param {string} id - 要查询的代理用户 ID。
+ * @returns {Promise<void>} - 初始化表单的 Promise 实例。
+ */
+const getAgentUserData = async (id: string): Promise<void> => {
+	loading.value = true; // 显示加载状态
+
+	try {
+		const res = await getObj(id); // 执行查询操作
+		Object.assign(form, res.data); // 将查询到的数据合并到表单中
+	} catch (err) {
+		useMessage().error('操作失败'); // 如果查询失败,则显示错误提示信息
+	} finally {
+		loading.value = false; // 结束加载状态
+	}
+};
+
+// 暴露变量
+defineExpose({
+	openDialog,
+});
+</script>

+ 166 - 0
src/views/agent/list/index.vue

@@ -0,0 +1,166 @@
+<template>
+	<div class="layout-padding">
+		<div class="layout-padding-auto layout-padding-view">
+			<el-row class="ml10" v-show="showSearch">
+				<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
+					<el-form-item :label="$t('agentUser.agentName')" prop="query">
+						<el-input :placeholder="$t('agentUser.searchAgentAccount')" style="max-width: 180px" v-model="state.queryForm.query" />
+					</el-form-item>
+					<el-form-item>
+						<el-button @click="getDataList" icon="search" type="primary">
+							{{ $t('common.queryBtn') }}
+						</el-button>
+						<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
+					</el-form-item>
+				</el-form>
+			</el-row>
+			<el-row>
+				<div class="mb8" style="width: 100%">
+					<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary" v-auth="'agent'">
+						{{ $t('common.addBtn') }}
+					</el-button>
+					<right-toolbar
+						@queryTable="getDataList"
+						class="ml10"
+						style="float: right; margin-right: 20px"
+						v-model:showSearch="showSearch"
+					></right-toolbar>
+				</div>
+			</el-row>
+			<el-table
+				:data="state.dataList"
+				@selection-change="handleSelectionChange"
+				@sort-change="sortChangeHandle"
+				style="width: 100%"
+				v-loading="state.loading"
+				border
+				:cell-style="tableStyle.cellStyle"
+				:header-cell-style="tableStyle.headerCellStyle"
+			>
+				<el-table-column align="center" type="selection" width="40" />
+				<el-table-column :label="$t('agentUser.agentId')" prop="userId" show-overflow-tooltip />
+				<el-table-column :label="$t('agentUser.agentName')" prop="agentName" show-overflow-tooltip />
+				<el-table-column :label="$t('agentUser.status')" prop="status" show-overflow-tooltip>
+					<template #default="scope">
+						<el-switch
+							v-model="scope.row.status"
+							:active-value="true"
+							:inactive-value="false"
+							@change="handleStatusChange(scope.row)"
+							v-auth="'agent'"
+						/>
+					</template>
+				</el-table-column>
+				<el-table-column :label="$t('agentUser.operation')" fixed="right" width="200">
+					<template #default="scope">
+						<el-button icon="View" @click="handleView(scope.row)" text type="primary" v-auth="'agent'">{{ $t('agentUser.viewBtn') }}</el-button>
+						<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.userId)" text type="primary" v-auth="'agent'"
+							>{{ $t('common.editBtn') }}
+						</el-button>
+						<el-button icon="Key" @click="handleChangePwd(scope.row)" text type="warning" v-auth="'agent'">{{
+							$t('agentUser.changePwdBtn')
+						}}</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
+		</div>
+
+		<!-- 编辑、新增  -->
+		<form-dialog @refresh="getDataList(false)" ref="formDialogRef" />
+
+		<!-- 修改密码 -->
+		<change-pwd-dialog @refresh="getDataList(false)" ref="changePwdDialogRef" />
+	</div>
+</template>
+
+<script lang="ts" name="systemAgentUser" setup>
+import { BasicTableProps, useTable } from '/@/hooks/table';
+import { fetchList, changeStatus } from '/@/api/agent/agentUser';
+import { useMessage, useMessageBox } from '/@/hooks/message';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+// 引入组件
+const FormDialog = defineAsyncComponent(() => import('./form.vue'));
+const ChangePwdDialog = defineAsyncComponent(() => import('./changePwd.vue'));
+
+// 定义变量内容
+const formDialogRef = ref();
+const changePwdDialogRef = ref();
+// 搜索变量
+const queryRef = ref();
+const showSearch = ref(true);
+// 多选变量
+const selectObjs = ref([]) as any;
+const multiple = ref(true);
+
+const state: BasicTableProps = reactive<BasicTableProps>({
+	queryForm: {},
+	pageList: fetchList,
+	descs: ['create_time'],
+});
+
+//  table hook
+const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle } = useTable(state);
+
+// 清空搜索条件
+const resetQuery = () => {
+	// 清空搜索条件
+	queryRef.value.resetFields();
+	// 清空多选
+	selectObjs.value = [];
+	getDataList();
+};
+
+// 多选事件
+const handleSelectionChange = (objs: { userId: string }[]) => {
+	selectObjs.value = objs.map(({ userId }) => userId);
+	multiple.value = !objs.length;
+};
+
+// 状态切换
+const handleStatusChange = async (row: any) => {
+	try {
+		await changeStatus(row.userId);
+		useMessage().success(t('agentUser.statusChangeSuccess'));
+		getDataList(false);
+	} catch (err: any) {
+		useMessage().error(err.msg);
+		// 恢复原状态
+		row.status = !row.status;
+	}
+};
+
+// 批量启用/禁用
+const handleBatchChangeStatus = async () => {
+	if (selectObjs.value.length === 0) {
+		useMessage().warning('请选择要操作的数据');
+		return;
+	}
+
+	try {
+		await useMessageBox().confirm('确认要批量修改状态吗?');
+		for (const id of selectObjs.value) {
+			await changeStatus(id);
+		}
+		useMessage().success('批量操作成功');
+		getDataList(false);
+	} catch (err: any) {
+		if (err !== 'cancel') {
+			useMessage().error(err.msg || '操作失败');
+		}
+	}
+};
+
+// 查看详情
+const handleView = (row: any) => {
+	formDialogRef.value.openDialog(row.userId, true);
+};
+
+// 修改密码
+const handleChangePwd = (row: any) => {
+	changePwdDialogRef.value.openDialog(row.userId);
+};
+</script>

+ 96 - 0
src/views/merchant/list/changePwd.vue

@@ -0,0 +1,96 @@
+<template>
+	<el-dialog :close-on-click-modal="false" :title="$t('merchantUser.changePwdTitle')" draggable v-model="visible" width="500px">
+		<el-form :model="form" :rules="dataRules" label-width="100px" ref="dataFormRef" v-loading="loading">
+			<el-form-item :label="$t('merchantUser.newPassword')" prop="newPwd">
+				<el-input :placeholder="$t('merchantUser.inputNewPasswordTip')" type="password" v-model="form.newPwd" show-password />
+			</el-form-item>
+
+			<el-form-item :label="$t('merchantUser.confirmPassword')" prop="confirmPwd">
+				<el-input :placeholder="$t('merchantUser.inputConfirmPasswordTip')" type="password" v-model="form.confirmPwd" show-password />
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
+				<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" name="ChangePwdDialog" setup>
+import { useMessage } from '/@/hooks/message';
+import { changePwd } from '/@/api/merchant/merchantUser';
+import { useI18n } from 'vue-i18n';
+
+const emit = defineEmits(['refresh']);
+
+const { t } = useI18n();
+// 定义变量内容
+const dataFormRef = ref();
+const visible = ref(false);
+const loading = ref(false);
+const userId = ref('');
+
+// 提交表单数据
+const form = reactive({
+	newPwd: '',
+	confirmPwd: '',
+});
+
+// 自定义校验规则
+const validateConfirmPwd = (rule: any, value: any, callback: any) => {
+	if (value === '') {
+		callback(new Error(t('merchantUser.confirmPasswordRequired')));
+	} else if (value !== form.newPwd) {
+		callback(new Error(t('merchantUser.passwordNotMatch')));
+	} else {
+		callback();
+	}
+};
+
+// 定义校验规则
+const dataRules = ref({
+	newPwd: [
+		{ required: true, message: t('merchantUser.newPasswordRequired'), trigger: 'blur' },
+		{ min: 6, max: 20, message: t('merchantUser.passwordLengthTip'), trigger: 'blur' },
+	],
+	confirmPwd: [{ required: true, validator: validateConfirmPwd, trigger: 'blur' }],
+});
+
+// 打开弹窗
+const openDialog = (id: string) => {
+	visible.value = true;
+	userId.value = id;
+
+	// 重置表单数据
+	nextTick(() => {
+		dataFormRef.value?.resetFields();
+	});
+};
+
+// 提交
+const onSubmit = async () => {
+	const valid = await dataFormRef.value.validate().catch(() => {});
+	if (!valid) return false;
+
+	try {
+		loading.value = true;
+		await changePwd(userId.value, {
+			newPwd: form.newPwd,
+		});
+		useMessage().success(t('merchantUser.changePwdSuccess'));
+		visible.value = false;
+		emit('refresh');
+	} catch (err: any) {
+		useMessage().error(err.msg);
+	} finally {
+		loading.value = false;
+	}
+};
+
+// 暴露变量
+defineExpose({
+	openDialog,
+});
+</script>

+ 245 - 0
src/views/merchant/list/form.vue

@@ -0,0 +1,245 @@
+<template>
+	<el-dialog
+		:close-on-click-modal="false"
+		:title="form.userId ? (readonly ? '查看详情' : $t('common.editBtn')) : $t('common.addBtn')"
+		draggable
+		v-model="visible"
+		width="920px"
+	>
+		<el-alert v-if="!form.userId" :title="$t('merchantUser.defaultPasswordTip')" type="warning" :closable="false" style="margin-bottom: 15px" />
+		<el-form :model="form" :rules="dataRules" label-width="140px" ref="dataFormRef" v-loading="loading">
+			<!-- 基本信息 -->
+			<el-divider content-position="left">{{ $t('merchantUser.basicInfo') }}</el-divider>
+			<el-row :gutter="24">
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.merchantName')" prop="merchantName">
+						<el-input :placeholder="$t('merchantUser.inputMerchantNameTip')" v-model="form.merchantName" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.username')" prop="username">
+						<el-input :placeholder="$t('merchantUser.inputUsernameTip')" v-model="form.username" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.realname')" prop="realname">
+						<el-input :placeholder="$t('merchantUser.inputRealnameTip')" v-model="form.realname" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.phone')" prop="phone">
+						<el-input :placeholder="$t('merchantUser.inputPhoneTip')" v-model="form.phone" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.email')" prop="email">
+						<el-input :placeholder="$t('merchantUser.inputEmailTip')" v-model="form.email" :disabled="readonly || !!form.userId" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.idcard')" prop="idcard">
+						<el-input :placeholder="$t('merchantUser.inputIdcardTip')" v-model="form.idcard" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.contactAddress')" prop="contactAddress">
+						<el-input :placeholder="$t('merchantUser.inputContactAddressTip')" v-model="form.contactAddress" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.agentId')" prop="agentId">
+						<el-select v-model="form.agentId" :placeholder="$t('merchantUser.selectAgentTip')" :disabled="readonly" style="width: 100%">
+							<el-option v-for="item in agentList" :key="item.userId" :label="item.agentName" :value="item.userId" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.offlineRechargeRate')" prop="offlineRechargeRate">
+						<el-input-number
+							:placeholder="$t('merchantUser.inputOfflineRechargeRateTip')"
+							v-model="form.offlineRechargeRate"
+							:min="0"
+							:max="100"
+							:precision="2"
+							:disabled="readonly"
+							style="width: 100%"
+						/>
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.status')" prop="status">
+						<el-radio-group v-model="form.status" :disabled="readonly || !!form.userId">
+							<el-radio :label="true">{{ $t('merchantUser.statusEnable') }}</el-radio>
+							<el-radio :label="false">{{ $t('merchantUser.statusDisable') }}</el-radio>
+						</el-radio-group>
+					</el-form-item>
+				</el-col>
+			</el-row>
+
+			<!-- 网站信息 -->
+			<el-divider content-position="left">{{ $t('merchantUser.websiteInfo') }}</el-divider>
+			<el-row :gutter="24">
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.websiteName')" prop="websiteName">
+						<el-input :placeholder="$t('merchantUser.inputWebsiteNameTip')" v-model="form.websiteName" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20">
+					<el-form-item :label="$t('merchantUser.websiteAddress')" prop="websiteAddress">
+						<el-input :placeholder="$t('merchantUser.inputWebsiteAddressTip')" v-model="form.websiteAddress" :disabled="readonly" />
+					</el-form-item>
+				</el-col>
+
+				<el-col :span="12" class="mb20" v-if="form.userId">
+					<el-form-item :label="$t('merchantUser.appId')" prop="appId">
+						<el-input :placeholder="'AppId'" v-model="form.appId" disabled />
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="visible = false">{{ readonly ? $t('common.closeBtn') : $t('common.cancelButtonText') }}</el-button>
+				<el-button @click="onSubmit" type="primary" :disabled="loading" v-if="!readonly">{{ $t('common.confirmButtonText') }}</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script lang="ts" name="MerchantUserDialog" setup>
+// 定义子组件向父组件传值/事件
+import { useMessage } from '/@/hooks/message';
+import { addObj, getObj, putObj, getAgentList } from '/@/api/merchant/merchantUser';
+import { useI18n } from 'vue-i18n';
+import { rule } from '/@/utils/validate';
+
+const emit = defineEmits(['refresh']);
+
+const { t } = useI18n();
+// 定义变量内容
+const dataFormRef = ref();
+const visible = ref(false);
+const loading = ref(false);
+const readonly = ref(false);
+const agentList = ref<any[]>([]);
+
+// 提交表单数据(严格按照接口文档字段)
+const form = reactive({
+	userId: '',
+	username: '',
+	merchantName: '',
+	phone: '',
+	email: '',
+	websiteName: '',
+	websiteAddress: '',
+	appId: '',
+	idcard: '',
+	realname: '',
+	contactAddress: '',
+	offlineRechargeRate: 0,
+	status: true,
+	agentId: undefined as number | undefined,
+});
+
+// 定义校验规则(根据接口文档,必填字段:username, merchantName, phone, email)
+const dataRules = ref({
+	username: [
+		{ required: true, message: t('merchantUser.usernameRequired'), trigger: 'blur' },
+		{ validator: rule.overLength, trigger: 'blur' },
+	],
+	merchantName: [
+		{ required: true, message: t('merchantUser.merchantNameRequired'), trigger: 'blur' },
+		{ validator: rule.overLength, trigger: 'blur' },
+	],
+	phone: [
+		{ required: true, message: t('merchantUser.phoneRequired'), trigger: 'blur' },
+		{ validator: rule.validatePhone, trigger: 'blur' },
+	],
+	email: [
+		{ required: true, message: t('merchantUser.emailRequired'), trigger: 'blur' },
+		{ validator: rule.email, trigger: 'blur' },
+	],
+});
+
+// 打开弹窗
+const openDialog = (id: string, isReadonly = false) => {
+	visible.value = true;
+	readonly.value = isReadonly;
+	form.userId = '';
+
+	// 重置表单数据
+	nextTick(() => {
+		dataFormRef.value?.resetFields();
+	});
+
+	// 加载代理商列表
+	loadAgentList();
+
+	// 获取商户用户信息
+	if (id) {
+		form.userId = id;
+		getMerchantUserData(id);
+	}
+};
+
+// 加载代理商列表
+const loadAgentList = async () => {
+	try {
+		const res = await getAgentList('0');
+		agentList.value = res.data || [];
+	} catch (err: any) {
+		useMessage().error(err.msg);
+	}
+};
+
+// 获取商户用户数据
+const getMerchantUserData = (id: string) => {
+	loading.value = true;
+	getObj(id)
+		.then((res: any) => {
+			Object.assign(form, res.data);
+		})
+		.finally(() => {
+			loading.value = false;
+		});
+};
+
+// 提交
+const onSubmit = async () => {
+	const valid = await dataFormRef.value.validate().catch(() => {});
+	if (!valid) return false;
+
+	try {
+		loading.value = true;
+		if (form.userId) {
+			await putObj(form.userId, form);
+		} else {
+			await addObj(form);
+		}
+		useMessage().success(t(form.userId ? 'common.editSuccessText' : 'common.addSuccessText'));
+		visible.value = false;
+		emit('refresh');
+	} catch (err: any) {
+		useMessage().error(err.msg);
+	} finally {
+		loading.value = false;
+	}
+};
+
+/**
+ * 暴露变量
+ */
+defineExpose({
+	openDialog,
+});
+</script>

+ 140 - 0
src/views/merchant/list/index.vue

@@ -0,0 +1,140 @@
+<template>
+	<div class="layout-padding">
+		<div class="layout-padding-auto layout-padding-view">
+			<el-row class="ml10" v-show="showSearch">
+				<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
+					<el-form-item :label="$t('merchantUser.merchantName')" prop="query">
+						<el-input :placeholder="$t('merchantUser.searchMerchantAccount')" style="max-width: 180px" v-model="state.queryForm.query" />
+					</el-form-item>
+					<el-form-item>
+						<el-button @click="getDataList" icon="search" type="primary">
+							{{ $t('common.queryBtn') }}
+						</el-button>
+						<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
+					</el-form-item>
+				</el-form>
+			</el-row>
+			<el-row>
+				<div class="mb8" style="width: 100%">
+					<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary" v-auth="'merchant'">
+						{{ $t('common.addBtn') }}
+					</el-button>
+					<right-toolbar
+						@queryTable="getDataList"
+						class="ml10"
+						style="float: right; margin-right: 20px"
+						v-model:showSearch="showSearch"
+					></right-toolbar>
+				</div>
+			</el-row>
+			<el-table
+				:data="state.dataList"
+				@selection-change="handleSelectionChange"
+				@sort-change="sortChangeHandle"
+				style="width: 100%"
+				v-loading="state.loading"
+				border
+				:cell-style="tableStyle.cellStyle"
+				:header-cell-style="tableStyle.headerCellStyle"
+			>
+				<el-table-column align="center" type="selection" width="40" />
+				<el-table-column :label="$t('merchantUser.merchantId')" prop="userId" show-overflow-tooltip />
+				<el-table-column :label="$t('merchantUser.merchantName')" prop="merchantName" show-overflow-tooltip />
+				<el-table-column :label="$t('merchantUser.agentName')" prop="agentName" show-overflow-tooltip />
+				<el-table-column :label="$t('merchantUser.status')" prop="status" show-overflow-tooltip>
+					<template #default="scope">
+						<el-switch
+							v-model="scope.row.status"
+							@change="handleStatusChange(scope.row)"
+							:active-value="true"
+							:inactive-value="false"
+							v-auth="'merchant'"
+						/>
+					</template>
+				</el-table-column>
+				<el-table-column :label="$t('merchantUser.operation')" fixed="right" width="200">
+					<template #default="scope">
+						<el-button icon="View" @click="handleView(scope.row)" text type="primary" v-auth="'merchant'">{{ $t('merchantUser.viewBtn') }}</el-button>
+						<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.userId)" text type="primary" v-auth="'merchant'"
+							>{{ $t('common.editBtn') }}
+						</el-button>
+						<el-button icon="Key" @click="handleChangePwd(scope.row)" text type="warning" v-auth="'merchant'">{{ $t('merchantUser.changePwdBtn') }}</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
+		</div>
+
+		<!-- 编辑、新增 -->
+		<form-dialog @refresh="getDataList(false)" ref="formDialogRef" />
+
+		<!-- 修改密码 -->
+		<change-pwd-dialog @refresh="getDataList(false)" ref="changePwdDialogRef" />
+	</div>
+</template>
+
+<script lang="ts" name="systemMerchantUser" setup>
+import { BasicTableProps, useTable } from '/@/hooks/table';
+import { fetchList, changeStatus } from '/@/api/merchant/merchantUser';
+import { useMessage, useMessageBox } from '/@/hooks/message';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+// 引入组件
+const FormDialog = defineAsyncComponent(() => import('./form.vue'));
+const ChangePwdDialog = defineAsyncComponent(() => import('./changePwd.vue'));
+
+// 定义变量内容
+const formDialogRef = ref();
+const changePwdDialogRef = ref();
+const queryRef = ref();
+const showSearch = ref(true);
+const selectObjs = ref([]);
+const multiple = ref(true);
+
+// 定义表格查询、变更
+const state: BasicTableProps = reactive<BasicTableProps>({
+	queryForm: {
+		query: '',
+	},
+	pageList: fetchList,
+});
+
+const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle } = useTable(state);
+
+// 重置查询
+const resetQuery = () => {
+	queryRef.value?.resetFields();
+	getDataList();
+};
+
+// 多选事件
+const handleSelectionChange = (objs: any) => {
+	selectObjs.value = objs.map((val: any) => val.userId);
+	multiple.value = !objs.length;
+};
+
+// 状态切换
+const handleStatusChange = async (row: any) => {
+	try {
+		await changeStatus(row.userId);
+		useMessage().success(t('merchantUser.statusChangeSuccess'));
+		getDataList(false);
+	} catch (err: any) {
+		useMessage().error(err.msg);
+		// 恢复原状态
+		row.status = !row.status;
+	}
+};
+
+// 查看详情
+const handleView = (row: any) => {
+	formDialogRef.value.openDialog(row.userId, true);
+};
+
+// 修改密码
+const handleChangePwd = (row: any) => {
+	changePwdDialogRef.value.openDialog(row.userId);
+};
+</script>