Ver código fonte

feat:add setting and statistisc

叶静 1 mês atrás
pai
commit
06c93cd24e
43 arquivos alterados com 2761 adições e 7345 exclusões
  1. 0 94
      doc/1.md
  2. 0 460
      doc/10.md
  3. 0 169
      doc/11.md
  4. 0 186
      doc/12.md
  5. 0 161
      doc/13.md
  6. 0 197
      doc/14.md
  7. 0 204
      doc/15.md
  8. 0 151
      doc/16.md
  9. 0 121
      doc/17.md
  10. 0 86
      doc/18.md
  11. 0 198
      doc/19.md
  12. 0 108
      doc/2.md
  13. 0 257
      doc/20.md
  14. 0 167
      doc/21.md
  15. 0 199
      doc/22.md
  16. 0 197
      doc/23.md
  17. 0 83
      doc/24.md
  18. 0 479
      doc/25.md
  19. 0 340
      doc/26.md
  20. 0 692
      doc/27.md
  21. 0 260
      doc/3.md
  22. 0 240
      doc/4.md
  23. 0 128
      doc/5.md
  24. 0 177
      doc/6.md
  25. 0 255
      doc/7.md
  26. 0 107
      doc/8.md
  27. 0 164
      doc/9.md
  28. 0 1420
      doc/PIGX前端技术文档汇总.md
  29. 198 0
      doc/bmd.json
  30. 192 0
      doc/google.json
  31. 1117 0
      doc/order.json
  32. 9 8
      package.json
  33. 38 0
      src/api/admin/google.ts
  34. 80 0
      src/api/admin/setting.ts
  35. 2 2
      src/api/login/index.ts
  36. 12 0
      src/api/statistics/index.ts
  37. 56 0
      src/config/menuConfig.ts
  38. 9 10
      src/router/backEnd.ts
  39. 8 6
      src/utils/request.ts
  40. 284 16
      src/views/home/index.vue
  41. 20 2
      src/views/login/component/password.vue
  42. 735 0
      src/views/settings/security/index.vue
  43. 1 1
      tsconfig.json

+ 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 类型的数据,并在组件中被调用。
-
- |
-
-### 本页导航
-
-卡槽扩展
-
-属性说明

+ 0 - 1420
doc/PIGX前端技术文档汇总.md

@@ -1,1420 +0,0 @@
-# PIGX 前端技术文档汇总
-
-> **更新日期**: 2025-10-23  
-> **适配版本**: 5.0 以上单体和微服务版本
-
----
-
-## 目录
-
-- [一、环境配置](#一环境配置)
-  - [1.1 ENV 环境配置](#11-env环境配置)
-  - [1.2 前端配置项说明](#12-前端配置项说明)
-- [二、项目结构](#二项目结构)
-  - [2.1 目录结构](#21-目录结构)
-- [三、核心功能](#三核心功能)
-  - [3.1 国际化配置](#31-国际化配置)
-  - [3.2 字体图标配置](#32-字体图标配置)
-  - [3.3 权限管理](#33-权限管理)
-  - [3.4 路由管理](#34-路由管理)
-  - [3.5 标签页管理](#35-标签页管理)
-  - [3.6 数据状态管理](#36-数据状态管理)
-- [四、工具函数](#四工具函数)
-  - [4.1 字典工具使用](#41-字典工具使用)
-  - [4.2 参数工具使用](#42-参数工具使用)
-  - [4.3 通用工具函数](#43-通用工具函数)
-- [五、组件使用](#五组件使用)
-  - [5.1 表格组件](#51-表格组件)
-  - [5.2 表格分页组件](#52-表格分页组件)
-  - [5.3 表格工具栏组件](#53-表格工具栏组件)
-  - [5.4 上传组件](#54-上传组件)
-  - [5.5 富文本组件](#55-富文本组件)
-  - [5.6 代码编辑组件](#56-代码编辑组件)
-  - [5.7 图表功能](#57-图表功能)
-  - [5.8 左侧查询树](#58-左侧查询树)
-  - [5.9 组织架构组件](#59-组织架构组件)
-  - [5.10 标签列表组件](#510-标签列表组件)
-  - [5.11 悬浮输入组件](#511-悬浮输入组件)
-  - [5.12 文字提示组件](#512-文字提示组件)
-  - [5.13 省市区街四级联动组件](#513-省市区街四级联动组件)
-  - [5.14 表单校验](#514-表单校验)
-- [六、首页开发](#六首页开发)
-  - [6.1 首页组件开发](#61-首页组件开发)
-
----
-
-## 一、环境配置
-
-### 1.1 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)                                   |
-
-### 1.2 前端配置项说明
-
-**配置文件**: `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`        | 是否开启菜单背景颜色渐变 |
-
-#### 界面设置
-
-| 配置项               | 默认值  | 描述                     |
-| -------------------- | ------- | ------------------------ |
-| `isCollapse`         | `false` | 是否开启菜单水平折叠效果 |
-| `isUniqueOpened`     | `true`  | 是否开启菜单手风琴效果   |
-| `isFixedHeader`      | `false` | 是否开启固定 Header      |
-| `isClassicSplitMenu` | `false` | 是否开启经典布局分割菜单 |
-| `isLockScreen`       | `false` | 是否开启自动锁屏         |
-| `lockScreenTime`     | `30`    | 开启自动锁屏倒计时(s/秒) |
-
-#### 界面显示
-
-| 配置项               | 默认值  | 描述                         |
-| -------------------- | ------- | ---------------------------- |
-| `isShowLogo`         | `true`  | 是否开启侧边栏 Logo          |
-| `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`  | 水印文案                     |
-
-#### 其它设置
-
-| 配置项               | 默认值             | 描述                 |
-| -------------------- | ------------------ | -------------------- |
-| `tagsStyle`          | `tags-style-five`  | Tagsview 风格        |
-| `animation`          | `slide-right`      | 主页面切换动画       |
-| `columnsAsideStyle`  | `columns-round`    | 分栏高亮风格         |
-| `columnsAsideLayout` | `columns-vertical` | 分栏布局风格         |
-| `layout`             | `defaults`         | 布局设置             |
-| `isRequestRoutes`    | `true`             | 后端控制路由是否开启 |
-
----
-
-## 二、项目结构
-
-### 2.1 目录结构
-
-```
-├── 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` 配置文件内容。
-
----
-
-## 三、核心功能
-
-### 3.1 国际化配置
-
-框架内置 `中文简体`、`英文`
-
-#### 多国语言配置
-
-**前端配置国际化**
-
-> 注意:页面国际化数据最好放 `同级的目录中 i18n` 里。`/@/i18n` 为框架内置,为了更好的升级,最好别添加到里面
-
-**后端配置国际化**
-
-与前端 i18n 配置 ts 文件格式相同,i18n 可以通过后台进行国际化管理的配置和使用。
-
-#### 国际化使用
-
-**页面上使用 `.vue`,`$t('xxx.xxx')`**
-
-```vue
-<el-button>
-  <span>{{ $t('message.account.accountBtnText') }}</span>
-</el-button>
-
-<el-divider content-position="left">
-  {{ $t('message.layout.oneTitle') }}
-</el-divider>
-```
-
-**ts 上使用 `.ts`,`i18n.global.t(xxx)`**
-
-```typescript
-import { i18n } from '/@/i18n/index';
-
-const webTitle = i18n.global.t(router.currentRoute.value.meta.title as any);
-```
-
-**setup 里使用 ,`t(xxx)`**
-
-```typescript
-<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>
-```
-
-### 3.2 字体图标配置
-
-#### 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>` 包裹着
-
-```vue
-<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. 访问 [iconfont 官网](https://www.iconfont.cn/) 并登录
-2. 创建新项目 -> 设置`FontClass/Symbol 前缀`为 `icon`,`Font Family` 为 `iconfont`
-3. 添加所需图标到项目 -> 生成在线链接
-
-**2. 设置在线链接**
-
-代码位置:`/@/utils/setIconfont.ts`
-
-```typescript
-// `/@/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. 界面中使用**
-
-> ⚠️ **警告**:
->
-> - iconfont(阿里巴巴素材库):需要添加 `iconfont` 前缀,如:`iconfont xitongshezhi`
-> - font-awesome:需要添加 `fa` 前缀,如:`fa xitongshezhi`
-
-```vue
-<!-- 项目使用 -->
-<i class="iconfont xitongshezhi"></i>
-<!-- <i class="fa xitongshezhi"></i> -->
-
-<!-- 或者 -->
-<SvgIcon name="iconfont xitongshezhi"></SvgIcon>
-<!-- <SvgIcon name="fa xitongshezhi"></SvgIcon> -->
-```
-
-#### 本地图标
-
-支持下载 svg ,放在前端的 icons 目录
-
-前端可通过 local-文件名的形式加载
-
-```vue
-<SvgIcon name="local-gitee" :size="30" />
-```
-
-#### 阿里巴巴图标库离线
-
-为了提高系统的稳定性和加载速度,我们可以将原本使用的阿里巴巴在线图标库转换为本地离线使用。
-
-**1. 下载图标资源包**
-
-[点击下载 PIGX-UI 都有依赖的阿里巴巴图标](https://minio.pigx.vip/oss/202501/1737972483.zip)
-
-**2. 创建本地图标目录**
-
-```bash
-mkdir -p pigx-ui/public/assets/iconfont
-```
-
-**3. 复制资源文件**
-
-将下载的资源包中的以下文件复制到 `public/assets/iconfont/` 目录:
-
-- iconfont.css
-- iconfont.ttf
-- iconfont.woff
-- iconfont.woff2
-
-**4. 修改配置文件**
-
-修改 `src/utils/setIconfont.ts` 文件中的图标引用路径:
-
-```typescript
-const cssCdnUrlList: Array<string> = [
-	'/assets/iconfont/iconfont.css', // 本地图标文件
-	'/assets/styles/font-awesome.min.css',
-];
-```
-
-### 3.3 权限管理
-
-#### 1. 组件方式
-
-组件位置:`/@/components/auth`
-
-**单个权限验证(:value="xxx")**
-
-```vue
-<template>
-	<!-- 使用 -->
-	<Auth :value="'btn.add'" />
-</template>
-
-<script setup lang="ts" name="xxx">
-// 局部引入
-import Auth from '/@/components/auth/auth.vue';
-</script>
-```
-
-**多个权限验证,满足一个则显示(:value="[xxx,xxx]")**
-
-```vue
-<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>
-```
-
-**多个权限验证,全部满足则显示(:value="[xxx,xxx]")**
-
-```vue
-<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. 指令方式
-
-指令位置:`/@/directive/authDirective.ts`
-
-**单个权限验证(v-auth="xxx")**
-
-```vue
-<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-auths="[xxx,xxx]")**
-
-```vue
-<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-all="[xxx,xxx]")**
-
-```vue
-<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. 函数方式
-
-方法位置:`/@/utils/authFunction.ts`,用于方法中的判断
-
-```typescript
-<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>
-```
-
-或者在模板中使用:
-
-```vue
-<div v-if="auth('sys_file_del')">...</div>
-```
-
-### 3.4 路由管理
-
-#### 静态路由
-
-静态路由是指直接在前端代码中配置的路由,不需要通过后端接口动态获取。这些路由在项目编译时就已确定,适用于固定不变的页面导航结构。
-
-在 PIGX-UI 中使用静态路由的主要原因:适合配置系统级别的页面(如登录、404 等),可以独立于后端菜单权限系统(不需要鉴权等配置)
-
-**路由配置位置**
-
-```
-src/
-  └── router/
-     └── route.ts          # 路由配置文件
-```
-
-**属性配置说明**
-
-| 配置项        | 说明                                                                       |
-| ------------- | -------------------------------------------------------------------------- |
-| `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 标签页,同时也可以传递参数。
-
-**代码实现方式**
-
-**① 菜单管理中定义隐藏菜单**
-
-> ⚠️ 注意为角色分配该菜单的权限。
-
-**② 点击目标按钮触发路由跳转**
-
-```typescript
-const click = () => {
-	router.push({
-		path: '/app/appArticle/form',
-		query: { tagsViewName: '动态路由测试', param1: '123' },
-	});
-};
-```
-
-**③ 在跳转的页面获取请求参数**
-
-```typescript
-const route = useRoute();
-
-onMounted(() => {
-	console.log(route.query.tagsViewName);
-	console.log(route.query.param1);
-});
-```
-
-#### 菜单参数方式
-
-在多个菜单中引用同一个路由下的组件,通过路由进行区分。
-
-**① 配置菜单(带参)**
-
-指向 /admin/test/index 组件
-
-```
-AAA /admin/test/1
-BBB /admin/test/2
-```
-
-**② 页面获取参数**
-
-admin/test/index.vue
-
-```typescript
-const route = useRoute();
-
-onMounted(() => {
-	// test/index/参数
-	const parts = route.path.split('/');
-	const lastParam = parts[parts.length - 1];
-	console.log(lastParam);
-});
-```
-
-### 3.5 标签页管理
-
-#### 1. 指定标签页名称
-
-跳转函数中指定路由参数 `tagsViewName`。
-
-```typescript
-const router = useRouter();
-router.push({ path: '/xxx', query: { tagsViewName: '标签名称' } });
-```
-
-#### 2. 刷新当前页面
-
-```typescript
-import { useRoute } from 'vue-router';
-import mittBus from '/@/utils/mitt';
-
-const route = useRoute();
-
-// 刷新当前页面
-const refreshPage = () => {
-	mittBus.emit('onCurrentContextmenuClick', {
-		contextMenuClickId: 0,
-		...route,
-	});
-};
-```
-
-#### 3. 关闭当前页面
-
-```typescript
-// 关闭当前页面
-const closePage = () => {
-	mittBus.emit('onCurrentContextmenuClick', {
-		contextMenuClickId: 1,
-		...route,
-	});
-};
-```
-
-#### 4. 关闭其它页面
-
-```typescript
-// 关闭除当前页外的其它页面
-const closeOthers = () => {
-	mittBus.emit('onCurrentContextmenuClick', {
-		contextMenuClickId: 2,
-		...route,
-	});
-};
-```
-
-#### 5. 关闭全部页面
-
-```typescript
-// 关闭所有页面
-const closeAll = () => {
-	mittBus.emit('onCurrentContextmenuClick', {
-		contextMenuClickId: 3,
-		...route,
-	});
-};
-```
-
-#### 6. 全屏显示
-
-```typescript
-// 当前页面全屏显示
-const fullscreen = () => {
-	mittBus.emit('onCurrentContextmenuClick', {
-		contextMenuClickId: 4,
-		...route,
-	});
-};
-```
-
-**操作 ID 说明**
-
-| 操作 ID | 功能说明       |
-| ------- | -------------- |
-| 0       | 刷新当前页面   |
-| 1       | 关闭当前页面   |
-| 2       | 关闭其它页面   |
-| 3       | 关闭全部页面   |
-| 4       | 当前页全屏显示 |
-
-### 3.6 数据状态管理
-
-框架中数据状态使用 vuex Module 模块化进行管理,您可能需要了解 [vuex 核心概念 Module](https://next.vuex.vuejs.org/zh/guide/modules.html)
-
-#### pinia
-
-代码位置:`/src/stores`
-
-相关文档:[pinia 官网](https://pinia.vuejs.org/)
-
-相关文档:[vuex 3.x 官网](https://v3.vuex.vuejs.org/zh/)
-
-#### 全局引入
-
-页面模块已做全局自动引入,代码位置:`/@/store/index.ts`。
-
-```typescript
-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 定义**
-
-`/@/store/interface/index.ts`,如:路由缓存列表 `KeepAliveNamesState`
-
-```typescript
-// 路由缓存列表
-export interface KeepAliveNamesState {
-	keepAliveNames: Array<string>;
-}
-```
-
-**2. interface 使用**
-
-在 `/@/store/modules/` 新增 `keepAliveNames.ts`,界面写入如下代码:
-
-```typescript
-import { Module } from 'vuex';
-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;
-```
-
-#### 使用模块
-
-**1. 在 .ts 中使用**
-
-```typescript
-import { store } from '/@/store/index.ts';
-
-// dispatch
-store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
-
-// 或者 commit
-// store.commit("keepAliveNames/getCacheKeepAlive", cacheList);
-```
-
-**2. 在 .vue 中使用**
-
-```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>
-```
-
----
-
-## 四、工具函数
-
-### 4.1 字典工具使用
-
-#### 1. useDict 函数
-
-字典类型对应 sys_dict 表中字典数据
-
-```typescript
-import {useDict} from '/@/hooks/dict';
-
-const {字典类型A, 字典类型B} = useDict('字典类型A','字典类型B');
-```
-
-> ⚠️ **注意**:element-plus 的 radio 和 select 等类型组件对 value 字段有强制的数据类型要求。实体字段应该使用字符串而不是数字类型来对应字典功能使用。
-
-#### 2. 页面使用 dict-tag
-
-```vue
-<el-table-column>
-  <template #default="scope">
-    <dict-tag :options="字典类型" :value="scope.row.xx"></dict-tag>
-  </template>
-</el-table-column>
-```
-
-### 4.2 参数工具使用
-
-#### 1. useParam 函数
-
-| 入参                                 | 出参                                   |
-| ------------------------------------ | -------------------------------------- |
-| sys_public_param 表中 publicKey 字段 | sys_public_param 表中 publicValue 字段 |
-
-```typescript
-import { useParam } from '/@/hooks/param';
-const param = useParam('GEN_TABLE_PREFIX');
-```
-
-#### 2. 页面使用
-
-```vue
-{{ useParam('GEN_TABLE_PREFIX') }}
-```
-
-### 4.3 通用工具函数
-
-#### 点击复制文本
-
-```vue
-<button @click="copyText('文案内容')">复制</button>
-```
-
-```typescript
-const { copyText } = commonFunction();
-```
-
-#### 格式化时间
-
-**html 代码中直接使用 parseDate parseTime 进行格式化**
-
-```vue
-<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 中需要手动导入**
-
-```typescript
-import { formatDate, parseDate } from '/@/utils/formatTime';
-```
-
-#### 获取后端参数
-
-```typescript
-import params from '/@/utils/params';
-
-let result = await params.get('参数管理中的KEY');
-```
-
----
-
-## 五、组件使用
-
-### 5.1 表格组件
-
-#### 1. useTable 函数是什么
-
-官方对自定义 hook 定义:在 Vue 应用的概念中,"组合式函数" (Composables) 是一个利用 Vue 组合式 API 来封装和复用有状态逻辑的函数。
-
-**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`。返回一个 Promise 对象,用于异步处理结果        |
-
-#### 2. 页面中如何使用
-
-```typescript
-// 使用 useTable 自动生成表格一些通用方法
-const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
-```
-
-#### 3. useTable 初始化 state 如何构建
-
-如果你想通过 useTable 生成一些通用的表格方法,那么就需要向它提供一些初始值,比如查询的 URL 和分页大小等参数。
-
-```typescript
-const state: BasicTableProps = reactive<BasicTableProps>({
-	queryForm: {},
-	pageList: pageList,
-});
-```
-
-**完整的 BasicTable 定义属性如下**
-
-```typescript
-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;
-}
-```
-
-### 5.2 表格分页组件
-
-#### 分页组件使用
-
-分页组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
-
-```vue
-<pagination v-bind="state.pagination" @current-change="currentChangeHandle" @size-change="sizeChangeHandle"></pagination>
-```
-
-```typescript
-const { currentChangeHandle, sizeChangeHandle } = useTable(state);
-```
-
-#### 属性说明
-
-| 属性        | 类型     | 默认值                                      | 说明                 |
-| ----------- | -------- | ------------------------------------------- | -------------------- |
-| `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'` | 分页组件的布局       |
-
-### 5.3 表格工具栏组件
-
-#### 工具栏组件使用
-
-工具栏组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
-
-```vue
-<right-toolbar v-model:showSearch="showSearch" :export="'sys_user_export'" @exportExcel="exportExcel" @queryTable="getDataList" />
-```
-
-```typescript
-const { getDataList } = useTable(state);
-```
-
-#### 属性说明
-
-| 属性         | 类型                | 默认值                                                             | 说明             |
-| ------------ | ------------------- | ------------------------------------------------------------------ | ---------------- |
-| `showSearch` | `Boolean`           | `true`                                                             | 是否显示搜索框   |
-| `export`     | `String or Boolean` | `当设置为true的显示,如设置为权限字符串则根据当前用户权限动态控制` | 是否导出下载按钮 |
-| `search`     | `Boolean`           | `true`                                                             | 是否显示搜索框   |
-| `gutter`     | `Number`            | `10`                                                               | 列表项之间的间距 |
-
-### 5.4 上传组件
-
-#### 普通文件上传
-
-```vue
-<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`                                                                              |
-
-#### 图片上传
-
-```vue
-<upload-img v-model:imageUrl="formData.avatar" borderRadius="50%">
-  <template #empty>
-    <el-icon><Avatar /></el-icon>
-    <span>请上传头像</span>
-  </template>
-</upload-img>
-```
-
-**属性说明**
-
-| 属性名称        | 描述                                       | 类型                                                                             |
-| --------------- | ------------------------------------------ | -------------------------------------------------------------------------------- |
-| `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 文件上传
-
-```vue
-<upload-excel
-	ref="excelUploadRef"
-	:title="$t('sysuser.importUserTip')"
-	temp-url="/admin/sys-file/local/file/user.xlsx"
-	url="/admin/user/import"
-	@refreshDataList="getDataList"
-/>
-```
-
-**属性说明**
-
-| 属性名称  | 描述                        | 类型     |
-| --------- | --------------------------- | -------- |
-| `url`     | 导入文件后台接口            | `String` |
-| `title`   | 弹出框标题                  | `String` |
-| `tempUrl` | 获取当前导如 excel 模板地址 | `String` |
-
-### 5.5 富文本组件
-
-Wangeditor 是一款基于 Web 的所见即所得富文本编辑器,它提供了丰富的富文本编辑功能,支持插入图片、音视频等多媒体内容,并且可以通过自定义插件扩展其功能。
-
-#### 页面使用
-
-```vue
-<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"` |
-
-### 5.6 代码编辑组件
-
-#### 引入组件
-
-```typescript
-const CodeEditor = defineAsyncComponent(() => import('/@/components/CodeEditor/index.vue'));
-```
-
-#### 使用方法
-
-```vue
-<template>
-	<div>
-		<CodeEditor v-model="code" mode="go" theme="idea" :readOnly="false" :height="300" />
-	</div>
-</template>
-```
-
-#### Props
-
-| 属性         | 类型               | 默认值   | 说明                  |
-| ------------ | ------------------ | -------- | --------------------- |
-| `modelValue` | `String`           | `''`     | 绑定的代码内容        |
-| `mode`       | `String`           | `'go'`   | 代码语言              |
-| `theme`      | `String`           | `'idea'` | 代码编辑器的主题      |
-| `height`     | `[String, Number]` | `300`    | 代码编辑器的高度      |
-| `options`    | `Object`           | `{}`     | CodeMirror 的配置选项 |
-| `readOnly`   | `Boolean`          | `false`  | 是否只读              |
-
-### 5.7 图表功能
-
-Vue Echarts 是一个 Vue.js 的 ECharts 图表组件,对 EChart 进行了封装,简化了 Echart 图表的使用。
-
-pigx-ui 默认引入了 vue-echarts ,业务代码中可以非常方便地使用相关的 EChart 图表组件【例如:日志管理】。
-
-#### 快速使用
-
-1. 访问 [ECharts 官网](https://echarts.apache.org/examples/zh/index.html#chart-type-bar),选择目标类型的图表组件,获取图表的 option 配置 JSON。
-
-2. 访问 [vue-echarts 代码生成器](https://vue-echarts.dev/#codegen)。
-
-#### 业务页面使用 vue-echarts
-
-```vue
-<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)
-</script>
-```
-
-### 5.8 左侧查询树
-
-```vue
-<query-tree :query="state.queryList" @node-click="handleNodeClick">
-</query-tree>
-```
-
-```typescript
-const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
-
-const state = reactive({
-	queryList: (name: String) => {
-		return api({ name: name });
-	},
-});
-
-const handleNodeClick = (e: any) => {};
-```
-
-#### 卡槽扩展
-
-```vue
-<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 类型的数据,并在组件中被调用 |
-
-### 5.9 组织架构组件
-
-#### 页面使用
-
-```vue
-<template>
-	<org-selector v-model:orgList="userList" type="user" :multiple="false" />
-</template>
-
-<script setup>
-import orgSelector from '/@/components/OrgSelector/index.vue';
-</script>
-```
-
-#### 数据格式
-
-```json
-[
-	{
-		"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` |
-
-### 5.10 标签列表组件
-
-#### 使用方法
-
-```vue
-<tag-list buttonText="+手机号" v-model="phoneList" />
-;
-
-<script setup>
-const phoneList = ref([]);
-</script>
-```
-
-#### 属性说明
-
-| 属性         | 类型                                     | 默认值      | 说明                   |
-| ------------ | ---------------------------------------- | ----------- | ---------------------- |
-| `modelValue` | `Array[String]`                          | `[]`        | 双向绑定绑定的标签数组 |
-| `buttonText` | `String`                                 | `+ New Tag` | 按钮显示的文本         |
-| `tagType`    | `'success', 'info', 'warning', 'danger'` | -           | 按钮显示类型           |
-
-### 5.11 悬浮输入组件
-
-```typescript
-const PopoverInput = defineAsyncComponent(() => import('/@/components/PopoverInput/index.vue'));
-```
-
-```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`    |
-
-### 5.12 文字提示组件
-
-```vue
-<el-form-item label="初始浏览量" prop="visit">
-  <template #label>
-    浏览量<tip content="初始值" />
-  </template>
-</el-form-item>
-```
-
-#### 属性说明
-
-| 属性名称    | 描述     | 类型     | 默认值        |
-| ----------- | -------- | -------- | ------------- |
-| `content`   | 内容     | `String` | -             |
-| `placement` | 放置位置 | `String` | `'top-start'` |
-
-### 5.13 省市区街四级联动组件
-
-#### 省市区三级联动
-
-```typescript
-const ChinaArea = defineAsyncComponent(() => import('/@/components/ChinaArea/index.vue'));
-```
-
-```vue
-<china-area v-model="data" @change="handleChange" />
-;
-
-<script setup>
-// 双向绑定数据 自动回显: 北京市/市辖区/东城区
-const data = ref('11,1101,110101');
-
-// 可选 输出: 11,1101,110101
-const handleChange = (val: String) => {};
-</script>
-```
-
-#### 属性说明
-
-| 属性名称  | 描述                      | 类型       |
-| --------- | ------------------------- | ---------- |
-| `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 年的数据)中不存在对应地区,您可以根据规则自行新增。请注意,编码需保持唯一。
-
-### 5.14 表单校验
-
-#### 表单校验使用
-
-Form 组件允许你验证用户的输入是否符合规范,来帮助你找到和纠正错误。
-
-Form 组件提供了表单验证的功能,只需为 rules 属性传入约定的验证规则,并将 form-Item 的 prop 属性设置为需要验证的特殊键值即可。
-
-```typescript
-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',
-		},
-	],
-});
-```
-
-> ⚠️ **注意**:element-plus 的 radio 和 select 等类型组件对 value 字段有强制的数据类型要求。实体字段应该使用字符串而不是数字类型来对应字典功能使用。
-
-#### 内置规则
-
-| 函数名称                    | 函数作用                                        |
-| --------------------------- | ----------------------------------------------- |
-| `validateExist`             | 根据字段自动查询后台是否重复                    |
-| `overLength`                | 校验用户输入的长度避免超长,范围为 0-255 个字符 |
-| `validatorNameCn`           | 校验用户输入是否为中文、英文、数字包括下划线    |
-| `validatorCapital`          | 校验用户输入是否为大写英文、下划线              |
-| `validatorLowercase`        | 校验用户输入是否为小写英文、下划线              |
-| `validatorLower`            | 校验用户输入是否为小写英文                      |
-| `checkSpace`                | 校验输入是否包含首尾空白字符                    |
-| `validatePhone`             | 校验手机号的合法性                              |
-| `number`                    | 校验输入是否为数字                              |
-| `letter`                    | 校验输入是否为字母                              |
-| `letterAndNumber`           | 校验输入是否为字母和数字                        |
-| `mobilePhone`               | 校验输入是否为正确格式的手机号码                |
-| `letterStartNumberIncluded` | 校验输入是否以字母开头,可包含数字              |
-| `noChinese`                 | 校验输入是否包含中文字符                        |
-| `chinese`                   | 校验输入是否为中文字符                          |
-| `email`                     | 校验输入是否为正确格式的电子邮箱                |
-| `url`                       | 校验输入是否为正确格式的 URL                    |
-| `regExp`                    | 校验输入是否符合给定的正则表达式                |
-
----
-
-## 六、首页开发
-
-### 6.1 首页组件开发
-
-#### 开发组件
-
-在 `src/views/home/widgets/components` 目录下创建组件
-
-#### 挂载组件
-
-在 `src/views/home/widgets/index.vue` 中挂载组件,将 myGrid 数组增加上一步创建的组件文件名称
-
-```typescript
-const myGrid = ['test-demo'];
-```
-
----
-
-## 总结
-
-本文档汇总了 PIGX 前端技术框架的核心内容,包括:
-
-- ✅ **环境配置**:ENV 配置、前端配置项说明
-- ✅ **项目结构**:完整的目录结构说明
-- ✅ **核心功能**:国际化、图标、权限、路由、标签页、状态管理
-- ✅ **工具函数**:字典、参数、通用工具函数
-- ✅ **组件使用**:表格、分页、上传、富文本、代码编辑、图表等 14 个常用组件
-- ✅ **首页开发**:首页组件开发指南
-
-更多详细信息请参考官方文档:[https://pig4cloud.com](https://pig4cloud.com)
-
----
-
-**文档版本**: v1.0  
-**最后更新**: 2025-10-23  
-**维护团队**: PIGX 开发团队

+ 198 - 0
doc/bmd.json

@@ -0,0 +1,198 @@
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "默认模块",
+    "description": "",
+    "version": "1.0.0"
+  },
+  "tags": [],
+  "paths": {
+    "/merchant/getWhitelist": {
+      "get": {
+        "summary": "查看白名单",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RString"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": ""
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchant/editWhitelist": {
+      "patch": {
+        "summary": "设置白名单",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/EditMerchantSafeRO",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": 0,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/merchant/editSecondaryPwd": {
+      "patch": {
+        "summary": "设置二级密码",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/EditMerchantSafeRO",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "ok": false,
+                  "code": 0,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "RString": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "string",
+            "description": "数据"
+          }
+        }
+      },
+      "EditMerchantSafeRO": {
+        "type": "object",
+        "properties": {
+          "whitelist": {
+            "type": "string",
+            "description": "白名单"
+          },
+          "secondaryPwd": {
+            "type": "string",
+            "description": "二级密码"
+          },
+          "oldSecondaryPwd": {
+            "type": "string",
+            "description": "旧二级密码"
+          }
+        }
+      },
+      "R": {
+        "type": "object",
+        "properties": {
+          "ok": {
+            "type": "boolean"
+          },
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "object",
+            "properties": {},
+            "description": "数据"
+          }
+        }
+      }
+    },
+    "securitySchemes": {
+      "bearer": {
+        "type": "http",
+        "scheme": "bearer"
+      }
+    }
+  },
+  "servers": [],
+  "security": []
+}

+ 192 - 0
doc/google.json

@@ -0,0 +1,192 @@
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "默认模块",
+    "description": "",
+    "version": "1.0.0"
+  },
+  "tags": [],
+  "paths": {
+    "/google/getCode": {
+      "post": {
+        "summary": "获取二维码",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RString"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": ""
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/google/binding": {
+      "get": {
+        "summary": "绑定验证码",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "code",
+            "in": "query",
+            "description": "",
+            "required": false,
+            "example": 487722,
+            "schema": {
+              "type": "integer"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": ""
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    },
+    "/google/unbinding": {
+      "post": {
+        "summary": "解绑验证码",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/GoogleUnbindingRO",
+                "description": ""
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/R",
+                  "description": "响应信息主体"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": ""
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": [
+          {
+            "bearer": []
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "RString": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "string",
+            "description": "数据"
+          }
+        }
+      },
+      "GoogleUnbindingRO": {
+        "type": "object",
+        "properties": {
+          "pwd": {
+            "type": "string",
+            "description": ""
+          }
+        },
+        "required": [
+          "pwd"
+        ]
+      },
+      "R": {
+        "type": "object",
+        "properties": {
+          "ok": {
+            "type": "boolean"
+          },
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "type": "object",
+            "properties": {},
+            "description": "数据"
+          }
+        }
+      }
+    },
+    "securitySchemes": {
+      "bearer": {
+        "type": "http",
+        "scheme": "bearer"
+      }
+    }
+  },
+  "servers": [],
+  "security": []
+}

+ 1117 - 0
doc/order.json

@@ -0,0 +1,1117 @@
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "默认模块",
+    "description": "",
+    "version": "1.0.0"
+  },
+  "tags": [],
+  "paths": {
+    "/admin/payOrder/page": {
+      "post": {
+        "summary": "分页查询列表",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/PayOrderPageDTO",
+                "description": "参数集"
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RIPagePayOrder",
+                  "description": "用户集合"
+                },
+                "example": {
+                  "ok": false,
+                  "code": 0,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": []
+      }
+    },
+    "/admin/payOrder/statistics": {
+      "post": {
+        "summary": "代付列表统计",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/PayOrderPageDTO",
+                "description": "参数集"
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RPayOrderStatisticsRO",
+                  "description": "用户集合"
+                },
+                "example": {
+                  "ok": false,
+                  "code": 0,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": []
+      }
+    },
+    "/admin/withdrawOrder/page": {
+      "post": {
+        "summary": "分页查询列表",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/WithdrawOrderPageDTO",
+                "description": "参数集"
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RIPageWithdrawOrder",
+                  "description": "用户集合"
+                },
+                "example": {
+                  "ok": false,
+                  "code": 0,
+                  "msg": "",
+                  "data": {}
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": []
+      }
+    },
+    "/admin/payNotify/page": {
+      "get": {
+        "summary": "分页查询列表",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [
+          {
+            "name": "appId",
+            "in": "query",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "name": "orderId",
+            "in": "query",
+            "description": "",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/RPayNotifyRO",
+                  "description": "通知记录"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": {
+                    "id": 0,
+                    "orderId": "",
+                    "status": 0,
+                    "nextNotifyTime": "",
+                    "lastExecuteTime": "",
+                    "notifyTimes": 0,
+                    "maxNotifyTimes": 0,
+                    "notifyUrl": "",
+                    "errorMsg": "",
+                    "payNotifyLogs": [
+                      {
+                        "notifyTimes": 0,
+                        "response": "",
+                        "status": 0,
+                        "createTime": ""
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": []
+      }
+    },
+    "/statistisc/index": {
+      "get": {
+        "summary": "首页数据统计 index_select",
+        "deprecated": false,
+        "description": "",
+        "tags": [],
+        "parameters": [],
+        "responses": {
+          "200": {
+            "description": "",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/ROrderStatisticsVO"
+                },
+                "example": {
+                  "code": 0,
+                  "msg": "",
+                  "data": {
+                    "submitCreateNum": 0,
+                    "payOrderNum": 0,
+                    "submitCreateAmount": 0,
+                    "payOrderAmount": 0,
+                    "withdrawOrderNum": 0,
+                    "withdrawOrderSuccessNum": 0,
+                    "withdrawOrderAmount": 0,
+                    "withdrawOrderSuccessAmount": 0,
+                    "paySuccessRate": 0
+                  }
+                }
+              }
+            },
+            "headers": {}
+          }
+        },
+        "security": []
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "PayNotifyLogRO": {
+        "type": "object",
+        "properties": {
+          "notifyTimes": {
+            "type": "integer",
+            "description": "第几次被通知\n\n对应到{@link MchPayNotifyTask#getNotifyTimes()}"
+          },
+          "response": {
+            "type": "string",
+            "description": "HTTP 响应结果"
+          },
+          "status": {
+            "type": "integer",
+            "description": "支付通知状态\n\n枚举{@link PayNotifyStatusEnum}"
+          },
+          "createTime": {
+            "type": "string",
+            "description": "创建时间"
+          }
+        }
+      },
+      "PayOrder": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "createTime": {
+            "type": "string",
+            "description": "创建时间"
+          },
+          "updateTime": {
+            "type": "string",
+            "description": "修改时间"
+          },
+          "appId": {
+            "type": "string",
+            "description": "appId"
+          },
+          "mchOrderNo": {
+            "type": "string",
+            "description": "商户订单号"
+          },
+          "orderStatus": {
+            "type": "string",
+            "description": "订单状态",
+            "enum": [
+              "CREATE_ORDER",
+              "PAY_SUCCESS",
+              "PAY_FAIL",
+              "CANCEL_ORDER",
+              "PAY_TIMEOUT"
+            ]
+          },
+          "currency": {
+            "type": "string",
+            "description": "币种"
+          },
+          "amount": {
+            "type": "number",
+            "description": "订单原始金额"
+          },
+          "clientIp": {
+            "type": "string",
+            "description": "客户端IP"
+          },
+          "device": {
+            "type": "string",
+            "description": "设备"
+          },
+          "returnUrl": {
+            "type": "string",
+            "description": "支付结果前端跳转URL"
+          },
+          "notifyUrl": {
+            "type": "string",
+            "description": "支付结果后台回调URL"
+          },
+          "subject": {
+            "type": "string",
+            "description": "主题"
+          },
+          "body": {
+            "type": "string",
+            "description": "内容不能为空"
+          },
+          "extra": {
+            "type": "string",
+            "description": "扩展参数"
+          },
+          "reqTime": {
+            "type": "string",
+            "description": "请求时间"
+          },
+          "merchantUserId": {
+            "type": "integer",
+            "description": "商户id",
+            "format": "int64"
+          },
+          "agentUserId": {
+            "type": "integer",
+            "description": "代理商id",
+            "format": "int64"
+          },
+          "paymentTypeId": {
+            "type": "integer",
+            "description": "通道类型id",
+            "format": "int64"
+          },
+          "paymentChannelId": {
+            "type": "integer",
+            "description": "支付通道id",
+            "format": "int64"
+          },
+          "paymentChannelName": {
+            "type": "string",
+            "description": "支付通道名称"
+          },
+          "feeStatus": {
+            "type": "boolean",
+            "description": "获取通道费率成功标识"
+          },
+          "mFeeType": {
+            "type": "string",
+            "description": "平台手续费类型",
+            "enum": [
+              "PERCENTAGE",
+              "FIXED",
+              "MIXED"
+            ]
+          },
+          "mFeeRate": {
+            "type": "number",
+            "description": "平台手续费比例(百分比)"
+          },
+          "mFeeEvery": {
+            "type": "number",
+            "description": "平台手续费固定金额"
+          },
+          "mFee": {
+            "type": "number",
+            "description": "平台手续费"
+          },
+          "aFeeType": {
+            "type": "string",
+            "description": "代理商手续费类型",
+            "enum": [
+              "PERCENTAGE",
+              "FIXED",
+              "MIXED"
+            ]
+          },
+          "aFeeRate": {
+            "type": "number",
+            "description": "代理商手续费比例(百分比)"
+          },
+          "aFeeEvery": {
+            "type": "number",
+            "description": "代理商手续费固定金额"
+          },
+          "aFee": {
+            "type": "number",
+            "description": "代理商手续"
+          },
+          "noticeDatetime": {
+            "type": "string",
+            "description": "支付完成时间"
+          },
+          "noticeAmount": {
+            "type": "number",
+            "description": "实际支付金额"
+          },
+          "noticeMFee": {
+            "type": "number",
+            "description": "实际平台手续费"
+          },
+          "noticeAFee": {
+            "type": "number",
+            "description": "实际平台手续费"
+          },
+          "transactionId": {
+            "type": "string",
+            "description": "上游三方支付流水号"
+          }
+        }
+      },
+      "WithdrawOrder": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "createTime": {
+            "type": "string",
+            "description": "创建时间"
+          },
+          "updateTime": {
+            "type": "string",
+            "description": "修改时间"
+          },
+          "appId": {
+            "type": "string",
+            "description": "appId"
+          },
+          "mchOrderNo": {
+            "type": "string",
+            "description": "商户订单号"
+          },
+          "orderStatus": {
+            "type": "string",
+            "description": "订单状态",
+            "enum": [
+              "CREATE_ORDER",
+              "WITHDRAW_SUCCESS",
+              "WITHDRAW_FAIL"
+            ]
+          },
+          "currencyType": {
+            "type": "string",
+            "description": "币种"
+          },
+          "amount": {
+            "type": "number",
+            "description": "订单原始金额"
+          },
+          "notifyUrl": {
+            "type": "string",
+            "description": "支付结果后台回调URL"
+          },
+          "subject": {
+            "type": "string",
+            "description": "主题"
+          },
+          "payUsername": {
+            "type": "string",
+            "description": "用户姓名"
+          },
+          "payBankNumber": {
+            "type": "string",
+            "description": "银行账号"
+          },
+          "payBankName": {
+            "type": "string",
+            "description": "银行名称"
+          },
+          "payAttach": {
+            "type": "string",
+            "description": "扩展参数"
+          },
+          "payEmail": {
+            "type": "string",
+            "description": "用户邮箱"
+          },
+          "payMobile": {
+            "type": "string",
+            "description": "用户电话"
+          },
+          "reqTime": {
+            "type": "string",
+            "description": "请求时间"
+          },
+          "merchantUserId": {
+            "type": "integer",
+            "description": "商户id",
+            "format": "int64"
+          },
+          "paymentTypeId": {
+            "type": "integer",
+            "description": "通道类型id",
+            "format": "int64"
+          },
+          "paymentChannelId": {
+            "type": "integer",
+            "description": "支付通道id",
+            "format": "int64"
+          },
+          "feeStatus": {
+            "type": "boolean",
+            "description": "获取通道费率成功标识"
+          },
+          "mFeeType": {
+            "type": "string",
+            "description": "平台手续费类型",
+            "enum": [
+              "PERCENTAGE",
+              "FIXED",
+              "MIXED"
+            ]
+          },
+          "mFeeRate": {
+            "type": "number",
+            "description": "平台手续费比例(百分比)"
+          },
+          "mFeeEvery": {
+            "type": "number",
+            "description": "平台手续费固定金额"
+          },
+          "mFee": {
+            "type": "number",
+            "description": "平台手续费"
+          },
+          "aFeeType": {
+            "type": "string",
+            "description": "代理商手续费类型",
+            "enum": [
+              "PERCENTAGE",
+              "FIXED",
+              "MIXED"
+            ]
+          },
+          "aFeeRate": {
+            "type": "number",
+            "description": "代理商手续费比例(百分比)"
+          },
+          "aFeeEvery": {
+            "type": "number",
+            "description": "代理商手续费固定金额"
+          },
+          "aFee": {
+            "type": "number",
+            "description": "代理商手续"
+          },
+          "noticeDatetime": {
+            "type": "string",
+            "description": "支付完成时间"
+          },
+          "noticeAmount": {
+            "type": "number",
+            "description": "实际支付金额"
+          },
+          "noticeMFee": {
+            "type": "number",
+            "description": "实际平台手续费"
+          },
+          "noticeAFee": {
+            "type": "number",
+            "description": "实际平台手续费"
+          },
+          "transactionId": {
+            "type": "string",
+            "description": "上游三方支付流水号"
+          }
+        }
+      },
+      "OrderStatisticsVO": {
+        "type": "object",
+        "properties": {
+          "submitCreateNum": {
+            "type": "integer",
+            "description": "提交订单数"
+          },
+          "payOrderNum": {
+            "type": "integer",
+            "description": "支付订单数"
+          },
+          "submitCreateAmount": {
+            "type": "number",
+            "description": "提交订单金额"
+          },
+          "payOrderAmount": {
+            "type": "number",
+            "description": "支付订单金额"
+          },
+          "withdrawOrderNum": {
+            "type": "integer",
+            "description": "提现订单数"
+          },
+          "withdrawOrderSuccessNum": {
+            "type": "integer",
+            "description": "提现订单成功数"
+          },
+          "withdrawOrderAmount": {
+            "type": "number",
+            "description": "提现订单金额"
+          },
+          "withdrawOrderSuccessAmount": {
+            "type": "number",
+            "description": "提现订单成功金额"
+          },
+          "paySuccessRate": {
+            "type": "number",
+            "description": "支付成功率"
+          }
+        }
+      },
+      "": {
+        "type": "object",
+        "properties": {}
+      },
+      "PayNotifyRO": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "description": "",
+            "format": "int64"
+          },
+          "orderId": {
+            "type": "string",
+            "description": "平台订单ID"
+          },
+          "status": {
+            "type": "integer",
+            "description": "通知状态\n\n枚举{@link PayNotifyStatusEnum}"
+          },
+          "nextNotifyTime": {
+            "type": "string",
+            "description": "下一次通知时间"
+          },
+          "lastExecuteTime": {
+            "type": "string",
+            "description": "最后一次执行时间"
+          },
+          "notifyTimes": {
+            "type": "integer",
+            "description": "当前通知次数"
+          },
+          "maxNotifyTimes": {
+            "type": "integer",
+            "description": "最大可通知次数"
+          },
+          "notifyUrl": {
+            "type": "string",
+            "description": "通知地址"
+          },
+          "errorMsg": {
+            "type": "string",
+            "description": "失败原因"
+          },
+          "payNotifyLogs": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/PayNotifyLogRO",
+              "description": "com.mw.bridging.open.ro.PayNotifyLogRO"
+            },
+            "description": "通知日志"
+          }
+        }
+      },
+      "ROrderStatisticsVO": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/OrderStatisticsVO",
+            "description": "数据"
+          }
+        }
+      },
+      "RPayNotifyRO": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/PayNotifyRO",
+            "description": "数据"
+          }
+        }
+      },
+      "IPagePayOrder": {
+        "type": "object",
+        "properties": {
+          "records": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/PayOrder",
+              "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": ""
+          },
+          "pages": {
+            "type": "integer",
+            "format": "int64"
+          }
+        }
+      },
+      "IPageWithdrawOrder": {
+        "type": "object",
+        "properties": {
+          "records": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/WithdrawOrder",
+              "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": ""
+          },
+          "pages": {
+            "type": "integer",
+            "format": "int64"
+          }
+        }
+      },
+      "PayOrderPageDTO": {
+        "type": "object",
+        "properties": {
+          "records": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/1"
+            },
+            "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": ""
+          },
+          "mchOrderNo": {
+            "type": "string",
+            "description": "商户单号"
+          },
+          "transactionId": {
+            "type": "string",
+            "description": "支付单号"
+          },
+          "orderStatus": {
+            "type": "string",
+            "description": "订单状态",
+            "enum": [
+              "CREATE_ORDER",
+              "PAY_SUCCESS",
+              "PAY_FAIL",
+              "CANCEL_ORDER",
+              "PAY_TIMEOUT"
+            ]
+          },
+          "startTime": {
+            "type": "string",
+            "description": "开始时间"
+          },
+          "endTime": {
+            "type": "string",
+            "description": "结束时间"
+          },
+          "paymentChannelId": {
+            "type": "integer",
+            "description": "支付通道id",
+            "format": "int64"
+          }
+        }
+      },
+      "WithdrawOrderPageDTO": {
+        "type": "object",
+        "properties": {
+          "records": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/1"
+            },
+            "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": ""
+          },
+          "mchOrderNo": {
+            "type": "string",
+            "description": "商户单号"
+          },
+          "transactionId": {
+            "type": "string",
+            "description": "支付单号"
+          },
+          "orderStatus": {
+            "type": "string",
+            "description": "订单状态",
+            "enum": [
+              "CREATE_ORDER",
+              "WITHDRAW_SUCCESS",
+              "WITHDRAW_FAIL"
+            ]
+          },
+          "startTime": {
+            "type": "string",
+            "description": "开始时间"
+          },
+          "endTime": {
+            "type": "string",
+            "description": "结束时间"
+          }
+        }
+      },
+      "RIPagePayOrder": {
+        "type": "object",
+        "properties": {
+          "ok": {
+            "type": "boolean"
+          },
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/IPagePayOrder",
+            "description": "数据"
+          }
+        }
+      },
+      "RIPageWithdrawOrder": {
+        "type": "object",
+        "properties": {
+          "ok": {
+            "type": "boolean"
+          },
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/IPageWithdrawOrder",
+            "description": "数据"
+          }
+        }
+      },
+      "OrderItem": {
+        "type": "object",
+        "properties": {
+          "column": {
+            "type": "string",
+            "description": ""
+          },
+          "asc": {
+            "type": "boolean",
+            "description": ""
+          }
+        }
+      },
+      "PayOrderStatisticsRO": {
+        "type": "object",
+        "properties": {
+          "numberOrders": {
+            "type": "integer",
+            "description": "提交订单数"
+          },
+          "totalOrderAmount": {
+            "type": "number",
+            "description": "订单总金额"
+          },
+          "paidOrders": {
+            "type": "integer",
+            "description": "已付订单数"
+          },
+          "totalAmountPaid": {
+            "type": "number",
+            "description": "已付总金额"
+          },
+          "totalMerchantAmount": {
+            "type": "number",
+            "description": "商户总收入"
+          },
+          "totalAgentAmount": {
+            "type": "number",
+            "description": "代理商总收入"
+          },
+          "unpaidOrders": {
+            "type": "integer",
+            "description": "未付订单数"
+          },
+          "totalAmountUnpaid": {
+            "type": "number",
+            "description": "未付总金额"
+          }
+        }
+      },
+      "RPayOrderStatisticsRO": {
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "description": "返回标记:成功标记=0,失败标记=1"
+          },
+          "msg": {
+            "type": "string",
+            "description": "返回信息"
+          },
+          "data": {
+            "$ref": "#/components/schemas/PayOrderStatisticsRO",
+            "description": "数据"
+          }
+        }
+      }
+    },
+    "securitySchemes": {}
+  },
+  "servers": [],
+  "security": []
+}

+ 9 - 8
package.json

@@ -15,17 +15,12 @@
 		"@axolo/json-editor-vue": "^0.3.2",
 		"@chenfengyuan/vue-qrcode": "^2.0.0",
 		"@element-plus/icons-vue": "^2.0.10",
+		"@form-create/element-ui": "3.2.16",
+		"@microsoft/fetch-event-source": "^2.0.1",
 		"@popperjs/core": "2.11.8",
 		"@vueuse/core": "^10.4.1",
 		"@wangeditor-next/editor": "5.6.34",
 		"@wangeditor-next/editor-for-vue": "5.1.14",
-		"@microsoft/fetch-event-source": "^2.0.1",
-		"marked": "^12.0.2",
-		"markmap-common": "0.15.6",
-		"markmap-lib": "0.15.8",
-		"markmap-view": "0.15.8",
-		"@form-create/element-ui": "3.2.16",
-		"form-create-designer": "3.2.11-oem",
 		"autoprefixer": "^10.4.7",
 		"axios": "^1.3.3",
 		"codemirror": "5.65.5",
@@ -34,16 +29,21 @@
 		"driver.js": "^0.9.8",
 		"echarts": "^5.4.1",
 		"element-plus": "2.5.5",
+		"form-create-designer": "3.2.11-oem",
 		"highlight.js": "^11.7.0",
 		"js-base64": "^3.7.7",
 		"js-cookie": "^3.0.1",
 		"json-editor-vue3": "^1.1.1",
 		"lodash": "^4.17.21",
+		"marked": "^12.0.2",
+		"markmap-common": "0.15.6",
+		"markmap-lib": "0.15.8",
+		"markmap-view": "0.15.8",
 		"mitt": "^3.0.0",
 		"nprogress": "^0.2.0",
 		"pinia": "2.0.32",
 		"postcss": "8.4.40",
-		"qrcode": "1.5.1",
+		"qrcode": "^1.5.1",
 		"qs": "^6.11.0",
 		"screenfull": "^6.0.2",
 		"sm-crypto": "^0.3.12",
@@ -66,6 +66,7 @@
 		"@types/markdown-it": "^14.1.1",
 		"@types/node": "^18.14.0",
 		"@types/nprogress": "^0.2.0",
+		"@types/qrcode": "^1.5.6",
 		"@types/sm-crypto": "^0.3.4",
 		"@types/sortablejs": "^1.15.0",
 		"@typescript-eslint/eslint-plugin": "^5.53.0",

+ 38 - 0
src/api/admin/google.ts

@@ -0,0 +1,38 @@
+import request from '/@/utils/request';
+
+/**
+ * 获取Google验证器二维码
+ * @returns 返回base64编码的二维码图片
+ */
+export function getGoogleCode() {
+	return request({
+		url: '/admin/google/getCode',
+		method: 'post',
+	});
+}
+
+/**
+ * 绑定Google验证器
+ * @param code 6位验证码
+ * @returns 绑定结果
+ */
+export function bindingGoogle(code: string) {
+	return request({
+		url: '/admin/google/binding',
+		method: 'get',
+		params: { code },
+	});
+}
+
+/**
+ * 解绑Google验证器
+ * @param pwd 登录密码
+ * @returns 解绑结果
+ */
+export function unbindingGoogle(pwd: string) {
+	return request({
+		url: '/admin/google/unbinding',
+		method: 'post',
+		data: { pwd },
+	});
+}

+ 80 - 0
src/api/admin/setting.ts

@@ -0,0 +1,80 @@
+import request from '/@/utils/request';
+
+/**
+ * 获取Google验证器二维码
+ * @returns 返回base64编码的二维码图片
+ */
+export function getGoogleCode() {
+	return request({
+		url: '/admin/google/getCode',
+		method: 'post',
+	});
+}
+
+/**
+ * 绑定Google验证器
+ * @param code 6位验证码
+ * @returns 绑定结果
+ */
+export function bindingGoogle(code: string) {
+	return request({
+		url: '/admin/google/binding',
+		method: 'get',
+		params: { code },
+	});
+}
+
+/**
+ * 解绑Google验证器
+ * @param pwd 登录密码(明文)
+ * @returns 解绑结果
+ */
+export function unbindingGoogle(pwd: string) {
+	// 密码加密,与登录时使用相同的加密方式
+	return request({
+		url: '/admin/google/unbinding',
+		method: 'post',
+		data: { pwd },
+	});
+}
+
+/**
+ * 查看白名单
+ * @returns 返回白名单字符串
+ */
+export function getWhitelist() {
+	return request({
+		url: '/admin/merchant/getWhitelist',
+		method: 'get',
+	});
+}
+
+/**
+ * 设置白名单
+ * @param whitelist 白名单字符串
+ * @returns 设置结果
+ */
+export function editWhitelist(whitelist: string) {
+	return request({
+		url: '/admin/merchant/editWhitelist',
+		method: 'patch',
+		data: { whitelist },
+	});
+}
+
+/**
+ * 设置支付密码(二级密码)
+ * @param secondaryPwd 新的支付密码
+ * @param oldSecondaryPwd 旧的支付密码(可选,首次设置时为空)
+ * @returns 设置结果
+ */
+export function editSecondaryPwd(secondaryPwd: string, oldSecondaryPwd?: string) {
+	return request({
+		url: '/admin/merchant/editSecondaryPwd',
+		method: 'patch',
+		data: {
+			secondaryPwd,
+			oldSecondaryPwd: oldSecondaryPwd || '',
+		},
+	});
+}

+ 2 - 2
src/api/login/index.ts

@@ -50,11 +50,11 @@ export const login = (data: any) => {
 	Session.set('basicAuth', basicAuth);
 	// 密码加密
 	const encPassword = other.encryption(data.password, import.meta.env.VITE_PWD_ENC_KEY);
-	const { username, randomStr, code, grant_type, scope } = data;
+	const { username, randomStr, code, grant_type, scope, googleCaptcha } = data;
 	return request({
 		url: '/auth/oauth2/token',
 		method: 'post',
-		params: { username, randomStr, code, grant_type, scope },
+		params: { username, randomStr, code, grant_type, scope, googleCaptcha },
 		data: { password: encPassword },
 		headers: {
 			skipToken: true,

+ 12 - 0
src/api/statistics/index.ts

@@ -0,0 +1,12 @@
+import request from '/@/utils/request';
+
+/**
+ * 首页数据统计
+ * @returns 返回统计数据
+ */
+export function getIndexStatistics() {
+	return request({
+		url: '/open/statistisc/index',
+		method: 'get',
+	});
+}

+ 56 - 0
src/config/menuConfig.ts

@@ -0,0 +1,56 @@
+/**
+ * 固定导航菜单配置
+ * @description 系统的导航菜单固定配置,不再从后端获取
+ */
+
+export function getStaticMenuData() {
+	return {
+		code: 0,
+		msg: null,
+		data: [
+			{
+				id: '3000',
+				parentId: '-1',
+				weight: 1,
+				name: '系统设置',
+				path: '/settings',
+				componentPath: null,
+				meta: {
+					isLink: '',
+					isIframe: false,
+					isKeepAlive: false,
+					icon: 'iconfont icon-xitongshezhi',
+					isAffix: false,
+					title: '系统设置',
+					isHide: false,
+				},
+				sortOrder: 1,
+				menuType: '0',
+				permission: null,
+				children: [
+					{
+						id: '3001',
+						parentId: '3000',
+						weight: 0,
+						name: '安全中心',
+						path: '/settings/security/index',
+						componentPath: null,
+						meta: {
+							isLink: '',
+							isIframe: false,
+							isKeepAlive: false,
+							icon: 'iconfont icon-xitongshezhi',
+							isAffix: false,
+							title: '安全中心',
+							isHide: false,
+						},
+						sortOrder: 0,
+						menuType: '0',
+						permission: null,
+					},
+				],
+			},
+		],
+		ok: true,
+	};
+}

+ 9 - 10
src/router/backEnd.ts

@@ -8,12 +8,9 @@ import { baseRoutes, notFoundAndNoPower, dynamicRoutes } from '/@/router/route';
 import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
 import { useRoutesList } from '/@/stores/routesList';
 import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
-import { useMenuApi } from '/@/api/admin/menu';
+import { getStaticMenuData } from '/@/config/menuConfig';
 
-// 后端控制路由
-
-// 引入 api 请求接口
-const menuApi = useMenuApi();
+// 后端控制路由(已改为从配置文件读取固定菜单)
 
 /**
  * 获取目录下的 .vue、.tsx 全部文件
@@ -100,12 +97,13 @@ export async function setAddRoute() {
 }
 
 /**
- * 请求后端路由菜单接口
- * @description isRequestRoutes 为 true,则开启后端控制路由
- * @returns 返回后端路由菜单数据
+ * 获取路由菜单数据(从配置文件读取)
+ * @description 不再从后端API获取,改为从配置文件读取固定菜单
+ * @returns 返回路由菜单数据
  */
 export function getBackEndControlRoutes() {
-	return menuApi.getAdminMenu();
+	// 从配置文件获取固定菜单数据
+	return Promise.resolve(getStaticMenuData());
 }
 
 /**
@@ -132,7 +130,8 @@ export function backEndComponent(routes: any) {
 				item.component = () => import('/@/layout/routerView/link.vue');
 			}
 			item.path = '/iframes/' + window.btoa(item.path);
-		} else if (item.componentPath) { // 支持动态路径  /a/1 ==> /a  ; /b/1 ==> /b
+		} else if (item.componentPath) {
+			// 支持动态路径  /a/1 ==> /a  ; /b/1 ==> /b
 			item.component = dynamicImport(dynamicViewsModules, item.componentPath);
 		} else {
 			item.component = dynamicImport(dynamicViewsModules, item.path);

+ 8 - 6
src/utils/request.ts

@@ -1,6 +1,6 @@
 import axios, { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
 import { Local, Session, STORAGE_KEYS } from '/@/utils/storage';
-import { useMessageBox } from '/@/hooks/message';
+import { useMessageBox, useMessage } from '/@/hooks/message';
 import qs from 'qs';
 import other from './other';
 import { wrapEncryption, encryptRequestParams, decrypt } from './apiCrypto';
@@ -82,14 +82,16 @@ service.interceptors.request.use(
  * @returns 如果响应成功,则返回响应的data属性;否则,抛出错误或者执行其他操作
  */
 const handleResponse = (response: AxiosResponse<any>) => {
-	if (response.data.code === 1) {
-		throw response.data;
-	}
-
 	// 针对密文返回解密
 	if (response.data.encryption) {
 		response.data = decrypt(response.data.encryption);
-		return response.data;
+	}
+
+	// 当 code 不等于 0 时,显示错误消息并抛出错误
+	if (response.data.code !== undefined && response.data.code !== 0) {
+		const errorMsg = response.data.msg || '操作失败';
+		useMessage().error(errorMsg);
+		throw response.data;
 	}
 
 	return response.data;

+ 284 - 16
src/views/home/index.vue

@@ -1,24 +1,292 @@
 <template>
-  <div>
-    <div v-if="pageLoading">
-      <el-main>
-        <el-card shadow="never">
-          <el-skeleton :rows="1"></el-skeleton>
-        </el-card>
-        <el-card shadow="never" style="margin-top: 15px;">
-          <el-skeleton></el-skeleton>
-        </el-card>
-      </el-main>
-    </div>
-    <widgets/>
-  </div>
+	<div class="home-container">
+		<el-row :gutter="20" v-loading="loading">
+			<!-- 提交订单 -->
+			<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+				<el-card shadow="hover" class="stat-card">
+					<div class="stat-item">
+						<div class="stat-icon" style="background: #409eff">
+							<el-icon :size="28"><DocumentAdd /></el-icon>
+						</div>
+						<div class="stat-info">
+							<div class="stat-title">提交订单</div>
+							<div class="stat-number">{{ statistics.submitCreateNum || 0 }}</div>
+							<div class="stat-desc">金额: {{ formatAmount(statistics.submitCreateAmount) }}</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+
+			<!-- 支付订单 -->
+			<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+				<el-card shadow="hover" class="stat-card">
+					<div class="stat-item">
+						<div class="stat-icon" style="background: #67c23a">
+							<el-icon :size="28"><Wallet /></el-icon>
+						</div>
+						<div class="stat-info">
+							<div class="stat-title">支付订单</div>
+							<div class="stat-number">{{ statistics.payOrderNum || 0 }}</div>
+							<div class="stat-desc">金额: {{ formatAmount(statistics.payOrderAmount) }}</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+
+			<!-- 提现订单 -->
+			<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+				<el-card shadow="hover" class="stat-card">
+					<div class="stat-item">
+						<div class="stat-icon" style="background: #e6a23c">
+							<el-icon :size="28"><Money /></el-icon>
+						</div>
+						<div class="stat-info">
+							<div class="stat-title">提现订单</div>
+							<div class="stat-number">{{ statistics.withdrawOrderNum || 0 }}</div>
+							<div class="stat-desc">金额: {{ formatAmount(statistics.withdrawOrderAmount) }}</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+
+			<!-- 提现成功 -->
+			<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+				<el-card shadow="hover" class="stat-card">
+					<div class="stat-item">
+						<div class="stat-icon" style="background: #f56c6c">
+							<el-icon :size="28"><CircleCheck /></el-icon>
+						</div>
+						<div class="stat-info">
+							<div class="stat-title">提现成功</div>
+							<div class="stat-number">{{ statistics.withdrawOrderSuccessNum || 0 }}</div>
+							<div class="stat-desc">金额: {{ formatAmount(statistics.withdrawOrderSuccessAmount) }}</div>
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+
+		<!-- 支付成功率 -->
+		<el-row :gutter="20" style="margin-top: 20px">
+			<el-col :span="24">
+				<el-card shadow="hover" class="rate-card">
+					<div class="rate-item">
+						<div class="rate-icon">
+							<el-icon :size="40"><TrendCharts /></el-icon>
+						</div>
+						<div class="rate-info">
+							<div class="rate-title">支付成功率</div>
+							<div class="rate-number">{{ formatRate(statistics.paySuccessRate) }}</div>
+						</div>
+						<div class="rate-progress">
+							<el-progress :percentage="statistics.paySuccessRate || 0" :stroke-width="20" :text-inside="true" />
+						</div>
+					</div>
+				</el-card>
+			</el-col>
+		</el-row>
+	</div>
 </template>
 
 <script setup lang="ts" name="dashboard">
-const Widgets = defineAsyncComponent(() => import('./widgets/index.vue'));
-const pageLoading = ref(true);
+import { ref, onMounted } from 'vue';
+import { DocumentAdd, Wallet, Money, CircleCheck, TrendCharts } from '@element-plus/icons-vue';
+import { getIndexStatistics } from '/@/api/statistics/index';
+import { ElMessage } from 'element-plus';
+
+// 统计数据
+const statistics = ref({
+	submitCreateNum: 0,
+	payOrderNum: 0,
+	submitCreateAmount: 0,
+	payOrderAmount: 0,
+	withdrawOrderNum: 0,
+	withdrawOrderSuccessNum: 0,
+	withdrawOrderAmount: 0,
+	withdrawOrderSuccessAmount: 0,
+	paySuccessRate: 0,
+});
+
+const loading = ref(false);
+
+// 格式化金额
+const formatAmount = (amount: number | undefined) => {
+	if (!amount) return '¥0.00';
+	return `¥${amount.toFixed(2)}`;
+};
+
+// 格式化百分比
+const formatRate = (rate: number | undefined) => {
+	if (!rate) return '0%';
+	return `${rate.toFixed(2)}%`;
+};
+
+// 加载统计数据
+const loadStatistics = async () => {
+	loading.value = true;
+	try {
+		const res = await getIndexStatistics();
+		if (res.code === 0) {
+			statistics.value = res.data;
+		} else {
+			ElMessage.error(res.msg || '加载统计数据失败');
+		}
+	} catch (error) {
+		ElMessage.error('加载统计数据失败');
+	} finally {
+		loading.value = false;
+	}
+};
 
 onMounted(() => {
-  pageLoading.value = false;
+	loadStatistics();
 });
 </script>
+
+<style scoped lang="scss">
+.home-container {
+	padding: 20px;
+
+	.stat-card {
+		margin-bottom: 20px;
+		transition: all 0.3s;
+
+		&:hover {
+			transform: translateY(-2px);
+		}
+
+		.stat-item {
+			display: flex;
+			align-items: center;
+			padding: 10px;
+
+			.stat-icon {
+				width: 60px;
+				height: 60px;
+				border-radius: 8px;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #fff;
+				margin-right: 20px;
+			}
+
+			.stat-info {
+				flex: 1;
+
+				.stat-title {
+					font-size: 14px;
+					color: var(--el-text-color-secondary);
+					margin-bottom: 8px;
+				}
+
+				.stat-number {
+					font-size: 28px;
+					font-weight: bold;
+					color: var(--el-text-color-primary);
+					margin-bottom: 5px;
+				}
+
+				.stat-desc {
+					font-size: 13px;
+					color: var(--el-text-color-regular);
+				}
+			}
+		}
+	}
+
+	.rate-card {
+		.rate-item {
+			display: flex;
+			align-items: center;
+			padding: 20px 10px;
+
+			.rate-icon {
+				width: 80px;
+				height: 80px;
+				border-radius: 50%;
+				background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #fff;
+				margin-right: 30px;
+			}
+
+			.rate-info {
+				margin-right: 30px;
+
+				.rate-title {
+					font-size: 16px;
+					color: var(--el-text-color-secondary);
+					margin-bottom: 10px;
+				}
+
+				.rate-number {
+					font-size: 36px;
+					font-weight: bold;
+					color: var(--el-text-color-primary);
+				}
+			}
+
+			.rate-progress {
+				flex: 1;
+				min-width: 300px;
+			}
+		}
+	}
+}
+
+@media (max-width: 768px) {
+	.home-container {
+		padding: 10px;
+
+		.stat-card {
+			margin-bottom: 10px;
+
+			.stat-item {
+				.stat-icon {
+					width: 50px;
+					height: 50px;
+					margin-right: 15px;
+				}
+
+				.stat-info {
+					.stat-number {
+						font-size: 24px;
+					}
+				}
+			}
+		}
+
+		.rate-card {
+			.rate-item {
+				flex-direction: column;
+				align-items: flex-start;
+				padding: 15px;
+
+				.rate-icon {
+					width: 60px;
+					height: 60px;
+					margin-right: 0;
+					margin-bottom: 15px;
+				}
+
+				.rate-info {
+					margin-right: 0;
+					margin-bottom: 15px;
+
+					.rate-number {
+						font-size: 28px;
+					}
+				}
+
+				.rate-progress {
+					width: 100%;
+					min-width: auto;
+				}
+			}
+		}
+	}
+}
+</style>

+ 20 - 2
src/views/login/component/password.vue

@@ -39,6 +39,23 @@
 				</template>
 			</el-input>
 		</el-form-item>
+		<el-form-item class="login-animation3" prop="googleCaptcha">
+			<el-input
+				text
+				maxlength="6"
+				placeholder="谷歌验证码(若没有可以不填)"
+				v-model="state.ruleForm.googleCaptcha"
+				clearable
+				autocomplete="off"
+				class="dark:bg-slate-700 dark:text-slate-200"
+			>
+				<template #prefix>
+					<el-icon class="el-input__icon dark:text-slate-400">
+						<ele-Key />
+					</el-icon>
+				</template>
+			</el-input>
+		</el-form-item>
 		<el-form-item class="login-animation2" prop="code" v-if="verifyImageEnable">
 			<el-col :span="15">
 				<el-input text maxlength="4" :placeholder="$t('mobile.placeholder2')" v-model="state.ruleForm.code" clearable autocomplete="off">
@@ -108,8 +125,9 @@ const state = reactive({
 	isShowPassword: false, // 是否显示密码
 	ruleForm: {
 		// 表单数据
-		username: 'test2', // 用户名
-		password: '123456', // 密码
+		username: '', // 用户名
+		password: '', // 密码
+		googleCaptcha: '', // Google验证码
 		code: '', // 验证码
 		randomStr: 'blockPuzzle', // 验证码随机数
 	},

+ 735 - 0
src/views/settings/security/index.vue

@@ -0,0 +1,735 @@
+<template>
+	<div class="security-container">
+		<div class="security-header">
+			<h2 class="page-title">
+				<el-icon :size="24"><Lock /></el-icon>
+				安全中心
+			</h2>
+			<p class="page-desc">管理您的账号安全设置,保护账户信息</p>
+		</div>
+
+		<div class="security-grid">
+			<!-- 支付密码卡片 -->
+			<el-card class="security-card" shadow="hover">
+				<div class="card-icon payment-icon">
+					<el-icon :size="40"><Lock /></el-icon>
+				</div>
+				<div class="card-content">
+					<h3 class="card-title">支付密码</h3>
+					<p class="card-desc">{{ isPaymentPwdSet ? '已设置支付密码' : '未设置支付密码,建议设置以提高账号安全性' }}</p>
+					<div class="card-status">
+						<el-tag :type="isPaymentPwdSet ? 'success' : 'info'" size="small">
+							{{ isPaymentPwdSet ? '已开启' : '未开启' }}
+						</el-tag>
+					</div>
+				</div>
+				<div class="card-action">
+					<el-button v-if="!isPaymentPwdSet" type="primary" @click="handleSetPaymentPwd">立即设置</el-button>
+					<el-button v-else type="primary" plain @click="handleSetPaymentPwd">修改密码</el-button>
+				</div>
+			</el-card>
+
+			<!-- 白名单卡片 -->
+			<el-card class="security-card" shadow="hover">
+				<div class="card-icon whitelist-icon">
+					<el-icon :size="40"><List /></el-icon>
+				</div>
+				<div class="card-content">
+					<h3 class="card-title">白名单设置</h3>
+					<p class="card-desc">设置允许访问的IP地址白名单</p>
+				</div>
+				<div class="card-action">
+					<el-button type="primary" @click="handleSetWhitelist">设置白名单</el-button>
+				</div>
+			</el-card>
+
+			<!-- Google验证器卡片 -->
+			<el-card class="security-card" shadow="hover">
+				<div class="card-icon google-icon">
+					<svg class="google-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+						<path
+							d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
+							fill="#4285F4"
+						/>
+						<path
+							d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
+							fill="#34A853"
+						/>
+						<path
+							d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
+							fill="#FBBC05"
+						/>
+						<path
+							d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
+							fill="#EA4335"
+						/>
+					</svg>
+				</div>
+				<div class="card-content">
+					<h3 class="card-title">Google验证器</h3>
+					<p class="card-desc">{{ isGoogleBound ? '已绑定Google验证器' : '未绑定Google验证器,建议开启以提高账号安全性' }}</p>
+					<div class="card-status">
+						<el-tag :type="isGoogleBound ? 'success' : 'info'" size="small">
+							{{ isGoogleBound ? '已开启' : '未开启' }}
+						</el-tag>
+					</div>
+				</div>
+				<div class="card-action">
+					<el-button v-if="!isGoogleBound" type="primary" @click="handleBindGoogle">立即绑定</el-button>
+					<el-button v-else type="danger" plain @click="handleUnbindGoogle">解除绑定</el-button>
+				</div>
+			</el-card>
+		</div>
+
+		<!-- Google验证器绑定对话框 -->
+		<el-dialog v-model="googleDialogVisible" title="绑定Google验证器" width="500px" :close-on-click-modal="false">
+			<div class="google-bind-content">
+				<el-steps :active="googleBindStep" finish-status="success" align-center>
+					<el-step title="扫描二维码" />
+					<el-step title="输入验证码" />
+					<el-step title="完成" />
+				</el-steps>
+
+				<div v-if="googleBindStep === 0" class="step-content">
+					<div class="qrcode-container">
+						<div v-show="googleAuth.loading" class="loading-box">
+							<el-icon class="is-loading" :size="40"><Loading /></el-icon>
+							<p>正在生成二维码...</p>
+						</div>
+						<div v-show="!googleAuth.loading && googleAuth.qrCode" class="qrcode-box">
+							<canvas ref="qrcodeCanvas"></canvas>
+							<p class="qrcode-tip">请使用Google Authenticator扫描二维码</p>
+						</div>
+					</div>
+					<div class="step-actions">
+						<el-button @click="googleDialogVisible = false">取消</el-button>
+						<el-button type="primary" @click="googleBindStep = 1" :disabled="!googleAuth.qrCode">下一步</el-button>
+					</div>
+				</div>
+
+				<div v-if="googleBindStep === 1" class="step-content">
+					<el-form ref="googleFormRef" :model="googleForm" :rules="googleRules" label-width="100px">
+						<el-form-item label="验证码" prop="code">
+							<el-input v-model="googleForm.code" placeholder="请输入6位验证码" maxlength="6" show-word-limit clearable />
+						</el-form-item>
+						<el-alert title="请打开Google Authenticator应用,输入显示的6位数字验证码" type="info" :closable="false" />
+					</el-form>
+					<div class="step-actions">
+						<el-button @click="googleBindStep = 0">上一步</el-button>
+						<el-button type="primary" @click="submitGoogleBind" :loading="googleAuth.binding">确认绑定</el-button>
+					</div>
+				</div>
+
+				<div v-if="googleBindStep === 2" class="step-content">
+					<el-result icon="success" title="绑定成功" sub-title="您已成功绑定Google验证器">
+						<template #extra>
+							<el-button type="primary" @click="closeGoogleDialog">完成</el-button>
+						</template>
+					</el-result>
+				</div>
+			</div>
+		</el-dialog>
+
+		<!-- Google验证器解绑对话框 -->
+		<el-dialog v-model="unbindDialogVisible" title="解除绑定Google验证器" width="450px" :close-on-click-modal="false">
+			<el-form ref="unbindFormRef" :model="unbindForm" :rules="unbindRules" label-width="80px">
+				<el-alert title="解除绑定后,您将无法使用Google验证器进行二次验证" type="warning" :closable="false" style="margin-bottom: 20px" />
+				<el-form-item label="登录密码" prop="pwd">
+					<el-input v-model="unbindForm.pwd" type="password" placeholder="请输入登录密码" show-password clearable />
+				</el-form-item>
+			</el-form>
+			<template #footer>
+				<el-button @click="unbindDialogVisible = false">取消</el-button>
+				<el-button type="danger" @click="submitGoogleUnbind" :loading="googleAuth.unbinding">确认解绑</el-button>
+			</template>
+		</el-dialog>
+
+		<!-- 支付密码设置对话框 -->
+		<el-dialog
+			v-model="paymentPwdDialogVisible"
+			:title="isPaymentPwdSet ? '修改支付密码' : '设置支付密码'"
+			width="450px"
+			:close-on-click-modal="false"
+		>
+			<el-form ref="paymentPwdFormRef" :model="paymentPwdForm" :rules="paymentPwdRules" label-width="100px">
+				<el-alert v-if="!isPaymentPwdSet" title="首次设置支付密码,无需输入旧密码" type="info" :closable="false" style="margin-bottom: 20px" />
+				<el-form-item v-if="isPaymentPwdSet" label="旧密码" prop="oldPassword">
+					<el-input v-model="paymentPwdForm.oldPassword" type="password" placeholder="请输入旧支付密码" show-password clearable />
+				</el-form-item>
+				<el-form-item label="新密码" prop="newPassword">
+					<el-input v-model="paymentPwdForm.newPassword" type="password" placeholder="请输入新支付密码" show-password clearable />
+				</el-form-item>
+				<el-form-item label="确认密码" prop="confirmPassword">
+					<el-input v-model="paymentPwdForm.confirmPassword" type="password" placeholder="请再次输入新支付密码" show-password clearable />
+				</el-form-item>
+			</el-form>
+			<template #footer>
+				<el-button @click="paymentPwdDialogVisible = false">取消</el-button>
+				<el-button type="primary" @click="submitPaymentPwd" :loading="paymentPwdSubmitting">确认</el-button>
+			</template>
+		</el-dialog>
+
+		<!-- 白名单设置对话框 -->
+		<el-dialog v-model="whitelistDialogVisible" title="白名单设置" width="550px" :close-on-click-modal="false">
+			<el-form ref="whitelistFormRef" :model="whitelistForm" :rules="whitelistRules" label-width="80px">
+				<el-alert title="请输入允许访问的IP地址,多个IP用英文逗号分隔" type="info" :closable="false" style="margin-bottom: 20px" />
+				<el-form-item label="IP地址" prop="whitelist">
+					<el-input v-model="whitelistForm.whitelist" type="textarea" :rows="6" placeholder="例如: 192.168.1.1,192.168.1.2" clearable />
+				</el-form-item>
+				<el-form-item>
+					<el-text type="info" size="small">提示: 留空表示不限制IP访问</el-text>
+				</el-form-item>
+			</el-form>
+			<template #footer>
+				<el-button @click="whitelistDialogVisible = false">取消</el-button>
+				<el-button type="primary" @click="submitWhitelist" :loading="whitelistSubmitting">确认</el-button>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script setup lang="ts" name="settingsSecurity">
+import { ref, reactive, computed, nextTick } from 'vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { Lock, Loading, List } from '@element-plus/icons-vue';
+import { getGoogleCode, bindingGoogle, unbindingGoogle, getWhitelist, editWhitelist, editSecondaryPwd } from '/@/api/admin/setting';
+import { useUserInfo } from '/@/stores/userInfo';
+import { Session } from '/@/utils/storage';
+import QRCode from 'qrcode';
+
+// 获取用户信息store
+const userStore = useUserInfo();
+
+// 二维码canvas引用
+const qrcodeCanvas = ref<HTMLCanvasElement>();
+
+// 从全局用户信息获取绑定状态
+const isGoogleBound = computed(() => userStore.userInfos?.user?.googleSecretFlag || false);
+
+// 从全局用户信息获取支付密码设置状态
+const isPaymentPwdSet = computed(() => userStore.userInfos?.user?.secondaryPwdFlag || false);
+
+// 白名单数据
+const whitelistData = ref('');
+
+const googleAuth = reactive({
+	qrCode: '', // 二维码数据
+	loading: false, // 加载中
+	binding: false, // 绑定中
+	unbinding: false, // 解绑中
+});
+
+// Google绑定对话框
+const googleDialogVisible = ref(false);
+const googleBindStep = ref(0); // 0:扫描二维码 1:输入验证码 2:完成
+const googleFormRef = ref();
+const googleForm = reactive({
+	code: '',
+});
+
+// Google绑定表单验证
+const googleRules = {
+	code: [
+		{ required: true, message: '请输入验证码', trigger: 'blur' },
+		{ len: 6, message: '验证码必须为6位数字', trigger: 'blur' },
+		{ pattern: /^\d{6}$/, message: '验证码必须为6位数字', trigger: 'blur' },
+	],
+};
+
+// Google解绑对话框
+const unbindDialogVisible = ref(false);
+const unbindFormRef = ref();
+const unbindForm = reactive({
+	pwd: '',
+});
+
+// Google解绑表单验证
+const unbindRules = {
+	pwd: [{ required: true, message: '请输入登录密码', trigger: 'blur' }],
+};
+
+// 支付密码设置对话框
+const paymentPwdDialogVisible = ref(false);
+const paymentPwdFormRef = ref();
+const paymentPwdSubmitting = ref(false);
+const paymentPwdForm = reactive({
+	oldPassword: '',
+	newPassword: '',
+	confirmPassword: '',
+});
+
+// 支付密码表单验证
+const validateConfirmPassword = (rule: any, value: any, callback: any) => {
+	if (value === '') {
+		callback(new Error('请再次输入新支付密码'));
+	} else if (value !== paymentPwdForm.newPassword) {
+		callback(new Error('两次输入的密码不一致'));
+	} else {
+		callback();
+	}
+};
+
+const paymentPwdRules = computed(() => {
+	const rules: any = {
+		newPassword: [
+			{ required: true, message: '请输入新支付密码', trigger: 'blur' },
+			{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' },
+		],
+		confirmPassword: [{ validator: validateConfirmPassword, trigger: 'blur' }],
+	};
+	if (isPaymentPwdSet.value) {
+		rules.oldPassword = [{ required: true, message: '请输入旧支付密码', trigger: 'blur' }];
+	}
+	return rules;
+});
+
+// 白名单设置对话框
+const whitelistDialogVisible = ref(false);
+const whitelistFormRef = ref();
+const whitelistSubmitting = ref(false);
+const whitelistForm = reactive({
+	whitelist: '',
+});
+
+// 白名单表单验证
+const whitelistRules = {
+	whitelist: [
+		{
+			pattern: /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(,\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})*$/,
+			message: '请输入正确的IP地址格式',
+			trigger: 'blur',
+			required: false,
+		},
+	],
+};
+
+// 获取Google验证器二维码
+const getGoogleQrCode = async () => {
+	googleAuth.loading = true;
+	try {
+		const res = await getGoogleCode();
+		if (res.code === 0) {
+			googleAuth.qrCode = res.data; // 保存二维码数据字符串
+			googleAuth.loading = false; // 先关闭 loading
+			// 等待DOM更新后生成二维码
+			await nextTick();
+			if (qrcodeCanvas.value) {
+				try {
+					await QRCode.toCanvas(qrcodeCanvas.value, res.data, {
+						width: 250,
+						margin: 2,
+						color: {
+							dark: '#000000',
+							light: '#ffffff',
+						},
+						errorCorrectionLevel: 'M',
+					});
+				} catch (err) {
+					ElMessage.error('二维码生成失败');
+				}
+			} else {
+				ElMessage.error('二维码生成失败');
+			}
+			return; // 提前返回,不执行 finally
+		} else {
+			ElMessage.error(res.msg || '获取二维码失败');
+		}
+	} catch (error) {
+		ElMessage.error('获取二维码失败');
+	} finally {
+		googleAuth.loading = false;
+	}
+};
+
+// 绑定Google验证器
+const handleBindGoogle = () => {
+	googleDialogVisible.value = true;
+	googleBindStep.value = 0;
+	googleForm.code = '';
+	googleAuth.qrCode = '';
+	getGoogleQrCode();
+};
+
+// 提交Google绑定
+const submitGoogleBind = async () => {
+	if (!googleFormRef.value) return;
+	await googleFormRef.value.validate(async (valid: boolean) => {
+		if (valid) {
+			googleAuth.binding = true;
+			try {
+				const res = await bindingGoogle(googleForm.code);
+				if (res.code === 0) {
+					googleBindStep.value = 2;
+					// 使用确认框提示用户
+					await ElMessageBox.alert('绑定成功,点击确定后将自动注销并跳转到登录页', '绑定成功', {
+						confirmButtonText: '确定',
+						type: 'success',
+						showClose: false,
+						callback: () => {
+							Session.clear();
+							window.location.href = '/login';
+						},
+					});
+				}
+			} catch (error) {
+				// 全局已经显示错误消息,这里只需要捕获异常
+			} finally {
+				googleAuth.binding = false;
+			}
+		}
+	});
+};
+
+// 关闭Google绑定对话框
+const closeGoogleDialog = () => {
+	googleDialogVisible.value = false;
+	googleBindStep.value = 0;
+	googleForm.code = '';
+};
+
+// 解绑Google验证器
+const handleUnbindGoogle = () => {
+	unbindDialogVisible.value = true;
+	unbindForm.pwd = '';
+};
+
+// 提交Google解绑
+const submitGoogleUnbind = async () => {
+	if (!unbindFormRef.value) return;
+	await unbindFormRef.value.validate(async (valid: boolean) => {
+		if (valid) {
+			googleAuth.unbinding = true;
+			try {
+				const res = await unbindingGoogle(unbindForm.pwd);
+				if (res.code === 0) {
+					unbindDialogVisible.value = false;
+					// 使用确认框提示用户
+					await ElMessageBox.alert('解绑成功,点击确定后将自动注销并跳转到登录页', '解绑成功', {
+						confirmButtonText: '确定',
+						type: 'success',
+						showClose: false,
+						callback: () => {
+							Session.clear();
+							window.location.href = '/login';
+						},
+					});
+				}
+			} catch (error) {
+				// 全局已经显示错误消息,这里只需要捕获异常
+			} finally {
+				googleAuth.unbinding = false;
+			}
+		}
+	});
+};
+
+// 打开支付密码设置对话框
+const handleSetPaymentPwd = () => {
+	paymentPwdDialogVisible.value = true;
+	paymentPwdForm.oldPassword = '';
+	paymentPwdForm.newPassword = '';
+	paymentPwdForm.confirmPassword = '';
+};
+
+// 提交支付密码设置
+const submitPaymentPwd = async () => {
+	if (!paymentPwdFormRef.value) return;
+	await paymentPwdFormRef.value.validate(async (valid: boolean) => {
+		if (valid) {
+			paymentPwdSubmitting.value = true;
+			try {
+				const res = await editSecondaryPwd(paymentPwdForm.newPassword, isPaymentPwdSet.value ? paymentPwdForm.oldPassword : undefined);
+				if (res.code === 0) {
+					paymentPwdDialogVisible.value = false;
+					// 使用确认框提示用户
+					await ElMessageBox.alert('设置成功,点击确定后将自动注销并跳转到登录页', '设置成功', {
+						confirmButtonText: '确定',
+						type: 'success',
+						showClose: false,
+						callback: () => {
+							Session.clear();
+							window.location.href = '/login';
+						},
+					});
+				}
+			} catch (error) {
+				// 全局已经显示错误消息
+			} finally {
+				paymentPwdSubmitting.value = false;
+			}
+		}
+	});
+};
+
+// 打开白名单设置对话框
+const handleSetWhitelist = async () => {
+	whitelistDialogVisible.value = true;
+	// 加载当前白名单
+	try {
+		const res = await getWhitelist();
+		if (res.code === 0) {
+			whitelistForm.whitelist = res.data || '';
+		}
+	} catch (error) {
+		// 加载失败不影响打开对话框
+	}
+};
+
+// 提交白名单设置
+const submitWhitelist = async () => {
+	if (!whitelistFormRef.value) return;
+	await whitelistFormRef.value.validate(async (valid: boolean) => {
+		if (valid) {
+			whitelistSubmitting.value = true;
+			try {
+				const res = await editWhitelist(whitelistForm.whitelist.trim());
+				if (res.code === 0) {
+					ElMessage.success('设置成功');
+					whitelistDialogVisible.value = false;
+					whitelistData.value = whitelistForm.whitelist.trim();
+				}
+			} catch (error) {
+				// 全局已经显示错误消息
+			} finally {
+				whitelistSubmitting.value = false;
+			}
+		}
+	});
+};
+
+// 初始化加载白名单数据
+const loadWhitelist = async () => {
+	try {
+		const res = await getWhitelist();
+		if (res.code === 0) {
+			whitelistData.value = res.data || '';
+		}
+	} catch (error) {
+		// 加载失败不影响页面显示
+	}
+};
+
+// 页面加载时获取白名单数据
+loadWhitelist();
+</script>
+
+<style scoped lang="scss">
+.security-container {
+	padding: 24px;
+	min-height: calc(100vh - 100px);
+
+	.security-header {
+		margin-bottom: 32px;
+
+		.page-title {
+			display: flex;
+			align-items: center;
+			gap: 12px;
+			font-size: 24px;
+			font-weight: 600;
+			color: var(--el-text-color-primary);
+			margin: 0 0 8px 0;
+		}
+
+		.page-desc {
+			font-size: 14px;
+			color: var(--el-text-color-secondary);
+			margin: 0;
+		}
+	}
+
+	.security-grid {
+		display: grid;
+		grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
+		gap: 24px;
+		max-width: 1400px;
+
+		.security-card {
+			position: relative;
+			padding: 28px;
+			transition: all 0.3s ease;
+			border-radius: 12px;
+			cursor: default;
+
+			&:hover {
+				transform: translateY(-4px);
+				box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+			}
+
+			.card-icon {
+				width: 64px;
+				height: 64px;
+				border-radius: 12px;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-bottom: 20px;
+
+				&.payment-icon {
+					background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+					color: #fff;
+				}
+
+				&.whitelist-icon {
+					background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+					color: #fff;
+				}
+
+				&.google-icon {
+					background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+					padding: 12px;
+
+					.google-svg {
+						width: 40px;
+						height: 40px;
+					}
+				}
+			}
+
+			.card-content {
+				flex: 1;
+				min-height: 80px;
+
+				.card-title {
+					font-size: 18px;
+					font-weight: 600;
+					color: var(--el-text-color-primary);
+					margin: 0 0 8px 0;
+				}
+
+				.card-desc {
+					font-size: 13px;
+					color: var(--el-text-color-secondary);
+					line-height: 1.6;
+					margin: 0 0 12px 0;
+				}
+
+				.card-status {
+					margin-top: 8px;
+				}
+			}
+
+			.card-action {
+				margin-top: 20px;
+				display: flex;
+				gap: 12px;
+
+				.el-button {
+					flex: 1;
+				}
+			}
+		}
+	}
+
+	// Google绑定对话框样式
+	.google-bind-content {
+		padding: 20px 0;
+
+		.el-steps {
+			margin-bottom: 40px;
+
+			// 自定义步骤条样式
+			:deep(.el-step__head) {
+				.el-step__icon {
+					width: 30px;
+					height: 30px;
+
+					.el-step__icon-inner {
+						font-size: 18px !important;
+						font-weight: 600 !important;
+					}
+				}
+			}
+
+			:deep(.el-step__title) {
+				font-size: 13px;
+			}
+		}
+
+		.step-content {
+			min-height: 300px;
+
+			.qrcode-container {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				min-height: 280px;
+
+				.loading-box {
+					text-align: center;
+
+					p {
+						margin-top: 16px;
+						color: var(--el-text-color-secondary);
+					}
+				}
+
+				.qrcode-box {
+					text-align: center;
+
+					canvas {
+						border: 1px solid var(--el-border-color);
+						border-radius: 8px;
+						padding: 12px;
+						background: #fff;
+					}
+
+					.qrcode-tip {
+						margin-top: 16px;
+						font-size: 14px;
+						color: var(--el-text-color-secondary);
+					}
+				}
+			}
+
+			.step-actions {
+				display: flex;
+				justify-content: center;
+				gap: 12px;
+				margin-top: 32px;
+			}
+
+			.el-result {
+				padding: 40px 0;
+			}
+		}
+	}
+}
+
+// 响应式布局
+@media (max-width: 1200px) {
+	.security-container {
+		.security-grid {
+			grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+		}
+	}
+}
+
+@media (max-width: 768px) {
+	.security-container {
+		padding: 16px;
+
+		.security-header {
+			margin-bottom: 24px;
+
+			.page-title {
+				font-size: 20px;
+			}
+		}
+
+		.security-grid {
+			grid-template-columns: 1fr;
+			gap: 16px;
+
+			.security-card {
+				padding: 20px;
+
+				.card-icon {
+					width: 56px;
+					height: 56px;
+				}
+			}
+		}
+	}
+}
+</style>

+ 1 - 1
tsconfig.json

@@ -45,7 +45,7 @@
 		"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
 		"baseUrl": "." /* Base directory to resolve non-absolute module names. */,
 		"paths": {
-			"/@/*": ["src/*"]
+			"/@/*": ["./src/*"]
 		} /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */,
 		// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
 		// "typeRoots": [],                       /* List of folders to include type definitions from. */