Compare commits
52 Commits
2026-04
...
8054b44e88
| Author | SHA1 | Date | |
|---|---|---|---|
| 8054b44e88 | |||
|
|
5eb5a01b50 | ||
|
|
e77c57f8d0 | ||
|
|
22011188a1 | ||
|
|
c72ba3e5db | ||
|
|
7f1c3e31c0 | ||
|
|
6c70a776a0 | ||
|
|
dc3b3cfc74 | ||
|
|
04c5eb7185 | ||
|
|
d0d62ab0af | ||
|
|
b3d671a93e | ||
|
|
888b8d1bf4 | ||
|
|
ee9cd057b8 | ||
|
|
8bca4191f2 | ||
|
|
69e6a1f93f | ||
|
|
71df1ac4be | ||
|
|
cd2be0f4aa | ||
|
|
855c569535 | ||
| 6a84d28101 | |||
|
|
1a69be62a0 | ||
|
|
02caca969e | ||
|
|
3f1af5e4cc | ||
|
|
88e9812d5f | ||
|
|
83a827ba5b | ||
| 40b1092718 | |||
|
|
83a1128884 | ||
| 1a44a2f9e0 | |||
|
|
5044c88946 | ||
|
|
51a862ed00 | ||
|
|
1ca8e536dd | ||
|
|
2445cfbff3 | ||
|
|
21ac0611cd | ||
|
|
ff841cfa93 | ||
|
|
01cc29c8b2 | ||
|
|
a324f7afcf | ||
|
|
4272f7756e | ||
|
|
070e404bbb | ||
| ed60e2b7f3 | |||
| 7785d4f708 | |||
| 0c64711dd8 | |||
|
|
d85dba8bf8 | ||
|
|
56b8158f4a | ||
| 765507398e | |||
| 9224ea17b8 | |||
| dc08f7d1ac | |||
| 1652b5faf8 | |||
|
|
fae2a7d735 | ||
|
|
bf3a99cbf3 | ||
|
|
2e7c0b7f44 | ||
|
|
98e0f9de02 | ||
|
|
21756e05d4 | ||
|
|
abfdf29a38 |
6
.env.LN
Normal file
6
.env.LN
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# 辽宁嵌入
|
||||||
|
NODE_ENV = LN
|
||||||
|
VITE_NAME="LN"
|
||||||
|
# 电网一张图 地图图层
|
||||||
|
VITE_NARIMAP=null
|
||||||
|
VITE_NRGISCOMMON=null
|
||||||
6
.env.LNqr
Normal file
6
.env.LNqr
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# 辽宁嵌入
|
||||||
|
NODE_ENV = LNqr
|
||||||
|
VITE_NAME="LNqr"
|
||||||
|
# 电网一张图 地图图层
|
||||||
|
VITE_NARIMAP=null
|
||||||
|
VITE_NRGISCOMMON=null
|
||||||
156
README.md
156
README.md
@@ -1,78 +1,78 @@
|
|||||||
#### 介绍
|
#### 介绍
|
||||||
|
|
||||||
```
|
```
|
||||||
Vue 3 + TypeScript + Vite这个模板可以帮助您开始使用Vue 3和TypeScript在Vite中进行开发。该模板使用了Vue 3的<script setup>单文件组件,请查看script setup文档了解更多信息。
|
Vue 3 + TypeScript + Vite这个模板可以帮助您开始使用Vue 3和TypeScript在Vite中进行开发。该模板使用了Vue 3的<script setup>单文件组件,请查看script setup文档了解更多信息。
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 安装依赖&运行项目
|
#### 安装依赖&运行项目
|
||||||
|
|
||||||
> node version:^18.17.0 || >=20.5.0"
|
> node version:^18.17.0 || >=20.5.0"
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
#项目使用pnpm包管理器
|
#项目使用pnpm包管理器
|
||||||
npm i pnpm -g
|
npm i pnpm -g
|
||||||
|
|
||||||
#安装依赖
|
#安装依赖
|
||||||
pnpm i
|
pnpm i
|
||||||
|
|
||||||
#运行项目
|
#运行项目
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
#冀北现场启动命令 区分是否加载现场电网一张图内网api
|
#jb现场启动命令 区分是否加载现场电网一张图内网api
|
||||||
npm run dev:jibei
|
npm run dev:jibei
|
||||||
|
|
||||||
#去除后台所有模块名 如除/xxxx-boot
|
#去除后台所有模块名 如除/xxxx-boot
|
||||||
npm run dev:removeMode
|
npm run dev:removeMode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#因海南和冀北技术监督不同 通过修改文件的方式来区分
|
#因海南和jb技术监督不同 通过修改文件的方式来区分
|
||||||
#海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb
|
#海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb
|
||||||
#冀北打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn
|
#jb打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 页面编写-示例
|
#### 页面编写-示例
|
||||||
|
|
||||||
```
|
```
|
||||||
基础页面写法请查看`src/template`下的readme.md
|
基础页面写法请查看`src/template`下的readme.md
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 开发规范
|
#### 开发规范
|
||||||
|
|
||||||
> 初衷:养成合理的习惯,精力留在技术调研、业务开发中。
|
> 初衷:养成合理的习惯,精力留在技术调研、业务开发中。
|
||||||
>
|
>
|
||||||
> 常见点如下描述,更多的规范待前端开发人员有时间后,慢慢丰富。
|
> 常见点如下描述,更多的规范待前端开发人员有时间后,慢慢丰富。
|
||||||
|
|
||||||
- 命名风格:所有的包(文件夹)、文件名以小驼峰的风格命名,比如 xxxAaa,禁止 XxxAaa 或者 xxx-aaa。
|
- 命名风格:所有的包(文件夹)、文件名以小驼峰的风格命名,比如 xxxAaa,禁止 XxxAaa 或者 xxx-aaa。
|
||||||
- 命名语义:禁止中文命名或拼音,英文命名借用下工具,稍微准确一点,不要与实际业务相差太远。
|
- 命名语义:禁止中文命名或拼音,英文命名借用下工具,稍微准确一点,不要与实际业务相差太远。
|
||||||
- 功能组件创建风格:以**功能名称**命名文件夹,每个功能下以**index.vue**作为该功能的组件入口。正确示例参考:/src/views/auth/menu/index.vue。
|
- 功能组件创建风格:以**功能名称**命名文件夹,每个功能下以**index.vue**作为该功能的组件入口。正确示例参考:/src/views/auth/menu/index.vue。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- todo...:待后续补充。
|
- todo...:待后续补充。
|
||||||
|
|
||||||
#### 开发助手
|
#### 开发助手
|
||||||
|
|
||||||
##### 1、表格系列
|
##### 1、表格系列
|
||||||
|
|
||||||
- 页面表格以及表格页面按钮的弹出等功能参考:/views/pqs/voltageSags/sagGovern/index.vue
|
- 页面表格以及表格页面按钮的弹出等功能参考:/views/pqs/voltageSags/sagGovern/index.vue
|
||||||
- 表格中需要替换数据:
|
- 表格中需要替换数据:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 通过formatter函数返回实际需要返回的值
|
// 通过formatter函数返回实际需要返回的值
|
||||||
{
|
{
|
||||||
title: '数据来源', field: 'dataSource', minWidth: '130',
|
title: '数据来源', field: 'dataSource', minWidth: '130',
|
||||||
formatter: (row: any) => {
|
formatter: (row: any) => {
|
||||||
return row.dataSource == 0 ? '离线导入' : '监测点同步'
|
return row.dataSource == 0 ? '离线导入' : '监测点同步'
|
||||||
}
|
}
|
||||||
}****
|
}****
|
||||||
```
|
```
|
||||||
|
|
||||||
##### 2、样式系列
|
##### 2、样式系列
|
||||||
|
|
||||||
- 获取当前主体的高度:import { mainHeight } from '@/utils/layout'
|
- 获取当前主体的高度:import { mainHeight } from '@/utils/layout'
|
||||||
- 弹框内输入框长度设置 1 行 1 个 class="form-one" 1 行 2 个 class="form-two"
|
- 弹框内输入框长度设置 1 行 1 个 class="form-one" 1 行 2 个 class="form-two"
|
||||||
|
|
||||||
#### 依赖变更记录
|
#### 依赖变更记录
|
||||||
|
|
||||||
- 2024-04-25 新增 vform3,by 洪圣文,用于页面表单设计保存为 json,命令:pnpm i vform3-builds
|
- 2024-04-25 新增 vform3,by 洪圣文,用于页面表单设计保存为 json,命令:pnpm i vform3-builds
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<script src="/static/luckysheet/plugin.js"></script>
|
<script src="/static/luckysheet/plugin.js"></script>
|
||||||
<script src="/static/luckysheet/luckysheet.umd.js"></script>
|
<script src="/static/luckysheet/luckysheet.umd.js"></script>
|
||||||
|
|
||||||
<!-- 冀北地图 -->
|
<!-- jb地图 -->
|
||||||
<!--引入样式文件-->
|
<!--引入样式文件-->
|
||||||
<script src="%VITE_NARIMAP%"></script>
|
<script src="%VITE_NARIMAP%"></script>
|
||||||
<!-- <script src="%VITE_NRGISCOMMON%"></script> -->
|
<!-- <script src="%VITE_NRGISCOMMON%"></script> -->
|
||||||
|
|||||||
8813
package-lock.json
generated
8813
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
207
package.json
207
package.json
@@ -1,103 +1,108 @@
|
|||||||
{
|
{
|
||||||
"name": "canneng-admin",
|
"name": "canneng-admin",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --mode dev",
|
"dev": "vite --mode dev",
|
||||||
"dev:jibei": "vite --mode jibei",
|
"dev:jibei": "vite --mode jibei",
|
||||||
"dev:hainan": "vite --mode hainan",
|
"dev:hainan": "vite --mode hainan",
|
||||||
"dev:qujing": "vite --mode qujing",
|
"dev:qujing": "vite --mode qujing",
|
||||||
"dev:removeMode": "vite --mode removeMode",
|
"dev:LN": "vite --mode LN",
|
||||||
"build": "vite build --mode dev",
|
"dev:LNqr": "vite --mode LNqr",
|
||||||
"build:jibei": "vite build --mode jibei",
|
"dev:removeMode": "vite --mode removeMode",
|
||||||
"build:hainan": "vite build --mode hainan",
|
"build": "vite build --mode dev",
|
||||||
"build:qujing": "vite build --mode qujing",
|
"build:jibei": "vite build --mode jibei",
|
||||||
"build:removeMode": "vite build --mode removeMode",
|
"build:hainan": "vite build --mode hainan",
|
||||||
"preview": "vite preview"
|
"build:qujing": "vite build --mode qujing",
|
||||||
},
|
"build:LN": "vite build --mode LN",
|
||||||
"dependencies": {
|
"build:LNqr": "vite build --mode LNqr",
|
||||||
"@ant-design/colors": "^7.0.2",
|
"build:removeMode": "vite build --mode removeMode",
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"preview": "vite preview"
|
||||||
"@form-create/designer": "^3.1.3",
|
},
|
||||||
"@form-create/element-ui": "^3.1.24",
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
"@ant-design/colors": "^7.0.2",
|
||||||
"@kjgl77/datav-vue3": "^1.7.4",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@vue-office/docx": "^1.6.3",
|
"@form-create/designer": "^3.1.3",
|
||||||
"@vue-office/excel": "^1.7.8",
|
"@form-create/element-ui": "^3.1.24",
|
||||||
"@vue-office/pdf": "^2.0.2",
|
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||||
"@vueuse/core": "^10.7.0",
|
"@kjgl77/datav-vue3": "^1.7.4",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@vue-office/docx": "^1.6.3",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@vue-office/excel": "^1.7.8",
|
||||||
"@wangeditor/plugin-formula": "^1.0.11",
|
"@vue-office/pdf": "^2.0.2",
|
||||||
"axios": "^1.6.2",
|
"@vueuse/core": "^10.7.0",
|
||||||
"bpmn-js": "8.9.0",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"bpmn-js-properties-panel": "0.46.0",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"bpmn-js-token-simulation": "^0.10.0",
|
"@wangeditor/plugin-formula": "^1.0.11",
|
||||||
"bpmn-moddle": "^6.0.0",
|
"axios": "^1.6.2",
|
||||||
"camunda-bpmn-moddle": "^7.0.1",
|
"bpmn-js": "8.9.0",
|
||||||
"crypto-js": "^4.2.0",
|
"bpmn-js-properties-panel": "0.46.0",
|
||||||
"dayjs": "^1.11.10",
|
"bpmn-js-token-simulation": "^0.10.0",
|
||||||
"diagram-js": "^11.4.1",
|
"bpmn-moddle": "^6.0.0",
|
||||||
"diagram-js-minimap": "^2.0.4",
|
"camunda-bpmn-moddle": "^7.0.1",
|
||||||
"echarts": "^5.4.3",
|
"crypto-js": "^4.2.0",
|
||||||
"echarts-gl": "^2.0.9",
|
"dayjs": "^1.11.10",
|
||||||
"echarts-liquidfill": "^3.1.0",
|
"diagram-js": "^11.4.1",
|
||||||
"echarts4": "npm:echarts@^4.9.0",
|
"diagram-js-minimap": "^2.0.4",
|
||||||
"element-plus": "^2.9.11",
|
"echarts": "^5.4.3",
|
||||||
"exceljs": "^4.4.0",
|
"echarts-gl": "^2.0.9",
|
||||||
"file-saver": "^2.0.5",
|
"echarts-liquidfill": "^3.1.0",
|
||||||
"grid-layout-plus": "^1.1.0",
|
"echarts4": "npm:echarts@^4.9.0",
|
||||||
"html2canvas": "^1.4.1",
|
"element-plus": "^2.9.11",
|
||||||
"jquery": "^3.7.1",
|
"exceljs": "^4.4.0",
|
||||||
"js-pinyin": "^0.2.5",
|
"file-saver": "^2.0.5",
|
||||||
"jsencrypt": "^3.3.2",
|
"grid-layout-plus": "^1.1.0",
|
||||||
"katex": "^0.16.11",
|
"html2canvas": "^1.4.1",
|
||||||
"less": "^4.2.0",
|
"jquery": "^3.7.1",
|
||||||
"lodash-es": "^4.17.21",
|
"js-pinyin": "^0.2.5",
|
||||||
"luckyexcel": "^1.0.1",
|
"jsencrypt": "^3.3.2",
|
||||||
"luckysheet": "^2.1.13",
|
"katex": "^0.16.11",
|
||||||
"mathjax": "^3.2.2",
|
"less": "^4.2.0",
|
||||||
"min-dash": "^4.2.1",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"luckyexcel": "^1.0.1",
|
||||||
"mqtt": "^5.13.3",
|
"luckysheet": "^2.1.13",
|
||||||
"nprogress": "^0.2.0",
|
"mathjax": "^3.2.2",
|
||||||
"pinia": "^2.1.7",
|
"min-dash": "^4.2.1",
|
||||||
"pinia-plugin-persistedstate": "^3.2.1",
|
"mitt": "^3.0.1",
|
||||||
"qs": "^6.12.0",
|
"mqtt": "^5.13.3",
|
||||||
"screenfull": "^6.0.2",
|
"nprogress": "^0.2.0",
|
||||||
"splitpanes": "^3.1.5",
|
"pinia": "^2.1.7",
|
||||||
"steady-xml": "0.1.0",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
"svg-pan-zoom": "^3.6.2",
|
"qs": "^6.12.0",
|
||||||
"use-element-plus-theme": "^0.0.5",
|
"screenfull": "^6.0.2",
|
||||||
"vexip-ui": "^2.3.28",
|
"splitpanes": "^3.1.5",
|
||||||
"vue": "^3.3.11",
|
"steady-xml": "0.1.0",
|
||||||
"vue-baidu-map-3x": "^1.0.35",
|
"svg-pan-zoom": "^3.6.2",
|
||||||
"vue-baidu-map-offline": "^1.0.7",
|
"use-element-plus-theme": "^0.0.5",
|
||||||
"vue-demi": "^0.14.8",
|
"vexip-ui": "^2.3.28",
|
||||||
"vue-draggable-resizable": "3.0.0-beta.2",
|
"vue": "^3.3.11",
|
||||||
"vue-i18n": "9.10.2",
|
"vue-baidu-map-3x": "^1.0.35",
|
||||||
"vue-katex": "^0.5.0",
|
"vue-baidu-map-offline": "^1.0.7",
|
||||||
"vue-router": "4",
|
"vue-demi": "^0.14.8",
|
||||||
"vue-types": "^5.1.1",
|
"vue-draggable-resizable": "3.0.0-beta.2",
|
||||||
"vxe-table": "^4.5.17",
|
"vue-i18n": "9.10.2",
|
||||||
"vxe-table-plugin-export-xlsx": "^4.0.1",
|
"vue-katex": "^0.5.0",
|
||||||
"web-storage-cache": "^1.1.1",
|
"vue-router": "4",
|
||||||
"xe-utils": "^3.5.14",
|
"vue-types": "^5.1.1",
|
||||||
"yarn": "^1.22.22"
|
"vxe-pc-ui": "~4.15.19",
|
||||||
},
|
"vxe-table": "^4.19.22",
|
||||||
"devDependencies": {
|
"vxe-table-plugin-export-xlsx": "^4.0.7",
|
||||||
"@purge-icons/generated": "^0.9.0",
|
"web-storage-cache": "^1.1.1",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"xe-utils": "^3.5.14",
|
||||||
"@types/node": "^20.10.5",
|
"yarn": "^1.22.22"
|
||||||
"@types/splitpanes": "^2.2.6",
|
},
|
||||||
"@vitejs/plugin-vue": "^4.5.2",
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@purge-icons/generated": "^0.9.0",
|
||||||
"sass": "^1.69.5",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"typescript": "^5.2.2",
|
"@types/node": "^20.10.5",
|
||||||
"unplugin-auto-import": "^0.16.7",
|
"@types/splitpanes": "^2.2.6",
|
||||||
"vite": "^5.0.8",
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
"vite-plugin-mkcert": "^1.17.3",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"vue-tsc": "^1.8.25"
|
"sass": "^1.69.5",
|
||||||
}
|
"typescript": "^5.2.2",
|
||||||
|
"unplugin-auto-import": "^0.16.7",
|
||||||
|
"vite": "^5.0.8",
|
||||||
|
"vite-plugin-mkcert": "^1.17.3",
|
||||||
|
"vue-tsc": "^1.8.25"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4747,10 +4747,11 @@ window.BMAP_AUTHENTIC_KEY = ''
|
|||||||
c.Nm
|
c.Nm
|
||||||
? c.Nm.sa(b)
|
? c.Nm.sa(b)
|
||||||
: ((c.Nm = new U(b, {
|
: ((c.Nm = new U(b, {
|
||||||
icon: new qc(G.qa + 'blank.gif', {
|
// icon: new qc(G.qa + 'blank.gif', {
|
||||||
width: 1,
|
// width: 1,
|
||||||
height: 1
|
// height: 1
|
||||||
}),
|
// }),
|
||||||
|
icon: '',
|
||||||
offset: new O(0, 0),
|
offset: new O(0, 0),
|
||||||
clickable: t
|
clickable: t
|
||||||
})),
|
})),
|
||||||
@@ -5886,7 +5887,7 @@ window.BMAP_AUTHENTIC_KEY = ''
|
|||||||
Qc.prototype.co = function () {
|
Qc.prototype.co = function () {
|
||||||
this.Gb.src =
|
this.Gb.src =
|
||||||
0 < z.ca.ia && 6 >= z.ca.ia && this.GJ
|
0 < z.ca.ia && 6 >= z.ca.ia && this.GJ
|
||||||
? G.qa + 'blank.gif'
|
? '' //G.qa + 'blank.gif'
|
||||||
: '' !== this.src && this.Gb.src == this.src
|
: '' !== this.src && this.Gb.src == this.src
|
||||||
? this.src + '&t = ' + Date.now()
|
? this.src + '&t = ' + Date.now()
|
||||||
: this.src
|
: this.src
|
||||||
|
|||||||
14
src/App.vue
14
src/App.vue
@@ -9,16 +9,20 @@ import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
|||||||
import useSetTheme from '@/utils/setTheme'
|
import useSetTheme from '@/utils/setTheme'
|
||||||
import { onMounted } from 'vue'
|
import { onMounted } from 'vue'
|
||||||
useSetTheme()
|
useSetTheme()
|
||||||
onMounted(async () => {
|
const fetchMqttUrl = async () => {
|
||||||
const response = await fetch('/')
|
const response = await fetch('/')
|
||||||
const WebSocketUrl:any = response.headers.get('X-WebSocket-Url')
|
const WebSocketUrl: any = response.headers.get('X-WebSocket-Url')
|
||||||
const WebSocketUrl2:any = response.headers.get('X-WebSocket-Url2')
|
const WebSocketUrl2: any = response.headers.get('X-WebSocket-Url2')
|
||||||
const WebSocketUrl3:any = response.headers.get('X-WebSocket-Url3')
|
const WebSocketUrl3: any = response.headers.get('X-WebSocket-Url3')
|
||||||
const MqttUrl:any = response.headers.get('X-MqttUrl-Url')
|
const MqttUrl: any = response.headers.get('X-MqttUrl-Url')
|
||||||
localStorage.setItem('WebSocketUrl', WebSocketUrl)
|
localStorage.setItem('WebSocketUrl', WebSocketUrl)
|
||||||
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
|
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
|
||||||
localStorage.setItem('WebSocketUrl3', WebSocketUrl3)
|
localStorage.setItem('WebSocketUrl3', WebSocketUrl3)
|
||||||
localStorage.setItem('MqttUrl', MqttUrl)
|
localStorage.setItem('MqttUrl', MqttUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchMqttUrl()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData, requestDownload } from '@/utils/request'
|
||||||
|
|
||||||
// BPM 流程表达式 VO
|
// BPM 流程表达式 VO
|
||||||
export interface ProcessExpressionVO {
|
export interface ProcessExpressionVO {
|
||||||
@@ -12,31 +12,36 @@ export interface ProcessExpressionVO {
|
|||||||
export const ProcessExpressionApi = {
|
export const ProcessExpressionApi = {
|
||||||
// 查询BPM 流程表达式分页
|
// 查询BPM 流程表达式分页
|
||||||
getProcessExpressionPage: async (params: any) => {
|
getProcessExpressionPage: async (params: any) => {
|
||||||
return await request.get({ url: `/bpm/process-expression/page`, params })
|
return await requestData({ url: '/bpm/process-expression/page', method: 'GET', params })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 查询BPM 流程表达式详情
|
// 查询BPM 流程表达式详情
|
||||||
getProcessExpression: async (id: number) => {
|
getProcessExpression: async (id: number) => {
|
||||||
return await request.get({ url: `/bpm/process-expression/get?id=` + id })
|
return await requestData({ url: '/bpm/process-expression/get?id=' + id, method: 'GET' })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 新增BPM 流程表达式
|
// 新增BPM 流程表达式
|
||||||
createProcessExpression: async (data: ProcessExpressionVO) => {
|
createProcessExpression: async (data: ProcessExpressionVO) => {
|
||||||
return await request.post({ url: `/bpm/process-expression/create`, data })
|
return await requestData({ url: '/bpm/process-expression/create', method: 'POST', data })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 修改BPM 流程表达式
|
// 修改BPM 流程表达式
|
||||||
updateProcessExpression: async (data: ProcessExpressionVO) => {
|
updateProcessExpression: async (data: ProcessExpressionVO) => {
|
||||||
return await request.put({ url: `/bpm/process-expression/update`, data })
|
return await requestData({ url: '/bpm/process-expression/update', method: 'PUT', data })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 删除BPM 流程表达式
|
// 删除BPM 流程表达式
|
||||||
deleteProcessExpression: async (id: number) => {
|
deleteProcessExpression: async (id: number) => {
|
||||||
return await request.delete({ url: `/bpm/process-expression/delete?id=` + id })
|
return await requestData({ url: '/bpm/process-expression/delete?id=' + id, method: 'DELETE' })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 导出BPM 流程表达式 Excel
|
// 导出BPM 流程表达式 Excel
|
||||||
exportProcessExpression: async (params) => {
|
exportProcessExpression: async (params) => {
|
||||||
return await request.download({ url: `/bpm/process-expression/export-excel`, params })
|
return await requestDownload({
|
||||||
|
url: '/bpm/process-expression/export-excel',
|
||||||
|
method: 'GET',
|
||||||
|
params,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData } from '@/utils/request'
|
||||||
|
|
||||||
// BPM 流程监听器 VO
|
// BPM 流程监听器 VO
|
||||||
export interface ProcessListenerVO {
|
export interface ProcessListenerVO {
|
||||||
@@ -15,26 +15,26 @@ export interface ProcessListenerVO {
|
|||||||
export const ProcessListenerApi = {
|
export const ProcessListenerApi = {
|
||||||
// 查询流程监听器分页
|
// 查询流程监听器分页
|
||||||
getProcessListenerPage: async (params: any) => {
|
getProcessListenerPage: async (params: any) => {
|
||||||
return await request.get({ url: `/bpm/process-listener/page`, params })
|
return await requestData({ url: '/bpm/process-listener/page', method: 'GET', params })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 查询流程监听器详情
|
// 查询流程监听器详情
|
||||||
getProcessListener: async (id: number) => {
|
getProcessListener: async (id: number) => {
|
||||||
return await request.get({ url: `/bpm/process-listener/get?id=` + id })
|
return await requestData({ url: '/bpm/process-listener/get?id=' + id, method: 'GET' })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 新增流程监听器
|
// 新增流程监听器
|
||||||
createProcessListener: async (data: ProcessListenerVO) => {
|
createProcessListener: async (data: ProcessListenerVO) => {
|
||||||
return await request.post({ url: `/bpm/process-listener/create`, data })
|
return await requestData({ url: '/bpm/process-listener/create', method: 'POST', data })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 修改流程监听器
|
// 修改流程监听器
|
||||||
updateProcessListener: async (data: ProcessListenerVO) => {
|
updateProcessListener: async (data: ProcessListenerVO) => {
|
||||||
return await request.put({ url: `/bpm/process-listener/update`, data })
|
return await requestData({ url: '/bpm/process-listener/update', method: 'PUT', data })
|
||||||
},
|
},
|
||||||
|
|
||||||
// 删除流程监听器
|
// 删除流程监听器
|
||||||
deleteProcessListener: async (id: number) => {
|
deleteProcessListener: async (id: number) => {
|
||||||
return await request.delete({ url: `/bpm/process-listener/delete?id=` + id })
|
return await requestData({ url: '/bpm/process-listener/delete?id=' + id, method: 'DELETE' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,41 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData } from '@/utils/request'
|
||||||
|
|
||||||
export type UserGroupVO = {
|
export type UserGroupVO = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
userIds: number[]
|
userIds: number[]
|
||||||
status: number
|
status: number
|
||||||
remark: string
|
remark: string
|
||||||
createTime: string
|
createTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建用户组
|
// 创建用户组
|
||||||
export const createUserGroup = async (data: UserGroupVO) => {
|
export const createUserGroup = async (data: UserGroupVO) => {
|
||||||
return await request.post({
|
return await requestData({ url: '/bpm/user-group/create', method: 'POST', data })
|
||||||
url: '/bpm/user-group/create',
|
}
|
||||||
data: data
|
|
||||||
})
|
// 更新用户组
|
||||||
}
|
export const updateUserGroup = async (data: UserGroupVO) => {
|
||||||
|
return await requestData({ url: '/bpm/user-group/update', method: 'PUT', data })
|
||||||
// 更新用户组
|
}
|
||||||
export const updateUserGroup = async (data: UserGroupVO) => {
|
|
||||||
return await request.put({
|
// 删除用户组
|
||||||
url: '/bpm/user-group/update',
|
export const deleteUserGroup = async (id: number) => {
|
||||||
data: data
|
return await requestData({ url: '/bpm/user-group/delete?id=' + id, method: 'DELETE' })
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
// 获得用户组
|
||||||
// 删除用户组
|
export const getUserGroup = async (id: number) => {
|
||||||
export const deleteUserGroup = async (id: number) => {
|
return await requestData({ url: '/bpm/user-group/get?id=' + id, method: 'GET' })
|
||||||
return await request.delete({ url: '/bpm/user-group/delete?id=' + id })
|
}
|
||||||
}
|
|
||||||
|
// 获得用户组分页
|
||||||
// 获得用户组
|
export const getUserGroupPage = async (params) => {
|
||||||
export const getUserGroup = async (id: number) => {
|
return await requestData({ url: '/bpm/user-group/page', method: 'GET', params })
|
||||||
return await request.get({ url: '/bpm/user-group/get?id=' + id })
|
}
|
||||||
}
|
|
||||||
|
// 获取用户组精简信息列表
|
||||||
// 获得用户组分页
|
export const getUserGroupSimpleList = async (): Promise<UserGroupVO[]> => {
|
||||||
export const getUserGroupPage = async (params) => {
|
return await requestData({ url: '/bpm/user-group/simple-list', method: 'GET' })
|
||||||
return await request.get({ url: '/bpm/user-group/page', params })
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 获取用户组精简信息列表
|
|
||||||
export const getUserGroupSimpleList = async (): Promise<UserGroupVO[]> => {
|
|
||||||
return await request.get({ url: '/bpm/user-group/simple-list' })
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 获取区域中断终端
|
// 获取区域中断终端
|
||||||
export function getAreaOffDev(data) {
|
export function getAreaOffDev(data:any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/device-boot/device/getAreaOffDev',
|
url: '/device-boot/device/getAreaOffDev',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@@ -9,10 +9,28 @@ export function getAreaOffDev(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 获取区域中断终端
|
// 获取区域中断终端
|
||||||
export function getYwZtSubstation(data) {
|
export function getYwZtSubstation(data:any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/device-boot/ywZt/getYwZtSubstation',
|
url: '/device-boot/ywZt/getYwZtSubstation',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
params: data
|
params: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//终端周期检测
|
||||||
|
export function terminalCheckPage(data:any) {
|
||||||
|
return request({
|
||||||
|
url: '/device-boot/alarm/terminalCheckPage',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function userCheckUpload(data:any) {
|
||||||
|
return request({
|
||||||
|
url: '/device-boot/userReport/userCheckUpload',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -4,6 +4,10 @@ import request from '@/utils/request'
|
|||||||
export function getSubLineGiveAnAlarm(data: any) {
|
export function getSubLineGiveAnAlarm(data: any) {
|
||||||
return request({ url: '/harmonic-boot/gridDiagram/getSubLineGiveAnAlarm', method: 'post', data })
|
return request({ url: '/harmonic-boot/gridDiagram/getSubLineGiveAnAlarm', method: 'post', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAreaObjAlarm(data: any) {
|
||||||
|
return request({ url: '/harmonic-boot/gridDiagram/getAreaObjAlarm', method: 'post', data })
|
||||||
|
}
|
||||||
// 变电站详细列表
|
// 变电站详细列表
|
||||||
export function getPollutionAlarmPageData(data: any) {
|
export function getPollutionAlarmPageData(data: any) {
|
||||||
return request({ url: '/harmonic-boot/gridDiagram/getPollutionAlarmPageData', method: 'post', data })
|
return request({ url: '/harmonic-boot/gridDiagram/getPollutionAlarmPageData', method: 'post', data })
|
||||||
@@ -182,3 +186,7 @@ export function limitTableDetail(data: any) {
|
|||||||
export function downPollutionSensitiveUser(data: any) {
|
export function downPollutionSensitiveUser(data: any) {
|
||||||
return request({ url: '/harmonic-boot/PollutionSubstation/downPollutionSensitiveUser', method: 'post', data })
|
return request({ url: '/harmonic-boot/PollutionSubstation/downPollutionSensitiveUser', method: 'post', data })
|
||||||
}
|
}
|
||||||
|
//干扰源类型统计
|
||||||
|
export function loadTypeVOList(data: any) {
|
||||||
|
return request({ url: '/device-boot/gridDiagram/loadTypeVOList', method: 'post', data })
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData, requestDownload } from '@/utils/request'
|
||||||
|
|
||||||
export type DictDataVO = {
|
export type DictDataVO = {
|
||||||
id: number | undefined
|
id: number | undefined
|
||||||
sort: number | undefined
|
sort: number | undefined
|
||||||
label: string
|
label: string
|
||||||
value: string
|
value: string
|
||||||
dictType: string
|
dictType: string
|
||||||
status: number
|
status: number
|
||||||
colorType: string
|
colorType: string
|
||||||
cssClass: string
|
cssClass: string
|
||||||
remark: string
|
remark: string
|
||||||
createTime: Date
|
createTime: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典数据(精简)列表
|
// 查询字典数据(精简)列表
|
||||||
export const getSimpleDictDataList = () => {
|
export const getSimpleDictDataList = () => {
|
||||||
return request.get({ url: '/system/dict-data/simple-list' })
|
return requestData({ url: '/system/dict-data/simple-list', method: 'GET' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典数据列表
|
// 查询字典数据列表
|
||||||
export const getDictDataPage = (params: PageParam) => {
|
export const getDictDataPage = (params: PageParam) => {
|
||||||
return request.get({ url: '/system/dict-data/page', params })
|
return requestData({ url: '/system/dict-data/page', method: 'GET', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典数据详情
|
// 查询字典数据详情
|
||||||
export const getDictData = (id: number) => {
|
export const getDictData = (id: number) => {
|
||||||
return request.get({ url: '/system/dict-data/get?id=' + id })
|
return requestData({ url: '/system/dict-data/get?id=' + id, method: 'GET' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增字典数据
|
// 新增字典数据
|
||||||
export const createDictData = (data: DictDataVO) => {
|
export const createDictData = (data: DictDataVO) => {
|
||||||
return request.post({ url: '/system/dict-data/create', data })
|
return requestData({ url: '/system/dict-data/create', method: 'POST', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改字典数据
|
// 修改字典数据
|
||||||
export const updateDictData = (data: DictDataVO) => {
|
export const updateDictData = (data: DictDataVO) => {
|
||||||
return request.put({ url: '/system/dict-data/update', data })
|
return requestData({ url: '/system/dict-data/update', method: 'PUT', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除字典数据
|
// 删除字典数据
|
||||||
export const deleteDictData = (id: number) => {
|
export const deleteDictData = (id: number) => {
|
||||||
return request.delete({ url: '/system/dict-data/delete?id=' + id })
|
return requestData({ url: '/system/dict-data/delete?id=' + id, method: 'DELETE' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出字典类型数据
|
// 导出字典类型数据
|
||||||
export const exportDictData = (params) => {
|
export const exportDictData = (params) => {
|
||||||
return request.download({ url: '/system/dict-data/export', params })
|
return requestDownload({ url: '/system/dict-data/export', method: 'GET', params, responseType: 'blob' })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,45 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData, requestDownload } from '@/utils/request'
|
||||||
|
|
||||||
export type DictTypeVO = {
|
export type DictTypeVO = {
|
||||||
id: number | undefined
|
id: number | undefined
|
||||||
name: string
|
name: string
|
||||||
type: string
|
type: string
|
||||||
status: number
|
status: number
|
||||||
remark: string
|
remark: string
|
||||||
createTime: Date
|
createTime: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典(精简)列表
|
// 查询字典(精简)列表
|
||||||
export const getSimpleDictTypeList = () => {
|
export const getSimpleDictTypeList = () => {
|
||||||
return request.get({ url: '/system/dict-type/list-all-simple' })
|
return requestData({ url: '/system/dict-type/list-all-simple', method: 'GET' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典列表
|
// 查询字典列表
|
||||||
export const getDictTypePage = (params: PageParam) => {
|
export const getDictTypePage = (params: PageParam) => {
|
||||||
return request.get({ url: '/system/dict-type/page', params })
|
return requestData({ url: '/system/dict-type/page', method: 'GET', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询字典详情
|
// 查询字典详情
|
||||||
export const getDictType = (id: number) => {
|
export const getDictType = (id: number) => {
|
||||||
return request.get({ url: '/system/dict-type/get?id=' + id })
|
return requestData({ url: '/system/dict-type/get?id=' + id, method: 'GET' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增字典
|
// 新增字典
|
||||||
export const createDictType = (data: DictTypeVO) => {
|
export const createDictType = (data: DictTypeVO) => {
|
||||||
return request.post({ url: '/system/dict-type/create', data })
|
return requestData({ url: '/system/dict-type/create', method: 'POST', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改字典
|
// 修改字典
|
||||||
export const updateDictType = (data: DictTypeVO) => {
|
export const updateDictType = (data: DictTypeVO) => {
|
||||||
return request.put({ url: '/system/dict-type/update', data })
|
return requestData({ url: '/system/dict-type/update', method: 'PUT', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除字典
|
// 删除字典
|
||||||
export const deleteDictType = (id: number) => {
|
export const deleteDictType = (id: number) => {
|
||||||
return request.delete({ url: '/system/dict-type/delete?id=' + id })
|
return requestData({ url: '/system/dict-type/delete?id=' + id, method: 'DELETE' })
|
||||||
}
|
}
|
||||||
// 导出字典类型
|
|
||||||
export const exportDictType = (params) => {
|
// 导出字典类型
|
||||||
return request.download({ url: '/system/dict-type/export', params })
|
export const exportDictType = (params) => {
|
||||||
}
|
return requestDownload({ url: '/system/dict-type/export', method: 'GET', params, responseType: 'blob' })
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,50 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData } from '@/utils/request'
|
||||||
import qs from 'qs'
|
import qs from 'qs'
|
||||||
|
|
||||||
export interface NotifyMessageVO {
|
export interface NotifyMessageVO {
|
||||||
id: number
|
id: number
|
||||||
userId: number
|
userId: number
|
||||||
userType: number
|
userType: number
|
||||||
templateId: number
|
templateId: number
|
||||||
templateCode: string
|
templateCode: string
|
||||||
templateNickname: string
|
templateNickname: string
|
||||||
templateContent: string
|
templateContent: string
|
||||||
templateType: number
|
templateType: number
|
||||||
templateParams: string
|
templateParams: string
|
||||||
readStatus: boolean
|
readStatus: boolean
|
||||||
readTime: Date
|
readTime: Date
|
||||||
createTime: Date
|
createTime: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询站内信消息列表
|
// 查询站内信消息列表
|
||||||
export const getNotifyMessagePage = async (params: PageParam) => {
|
export const getNotifyMessagePage = async (params: any) => {
|
||||||
return await request.get({ url: '/system/notify-message/page', params })
|
return await requestData({ url: '/system/notify-message/page', method: 'GET', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得我的站内信分页
|
// 获得我的站内信分页
|
||||||
export const getMyNotifyMessagePage = async (params: PageParam) => {
|
export const getMyNotifyMessagePage = async (params: any) => {
|
||||||
return await request.get({ url: '/system/notify-message/my-page', params })
|
return await requestData({ url: '/system/notify-message/my-page', method: 'GET', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量标记已读
|
// 批量标记已读
|
||||||
export const updateNotifyMessageRead = async (ids) => {
|
export const updateNotifyMessageRead = async (ids: any) => {
|
||||||
return await request.put({
|
return await requestData({
|
||||||
url: '/system/notify-message/update-read?' + qs.stringify({ ids: ids }, { indices: false })
|
url: '/system/notify-message/update-read?' + qs.stringify({ ids: ids }, { indices: false }),
|
||||||
})
|
method: 'PUT'
|
||||||
}
|
})
|
||||||
|
}
|
||||||
// 标记所有站内信为已读
|
|
||||||
export const updateAllNotifyMessageRead = async () => {
|
// 标记所有站内信为已读
|
||||||
return await request.put({ url: '/system/notify-message/update-all-read' })
|
export const updateAllNotifyMessageRead = async () => {
|
||||||
}
|
return await requestData({ url: '/system/notify-message/update-all-read', method: 'PUT' })
|
||||||
|
}
|
||||||
// 获取当前用户的最新站内信列表
|
|
||||||
export const getUnreadNotifyMessageList = async () => {
|
// 获取当前用户的最新站内信列表
|
||||||
return await request.get({ url: '/system/notify-message/get-unread-list' })
|
export const getUnreadNotifyMessageList = async () => {
|
||||||
}
|
return await requestData({ url: '/system/notify-message/get-unread-list', method: 'GET' })
|
||||||
|
}
|
||||||
// 获得当前用户的未读站内信数量
|
|
||||||
export const getUnreadNotifyMessageCount = async () => {
|
// 获得当前用户的未读站内信数量
|
||||||
return await request.get({ url: '/system/notify-message/get-unread-count' })
|
export const getUnreadNotifyMessageCount = async () => {
|
||||||
}
|
return await requestData({ url: '/system/notify-message/get-unread-count', method: 'GET' })
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
import request from '@/config/axios'
|
import { requestData } from '@/utils/request'
|
||||||
|
|
||||||
export interface NotifyTemplateVO {
|
export interface NotifyTemplateVO {
|
||||||
id?: number
|
id?: number
|
||||||
name: string
|
name: string
|
||||||
nickname: string
|
nickname: string
|
||||||
code: string
|
code: string
|
||||||
content: string
|
content: string
|
||||||
type?: number
|
type?: number
|
||||||
params: string
|
params: string
|
||||||
status: number
|
status: number
|
||||||
remark: string
|
remark: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotifySendReqVO {
|
export interface NotifySendReqVO {
|
||||||
userId: number | null
|
userId: number | null
|
||||||
templateCode: string
|
templateCode: string
|
||||||
templateParams: Map<String, Object>
|
templateParams: Map<String, Object>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询站内信模板列表
|
// 查询站内信模板列表
|
||||||
export const getNotifyTemplatePage = async (params: PageParam) => {
|
export const getNotifyTemplatePage = async (params: PageParam) => {
|
||||||
return await request.get({ url: '/system/notify-template/page', params })
|
return await requestData({ url: '/system/notify-template/page', method: 'GET', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询站内信模板详情
|
// 查询站内信模板详情
|
||||||
export const getNotifyTemplate = async (id: number) => {
|
export const getNotifyTemplate = async (id: number) => {
|
||||||
return await request.get({ url: '/system/notify-template/get?id=' + id })
|
return await requestData({ url: '/system/notify-template/get?id=' + id, method: 'GET' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增站内信模板
|
// 新增站内信模板
|
||||||
export const createNotifyTemplate = async (data: NotifyTemplateVO) => {
|
export const createNotifyTemplate = async (data: NotifyTemplateVO) => {
|
||||||
return await request.post({ url: '/system/notify-template/create', data })
|
return await requestData({ url: '/system/notify-template/create', method: 'POST', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改站内信模板
|
// 修改站内信模板
|
||||||
export const updateNotifyTemplate = async (data: NotifyTemplateVO) => {
|
export const updateNotifyTemplate = async (data: NotifyTemplateVO) => {
|
||||||
return await request.put({ url: '/system/notify-template/update', data })
|
return await requestData({ url: '/system/notify-template/update', method: 'PUT', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除站内信模板
|
// 删除站内信模板
|
||||||
export const deleteNotifyTemplate = async (id: number) => {
|
export const deleteNotifyTemplate = async (id: number) => {
|
||||||
return await request.delete({ url: '/system/notify-template/delete?id=' + id })
|
return await requestData({ url: '/system/notify-template/delete?id=' + id, method: 'DELETE' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送站内信
|
// 发送站内信
|
||||||
export const sendNotify = (data: NotifySendReqVO) => {
|
export const sendNotify = (data: NotifySendReqVO) => {
|
||||||
return request.post({ url: '/system/notify-template/send-notify', data })
|
return requestData({ url: '/system/notify-template/send-notify', method: 'POST', data })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,215 +1,250 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import { LoginData } from '@/api/types'
|
import { LoginData } from '@/api/types'
|
||||||
import { useAdminInfo } from '@/stores/adminInfo'
|
import { useAdminInfo } from '@/stores/adminInfo'
|
||||||
import { sm3Digest } from '@/assets/commjs/sm3.js'
|
import { sm3Digest } from '@/assets/commjs/sm3.js'
|
||||||
import { sm2, encrypt } from '@/assets/commjs/sm2.js'
|
import { sm2, encrypt } from '@/assets/commjs/sm2.js'
|
||||||
|
|
||||||
// 获取公钥
|
// 获取公钥
|
||||||
export function gongkey(params?: any) {
|
export function gongkey(params?: any) {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
const adminInfo = useAdminInfo()
|
const adminInfo = useAdminInfo()
|
||||||
params = {
|
params = {
|
||||||
loginName: encrypt(adminInfo.$state.loginName)
|
loginName: encrypt(adminInfo.$state.loginName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return request({
|
return request({
|
||||||
url: '/user-boot/user/generateSm2Key',
|
url: '/user-boot/user/generateSm2Key',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pwdSm3(pwd: any, loginName?: string) {
|
export async function pwdSm3(pwd: any, loginName?: string) {
|
||||||
let publicKey = await gongkey(
|
let publicKey = await gongkey(
|
||||||
loginName
|
loginName
|
||||||
? {
|
? {
|
||||||
loginName: encrypt(loginName)
|
loginName: encrypt(loginName)
|
||||||
}
|
}
|
||||||
: false
|
: false
|
||||||
)
|
)
|
||||||
let sm3Pwd = sm3Digest(pwd) //SM3加密
|
let sm3Pwd = sm3Digest(pwd) //SM3加密
|
||||||
return sm2(sm3Pwd + '|' + pwd, publicKey.data, 0)
|
return sm2(sm3Pwd + '|' + pwd, publicKey.data, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
//登录获取token
|
//登录获取token
|
||||||
export async function login(params: any) {
|
export async function login(params: any) {
|
||||||
if (params.refresh_token == undefined) {
|
if (params.refresh_token == undefined) {
|
||||||
params.password = await pwdSm3(params.password, params.username)
|
params.password = await pwdSm3(params.password, params.username)
|
||||||
}
|
}
|
||||||
params.username = encrypt(params.username)
|
params.username = encrypt(params.username)
|
||||||
return request({
|
return request({
|
||||||
url: '/pqs-auth/oauth/token',
|
url: '/pqs-auth/oauth/token',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//辽宁嵌入登录获取token
|
||||||
//获取用户信息
|
export async function loginLNqr(data: any) {
|
||||||
export function getUserById() {
|
return request({
|
||||||
const adminInfo = useAdminInfo()
|
url: '/pqs-auth/oauth/lnLogin',
|
||||||
return request({
|
method: 'get',
|
||||||
url: '/user-boot/user/getUserById?id=' + adminInfo.userIndex,
|
params: data
|
||||||
method: 'get'
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
export async function lnRefreshToken(data: any) {
|
||||||
// 刷新token
|
return request({
|
||||||
// 导出一个名为refreshToken的函数,该函数返回一个Promise对象
|
url: '/pqs-auth/oauth/lnRefreshToken',
|
||||||
export function refreshToken(): Promise<any> {
|
method: 'get',
|
||||||
// 调用useAdminInfo函数获取管理员信息,并将其赋值给adminInfo变量
|
params: data
|
||||||
const adminInfo = useAdminInfo()
|
})
|
||||||
// 调用login函数,传入一个对象作为参数,该对象包含grant_type、refresh_token和username三个属性
|
}
|
||||||
// grant_type设置为'refresh_token',表示使用刷新令牌的方式获取新的访问令牌
|
|
||||||
// refresh_token使用adminInfo中的refresh_token属性
|
export async function logout() {
|
||||||
// username使用adminInfo中的loginName属性
|
return request({
|
||||||
// 返回login函数的调用结果,即一个Promise对象
|
url: '/pqs-auth/oauth/logout',
|
||||||
return login({
|
method: 'DELETE',
|
||||||
grant_type: 'refresh_token',
|
})
|
||||||
refresh_token: adminInfo.refresh_token,
|
}
|
||||||
username: adminInfo.loginName
|
|
||||||
})
|
|
||||||
}
|
//获取用户信息
|
||||||
|
export function getUserById() {
|
||||||
/**
|
const adminInfo = useAdminInfo()
|
||||||
* 获取营销用户列表
|
return request({
|
||||||
* @returns {AxiosPromise}
|
url: '/user-boot/user/getUserById?id=' + adminInfo.userIndex,
|
||||||
*/
|
method: 'get'
|
||||||
export const getMarketList = () => {
|
})
|
||||||
return request({
|
}
|
||||||
url: '/user-boot/user/getMarketList',
|
|
||||||
method: 'post'
|
// 刷新token
|
||||||
})
|
// 导出一个名为refreshToken的函数,该函数返回一个Promise对象
|
||||||
}
|
export function refreshToken(): Promise<any> {
|
||||||
|
// 调用useAdminInfo函数获取管理员信息,并将其赋值给adminInfo变量
|
||||||
export function add(data: any) {
|
const adminInfo = useAdminInfo()
|
||||||
return request({
|
// 调用login函数,传入一个对象作为参数,该对象包含grant_type、refresh_token和username三个属性
|
||||||
url: '/user-boot/user/add',
|
// grant_type设置为'refresh_token',表示使用刷新令牌的方式获取新的访问令牌
|
||||||
method: 'post',
|
// refresh_token使用adminInfo中的refresh_token属性
|
||||||
data: data
|
// username使用adminInfo中的loginName属性
|
||||||
})
|
// 返回login函数的调用结果,即一个Promise对象
|
||||||
}
|
return login({
|
||||||
|
grant_type: 'refresh_token',
|
||||||
export function edit(data: any) {
|
refresh_token: adminInfo.refresh_token,
|
||||||
return request({
|
username: adminInfo.loginName
|
||||||
url: '/user-boot/user/update',
|
})
|
||||||
method: 'put',
|
}
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
export function lnRefreshTokenTo(): Promise<any> {
|
||||||
|
// 调用useAdminInfo函数获取管理员信息,并将其赋值给adminInfo变量
|
||||||
export async function passwordConfirm(pwd: string) {
|
const adminInfo = useAdminInfo()
|
||||||
return request({
|
return lnRefreshToken({
|
||||||
url: '/user-boot/user/passwordConfirm?password=' + (await pwdSm3(pwd)),
|
refreshToken: adminInfo.refresh_token,
|
||||||
method: 'get'
|
clientId: "njcn",
|
||||||
})
|
clientSecret:"njcnpqs"
|
||||||
}
|
})
|
||||||
|
}
|
||||||
export function deluser(data: any) {
|
|
||||||
return request({
|
/**
|
||||||
url: '/user-boot/user/delete',
|
* 获取营销用户列表
|
||||||
method: 'delete',
|
* @returns {AxiosPromise}
|
||||||
params: data
|
*/
|
||||||
})
|
export const getMarketList = () => {
|
||||||
}
|
return request({
|
||||||
|
url: '/user-boot/user/getMarketList',
|
||||||
export function activateUser(data: any) {
|
method: 'post'
|
||||||
return request({
|
})
|
||||||
url: '/user-boot/user/activateUser',
|
}
|
||||||
method: 'put',
|
|
||||||
params: data
|
export function add(data: any) {
|
||||||
})
|
return request({
|
||||||
}
|
url: '/user-boot/user/add',
|
||||||
|
method: 'post',
|
||||||
export async function updatePassword(params: any) {
|
data: data
|
||||||
return request({
|
})
|
||||||
url: '/user-boot/user/updatePassword',
|
}
|
||||||
method: 'put',
|
|
||||||
params: {
|
export function edit(data: any) {
|
||||||
id: params.id,
|
return request({
|
||||||
newPassword: await pwdSm3(params.newPassword)
|
url: '/user-boot/user/update',
|
||||||
}
|
method: 'put',
|
||||||
})
|
data: data
|
||||||
}
|
})
|
||||||
|
}
|
||||||
export async function updateFirstPassword(params: any) {
|
|
||||||
return request({
|
export async function passwordConfirm(pwd: string) {
|
||||||
url: '/user-boot/user/updateFirstPassword',
|
return request({
|
||||||
method: 'put',
|
url: '/user-boot/user/passwordConfirm?password=' + (await pwdSm3(pwd)),
|
||||||
data: {
|
method: 'get'
|
||||||
name: encrypt(params.name),
|
})
|
||||||
password: await pwdSm3(params.password, params.name)
|
}
|
||||||
}
|
|
||||||
})
|
export function deluser(data: any) {
|
||||||
}
|
return request({
|
||||||
|
url: '/user-boot/user/delete',
|
||||||
export function checkUser(data: any) {
|
method: 'delete',
|
||||||
return request({
|
params: data
|
||||||
url: '/user-boot/user/check',
|
})
|
||||||
method: 'put',
|
}
|
||||||
data: data
|
|
||||||
})
|
export function activateUser(data: any) {
|
||||||
}
|
return request({
|
||||||
export function existMonitorDeptTree() {
|
url: '/user-boot/user/activateUser',
|
||||||
return request({
|
method: 'put',
|
||||||
url: '/user-boot/dept/existMonitorDeptTree',
|
params: data
|
||||||
method: 'post'
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
// 获取用户
|
export async function updatePassword(params: any) {
|
||||||
export function getUserByRoleType(data: any) {
|
return request({
|
||||||
return request({
|
url: '/user-boot/user/updatePassword',
|
||||||
url: '/user-boot/user/getUserByRoleType?roleType=' + data,
|
method: 'put',
|
||||||
method: 'GET'
|
params: {
|
||||||
})
|
id: params.id,
|
||||||
}
|
newPassword: await pwdSm3(params.newPassword)
|
||||||
|
}
|
||||||
// 获取部门下所有用户
|
})
|
||||||
export function listAllUserByDeptId(data: any) {
|
}
|
||||||
return request({
|
|
||||||
url: '/user-boot/user/listAllUserByDeptId?deptId=' + data,
|
export async function updateFirstPassword(params: any) {
|
||||||
method: 'GET'
|
return request({
|
||||||
})
|
url: '/user-boot/user/updateFirstPassword',
|
||||||
}
|
method: 'put',
|
||||||
|
data: {
|
||||||
// 根据id获取所有用户信息
|
name: encrypt(params.name),
|
||||||
export function getUserListByIds(data: any) {
|
password: await pwdSm3(params.password, params.name)
|
||||||
return request({
|
}
|
||||||
url: '/user-boot/user/getUserListByIds',
|
})
|
||||||
method: 'POST',
|
}
|
||||||
data
|
|
||||||
})
|
export function checkUser(data: any) {
|
||||||
}
|
return request({
|
||||||
|
url: '/user-boot/user/check',
|
||||||
/**
|
method: 'put',
|
||||||
* 查询所有用户不包括管理员
|
data: data
|
||||||
*/
|
})
|
||||||
export const getUserSimpleList = () => {
|
}
|
||||||
return request({
|
export function existMonitorDeptTree() {
|
||||||
url: '/user-boot/user/simpleList',
|
return request({
|
||||||
method: 'GET'
|
url: '/user-boot/dept/existMonitorDeptTree',
|
||||||
})
|
method: 'post'
|
||||||
}
|
})
|
||||||
|
}
|
||||||
/**
|
// 获取用户
|
||||||
* 查询所有用户包括管理员
|
export function getUserByRoleType(data: any) {
|
||||||
*/
|
return request({
|
||||||
export const getAllUserSimpleList = () => {
|
url: '/user-boot/user/getUserByRoleType?roleType=' + data,
|
||||||
return request({
|
method: 'GET'
|
||||||
url: '/user-boot/user/getAllUserSimpleList',
|
})
|
||||||
method: 'GET'
|
}
|
||||||
})
|
|
||||||
}
|
// 获取部门下所有用户
|
||||||
|
export function listAllUserByDeptId(data: any) {
|
||||||
export const getSysConfig = () => {
|
return request({
|
||||||
return request({
|
url: '/user-boot/user/listAllUserByDeptId?deptId=' + data,
|
||||||
url: '/system-boot/config/getSysConfig',
|
method: 'GET'
|
||||||
method: 'get'
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
// 驾驶舱组件配置
|
// 根据id获取所有用户信息
|
||||||
export const componentTree = () => {
|
export function getUserListByIds(data: any) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user-boot/component/componentTree',
|
url: '/user-boot/user/getUserListByIds',
|
||||||
method: 'GET'
|
method: 'POST',
|
||||||
})
|
data
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有用户不包括管理员
|
||||||
|
*/
|
||||||
|
export const getUserSimpleList = () => {
|
||||||
|
return request({
|
||||||
|
url: '/user-boot/user/simpleList',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有用户包括管理员
|
||||||
|
*/
|
||||||
|
export const getAllUserSimpleList = () => {
|
||||||
|
return request({
|
||||||
|
url: '/user-boot/user/getAllUserSimpleList',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSysConfig = () => {
|
||||||
|
return request({
|
||||||
|
url: '/system-boot/config/getSysConfig',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 驾驶舱组件配置
|
||||||
|
export const componentTree = () => {
|
||||||
|
return request({
|
||||||
|
url: '/user-boot/component/componentTree',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
BIN
src/assets/imgs/m0.png
Normal file
BIN
src/assets/imgs/m0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/imgs/m1.png
Normal file
BIN
src/assets/imgs/m1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/assets/imgs/m2.png
Normal file
BIN
src/assets/imgs/m2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/assets/imgs/m3.png
Normal file
BIN
src/assets/imgs/m3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
BIN
src/assets/imgs/m4.png
Normal file
BIN
src/assets/imgs/m4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -1,46 +1,46 @@
|
|||||||
<!-- 数据字典 Select 选择器 -->
|
<!-- 数据字典 Select 选择器 -->
|
||||||
<template>
|
<template>
|
||||||
<el-select class="w-1/1" v-bind="attrs">
|
<el-select class="w-1/1" v-bind="attrs" filterable>
|
||||||
<template v-if="valueType === 'int'">
|
<template v-if="valueType === 'int'">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(dict, index) in getIntDictOptions(dictType)"
|
v-for="(dict, index) in getIntDictOptions(dictType)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:label="dict.label"
|
:label="dict.label"
|
||||||
:value="dict.value"
|
:value="dict.value"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="valueType === 'str'">
|
<template v-if="valueType === 'str'">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(dict, index) in getStrDictOptions(dictType)"
|
v-for="(dict, index) in getStrDictOptions(dictType)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:label="dict.label"
|
:label="dict.label"
|
||||||
:value="dict.value"
|
:value="dict.value"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="valueType === 'bool'">
|
<template v-if="valueType === 'bool'">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(dict, index) in getBoolDictOptions(dictType)"
|
v-for="(dict, index) in getBoolDictOptions(dictType)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:label="dict.label"
|
:label="dict.label"
|
||||||
:value="dict.value"
|
:value="dict.value"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getBoolDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
import { getBoolDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||||
|
|
||||||
// 接受父组件参数
|
// 接受父组件参数
|
||||||
interface Props {
|
interface Props {
|
||||||
dictType: string // 字典类型
|
dictType: string // 字典类型
|
||||||
valueType: string // 字典值类型
|
valueType: string // 字典值类型
|
||||||
}
|
}
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
withDefaults(defineProps<Props>(), {
|
||||||
dictType: '',
|
dictType: '',
|
||||||
valueType: 'str'
|
valueType: 'str'
|
||||||
})
|
})
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
defineOptions({ name: 'DictSelect' })
|
defineOptions({ name: 'DictSelect' })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { downloadFile } from '@/api/system-boot/file'
|
|||||||
import { previewFile } from '@/utils/fileDownLoad'
|
import { previewFile } from '@/utils/fileDownLoad'
|
||||||
|
|
||||||
const { push, options, currentRoute } = useRouter()
|
const { push, options, currentRoute } = useRouter()
|
||||||
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
|
const VITE_FLAG = false//import.meta.env.VITE_NAME == 'jibei'
|
||||||
// const url = 'http://192.168.1.22:9009/excelreport' + currentRoute.value.href?.split('?')[1]
|
// const url = 'http://192.168.1.22:9009/excelreport' + currentRoute.value.href?.split('?')[1]
|
||||||
const url = ref('')
|
const url = ref('')
|
||||||
const excelOptions = ref({})
|
const excelOptions = ref({})
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ const highlightDiagram = async () => {
|
|||||||
let findProcessTask = false //是否已经高亮了进行中的任务
|
let findProcessTask = false //是否已经高亮了进行中的任务
|
||||||
//进行中高亮之后的任务 key 集合,用于过滤掉 taskList 进行中后面的任务,避免进行中后面的数据 Hover 还有数据
|
//进行中高亮之后的任务 key 集合,用于过滤掉 taskList 进行中后面的任务,避免进行中后面的数据 Hover 还有数据
|
||||||
let removeTaskDefinitionKeyList = []
|
let removeTaskDefinitionKeyList = []
|
||||||
// debugger
|
//
|
||||||
//芋道这里取值是rootElements[0].flowElements
|
//芋道这里取值是rootElements[0].flowElements
|
||||||
bpmnModeler.getDefinitions().rootElements[1].flowElements?.forEach((n: any) => {
|
bpmnModeler.getDefinitions().rootElements[1].flowElements?.forEach((n: any) => {
|
||||||
let activity: any = activityList.find((m: any) => m.key === n.id) // 找到对应的活动
|
let activity: any = activityList.find((m: any) => m.key === n.id) // 找到对应的活动
|
||||||
@@ -135,7 +135,6 @@ const highlightDiagram = async () => {
|
|||||||
// 处理 outgoing 出线
|
// 处理 outgoing 出线
|
||||||
const outgoing = getActivityOutgoing(activity)
|
const outgoing = getActivityOutgoing(activity)
|
||||||
outgoing?.forEach((nn: any) => {
|
outgoing?.forEach((nn: any) => {
|
||||||
// debugger
|
|
||||||
let targetActivity: any = activityList.find((m: any) => m.key === nn.targetRef.id)
|
let targetActivity: any = activityList.find((m: any) => m.key === nn.targetRef.id)
|
||||||
// 如果目标活动存在,则根据该活动是否结束,进行【bpmn:SequenceFlow】连线的高亮设置
|
// 如果目标活动存在,则根据该活动是否结束,进行【bpmn:SequenceFlow】连线的高亮设置
|
||||||
if (targetActivity) {
|
if (targetActivity) {
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
<div class="panel-tab__content">
|
<div class="panel-tab__content">
|
||||||
<el-form :model="flowConditionForm" label-width="90px" size="small">
|
<el-form :model="flowConditionForm" label-width="90px" size="small">
|
||||||
<el-form-item label="流转类型">
|
<el-form-item label="流转类型">
|
||||||
<el-select v-model="flowConditionForm.type" @change="updateFlowType">
|
<el-select v-model="flowConditionForm.type" @change="updateFlowType" filterable>
|
||||||
<el-option label="普通流转路径" value="normal" />
|
<el-option label="普通流转路径" value="normal" />
|
||||||
<el-option label="默认流转路径" value="default" />
|
<el-option label="默认流转路径" value="default" />
|
||||||
<el-option label="条件流转路径" value="condition" />
|
<el-option label="条件流转路径" value="condition" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="条件格式" v-if="flowConditionForm.type === 'condition'" key="condition">
|
<el-form-item label="条件格式" v-if="flowConditionForm.type === 'condition'" key="condition">
|
||||||
<el-select v-model="flowConditionForm.conditionType">
|
<el-select v-model="flowConditionForm.conditionType" filterable>
|
||||||
<el-option label="表达式" value="expression" />
|
<el-option label="表达式" value="expression" />
|
||||||
<el-option label="脚本" value="script" />
|
<el-option label="脚本" value="script" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<el-input v-model="flowConditionForm.language" clearable @change="updateFlowCondition" />
|
<el-input v-model="flowConditionForm.language" clearable @change="updateFlowCondition" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="脚本类型" key="scriptType">
|
<el-form-item label="脚本类型" key="scriptType">
|
||||||
<el-select v-model="flowConditionForm.scriptType">
|
<el-select v-model="flowConditionForm.scriptType" filterable>
|
||||||
<el-option label="内联脚本" value="inlineScript" />
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
<el-option label="外部脚本" value="externalScript" />
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|||||||
@@ -1,481 +1,481 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="panel-tab__content">
|
<div class="panel-tab__content">
|
||||||
<el-form label-width="80px">
|
<el-form label-width="80px">
|
||||||
<el-form-item label="流程表单">
|
<el-form-item label="流程表单">
|
||||||
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
|
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
|
||||||
<el-select v-model="formKey" clearable @change="updateElementFormKey">
|
<el-select v-model="formKey" clearable @change="updateElementFormKey" filterable>
|
||||||
<el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" />
|
<el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- <el-form-item label="业务标识">-->
|
<!-- <el-form-item label="业务标识">-->
|
||||||
<!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
|
<!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
|
||||||
<!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
|
<!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
|
||||||
<!-- <el-option label="无" value="" />-->
|
<!-- <el-option label="无" value="" />-->
|
||||||
<!-- </el-select>-->
|
<!-- </el-select>-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!--字段列表-->
|
<!--字段列表-->
|
||||||
<!-- <div class="element-property list-property">-->
|
<!-- <div class="element-property list-property">-->
|
||||||
<!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
|
<!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
|
||||||
<!-- <el-table :data="fieldList" max-height="240" fit border>-->
|
<!-- <el-table :data="fieldList" max-height="240" fit border>-->
|
||||||
<!-- <el-table-column label="序号" type="index" width="50px" />-->
|
<!-- <el-table-column label="序号" type="index" width="50px" />-->
|
||||||
<!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column-->
|
<!-- <el-table-column-->
|
||||||
<!-- label="字段类型"-->
|
<!-- label="字段类型"-->
|
||||||
<!-- prop="type"-->
|
<!-- prop="type"-->
|
||||||
<!-- min-width="80px"-->
|
<!-- min-width="80px"-->
|
||||||
<!-- :formatter="(row) => fieldType[row.type] || row.type"-->
|
<!-- :formatter="(row) => fieldType[row.type] || row.type"-->
|
||||||
<!-- show-overflow-tooltip-->
|
<!-- show-overflow-tooltip-->
|
||||||
<!-- />-->
|
<!-- />-->
|
||||||
<!-- <el-table-column-->
|
<!-- <el-table-column-->
|
||||||
<!-- label="默认值"-->
|
<!-- label="默认值"-->
|
||||||
<!-- prop="defaultValue"-->
|
<!-- prop="defaultValue"-->
|
||||||
<!-- min-width="80px"-->
|
<!-- min-width="80px"-->
|
||||||
<!-- show-overflow-tooltip-->
|
<!-- show-overflow-tooltip-->
|
||||||
<!-- />-->
|
<!-- />-->
|
||||||
<!-- <el-table-column label="操作" width="90px">-->
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
<!-- <template #default="scope">-->
|
<!-- <template #default="scope">-->
|
||||||
<!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
|
<!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
|
||||||
<!-- >编辑</el-button-->
|
<!-- >编辑</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-divider direction="vertical" />-->
|
<!-- <el-divider direction="vertical" />-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- style="color: #ff4d4f"-->
|
<!-- style="color: #ff4d4f"-->
|
||||||
<!-- @click="removeField(scope, scope.$index)"-->
|
<!-- @click="removeField(scope, scope.$index)"-->
|
||||||
<!-- >移除</el-button-->
|
<!-- >移除</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </el-table-column>-->
|
<!-- </el-table-column>-->
|
||||||
<!-- </el-table>-->
|
<!-- </el-table>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- <div class="element-drawer__button">-->
|
<!-- <div class="element-drawer__button">-->
|
||||||
<!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
|
<!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
|
|
||||||
<!--字段配置侧边栏-->
|
<!--字段配置侧边栏-->
|
||||||
<!-- <el-drawer-->
|
<!-- <el-drawer-->
|
||||||
<!-- v-model="fieldModelVisible"-->
|
<!-- v-model="fieldModelVisible"-->
|
||||||
<!-- title="字段配置"-->
|
<!-- title="字段配置"-->
|
||||||
<!-- :size="`${width}px`"-->
|
<!-- :size="`${width}px`"-->
|
||||||
<!-- append-to-body-->
|
<!-- append-to-body-->
|
||||||
<!-- destroy-on-close-->
|
<!-- destroy-on-close-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-form :model="formFieldForm" label-width="90px">-->
|
<!-- <el-form :model="formFieldForm" label-width="90px">-->
|
||||||
<!-- <el-form-item label="字段ID">-->
|
<!-- <el-form-item label="字段ID">-->
|
||||||
<!-- <el-input v-model="formFieldForm.id" clearable />-->
|
<!-- <el-input v-model="formFieldForm.id" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="类型">-->
|
<!-- <el-form-item label="类型">-->
|
||||||
<!-- <el-select-->
|
<!-- <el-select-->
|
||||||
<!-- v-model="formFieldForm.typeType"-->
|
<!-- v-model="formFieldForm.typeType"-->
|
||||||
<!-- placeholder="请选择字段类型"-->
|
<!-- placeholder="请选择字段类型"-->
|
||||||
<!-- clearable-->
|
<!-- clearable-->
|
||||||
<!-- @change="changeFieldTypeType"-->
|
<!-- @change="changeFieldTypeType"-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
|
<!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
|
||||||
<!-- </el-select>-->
|
<!-- </el-select>-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
|
<!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
|
||||||
<!-- <el-input v-model="formFieldForm.type" clearable />-->
|
<!-- <el-input v-model="formFieldForm.type" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="名称">-->
|
<!-- <el-form-item label="名称">-->
|
||||||
<!-- <el-input v-model="formFieldForm.label" clearable />-->
|
<!-- <el-input v-model="formFieldForm.label" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
|
<!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
|
||||||
<!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
|
<!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="默认值">-->
|
<!-- <el-form-item label="默认值">-->
|
||||||
<!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
|
<!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- </el-form>-->
|
<!-- </el-form>-->
|
||||||
|
|
||||||
<!-- <!– 枚举值设置 –>-->
|
<!-- <!– 枚举值设置 –>-->
|
||||||
<!-- <template v-if="formFieldForm.type === 'enum'">-->
|
<!-- <template v-if="formFieldForm.type === 'enum'">-->
|
||||||
<!-- <el-divider key="enum-divider" />-->
|
<!-- <el-divider key="enum-divider" />-->
|
||||||
<!-- <p class="listener-filed__title" key="enum-title">-->
|
<!-- <p class="listener-filed__title" key="enum-title">-->
|
||||||
<!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
|
<!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
|
||||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
|
||||||
<!-- >添加枚举值</el-button-->
|
<!-- >添加枚举值</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </p>-->
|
<!-- </p>-->
|
||||||
<!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
|
<!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
|
||||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
<!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="操作" width="90px">-->
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
<!-- <template #default="scope">-->
|
<!-- <template #default="scope">-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
|
||||||
<!-- >编辑</el-button-->
|
<!-- >编辑</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-divider direction="vertical" />-->
|
<!-- <el-divider direction="vertical" />-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- style="color: #ff4d4f"-->
|
<!-- style="color: #ff4d4f"-->
|
||||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
|
||||||
<!-- >移除</el-button-->
|
<!-- >移除</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </el-table-column>-->
|
<!-- </el-table-column>-->
|
||||||
<!-- </el-table>-->
|
<!-- </el-table>-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
|
|
||||||
<!-- <!– 校验规则 –>-->
|
<!-- <!– 校验规则 –>-->
|
||||||
<!-- <el-divider key="validation-divider" />-->
|
<!-- <el-divider key="validation-divider" />-->
|
||||||
<!-- <p class="listener-filed__title" key="validation-title">-->
|
<!-- <p class="listener-filed__title" key="validation-title">-->
|
||||||
<!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
|
<!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
|
||||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
|
||||||
<!-- >添加约束</el-button-->
|
<!-- >添加约束</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </p>-->
|
<!-- </p>-->
|
||||||
<!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
|
<!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
|
||||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
<!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="操作" width="90px">-->
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
<!-- <template #default="scope">-->
|
<!-- <template #default="scope">-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
|
||||||
<!-- >编辑</el-button-->
|
<!-- >编辑</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-divider direction="vertical" />-->
|
<!-- <el-divider direction="vertical" />-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- style="color: #ff4d4f"-->
|
<!-- style="color: #ff4d4f"-->
|
||||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
|
||||||
<!-- >移除</el-button-->
|
<!-- >移除</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </el-table-column>-->
|
<!-- </el-table-column>-->
|
||||||
<!-- </el-table>-->
|
<!-- </el-table>-->
|
||||||
|
|
||||||
<!-- <!– 表单属性 –>-->
|
<!-- <!– 表单属性 –>-->
|
||||||
<!-- <el-divider key="property-divider" />-->
|
<!-- <el-divider key="property-divider" />-->
|
||||||
<!-- <p class="listener-filed__title" key="property-title">-->
|
<!-- <p class="listener-filed__title" key="property-title">-->
|
||||||
<!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
|
<!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
|
||||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
|
||||||
<!-- >添加属性</el-button-->
|
<!-- >添加属性</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </p>-->
|
<!-- </p>-->
|
||||||
<!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
|
<!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
|
||||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
<!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
|
<!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
|
||||||
<!-- <el-table-column label="操作" width="90px">-->
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
<!-- <template #default="scope">-->
|
<!-- <template #default="scope">-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
|
||||||
<!-- >编辑</el-button-->
|
<!-- >编辑</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-divider direction="vertical" />-->
|
<!-- <el-divider direction="vertical" />-->
|
||||||
<!-- <el-button-->
|
<!-- <el-button-->
|
||||||
<!-- type="primary"-->
|
<!-- type="primary"-->
|
||||||
<!-- link-->
|
<!-- link-->
|
||||||
<!-- style="color: #ff4d4f"-->
|
<!-- style="color: #ff4d4f"-->
|
||||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
|
||||||
<!-- >移除</el-button-->
|
<!-- >移除</el-button-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </el-table-column>-->
|
<!-- </el-table-column>-->
|
||||||
<!-- </el-table>-->
|
<!-- </el-table>-->
|
||||||
|
|
||||||
<!-- <!– 底部按钮 –>-->
|
<!-- <!– 底部按钮 –>-->
|
||||||
<!-- <div class="element-drawer__button">-->
|
<!-- <div class="element-drawer__button">-->
|
||||||
<!-- <el-button>取 消</el-button>-->
|
<!-- <el-button>取 消</el-button>-->
|
||||||
<!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
|
<!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </el-drawer>-->
|
<!-- </el-drawer>-->
|
||||||
|
|
||||||
<!-- <el-dialog-->
|
<!-- <el-dialog-->
|
||||||
<!-- v-model="fieldOptionModelVisible"-->
|
<!-- v-model="fieldOptionModelVisible"-->
|
||||||
<!-- :title="optionModelTitle"-->
|
<!-- :title="optionModelTitle"-->
|
||||||
<!-- width="600px"-->
|
<!-- width="600px"-->
|
||||||
<!-- append-to-body-->
|
<!-- append-to-body-->
|
||||||
<!-- destroy-on-close-->
|
<!-- destroy-on-close-->
|
||||||
<!-- >-->
|
<!-- >-->
|
||||||
<!-- <el-form :model="fieldOptionForm" label-width="96px">-->
|
<!-- <el-form :model="fieldOptionForm" label-width="96px">-->
|
||||||
<!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
|
<!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
|
||||||
<!-- <el-input v-model="fieldOptionForm.id" clearable />-->
|
<!-- <el-input v-model="fieldOptionForm.id" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
|
<!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
|
||||||
<!-- <el-input v-model="fieldOptionForm.name" clearable />-->
|
<!-- <el-input v-model="fieldOptionForm.name" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
|
<!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
|
||||||
<!-- <el-input v-model="fieldOptionForm.config" clearable />-->
|
<!-- <el-input v-model="fieldOptionForm.config" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
|
<!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
|
||||||
<!-- <el-input v-model="fieldOptionForm.value" clearable />-->
|
<!-- <el-input v-model="fieldOptionForm.value" clearable />-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- </el-form>-->
|
<!-- </el-form>-->
|
||||||
<!-- <template #footer>-->
|
<!-- <template #footer>-->
|
||||||
<!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
|
<!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
|
||||||
<!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
|
<!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
<!-- </el-dialog>-->
|
<!-- </el-dialog>-->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getFormSimpleList } from '@/api/bpm-boot/form'
|
import { getFormSimpleList } from '@/api/bpm-boot/form'
|
||||||
|
|
||||||
|
|
||||||
defineOptions({ name: 'ElementForm' })
|
defineOptions({ name: 'ElementForm' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: String,
|
id: String,
|
||||||
type: String
|
type: String
|
||||||
})
|
})
|
||||||
const prefix = inject('prefix')
|
const prefix = inject('prefix')
|
||||||
const width = inject('width')
|
const width = inject('width')
|
||||||
|
|
||||||
const formKey = ref('')
|
const formKey = ref('')
|
||||||
const businessKey = ref('')
|
const businessKey = ref('')
|
||||||
const optionModelTitle = ref('')
|
const optionModelTitle = ref('')
|
||||||
const fieldList = ref<any[]>([])
|
const fieldList = ref<any[]>([])
|
||||||
const formFieldForm = ref<any>({})
|
const formFieldForm = ref<any>({})
|
||||||
const fieldType = ref({
|
const fieldType = ref({
|
||||||
long: '长整型',
|
long: '长整型',
|
||||||
string: '字符串',
|
string: '字符串',
|
||||||
boolean: '布尔类',
|
boolean: '布尔类',
|
||||||
date: '日期类',
|
date: '日期类',
|
||||||
enum: '枚举类',
|
enum: '枚举类',
|
||||||
custom: '自定义类型'
|
custom: '自定义类型'
|
||||||
})
|
})
|
||||||
const formFieldIndex = ref(-1) // 编辑中的字段, -1 为新增
|
const formFieldIndex = ref(-1) // 编辑中的字段, -1 为新增
|
||||||
const formFieldOptionIndex = ref(-1) // 编辑中的字段配置项, -1 为新增
|
const formFieldOptionIndex = ref(-1) // 编辑中的字段配置项, -1 为新增
|
||||||
const fieldModelVisible = ref(false)
|
const fieldModelVisible = ref(false)
|
||||||
const fieldOptionModelVisible = ref(false)
|
const fieldOptionModelVisible = ref(false)
|
||||||
const fieldOptionForm = ref<any>({}) // 当前激活的字段配置项数据
|
const fieldOptionForm = ref<any>({}) // 当前激活的字段配置项数据
|
||||||
const fieldOptionType = ref('') // 当前激活的字段配置项弹窗 类型
|
const fieldOptionType = ref('') // 当前激活的字段配置项弹窗 类型
|
||||||
const fieldEnumList = ref<any[]>([]) // 枚举值列表
|
const fieldEnumList = ref<any[]>([]) // 枚举值列表
|
||||||
const fieldConstraintsList = ref<any[]>([]) // 约束条件列表
|
const fieldConstraintsList = ref<any[]>([]) // 约束条件列表
|
||||||
const fieldPropertiesList = ref<any[]>([]) // 绑定属性列表
|
const fieldPropertiesList = ref<any[]>([]) // 绑定属性列表
|
||||||
const bpmnELement = ref()
|
const bpmnELement = ref()
|
||||||
const elExtensionElements = ref()
|
const elExtensionElements = ref()
|
||||||
const formData = ref()
|
const formData = ref()
|
||||||
const otherExtensions = ref()
|
const otherExtensions = ref()
|
||||||
|
|
||||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||||
const resetFormList = () => {
|
const resetFormList = () => {
|
||||||
bpmnELement.value = bpmnInstances().bpmnElement
|
bpmnELement.value = bpmnInstances().bpmnElement
|
||||||
formKey.value = bpmnELement.value.businessObject.formKey
|
formKey.value = bpmnELement.value.businessObject.formKey
|
||||||
// if (formKey.value?.length > 0) {
|
// if (formKey.value?.length > 0) {
|
||||||
// formKey.value = parseInt(formKey.value)
|
// formKey.value = parseInt(formKey.value)
|
||||||
// }
|
// }
|
||||||
// 获取元素扩展属性 或者 创建扩展属性
|
// 获取元素扩展属性 或者 创建扩展属性
|
||||||
elExtensionElements.value =
|
elExtensionElements.value =
|
||||||
bpmnELement.value.businessObject.get('extensionElements') ||
|
bpmnELement.value.businessObject.get('extensionElements') ||
|
||||||
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
|
||||||
// 获取元素表单配置 或者 创建新的表单配置
|
// 获取元素表单配置 或者 创建新的表单配置
|
||||||
formData.value =
|
formData.value =
|
||||||
elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
|
elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] })
|
bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] })
|
||||||
|
|
||||||
// 业务标识 businessKey, 绑定在 formData 中
|
// 业务标识 businessKey, 绑定在 formData 中
|
||||||
businessKey.value = formData.value.businessKey
|
businessKey.value = formData.value.businessKey
|
||||||
|
|
||||||
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||||
otherExtensions.value = elExtensionElements.value.values.filter(
|
otherExtensions.value = elExtensionElements.value.values.filter(
|
||||||
(ex) => ex.$type !== `${prefix}:FormData`
|
(ex) => ex.$type !== `${prefix}:FormData`
|
||||||
)
|
)
|
||||||
|
|
||||||
// 复制原始值,填充表格
|
// 复制原始值,填充表格
|
||||||
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
|
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
|
||||||
|
|
||||||
// 更新元素扩展属性,避免后续报错
|
// 更新元素扩展属性,避免后续报错
|
||||||
updateElementExtensions()
|
updateElementExtensions()
|
||||||
}
|
}
|
||||||
const updateElementFormKey = () => {
|
const updateElementFormKey = () => {
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||||
formKey: formKey.value
|
formKey: formKey.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const updateElementBusinessKey = () => {
|
const updateElementBusinessKey = () => {
|
||||||
bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnELement.value), formData.value, {
|
bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnELement.value), formData.value, {
|
||||||
businessKey: businessKey.value
|
businessKey: businessKey.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 根据类型调整字段type
|
// 根据类型调整字段type
|
||||||
const changeFieldTypeType = (type) => {
|
const changeFieldTypeType = (type) => {
|
||||||
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
|
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
|
||||||
formFieldForm.value['type'] = type === 'custom' ? '' : type
|
formFieldForm.value['type'] = type === 'custom' ? '' : type
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开字段详情侧边栏
|
// 打开字段详情侧边栏
|
||||||
const openFieldForm = (field, index) => {
|
const openFieldForm = (field, index) => {
|
||||||
formFieldIndex.value = index
|
formFieldIndex.value = index
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
const FieldObject = formData.value.fields[index]
|
const FieldObject = formData.value.fields[index]
|
||||||
formFieldForm.value = JSON.parse(JSON.stringify(field))
|
formFieldForm.value = JSON.parse(JSON.stringify(field))
|
||||||
// 设置自定义类型
|
// 设置自定义类型
|
||||||
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
|
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
|
||||||
formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
|
formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
|
||||||
// 初始化枚举值列表
|
// 初始化枚举值列表
|
||||||
field.type === 'enum' &&
|
field.type === 'enum' &&
|
||||||
(fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
|
(fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
|
||||||
// 初始化约束条件列表
|
// 初始化约束条件列表
|
||||||
fieldConstraintsList.value = JSON.parse(
|
fieldConstraintsList.value = JSON.parse(
|
||||||
JSON.stringify(FieldObject?.validation?.constraints || [])
|
JSON.stringify(FieldObject?.validation?.constraints || [])
|
||||||
)
|
)
|
||||||
// 初始化自定义属性列表
|
// 初始化自定义属性列表
|
||||||
fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
|
fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
|
||||||
} else {
|
} else {
|
||||||
formFieldForm.value = {}
|
formFieldForm.value = {}
|
||||||
// 初始化枚举值列表
|
// 初始化枚举值列表
|
||||||
fieldEnumList.value = []
|
fieldEnumList.value = []
|
||||||
// 初始化约束条件列表
|
// 初始化约束条件列表
|
||||||
fieldConstraintsList.value = []
|
fieldConstraintsList.value = []
|
||||||
// 初始化自定义属性列表
|
// 初始化自定义属性列表
|
||||||
fieldPropertiesList.value = []
|
fieldPropertiesList.value = []
|
||||||
}
|
}
|
||||||
fieldModelVisible.value = true
|
fieldModelVisible.value = true
|
||||||
}
|
}
|
||||||
// 打开字段 某个 配置项 弹窗
|
// 打开字段 某个 配置项 弹窗
|
||||||
const openFieldOptionForm = (option, index, type) => {
|
const openFieldOptionForm = (option, index, type) => {
|
||||||
fieldOptionModelVisible.value = true
|
fieldOptionModelVisible.value = true
|
||||||
fieldOptionType.value = type
|
fieldOptionType.value = type
|
||||||
formFieldOptionIndex.value = index
|
formFieldOptionIndex.value = index
|
||||||
if (type === 'property') {
|
if (type === 'property') {
|
||||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||||
return (optionModelTitle.value = '属性配置')
|
return (optionModelTitle.value = '属性配置')
|
||||||
}
|
}
|
||||||
if (type === 'enum') {
|
if (type === 'enum') {
|
||||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||||
return (optionModelTitle.value = '枚举值配置')
|
return (optionModelTitle.value = '枚举值配置')
|
||||||
}
|
}
|
||||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||||
return (optionModelTitle.value = '约束条件配置')
|
return (optionModelTitle.value = '约束条件配置')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存字段 某个 配置项
|
// 保存字段 某个 配置项
|
||||||
const saveFieldOption = () => {
|
const saveFieldOption = () => {
|
||||||
if (formFieldOptionIndex.value === -1) {
|
if (formFieldOptionIndex.value === -1) {
|
||||||
if (fieldOptionType.value === 'property') {
|
if (fieldOptionType.value === 'property') {
|
||||||
fieldPropertiesList.value.push(fieldOptionForm.value)
|
fieldPropertiesList.value.push(fieldOptionForm.value)
|
||||||
}
|
}
|
||||||
if (fieldOptionType.value === 'constraint') {
|
if (fieldOptionType.value === 'constraint') {
|
||||||
fieldConstraintsList.value.push(fieldOptionForm.value)
|
fieldConstraintsList.value.push(fieldOptionForm.value)
|
||||||
}
|
}
|
||||||
if (fieldOptionType.value === 'enum') {
|
if (fieldOptionType.value === 'enum') {
|
||||||
fieldEnumList.value.push(fieldOptionForm.value)
|
fieldEnumList.value.push(fieldOptionForm.value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fieldOptionType.value === 'property' &&
|
fieldOptionType.value === 'property' &&
|
||||||
fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||||
fieldOptionType.value === 'constraint' &&
|
fieldOptionType.value === 'constraint' &&
|
||||||
fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||||
fieldOptionType.value === 'enum' &&
|
fieldOptionType.value === 'enum' &&
|
||||||
fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||||
}
|
}
|
||||||
fieldOptionModelVisible.value = false
|
fieldOptionModelVisible.value = false
|
||||||
fieldOptionForm.value = {}
|
fieldOptionForm.value = {}
|
||||||
}
|
}
|
||||||
// 保存字段配置
|
// 保存字段配置
|
||||||
const saveField = () => {
|
const saveField = () => {
|
||||||
const { id, type, label, defaultValue, datePattern } = formFieldForm.value
|
const { id, type, label, defaultValue, datePattern } = formFieldForm.value
|
||||||
const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, { id, type, label })
|
const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, { id, type, label })
|
||||||
defaultValue && (Field.defaultValue = defaultValue)
|
defaultValue && (Field.defaultValue = defaultValue)
|
||||||
datePattern && (Field.datePattern = datePattern)
|
datePattern && (Field.datePattern = datePattern)
|
||||||
// 构建属性
|
// 构建属性
|
||||||
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
|
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
|
||||||
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
|
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
|
||||||
return bpmnInstances().moddle.create(`${prefix}:Property`, {
|
return bpmnInstances().moddle.create(`${prefix}:Property`, {
|
||||||
id: fp.id,
|
id: fp.id,
|
||||||
value: fp.value
|
value: fp.value
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
|
Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
|
||||||
values: fieldPropertyList
|
values: fieldPropertyList
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 构建校验规则
|
// 构建校验规则
|
||||||
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
|
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
|
||||||
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
|
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
|
||||||
return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
|
return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
|
||||||
name: fc.name,
|
name: fc.name,
|
||||||
config: fc.config
|
config: fc.config
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
|
Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
|
||||||
constraints: fieldConstraintList
|
constraints: fieldConstraintList
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 构建枚举值
|
// 构建枚举值
|
||||||
if (fieldEnumList.value && fieldEnumList.value.length) {
|
if (fieldEnumList.value && fieldEnumList.value.length) {
|
||||||
Field.values = fieldEnumList.value.map((fe) => {
|
Field.values = fieldEnumList.value.map((fe) => {
|
||||||
return bpmnInstances().moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
|
return bpmnInstances().moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 更新数组 与 表单配置实例
|
// 更新数组 与 表单配置实例
|
||||||
if (formFieldIndex.value === -1) {
|
if (formFieldIndex.value === -1) {
|
||||||
fieldList.value.push(formFieldForm.value)
|
fieldList.value.push(formFieldForm.value)
|
||||||
formData.value.fields.push(Field)
|
formData.value.fields.push(Field)
|
||||||
} else {
|
} else {
|
||||||
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
|
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
|
||||||
formData.value.fields.splice(formFieldIndex.value, 1, Field)
|
formData.value.fields.splice(formFieldIndex.value, 1, Field)
|
||||||
}
|
}
|
||||||
updateElementExtensions()
|
updateElementExtensions()
|
||||||
fieldModelVisible.value = false
|
fieldModelVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除某个 字段的 配置项
|
// 移除某个 字段的 配置项
|
||||||
const removeFieldOptionItem = (option, index, type) => {
|
const removeFieldOptionItem = (option, index, type) => {
|
||||||
// console.log(option, 'option')
|
// console.log(option, 'option')
|
||||||
if (type === 'property') {
|
if (type === 'property') {
|
||||||
fieldPropertiesList.value.splice(index, 1)
|
fieldPropertiesList.value.splice(index, 1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (type === 'enum') {
|
if (type === 'enum') {
|
||||||
fieldEnumList.value.splice(index, 1)
|
fieldEnumList.value.splice(index, 1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fieldConstraintsList.value.splice(index, 1)
|
fieldConstraintsList.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
// 移除 字段
|
// 移除 字段
|
||||||
const removeField = (field, index) => {
|
const removeField = (field, index) => {
|
||||||
console.log(field, 'field')
|
console.log(field, 'field')
|
||||||
fieldList.value.splice(index, 1)
|
fieldList.value.splice(index, 1)
|
||||||
formData.value.fields.splice(index, 1)
|
formData.value.fields.splice(index, 1)
|
||||||
updateElementExtensions()
|
updateElementExtensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateElementExtensions = () => {
|
const updateElementExtensions = () => {
|
||||||
// 更新回扩展元素
|
// 更新回扩展元素
|
||||||
const newElExtensionElements = bpmnInstances().moddle.create(`bpmn:ExtensionElements`, {
|
const newElExtensionElements = bpmnInstances().moddle.create(`bpmn:ExtensionElements`, {
|
||||||
values: otherExtensions.value.concat(formData.value)
|
values: otherExtensions.value.concat(formData.value)
|
||||||
})
|
})
|
||||||
// 更新到元素上
|
// 更新到元素上
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||||
extensionElements: newElExtensionElements
|
extensionElements: newElExtensionElements
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const formList = ref([]) // 流程表单的下拉框的数据
|
const formList = ref([]) // 流程表单的下拉框的数据
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getFormSimpleList().then(res => {
|
await getFormSimpleList().then(res => {
|
||||||
formList.value = res.data
|
formList.value = res.data
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.id,
|
() => props.id,
|
||||||
(val) => {
|
(val) => {
|
||||||
val &&
|
val &&
|
||||||
val.length &&
|
val.length &&
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
resetFormList()
|
resetFormList()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,463 +1,459 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class='panel-tab__content'>
|
<div class='panel-tab__content'>
|
||||||
<el-table :data='elementListenersList' size='small' border>
|
<el-table :data='elementListenersList' size='small' border>
|
||||||
<el-table-column label='序号' width='80px' type='index' />
|
<el-table-column label='序号' width='80px' type='index' />
|
||||||
<el-table-column label='事件类型' min-width='100px' prop='event' />
|
<el-table-column label='事件类型' min-width='100px' prop='event' />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label='监听器类型'
|
label='监听器类型'
|
||||||
min-width='100px'
|
min-width='100px'
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
:formatter='(row) => listenerTypeObject[row.listenerType]'
|
:formatter='(row) => listenerTypeObject[row.listenerType]'
|
||||||
/>
|
/>
|
||||||
<el-table-column label='操作' width='100px'>
|
<el-table-column label='操作' width='100px'>
|
||||||
<template #default='scope'>
|
<template #default='scope'>
|
||||||
<el-button size='small' link @click='openListenerForm(scope.row, scope.$index)'
|
<el-button size='small' link @click='openListenerForm(scope.row, scope.$index)'
|
||||||
>编辑
|
>编辑
|
||||||
</el-button
|
</el-button
|
||||||
>
|
>
|
||||||
<el-divider direction='vertical' />
|
<el-divider direction='vertical' />
|
||||||
<el-button size='small' link style='color: #ff4d4f' @click='removeListener(scope.$index)'
|
<el-button size='small' link style='color: #ff4d4f' @click='removeListener(scope.$index)'
|
||||||
>移除
|
>移除
|
||||||
</el-button
|
</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class='element-drawer__button'>
|
<div class='element-drawer__button'>
|
||||||
<XButton
|
<XButton
|
||||||
type="primary"
|
type="primary"
|
||||||
preIcon="ep:plus"
|
preIcon="ep:plus"
|
||||||
title="添加监听器"
|
title="添加监听器"
|
||||||
size="small"
|
size="small"
|
||||||
@click="openListenerForm(null)"
|
@click="openListenerForm(null)"
|
||||||
/>
|
/>
|
||||||
<!-- <Plus type='primary'-->
|
<!-- <Plus type='primary'-->
|
||||||
<!-- title='添加监听器'-->
|
<!-- title='添加监听器'-->
|
||||||
<!-- size='small'-->
|
<!-- size='small'-->
|
||||||
<!-- @click='openListenerForm(null)' />-->
|
<!-- @click='openListenerForm(null)' />-->
|
||||||
<XButton
|
<XButton
|
||||||
type="success"
|
type="success"
|
||||||
preIcon="ep:select"
|
preIcon="ep:select"
|
||||||
title="选择监听器"
|
title="选择监听器"
|
||||||
size="small"
|
size="small"
|
||||||
@click="openProcessListenerDialog"
|
@click="openProcessListenerDialog"
|
||||||
/>
|
/>
|
||||||
<!-- <Select-->
|
<!-- <Select-->
|
||||||
<!-- type='success'-->
|
<!-- type='success'-->
|
||||||
<!-- title='选择监听器'-->
|
<!-- title='选择监听器'-->
|
||||||
<!-- size='small'-->
|
<!-- size='small'-->
|
||||||
<!-- @click='openProcessListenerDialog'-->
|
<!-- @click='openProcessListenerDialog'-->
|
||||||
<!-- />-->
|
<!-- />-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 监听器 编辑/创建 部分 -->
|
<!-- 监听器 编辑/创建 部分 -->
|
||||||
<el-drawer
|
<el-drawer
|
||||||
v-model='listenerFormModelVisible'
|
v-model='listenerFormModelVisible'
|
||||||
title='执行监听器'
|
title='执行监听器'
|
||||||
:size='`${width}px`'
|
:size='`${width}px`'
|
||||||
append-to-body
|
append-to-body
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
>
|
>
|
||||||
<el-form :model='listenerForm' label-width='96px' ref='listenerFormRef'>
|
<el-form :model='listenerForm' label-width='96px' ref='listenerFormRef'>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='事件类型'
|
label='事件类型'
|
||||||
prop='event'
|
prop='event'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model='listenerForm.event'>
|
<el-select v-model='listenerForm.event' filterable>
|
||||||
<el-option label='start' value='start' />
|
<el-option label='start' value='start' />
|
||||||
<el-option label='end' value='end' />
|
<el-option label='end' value='end' />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='监听器类型'
|
label='监听器类型'
|
||||||
prop='listenerType'
|
prop='listenerType'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model='listenerForm.listenerType'>
|
<el-select v-model='listenerForm.listenerType' filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for='i in Object.keys(listenerTypeObject)'
|
v-for='i in Object.keys(listenerTypeObject)'
|
||||||
:key='i'
|
:key='i'
|
||||||
:label='listenerTypeObject[i]'
|
:label='listenerTypeObject[i]'
|
||||||
:value='i'
|
:value='i'
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerForm.listenerType === 'classListener'"
|
v-if="listenerForm.listenerType === 'classListener'"
|
||||||
label='Java类'
|
label='Java类'
|
||||||
prop='class'
|
prop='class'
|
||||||
key='listener-class'
|
key='listener-class'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.class' clearable />
|
<el-input v-model='listenerForm.class' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerForm.listenerType === 'expressionListener'"
|
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||||
label='表达式'
|
label='表达式'
|
||||||
prop='expression'
|
prop='expression'
|
||||||
key='listener-expression'
|
key='listener-expression'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.expression' clearable />
|
<el-input v-model='listenerForm.expression' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||||
label='代理表达式'
|
label='代理表达式'
|
||||||
prop='delegateExpression'
|
prop='delegateExpression'
|
||||||
key='listener-delegate'
|
key='listener-delegate'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.delegateExpression' clearable />
|
<el-input v-model='listenerForm.delegateExpression' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='脚本格式'
|
label='脚本格式'
|
||||||
prop='scriptFormat'
|
prop='scriptFormat'
|
||||||
key='listener-script-format'
|
key='listener-script-format'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.scriptFormat' clearable />
|
<el-input v-model='listenerForm.scriptFormat' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='脚本类型'
|
label='脚本类型'
|
||||||
prop='scriptType'
|
prop='scriptType'
|
||||||
key='listener-script-type'
|
key='listener-script-type'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||||
>
|
>
|
||||||
<el-select v-model='listenerForm.scriptType'>
|
<el-select v-model='listenerForm.scriptType' filterable>
|
||||||
<el-option label='内联脚本' value='inlineScript' />
|
<el-option label='内联脚本' value='inlineScript' />
|
||||||
<el-option label='外部脚本' value='externalScript' />
|
<el-option label='外部脚本' value='externalScript' />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerForm.scriptType === 'inlineScript'"
|
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||||
label='脚本内容'
|
label='脚本内容'
|
||||||
prop='value'
|
prop='value'
|
||||||
key='listener-script'
|
key='listener-script'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.value' clearable />
|
<el-input v-model='listenerForm.value' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerForm.scriptType === 'externalScript'"
|
v-if="listenerForm.scriptType === 'externalScript'"
|
||||||
label='资源地址'
|
label='资源地址'
|
||||||
prop='resource'
|
prop='resource'
|
||||||
key='listener-resource'
|
key='listener-resource'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerForm.resource' clearable />
|
<el-input v-model='listenerForm.resource' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-divider />
|
<el-divider />
|
||||||
<p class='listener-filed__title'>
|
<p class='listener-filed__title'>
|
||||||
<span><Menu />注入字段:</span>
|
<span><Menu />注入字段:</span>
|
||||||
<XButton type='primary' @click='openListenerFieldForm(null)' title='添加字段' />
|
<XButton type='primary' @click='openListenerFieldForm(null)' title='添加字段' />
|
||||||
</p>
|
</p>
|
||||||
<el-table
|
<el-table
|
||||||
:data='fieldsListOfListener'
|
:data='fieldsListOfListener'
|
||||||
size='small'
|
size='small'
|
||||||
max-height='240'
|
max-height='240'
|
||||||
fit
|
fit
|
||||||
border
|
border
|
||||||
style='flex: none'
|
style='flex: none'
|
||||||
>
|
>
|
||||||
<el-table-column label='序号' width='80px' type='index' />
|
<el-table-column label='序号' width='80px' type='index' />
|
||||||
<el-table-column label='字段名称' min-width='100px' prop='name' />
|
<el-table-column label='字段名称' min-width='100px' prop='name' />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label='字段类型'
|
label='字段类型'
|
||||||
min-width='80px'
|
min-width='80px'
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
:formatter='(row) => fieldTypeObject[row.fieldType]'
|
:formatter='(row) => fieldTypeObject[row.fieldType]'
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label='字段值/表达式'
|
label='字段值/表达式'
|
||||||
min-width='100px'
|
min-width='100px'
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
:formatter='(row) => row.string || row.expression'
|
:formatter='(row) => row.string || row.expression'
|
||||||
/>
|
/>
|
||||||
<el-table-column label='操作' width='130px'>
|
<el-table-column label='操作' width='130px'>
|
||||||
<template #default='scope'>
|
<template #default='scope'>
|
||||||
<el-button size='small' link @click='openListenerFieldForm(scope.row, scope.$index)'
|
<el-button size='small' link @click='openListenerFieldForm(scope.row, scope.$index)'
|
||||||
>编辑
|
>编辑
|
||||||
</el-button
|
</el-button
|
||||||
>
|
>
|
||||||
<el-divider direction='vertical' />
|
<el-divider direction='vertical' />
|
||||||
<el-button
|
<el-button
|
||||||
size='small'
|
size='small'
|
||||||
link
|
link
|
||||||
style='color: #ff4d4f'
|
style='color: #ff4d4f'
|
||||||
@click='removeListenerField(scope.$index)'
|
@click='removeListenerField(scope.$index)'
|
||||||
>移除
|
>移除
|
||||||
</el-button
|
</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<div class='element-drawer__button'>
|
<div class='element-drawer__button'>
|
||||||
<el-button @click='listenerFormModelVisible = false'>取 消</el-button>
|
<el-button @click='listenerFormModelVisible = false'>取 消</el-button>
|
||||||
<el-button type='primary' @click='saveListenerConfig'>保 存</el-button>
|
<el-button type='primary' @click='saveListenerConfig'>保 存</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
||||||
<!-- 注入西段 编辑/创建 部分 -->
|
<!-- 注入西段 编辑/创建 部分 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
title='字段配置'
|
title='字段配置'
|
||||||
v-model='listenerFieldFormModelVisible'
|
v-model='listenerFieldFormModelVisible'
|
||||||
width='600px'
|
width='600px'
|
||||||
append-to-body
|
append-to-body
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
:model='listenerFieldForm'
|
:model='listenerFieldForm'
|
||||||
label-width='96spx'
|
label-width='96spx'
|
||||||
ref='listenerFieldFormRef'
|
ref='listenerFieldFormRef'
|
||||||
style='height: 136px'
|
style='height: 136px'
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='字段名称:'
|
label='字段名称:'
|
||||||
prop='name'
|
prop='name'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerFieldForm.name' clearable />
|
<el-input v-model='listenerFieldForm.name' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label='字段类型:'
|
label='字段类型:'
|
||||||
prop='fieldType'
|
prop='fieldType'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model='listenerFieldForm.fieldType'>
|
<el-select v-model='listenerFieldForm.fieldType' filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for='i in Object.keys(fieldTypeObject)'
|
v-for='i in Object.keys(fieldTypeObject)'
|
||||||
:key='i'
|
:key='i'
|
||||||
:label='fieldTypeObject[i]'
|
:label='fieldTypeObject[i]'
|
||||||
:value='i'
|
:value='i'
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerFieldForm.fieldType === 'string'"
|
v-if="listenerFieldForm.fieldType === 'string'"
|
||||||
label='字段值:'
|
label='字段值:'
|
||||||
prop='string'
|
prop='string'
|
||||||
key='field-string'
|
key='field-string'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerFieldForm.string' clearable />
|
<el-input v-model='listenerFieldForm.string' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="listenerFieldForm.fieldType === 'expression'"
|
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||||
label='表达式:'
|
label='表达式:'
|
||||||
prop='expression'
|
prop='expression'
|
||||||
key='field-expression'
|
key='field-expression'
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-input v-model='listenerFieldForm.expression' clearable />
|
<el-input v-model='listenerFieldForm.expression' clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button size='small' @click='listenerFieldFormModelVisible = false'>取 消</el-button>
|
<el-button size='small' @click='listenerFieldFormModelVisible = false'>取 消</el-button>
|
||||||
<el-button size='small' type='primary' @click='saveListenerFiled'>确 定</el-button>
|
<el-button size='small' type='primary' @click='saveListenerFiled'>确 定</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 选择弹窗 -->
|
<!-- 选择弹窗 -->
|
||||||
<ProcessListenerDialog ref='processListenerDialogRef' @select='selectProcessListener' />
|
<ProcessListenerDialog ref='processListenerDialogRef' @select='selectProcessListener' />
|
||||||
</template>
|
</template>
|
||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import XButton from '@/components/XButton/src/XButton.vue'
|
import XButton from '@/components/XButton/src/XButton.vue'
|
||||||
import { Plus, Select, Menu } from '@element-plus/icons-vue'
|
import { Plus, Select, Menu } from '@element-plus/icons-vue'
|
||||||
import { createListenerObject, updateElementExtensions } from '../../utils'
|
import { createListenerObject, updateElementExtensions } from '../../utils'
|
||||||
import {
|
import {
|
||||||
initListenerType,
|
initListenerType,
|
||||||
initListenerForm,
|
initListenerForm,
|
||||||
listenerType,
|
listenerType,
|
||||||
fieldType,
|
fieldType,
|
||||||
initListenerForm2
|
initListenerForm2
|
||||||
} from './utilSelf'
|
} from './utilSelf'
|
||||||
import ProcessListenerDialog from './ProcessListenerDialog.vue'
|
import ProcessListenerDialog from './ProcessListenerDialog.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'ElementListeners' })
|
defineOptions({ name: 'ElementListeners' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: String,
|
id: String,
|
||||||
type: String
|
type: String
|
||||||
})
|
})
|
||||||
const prefix = inject('prefix')
|
const prefix = inject('prefix')
|
||||||
const width = inject('width')
|
const width = inject('width')
|
||||||
const elementListenersList = ref<any[]>([]) // 监听器列表
|
const elementListenersList = ref<any[]>([]) // 监听器列表
|
||||||
const listenerForm = ref<any>({}) // 监听器详情表单
|
const listenerForm = ref<any>({}) // 监听器详情表单
|
||||||
const listenerFormModelVisible = ref(false) // 监听器 编辑 侧边栏显示状态
|
const listenerFormModelVisible = ref(false) // 监听器 编辑 侧边栏显示状态
|
||||||
const fieldsListOfListener = ref<any[]>([])
|
const fieldsListOfListener = ref<any[]>([])
|
||||||
const listenerFieldForm = ref<any>({}) // 监听器 注入字段 详情表单
|
const listenerFieldForm = ref<any>({}) // 监听器 注入字段 详情表单
|
||||||
const listenerFieldFormModelVisible = ref(false) // 监听器 注入字段表单弹窗 显示状态
|
const listenerFieldFormModelVisible = ref(false) // 监听器 注入字段表单弹窗 显示状态
|
||||||
const editingListenerIndex = ref(-1) // 监听器所在下标,-1 为新增
|
const editingListenerIndex = ref(-1) // 监听器所在下标,-1 为新增
|
||||||
const editingListenerFieldIndex = ref(-1) // 字段所在下标,-1 为新增
|
const editingListenerFieldIndex = ref(-1) // 字段所在下标,-1 为新增
|
||||||
const listenerTypeObject = ref(listenerType)
|
const listenerTypeObject = ref(listenerType)
|
||||||
const fieldTypeObject = ref(fieldType)
|
const fieldTypeObject = ref(fieldType)
|
||||||
const bpmnElement = ref()
|
const bpmnElement = ref()
|
||||||
const otherExtensionList = ref()
|
const otherExtensionList = ref()
|
||||||
const bpmnElementListeners = ref()
|
const bpmnElementListeners = ref()
|
||||||
const listenerFormRef = ref()
|
const listenerFormRef = ref()
|
||||||
const listenerFieldFormRef = ref()
|
const listenerFieldFormRef = ref()
|
||||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||||
|
|
||||||
const resetListenersList = () => {
|
const resetListenersList = () => {
|
||||||
bpmnElement.value = bpmnInstances().bpmnElement
|
bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
otherExtensionList.value = []
|
otherExtensionList.value = []
|
||||||
bpmnElementListeners.value =
|
bpmnElementListeners.value =
|
||||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
(ex) => ex.$type === `${prefix}:ExecutionListener`
|
(ex) => ex.$type === `${prefix}:ExecutionListener`
|
||||||
) ?? []
|
) ?? []
|
||||||
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
||||||
initListenerType(listener)
|
initListenerType(listener)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// 打开 监听器详情 侧边栏
|
// 打开 监听器详情 侧边栏
|
||||||
const openListenerForm = (listener, index?) => {
|
const openListenerForm = (listener, index?) => {
|
||||||
// debugger
|
if (listener) {
|
||||||
if (listener) {
|
listenerForm.value = initListenerForm(listener)
|
||||||
listenerForm.value = initListenerForm(listener)
|
editingListenerIndex.value = index
|
||||||
editingListenerIndex.value = index
|
} else {
|
||||||
} else {
|
listenerForm.value = {}
|
||||||
listenerForm.value = {}
|
editingListenerIndex.value = -1 // 标记为新增
|
||||||
editingListenerIndex.value = -1 // 标记为新增
|
}
|
||||||
}
|
if (listener && listener.fields) {
|
||||||
if (listener && listener.fields) {
|
fieldsListOfListener.value = listener.fields.map((field) => ({
|
||||||
fieldsListOfListener.value = listener.fields.map((field) => ({
|
...field,
|
||||||
...field,
|
fieldType: field.string ? 'string' : 'expression'
|
||||||
fieldType: field.string ? 'string' : 'expression'
|
}))
|
||||||
}))
|
} else {
|
||||||
} else {
|
fieldsListOfListener.value = []
|
||||||
fieldsListOfListener.value = []
|
listenerForm.value['fields'] = []
|
||||||
listenerForm.value['fields'] = []
|
}
|
||||||
}
|
// 打开侧边栏并清楚验证状态
|
||||||
// 打开侧边栏并清楚验证状态
|
listenerFormModelVisible.value = true
|
||||||
listenerFormModelVisible.value = true
|
nextTick(() => {
|
||||||
nextTick(() => {
|
if (listenerFormRef.value) {
|
||||||
if (listenerFormRef.value) {
|
listenerFormRef.value.clearValidate()
|
||||||
listenerFormRef.value.clearValidate()
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
// 打开监听器字段编辑弹窗
|
||||||
// 打开监听器字段编辑弹窗
|
const openListenerFieldForm = (field, index?) => {
|
||||||
const openListenerFieldForm = (field, index?) => {
|
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
||||||
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
editingListenerFieldIndex.value = field ? index : -1
|
||||||
editingListenerFieldIndex.value = field ? index : -1
|
listenerFieldFormModelVisible.value = true
|
||||||
listenerFieldFormModelVisible.value = true
|
nextTick(() => {
|
||||||
nextTick(() => {
|
if (listenerFieldFormRef.value) {
|
||||||
if (listenerFieldFormRef.value) {
|
listenerFieldFormRef.value.clearValidate()
|
||||||
listenerFieldFormRef.value.clearValidate()
|
}
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}
|
// 保存监听器注入字段
|
||||||
// 保存监听器注入字段
|
const saveListenerFiled = async () => {
|
||||||
const saveListenerFiled = async () => {
|
let validateStatus = await listenerFieldFormRef.value.validate()
|
||||||
// debugger
|
if (!validateStatus) return // 验证不通过直接返回
|
||||||
let validateStatus = await listenerFieldFormRef.value.validate()
|
if (editingListenerFieldIndex.value === -1) {
|
||||||
if (!validateStatus) return // 验证不通过直接返回
|
fieldsListOfListener.value.push(listenerFieldForm.value)
|
||||||
if (editingListenerFieldIndex.value === -1) {
|
listenerForm.value.fields.push(listenerFieldForm.value)
|
||||||
fieldsListOfListener.value.push(listenerFieldForm.value)
|
} else {
|
||||||
listenerForm.value.fields.push(listenerFieldForm.value)
|
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||||
} else {
|
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||||
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
}
|
||||||
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
listenerFieldFormModelVisible.value = false
|
||||||
}
|
nextTick(() => {
|
||||||
listenerFieldFormModelVisible.value = false
|
listenerFieldForm.value = {}
|
||||||
nextTick(() => {
|
})
|
||||||
listenerFieldForm.value = {}
|
}
|
||||||
})
|
// 移除监听器字段
|
||||||
}
|
const removeListenerField = (index) => {
|
||||||
// 移除监听器字段
|
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||||
const removeListenerField = (index) => {
|
confirmButtonText: '确 认',
|
||||||
// debugger
|
cancelButtonText: '取 消'
|
||||||
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
})
|
||||||
confirmButtonText: '确 认',
|
.then(() => {
|
||||||
cancelButtonText: '取 消'
|
fieldsListOfListener.value.splice(index, 1)
|
||||||
})
|
listenerForm.value.fields.splice(index, 1)
|
||||||
.then(() => {
|
})
|
||||||
fieldsListOfListener.value.splice(index, 1)
|
.catch(() => console.info('操作取消'))
|
||||||
listenerForm.value.fields.splice(index, 1)
|
}
|
||||||
})
|
// 移除监听器
|
||||||
.catch(() => console.info('操作取消'))
|
const removeListener = (index) => {
|
||||||
}
|
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||||
// 移除监听器
|
confirmButtonText: '确 认',
|
||||||
const removeListener = (index) => {
|
cancelButtonText: '取 消'
|
||||||
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
})
|
||||||
confirmButtonText: '确 认',
|
.then(() => {
|
||||||
cancelButtonText: '取 消'
|
bpmnElementListeners.value.splice(index, 1)
|
||||||
})
|
elementListenersList.value.splice(index, 1)
|
||||||
.then(() => {
|
updateElementExtensions(
|
||||||
bpmnElementListeners.value.splice(index, 1)
|
bpmnElement.value,
|
||||||
elementListenersList.value.splice(index, 1)
|
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||||
updateElementExtensions(
|
)
|
||||||
bpmnElement.value,
|
})
|
||||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
.catch(() => console.info('操作取消'))
|
||||||
)
|
}
|
||||||
})
|
// 保存监听器配置
|
||||||
.catch(() => console.info('操作取消'))
|
const saveListenerConfig = async () => {
|
||||||
}
|
let validateStatus = await listenerFormRef.value.validate()
|
||||||
// 保存监听器配置
|
if (!validateStatus) return // 验证不通过直接返回
|
||||||
const saveListenerConfig = async () => {
|
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
|
||||||
// debugger
|
if (editingListenerIndex.value === -1) {
|
||||||
let validateStatus = await listenerFormRef.value.validate()
|
bpmnElementListeners.value.push(listenerObject)
|
||||||
if (!validateStatus) return // 验证不通过直接返回
|
elementListenersList.value.push(listenerForm.value)
|
||||||
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
|
} else {
|
||||||
if (editingListenerIndex.value === -1) {
|
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
||||||
bpmnElementListeners.value.push(listenerObject)
|
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
||||||
elementListenersList.value.push(listenerForm.value)
|
}
|
||||||
} else {
|
// 保存其他配置
|
||||||
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
otherExtensionList.value =
|
||||||
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
}
|
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
||||||
// 保存其他配置
|
) ?? []
|
||||||
otherExtensionList.value =
|
updateElementExtensions(
|
||||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
bpmnElement.value,
|
||||||
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||||
) ?? []
|
)
|
||||||
updateElementExtensions(
|
// 4. 隐藏侧边栏
|
||||||
bpmnElement.value,
|
listenerFormModelVisible.value = false
|
||||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
listenerForm.value = {}
|
||||||
)
|
}
|
||||||
// 4. 隐藏侧边栏
|
|
||||||
listenerFormModelVisible.value = false
|
// 打开监听器弹窗
|
||||||
listenerForm.value = {}
|
const processListenerDialogRef = ref()
|
||||||
}
|
const openProcessListenerDialog = async () => {
|
||||||
|
processListenerDialogRef.value.open('execution')
|
||||||
// 打开监听器弹窗
|
}
|
||||||
const processListenerDialogRef = ref()
|
const selectProcessListener = (listener) => {
|
||||||
const openProcessListenerDialog = async () => {
|
const listenerForm = initListenerForm2(listener)
|
||||||
processListenerDialogRef.value.open('execution')
|
const listenerObject = createListenerObject(listenerForm, false, prefix)
|
||||||
}
|
bpmnElementListeners.value.push(listenerObject)
|
||||||
const selectProcessListener = (listener) => {
|
elementListenersList.value.push(listenerForm)
|
||||||
const listenerForm = initListenerForm2(listener)
|
|
||||||
const listenerObject = createListenerObject(listenerForm, false, prefix)
|
// 保存其他配置
|
||||||
bpmnElementListeners.value.push(listenerObject)
|
otherExtensionList.value =
|
||||||
elementListenersList.value.push(listenerForm)
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
||||||
// 保存其他配置
|
) ?? []
|
||||||
otherExtensionList.value =
|
updateElementExtensions(
|
||||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
bpmnElement.value,
|
||||||
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||||
) ?? []
|
)
|
||||||
updateElementExtensions(
|
}
|
||||||
bpmnElement.value,
|
|
||||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
watch(
|
||||||
)
|
() => props.id,
|
||||||
}
|
(val) => {
|
||||||
|
val &&
|
||||||
watch(
|
val.length &&
|
||||||
() => props.id,
|
nextTick(() => {
|
||||||
(val) => {
|
resetListenersList()
|
||||||
val &&
|
})
|
||||||
val.length &&
|
},
|
||||||
nextTick(() => {
|
{ immediate: true }
|
||||||
resetListenersList()
|
)
|
||||||
})
|
</script>
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
prop="event"
|
prop="event"
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model="listenerForm.event">
|
<el-select v-model="listenerForm.event" filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="i in Object.keys(listenerEventTypeObject)"
|
v-for="i in Object.keys(listenerEventTypeObject)"
|
||||||
:key="i"
|
:key="i"
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
prop="listenerType"
|
prop="listenerType"
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model="listenerForm.listenerType">
|
<el-select v-model="listenerForm.listenerType" filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="i in Object.keys(listenerTypeObject)"
|
v-for="i in Object.keys(listenerTypeObject)"
|
||||||
:key="i"
|
:key="i"
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
key="listener-script-type"
|
key="listener-script-type"
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||||
>
|
>
|
||||||
<el-select v-model="listenerForm.scriptType">
|
<el-select v-model="listenerForm.scriptType" filterable>
|
||||||
<el-option label="内联脚本" value="inlineScript" />
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
<el-option label="外部脚本" value="externalScript" />
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
|
|
||||||
<template v-if="listenerForm.event === 'timeout'">
|
<template v-if="listenerForm.event === 'timeout'">
|
||||||
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType">
|
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType">
|
||||||
<el-select v-model="listenerForm.eventDefinitionType">
|
<el-select v-model="listenerForm.eventDefinitionType" filterable>
|
||||||
<el-option label="统计时间" value="date" />
|
<el-option label="统计时间" value="date" />
|
||||||
<el-option label="持续时长" value="duration" />
|
<el-option label="持续时长" value="duration" />
|
||||||
<el-option label="循环" value="cycle" />
|
<el-option label="循环" value="cycle" />
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
prop="fieldType"
|
prop="fieldType"
|
||||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
>
|
>
|
||||||
<el-select v-model="listenerFieldForm.fieldType">
|
<el-select v-model="listenerFieldForm.fieldType" filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="i in Object.keys(fieldTypeObject)"
|
v-for="i in Object.keys(fieldTypeObject)"
|
||||||
:key="i"
|
:key="i"
|
||||||
|
|||||||
@@ -1,280 +1,280 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="panel-tab__content">
|
<div class="panel-tab__content">
|
||||||
<el-form label-width="90px">
|
<el-form label-width="90px">
|
||||||
<el-form-item label="快捷配置">
|
<el-form-item label="快捷配置">
|
||||||
<el-button size="small" @click="changeConfig('依次审批')">依次审批</el-button>
|
<el-button size="small" @click="changeConfig('依次审批')">依次审批</el-button>
|
||||||
<el-button size="small" @click="changeConfig('会签')">会签</el-button>
|
<el-button size="small" @click="changeConfig('会签')">会签</el-button>
|
||||||
<el-button size="small" @click="changeConfig('或签')">或签</el-button>
|
<el-button size="small" @click="changeConfig('或签')">或签</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="会签类型">
|
<el-form-item label="会签类型">
|
||||||
<el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType">
|
<el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType" filterable>
|
||||||
<el-option label="并行多重事件" value="ParallelMultiInstance" />
|
<el-option label="并行多重事件" value="ParallelMultiInstance" />
|
||||||
<el-option label="时序多重事件" value="SequentialMultiInstance" />
|
<el-option label="时序多重事件" value="SequentialMultiInstance" />
|
||||||
<el-option label="无" value="Null" />
|
<el-option label="无" value="Null" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
loopCharacteristics === 'ParallelMultiInstance' ||
|
loopCharacteristics === 'ParallelMultiInstance' ||
|
||||||
loopCharacteristics === 'SequentialMultiInstance'
|
loopCharacteristics === 'SequentialMultiInstance'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-form-item label="循环数量" key="loopCardinality">
|
<el-form-item label="循环数量" key="loopCardinality">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loopInstanceForm.loopCardinality"
|
v-model="loopInstanceForm.loopCardinality"
|
||||||
clearable
|
clearable
|
||||||
@change="updateLoopCardinality"
|
@change="updateLoopCardinality"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="集合" key="collection" v-show="false">
|
<el-form-item label="集合" key="collection" v-show="false">
|
||||||
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
|
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- add by 芋艿:由于「元素变量」暂时用不到,所以这里 display 为 none -->
|
<!-- add by 芋艿:由于「元素变量」暂时用不到,所以这里 display 为 none -->
|
||||||
<el-form-item label="元素变量" key="elementVariable" style="display: none">
|
<el-form-item label="元素变量" key="elementVariable" style="display: none">
|
||||||
<el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" />
|
<el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="完成条件" key="completionCondition">
|
<el-form-item label="完成条件" key="completionCondition">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loopInstanceForm.completionCondition"
|
v-model="loopInstanceForm.completionCondition"
|
||||||
clearable
|
clearable
|
||||||
@change="updateLoopCondition"
|
@change="updateLoopCondition"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- add by 芋艿:由于「异步状态」暂时用不到,所以这里 display 为 none -->
|
<!-- add by 芋艿:由于「异步状态」暂时用不到,所以这里 display 为 none -->
|
||||||
<el-form-item label="异步状态" key="async" style="display: none">
|
<el-form-item label="异步状态" key="async" style="display: none">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="loopInstanceForm.asyncBefore"
|
v-model="loopInstanceForm.asyncBefore"
|
||||||
label="异步前"
|
label="异步前"
|
||||||
@change="updateLoopAsync('asyncBefore')"
|
@change="updateLoopAsync('asyncBefore')"
|
||||||
/>
|
/>
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="loopInstanceForm.asyncAfter"
|
v-model="loopInstanceForm.asyncAfter"
|
||||||
label="异步后"
|
label="异步后"
|
||||||
@change="updateLoopAsync('asyncAfter')"
|
@change="updateLoopAsync('asyncAfter')"
|
||||||
/>
|
/>
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="loopInstanceForm.exclusive"
|
v-model="loopInstanceForm.exclusive"
|
||||||
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
||||||
label="排除"
|
label="排除"
|
||||||
@change="updateLoopAsync('exclusive')"
|
@change="updateLoopAsync('exclusive')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="重试周期"
|
label="重试周期"
|
||||||
prop="timeCycle"
|
prop="timeCycle"
|
||||||
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
||||||
key="timeCycle"
|
key="timeCycle"
|
||||||
>
|
>
|
||||||
<el-input v-model="loopInstanceForm.timeCycle" clearable @change="updateLoopTimeCycle" />
|
<el-input v-model="loopInstanceForm.timeCycle" clearable @change="updateLoopTimeCycle" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineOptions({ name: 'ElementMultiInstance' })
|
defineOptions({ name: 'ElementMultiInstance' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
businessObject: Object,
|
businessObject: Object,
|
||||||
type: String
|
type: String
|
||||||
})
|
})
|
||||||
const prefix = inject('prefix')
|
const prefix = inject('prefix')
|
||||||
const loopCharacteristics = ref('')
|
const loopCharacteristics = ref('')
|
||||||
//默认配置,用来覆盖原始不存在的选项,避免报错
|
//默认配置,用来覆盖原始不存在的选项,避免报错
|
||||||
const defaultLoopInstanceForm = ref({
|
const defaultLoopInstanceForm = ref({
|
||||||
completionCondition: '',
|
completionCondition: '',
|
||||||
loopCardinality: '',
|
loopCardinality: '',
|
||||||
extensionElements: [],
|
extensionElements: [],
|
||||||
asyncAfter: false,
|
asyncAfter: false,
|
||||||
asyncBefore: false,
|
asyncBefore: false,
|
||||||
exclusive: false
|
exclusive: false
|
||||||
})
|
})
|
||||||
const loopInstanceForm = ref<any>({})
|
const loopInstanceForm = ref<any>({})
|
||||||
const bpmnElement = ref(null)
|
const bpmnElement = ref(null)
|
||||||
const multiLoopInstance = ref(null)
|
const multiLoopInstance = ref(null)
|
||||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||||
|
|
||||||
const getElementLoop = (businessObject) => {
|
const getElementLoop = (businessObject) => {
|
||||||
if (!businessObject.loopCharacteristics) {
|
if (!businessObject.loopCharacteristics) {
|
||||||
loopCharacteristics.value = 'Null'
|
loopCharacteristics.value = 'Null'
|
||||||
loopInstanceForm.value = {}
|
loopInstanceForm.value = {}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics') {
|
if (businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics') {
|
||||||
loopCharacteristics.value = 'StandardLoop'
|
loopCharacteristics.value = 'StandardLoop'
|
||||||
loopInstanceForm.value = {}
|
loopInstanceForm.value = {}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (businessObject.loopCharacteristics.isSequential) {
|
if (businessObject.loopCharacteristics.isSequential) {
|
||||||
loopCharacteristics.value = 'SequentialMultiInstance'
|
loopCharacteristics.value = 'SequentialMultiInstance'
|
||||||
} else {
|
} else {
|
||||||
loopCharacteristics.value = 'ParallelMultiInstance'
|
loopCharacteristics.value = 'ParallelMultiInstance'
|
||||||
}
|
}
|
||||||
// 合并配置
|
// 合并配置
|
||||||
loopInstanceForm.value = {
|
loopInstanceForm.value = {
|
||||||
...defaultLoopInstanceForm.value,
|
...defaultLoopInstanceForm.value,
|
||||||
...businessObject.loopCharacteristics,
|
...businessObject.loopCharacteristics,
|
||||||
completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? '',
|
completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? '',
|
||||||
loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? ''
|
loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? ''
|
||||||
}
|
}
|
||||||
// 保留当前元素 businessObject 上的 loopCharacteristics 实例
|
// 保留当前元素 businessObject 上的 loopCharacteristics 实例
|
||||||
multiLoopInstance.value = bpmnInstances().bpmnElement.businessObject.loopCharacteristics
|
multiLoopInstance.value = bpmnInstances().bpmnElement.businessObject.loopCharacteristics
|
||||||
// 更新表单
|
// 更新表单
|
||||||
if (
|
if (
|
||||||
businessObject.loopCharacteristics.extensionElements &&
|
businessObject.loopCharacteristics.extensionElements &&
|
||||||
businessObject.loopCharacteristics.extensionElements.values &&
|
businessObject.loopCharacteristics.extensionElements.values &&
|
||||||
businessObject.loopCharacteristics.extensionElements.values.length
|
businessObject.loopCharacteristics.extensionElements.values.length
|
||||||
) {
|
) {
|
||||||
loopInstanceForm.value['timeCycle'] =
|
loopInstanceForm.value['timeCycle'] =
|
||||||
businessObject.loopCharacteristics.extensionElements.values[0].body
|
businessObject.loopCharacteristics.extensionElements.values[0].body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeLoopCharacteristicsType = (type) => {
|
const changeLoopCharacteristicsType = (type) => {
|
||||||
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
|
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
|
||||||
// 取消多实例配置
|
// 取消多实例配置
|
||||||
if (type === 'Null') {
|
if (type === 'Null') {
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
loopCharacteristics: null
|
loopCharacteristics: null
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 配置循环
|
// 配置循环
|
||||||
if (type === 'StandardLoop') {
|
if (type === 'StandardLoop') {
|
||||||
const loopCharacteristicsObject = bpmnInstances().moddle.create(
|
const loopCharacteristicsObject = bpmnInstances().moddle.create(
|
||||||
'bpmn:StandardLoopCharacteristics'
|
'bpmn:StandardLoopCharacteristics'
|
||||||
)
|
)
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
loopCharacteristics: loopCharacteristicsObject
|
loopCharacteristics: loopCharacteristicsObject
|
||||||
})
|
})
|
||||||
multiLoopInstance.value = null
|
multiLoopInstance.value = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 时序
|
// 时序
|
||||||
if (type === 'SequentialMultiInstance') {
|
if (type === 'SequentialMultiInstance') {
|
||||||
multiLoopInstance.value = bpmnInstances().moddle.create(
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
'bpmn:MultiInstanceLoopCharacteristics',
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
{ isSequential: true }
|
{ isSequential: true }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
multiLoopInstance.value = bpmnInstances().moddle.create(
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
'bpmn:MultiInstanceLoopCharacteristics',
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
{ collection: '${coll_userList}' }
|
{ collection: '${coll_userList}' }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
loopCharacteristics: toRaw(multiLoopInstance.value)
|
loopCharacteristics: toRaw(multiLoopInstance.value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 循环基数
|
// 循环基数
|
||||||
const updateLoopCardinality = (cardinality) => {
|
const updateLoopCardinality = (cardinality) => {
|
||||||
let loopCardinality = null
|
let loopCardinality = null
|
||||||
if (cardinality && cardinality.length) {
|
if (cardinality && cardinality.length) {
|
||||||
loopCardinality = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
loopCardinality = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
body: cardinality
|
body: cardinality
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
bpmnInstances().modeling.updateModdleProperties(
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
toRaw(bpmnElement.value),
|
toRaw(bpmnElement.value),
|
||||||
multiLoopInstance.value,
|
multiLoopInstance.value,
|
||||||
{
|
{
|
||||||
loopCardinality
|
loopCardinality
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 完成条件
|
// 完成条件
|
||||||
const updateLoopCondition = (condition) => {
|
const updateLoopCondition = (condition) => {
|
||||||
let completionCondition = null
|
let completionCondition = null
|
||||||
if (condition && condition.length) {
|
if (condition && condition.length) {
|
||||||
completionCondition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
completionCondition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
body: condition
|
body: condition
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
bpmnInstances().modeling.updateModdleProperties(
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
toRaw(bpmnElement.value),
|
toRaw(bpmnElement.value),
|
||||||
multiLoopInstance.value,
|
multiLoopInstance.value,
|
||||||
{
|
{
|
||||||
completionCondition
|
completionCondition
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重试周期
|
// 重试周期
|
||||||
const updateLoopTimeCycle = (timeCycle) => {
|
const updateLoopTimeCycle = (timeCycle) => {
|
||||||
const extensionElements = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
const extensionElements = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
values: [
|
values: [
|
||||||
bpmnInstances().moddle.create(`${prefix}:FailedJobRetryTimeCycle`, {
|
bpmnInstances().moddle.create(`${prefix}:FailedJobRetryTimeCycle`, {
|
||||||
body: timeCycle
|
body: timeCycle
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
bpmnInstances().modeling.updateModdleProperties(
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
toRaw(bpmnElement.value),
|
toRaw(bpmnElement.value),
|
||||||
multiLoopInstance.value,
|
multiLoopInstance.value,
|
||||||
{
|
{
|
||||||
extensionElements
|
extensionElements
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接更新的基础信息
|
// 直接更新的基础信息
|
||||||
const updateLoopBase = () => {
|
const updateLoopBase = () => {
|
||||||
bpmnInstances().modeling.updateModdleProperties(
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
toRaw(bpmnElement.value),
|
toRaw(bpmnElement.value),
|
||||||
multiLoopInstance.value,
|
multiLoopInstance.value,
|
||||||
{
|
{
|
||||||
collection: loopInstanceForm.value.collection || null,
|
collection: loopInstanceForm.value.collection || null,
|
||||||
elementVariable: loopInstanceForm.value.elementVariable || null
|
elementVariable: loopInstanceForm.value.elementVariable || null
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 各异步状态
|
// 各异步状态
|
||||||
const updateLoopAsync = (key) => {
|
const updateLoopAsync = (key) => {
|
||||||
const { asyncBefore, asyncAfter } = loopInstanceForm.value
|
const { asyncBefore, asyncAfter } = loopInstanceForm.value
|
||||||
let asyncAttr = Object.create(null)
|
let asyncAttr = Object.create(null)
|
||||||
if (!asyncBefore && !asyncAfter) {
|
if (!asyncBefore && !asyncAfter) {
|
||||||
// this.$set(this.loopInstanceForm, "exclusive", false);
|
// this.$set(this.loopInstanceForm, "exclusive", false);
|
||||||
loopInstanceForm.value['exclusive'] = false
|
loopInstanceForm.value['exclusive'] = false
|
||||||
asyncAttr = { asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null }
|
asyncAttr = { asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null }
|
||||||
} else {
|
} else {
|
||||||
asyncAttr[key] = loopInstanceForm.value[key]
|
asyncAttr[key] = loopInstanceForm.value[key]
|
||||||
}
|
}
|
||||||
bpmnInstances().modeling.updateModdleProperties(
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
toRaw(bpmnElement.value),
|
toRaw(bpmnElement.value),
|
||||||
multiLoopInstance.value,
|
multiLoopInstance.value,
|
||||||
asyncAttr
|
asyncAttr
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeConfig = (config) => {
|
const changeConfig = (config) => {
|
||||||
if (config === '依次审批') {
|
if (config === '依次审批') {
|
||||||
changeLoopCharacteristicsType('SequentialMultiInstance')
|
changeLoopCharacteristicsType('SequentialMultiInstance')
|
||||||
updateLoopCardinality('1')
|
updateLoopCardinality('1')
|
||||||
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
|
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
|
||||||
} else if (config === '会签') {
|
} else if (config === '会签') {
|
||||||
changeLoopCharacteristicsType('ParallelMultiInstance')
|
changeLoopCharacteristicsType('ParallelMultiInstance')
|
||||||
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
|
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
|
||||||
} else if (config === '或签') {
|
} else if (config === '或签') {
|
||||||
changeLoopCharacteristicsType('ParallelMultiInstance')
|
changeLoopCharacteristicsType('ParallelMultiInstance')
|
||||||
updateLoopCondition('${ nrOfCompletedInstances > 0 }')
|
updateLoopCondition('${ nrOfCompletedInstances > 0 }')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
multiLoopInstance.value = null
|
multiLoopInstance.value = null
|
||||||
bpmnElement.value = null
|
bpmnElement.value = null
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.businessObject,
|
() => props.businessObject,
|
||||||
(val) => {
|
(val) => {
|
||||||
bpmnElement.value = bpmnInstances().bpmnElement
|
bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
getElementLoop(val)
|
getElementLoop(val)
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,125 +1,125 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin-top: 16px">
|
<div style="margin-top: 16px">
|
||||||
<el-form-item label="消息实例">
|
<el-form-item label="消息实例">
|
||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-select v-model="bindMessageId" @change="updateTaskMessage">
|
<el-select v-model="bindMessageId" @change="updateTaskMessage" filterable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="key in Object.keys(messageMap)"
|
v-for="key in Object.keys(messageMap)"
|
||||||
:value="key"
|
:value="key"
|
||||||
:label="messageMap[key]"
|
:label="messageMap[key]"
|
||||||
:key="key"
|
:key="key"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<XButton
|
<XButton
|
||||||
type="primary"
|
type="primary"
|
||||||
preIcon="ep:plus"
|
preIcon="ep:plus"
|
||||||
style="margin-left: 8px"
|
style="margin-left: 8px"
|
||||||
@click="openMessageModel"
|
@click="openMessageModel"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="messageModelVisible"
|
v-model="messageModelVisible"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
title="创建新消息"
|
title="创建新消息"
|
||||||
width="400px"
|
width="400px"
|
||||||
append-to-body
|
append-to-body
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
>
|
>
|
||||||
<el-form :model="newMessageForm" size="small" label-width="90px">
|
<el-form :model="newMessageForm" size="small" label-width="90px">
|
||||||
<el-form-item label="消息ID">
|
<el-form-item label="消息ID">
|
||||||
<el-input v-model="newMessageForm.id" clearable />
|
<el-input v-model="newMessageForm.id" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="消息名称">
|
<el-form-item label="消息名称">
|
||||||
<el-input v-model="newMessageForm.name" clearable />
|
<el-input v-model="newMessageForm.name" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button size="small" type="primary" @click="createNewMessage">确 认</el-button>
|
<el-button size="small" type="primary" @click="createNewMessage">确 认</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineOptions({ name: 'ReceiveTask' })
|
defineOptions({ name: 'ReceiveTask' })
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: String,
|
id: String,
|
||||||
type: String
|
type: String
|
||||||
})
|
})
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
const bindMessageId = ref('')
|
const bindMessageId = ref('')
|
||||||
const newMessageForm = ref<any>({})
|
const newMessageForm = ref<any>({})
|
||||||
const messageMap = ref<any>({})
|
const messageMap = ref<any>({})
|
||||||
const messageModelVisible = ref(false)
|
const messageModelVisible = ref(false)
|
||||||
const bpmnElement = ref<any>()
|
const bpmnElement = ref<any>()
|
||||||
const bpmnMessageRefsMap = ref<any>()
|
const bpmnMessageRefsMap = ref<any>()
|
||||||
const bpmnRootElements = ref<any>()
|
const bpmnRootElements = ref<any>()
|
||||||
|
|
||||||
const bpmnInstances = () => (window as any).bpmnInstances
|
const bpmnInstances = () => (window as any).bpmnInstances
|
||||||
const getBindMessage = () => {
|
const getBindMessage = () => {
|
||||||
bpmnElement.value = bpmnInstances().bpmnElement
|
bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
bindMessageId.value = bpmnElement.value.businessObject?.messageRef?.id || '-1'
|
bindMessageId.value = bpmnElement.value.businessObject?.messageRef?.id || '-1'
|
||||||
}
|
}
|
||||||
const openMessageModel = () => {
|
const openMessageModel = () => {
|
||||||
messageModelVisible.value = true
|
messageModelVisible.value = true
|
||||||
newMessageForm.value = {}
|
newMessageForm.value = {}
|
||||||
}
|
}
|
||||||
const createNewMessage = () => {
|
const createNewMessage = () => {
|
||||||
if (messageMap.value[newMessageForm.value.id]) {
|
if (messageMap.value[newMessageForm.value.id]) {
|
||||||
message.error('该消息已存在,请修改id后重新保存')
|
message.error('该消息已存在,请修改id后重新保存')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newMessage = bpmnInstances().moddle.create('bpmn:Message', newMessageForm.value)
|
const newMessage = bpmnInstances().moddle.create('bpmn:Message', newMessageForm.value)
|
||||||
bpmnRootElements.value.push(newMessage)
|
bpmnRootElements.value.push(newMessage)
|
||||||
messageMap.value[newMessageForm.value.id] = newMessageForm.value.name
|
messageMap.value[newMessageForm.value.id] = newMessageForm.value.name
|
||||||
bpmnMessageRefsMap.value[newMessageForm.value.id] = newMessage
|
bpmnMessageRefsMap.value[newMessageForm.value.id] = newMessage
|
||||||
messageModelVisible.value = false
|
messageModelVisible.value = false
|
||||||
}
|
}
|
||||||
const updateTaskMessage = (messageId) => {
|
const updateTaskMessage = (messageId) => {
|
||||||
if (messageId === '-1') {
|
if (messageId === '-1') {
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
messageRef: null
|
messageRef: null
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
messageRef: bpmnMessageRefsMap.value[messageId]
|
messageRef: bpmnMessageRefsMap.value[messageId]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
bpmnMessageRefsMap.value = Object.create(null)
|
bpmnMessageRefsMap.value = Object.create(null)
|
||||||
bpmnRootElements.value = bpmnInstances().modeler.getDefinitions().rootElements
|
bpmnRootElements.value = bpmnInstances().modeler.getDefinitions().rootElements
|
||||||
bpmnRootElements.value
|
bpmnRootElements.value
|
||||||
.filter((el) => el.$type === 'bpmn:Message')
|
.filter((el) => el.$type === 'bpmn:Message')
|
||||||
.forEach((m) => {
|
.forEach((m) => {
|
||||||
bpmnMessageRefsMap.value[m.id] = m
|
bpmnMessageRefsMap.value[m.id] = m
|
||||||
messageMap.value[m.id] = m.name
|
messageMap.value[m.id] = m.name
|
||||||
})
|
})
|
||||||
messageMap.value['-1'] = '无'
|
messageMap.value['-1'] = '无'
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
bpmnElement.value = null
|
bpmnElement.value = null
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => props.id,
|
() => props.id,
|
||||||
() => {
|
() => {
|
||||||
// bpmnElement.value = bpmnInstances().bpmnElement
|
// bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
getBindMessage()
|
getBindMessage()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,99 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin-top: 16px">
|
<div style="margin-top: 16px">
|
||||||
<el-form-item label="脚本格式">
|
<el-form-item label="脚本格式">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="scriptTaskForm.scriptFormat"
|
v-model="scriptTaskForm.scriptFormat"
|
||||||
clearable
|
clearable
|
||||||
@input="updateElementTask()"
|
@input="updateElementTask()"
|
||||||
@change="updateElementTask()"
|
@change="updateElementTask()"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="脚本类型">
|
<el-form-item label="脚本类型">
|
||||||
<el-select v-model="scriptTaskForm.scriptType">
|
<el-select v-model="scriptTaskForm.scriptType" filterable>
|
||||||
<el-option label="内联脚本" value="inline" />
|
<el-option label="内联脚本" value="inline" />
|
||||||
<el-option label="外部资源" value="external" />
|
<el-option label="外部资源" value="external" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
|
<el-form-item label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="scriptTaskForm.script"
|
v-model="scriptTaskForm.script"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
resize="vertical"
|
resize="vertical"
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
clearable
|
clearable
|
||||||
@input="updateElementTask()"
|
@input="updateElementTask()"
|
||||||
@change="updateElementTask()"
|
@change="updateElementTask()"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="资源地址" v-show="scriptTaskForm.scriptType === 'external'">
|
<el-form-item label="资源地址" v-show="scriptTaskForm.scriptType === 'external'">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="scriptTaskForm.resource"
|
v-model="scriptTaskForm.resource"
|
||||||
clearable
|
clearable
|
||||||
@input="updateElementTask()"
|
@input="updateElementTask()"
|
||||||
@change="updateElementTask()"
|
@change="updateElementTask()"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结果变量">
|
<el-form-item label="结果变量">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="scriptTaskForm.resultVariable"
|
v-model="scriptTaskForm.resultVariable"
|
||||||
clearable
|
clearable
|
||||||
@input="updateElementTask()"
|
@input="updateElementTask()"
|
||||||
@change="updateElementTask()"
|
@change="updateElementTask()"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineOptions({ name: 'ScriptTask' })
|
defineOptions({ name: 'ScriptTask' })
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: String,
|
id: String,
|
||||||
type: String
|
type: String
|
||||||
})
|
})
|
||||||
const defaultTaskForm = ref({
|
const defaultTaskForm = ref({
|
||||||
scriptFormat: '',
|
scriptFormat: '',
|
||||||
script: '',
|
script: '',
|
||||||
resource: '',
|
resource: '',
|
||||||
resultVariable: ''
|
resultVariable: ''
|
||||||
})
|
})
|
||||||
const scriptTaskForm = ref<any>({})
|
const scriptTaskForm = ref<any>({})
|
||||||
const bpmnElement = ref()
|
const bpmnElement = ref()
|
||||||
|
|
||||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||||
|
|
||||||
const resetTaskForm = () => {
|
const resetTaskForm = () => {
|
||||||
for (let key in defaultTaskForm.value) {
|
for (let key in defaultTaskForm.value) {
|
||||||
let value = bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key]
|
let value = bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key]
|
||||||
scriptTaskForm.value[key] = value
|
scriptTaskForm.value[key] = value
|
||||||
}
|
}
|
||||||
scriptTaskForm.value.scriptType = scriptTaskForm.value.script ? 'inline' : 'external'
|
scriptTaskForm.value.scriptType = scriptTaskForm.value.script ? 'inline' : 'external'
|
||||||
}
|
}
|
||||||
const updateElementTask = () => {
|
const updateElementTask = () => {
|
||||||
let taskAttr = Object.create(null)
|
let taskAttr = Object.create(null)
|
||||||
taskAttr.scriptFormat = scriptTaskForm.value.scriptFormat || null
|
taskAttr.scriptFormat = scriptTaskForm.value.scriptFormat || null
|
||||||
taskAttr.resultVariable = scriptTaskForm.value.resultVariable || null
|
taskAttr.resultVariable = scriptTaskForm.value.resultVariable || null
|
||||||
if (scriptTaskForm.value.scriptType === 'inline') {
|
if (scriptTaskForm.value.scriptType === 'inline') {
|
||||||
taskAttr.script = scriptTaskForm.value.script || null
|
taskAttr.script = scriptTaskForm.value.script || null
|
||||||
taskAttr.resource = null
|
taskAttr.resource = null
|
||||||
} else {
|
} else {
|
||||||
taskAttr.resource = scriptTaskForm.value.resource || null
|
taskAttr.resource = scriptTaskForm.value.resource || null
|
||||||
taskAttr.script = null
|
taskAttr.script = null
|
||||||
}
|
}
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
bpmnElement.value = null
|
bpmnElement.value = null
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.id,
|
() => props.id,
|
||||||
() => {
|
() => {
|
||||||
bpmnElement.value = bpmnInstances().bpmnElement
|
bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
resetTaskForm()
|
resetTaskForm()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,185 +1,188 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form label-width='100px'>
|
<el-form label-width='100px'>
|
||||||
<el-form-item label='规则类型' prop='candidateStrategy'>
|
<el-form-item label='规则类型' prop='candidateStrategy'>
|
||||||
<el-select
|
<el-select
|
||||||
v-model='userTaskForm.candidateStrategy'
|
v-model='userTaskForm.candidateStrategy'
|
||||||
clearable
|
clearable
|
||||||
style='width: 100%'
|
style='width: 100%'
|
||||||
@change='changeCandidateStrategy'
|
@change='changeCandidateStrategy'
|
||||||
>
|
filterable
|
||||||
<el-option
|
>
|
||||||
v-for='dict in RuleTypeList'
|
<el-option
|
||||||
:key='dict.code'
|
v-for='dict in RuleTypeList'
|
||||||
:label='dict.name'
|
:key='dict.code'
|
||||||
:value='dict.code'
|
:label='dict.name'
|
||||||
/>
|
:value='dict.code'
|
||||||
</el-select>
|
/>
|
||||||
</el-form-item>
|
</el-select>
|
||||||
<el-form-item
|
</el-form-item>
|
||||||
v-if='userTaskForm.candidateStrategy == 10'
|
<el-form-item
|
||||||
label='指定角色'
|
v-if='userTaskForm.candidateStrategy == 10'
|
||||||
prop='candidateParam'
|
label='指定角色'
|
||||||
>
|
prop='candidateParam'
|
||||||
<el-select
|
>
|
||||||
v-model='userTaskForm.candidateParam'
|
<el-select
|
||||||
clearable
|
v-model='userTaskForm.candidateParam'
|
||||||
multiple
|
clearable
|
||||||
style='width: 100%'
|
multiple
|
||||||
@change='updateElementTask'
|
style='width: 100%'
|
||||||
>
|
@change='updateElementTask'
|
||||||
<el-option v-for='item in roleOptions' :key='item.id' :label='item.name' :value='item.id' />
|
filterable
|
||||||
</el-select>
|
>
|
||||||
</el-form-item>
|
<el-option v-for='item in roleOptions' :key='item.id' :label='item.name' :value='item.id' />
|
||||||
<el-form-item
|
</el-select>
|
||||||
v-if='userTaskForm.candidateStrategy == 20'
|
</el-form-item>
|
||||||
label='指定部门'
|
<el-form-item
|
||||||
prop='candidateParam'
|
v-if='userTaskForm.candidateStrategy == 20'
|
||||||
span='24'
|
label='指定部门'
|
||||||
>
|
prop='candidateParam'
|
||||||
<el-tree-select
|
span='24'
|
||||||
ref='treeRef'
|
>
|
||||||
v-model='userTaskForm.candidateParam'
|
<el-tree-select
|
||||||
:data='deptTreeOptions'
|
ref='treeRef'
|
||||||
:props='defaultProps'
|
v-model='userTaskForm.candidateParam'
|
||||||
empty-text='加载中,请稍后'
|
:data='deptTreeOptions'
|
||||||
multiple
|
:props='defaultProps'
|
||||||
node-key='id'
|
empty-text='加载中,请稍后'
|
||||||
show-checkbox
|
multiple
|
||||||
@change='updateElementTask'
|
node-key='id'
|
||||||
/>
|
show-checkbox
|
||||||
</el-form-item>
|
@change='updateElementTask'
|
||||||
|
/>
|
||||||
<el-form-item
|
</el-form-item>
|
||||||
v-if='userTaskForm.candidateStrategy == 30'
|
|
||||||
label='指定用户'
|
<el-form-item
|
||||||
prop='candidateParam'
|
v-if='userTaskForm.candidateStrategy == 30'
|
||||||
span='24'
|
label='指定用户'
|
||||||
>
|
prop='candidateParam'
|
||||||
<el-select
|
span='24'
|
||||||
v-model='userTaskForm.candidateParam'
|
>
|
||||||
clearable
|
<el-select
|
||||||
multiple
|
v-model='userTaskForm.candidateParam'
|
||||||
style='width: 100%'
|
clearable
|
||||||
@change='updateElementTask'
|
multiple
|
||||||
>
|
style='width: 100%'
|
||||||
<el-option
|
@change='updateElementTask'
|
||||||
v-for='item in userOptions'
|
filterable
|
||||||
:key='item.id'
|
>
|
||||||
:label='item.name'
|
<el-option
|
||||||
:value='item.id'
|
v-for='item in userOptions'
|
||||||
/>
|
:key='item.id'
|
||||||
</el-select>
|
:label='item.name'
|
||||||
</el-form-item>
|
:value='item.id'
|
||||||
|
/>
|
||||||
</el-form>
|
</el-select>
|
||||||
</template>
|
</el-form-item>
|
||||||
|
|
||||||
<script lang='ts' setup>
|
</el-form>
|
||||||
import { defaultProps, handleTree } from '@/utils/tree'
|
</template>
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
const dictData = useDictData()
|
<script lang='ts' setup>
|
||||||
const RuleTypeList = ref()
|
import { defaultProps, handleTree } from '@/utils/tree'
|
||||||
import { getRoleSimpleList } from '@/api/user-boot/role'
|
import { useDictData } from '@/stores/dictData'
|
||||||
import { getUserSimpleList } from '@/api/user-boot/user'
|
const dictData = useDictData()
|
||||||
|
const RuleTypeList = ref()
|
||||||
defineOptions({ name: 'UserTask' })
|
import { getRoleSimpleList } from '@/api/user-boot/role'
|
||||||
const props = defineProps({
|
import { getUserSimpleList } from '@/api/user-boot/user'
|
||||||
id: String,
|
|
||||||
type: String
|
defineOptions({ name: 'UserTask' })
|
||||||
})
|
const props = defineProps({
|
||||||
const userTaskForm = ref({
|
id: String,
|
||||||
candidateStrategy: '', // 分配规则
|
type: String
|
||||||
candidateParam: [] // 分配选项
|
})
|
||||||
})
|
const userTaskForm = ref({
|
||||||
const bpmnElement = ref()
|
candidateStrategy: '', // 分配规则
|
||||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
candidateParam: [] // 分配选项
|
||||||
|
})
|
||||||
export interface optionVO {
|
const bpmnElement = ref()
|
||||||
id: string
|
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||||
name: string
|
|
||||||
}
|
export interface optionVO {
|
||||||
|
id: string
|
||||||
const roleOptions = ref<optionVO[]>([]) // 角色列表
|
name: string
|
||||||
const userOptions = ref<optionVO[]>([]) // 用户列表
|
}
|
||||||
const deptTreeOptions = ref() // 部门树
|
|
||||||
|
const roleOptions = ref<optionVO[]>([]) // 角色列表
|
||||||
const resetTaskForm = () => {
|
const userOptions = ref<optionVO[]>([]) // 用户列表
|
||||||
const businessObject = bpmnElement.value.businessObject
|
const deptTreeOptions = ref() // 部门树
|
||||||
if (!businessObject) {
|
|
||||||
return
|
const resetTaskForm = () => {
|
||||||
}
|
const businessObject = bpmnElement.value.businessObject
|
||||||
if (businessObject.candidateStrategy != undefined) {
|
if (!businessObject) {
|
||||||
userTaskForm.value.candidateStrategy = businessObject.candidateStrategy
|
return
|
||||||
} else {
|
}
|
||||||
userTaskForm.value.candidateStrategy = undefined
|
if (businessObject.candidateStrategy != undefined) {
|
||||||
}
|
userTaskForm.value.candidateStrategy = businessObject.candidateStrategy
|
||||||
if (businessObject.candidateParam && businessObject.candidateParam.length > 0) {
|
} else {
|
||||||
if (userTaskForm.value.candidateStrategy === 60) {
|
userTaskForm.value.candidateStrategy = undefined
|
||||||
// 特殊:流程表达式,只有一个 input 输入框
|
}
|
||||||
userTaskForm.value.candidateParam = [businessObject.candidateParam]
|
if (businessObject.candidateParam && businessObject.candidateParam.length > 0) {
|
||||||
} else {
|
if (userTaskForm.value.candidateStrategy === 60) {
|
||||||
userTaskForm.value.candidateParam = businessObject.candidateParam.split(',')
|
// 特殊:流程表达式,只有一个 input 输入框
|
||||||
}
|
userTaskForm.value.candidateParam = [businessObject.candidateParam]
|
||||||
} else {
|
} else {
|
||||||
userTaskForm.value.candidateParam = []
|
userTaskForm.value.candidateParam = businessObject.candidateParam.split(',')
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
userTaskForm.value.candidateParam = []
|
||||||
/** 更新 candidateStrategy 字段时,需要清空 candidateParam,并触发 bpmn 图更新 */
|
}
|
||||||
const changeCandidateStrategy = () => {
|
}
|
||||||
userTaskForm.value.candidateParam = []
|
|
||||||
updateElementTask()
|
/** 更新 candidateStrategy 字段时,需要清空 candidateParam,并触发 bpmn 图更新 */
|
||||||
}
|
const changeCandidateStrategy = () => {
|
||||||
|
userTaskForm.value.candidateParam = []
|
||||||
/** 选中某个 options 时候,更新 bpmn 图 */
|
updateElementTask()
|
||||||
const updateElementTask = () => {
|
}
|
||||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
|
||||||
candidateStrategy: userTaskForm.value.candidateStrategy,
|
/** 选中某个 options 时候,更新 bpmn 图 */
|
||||||
candidateParam: userTaskForm.value.candidateParam.join(',')
|
const updateElementTask = () => {
|
||||||
})
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
}
|
candidateStrategy: userTaskForm.value.candidateStrategy,
|
||||||
|
candidateParam: userTaskForm.value.candidateParam.join(',')
|
||||||
// 打开监听器弹窗
|
})
|
||||||
const processExpressionDialogRef = ref()
|
}
|
||||||
const openProcessExpressionDialog = async () => {
|
|
||||||
processExpressionDialogRef.value.open()
|
// 打开监听器弹窗
|
||||||
}
|
const processExpressionDialogRef = ref()
|
||||||
const selectProcessExpression = (expression) => {
|
const openProcessExpressionDialog = async () => {
|
||||||
userTaskForm.value.candidateParam = [expression.expression]
|
processExpressionDialogRef.value.open()
|
||||||
}
|
}
|
||||||
|
const selectProcessExpression = (expression) => {
|
||||||
watch(
|
userTaskForm.value.candidateParam = [expression.expression]
|
||||||
() => props.id,
|
}
|
||||||
() => {
|
|
||||||
bpmnElement.value = bpmnInstances().bpmnElement
|
watch(
|
||||||
nextTick(() => {
|
() => props.id,
|
||||||
resetTaskForm()
|
() => {
|
||||||
})
|
bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
},
|
nextTick(() => {
|
||||||
{ immediate: true }
|
resetTaskForm()
|
||||||
)
|
})
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
onMounted(async () => {
|
)
|
||||||
// 获得角色列表
|
|
||||||
await getRoleSimpleList().then(res => {
|
|
||||||
roleOptions.value = res.data
|
onMounted(async () => {
|
||||||
})
|
// 获得角色列表
|
||||||
|
await getRoleSimpleList().then(res => {
|
||||||
// 获得用户列表
|
roleOptions.value = res.data
|
||||||
await getUserSimpleList().then(res => {
|
})
|
||||||
userOptions.value = res.data
|
|
||||||
})
|
// 获得用户列表
|
||||||
//传入type的名称
|
await getUserSimpleList().then(res => {
|
||||||
RuleTypeList.value = dictData.getBasicData('rule_type')
|
userOptions.value = res.data
|
||||||
|
})
|
||||||
//
|
//传入type的名称
|
||||||
// // 获得部门列表
|
RuleTypeList.value = dictData.getBasicData('rule_type')
|
||||||
// const deptOptions = await DeptApi.getSimpleDeptList()
|
|
||||||
// deptTreeOptions.value = handleTree(deptOptions, 'id')
|
//
|
||||||
})
|
// // 获得部门列表
|
||||||
|
// const deptOptions = await DeptApi.getSimpleDeptList()
|
||||||
onBeforeUnmount(() => {
|
// deptTreeOptions.value = handleTree(deptOptions, 'id')
|
||||||
bpmnElement.value = null
|
})
|
||||||
})
|
|
||||||
</script>
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ const prop = defineProps({
|
|||||||
width: { type: [String, Number] },
|
width: { type: [String, Number] },
|
||||||
height: { type: [String, Number] },
|
height: { type: [String, Number] },
|
||||||
timeKey: { type: [String, Number] },
|
timeKey: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
timeValue: { type: Object },
|
||||||
|
searchKey: { type: [String, Number] }
|
||||||
})
|
})
|
||||||
|
|
||||||
const headerHeight = ref(57)
|
const headerHeight = ref(57)
|
||||||
@@ -347,22 +348,22 @@ onMounted(() => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.searchKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
// watch(
|
||||||
() => prop.timeValue,
|
// () => prop.timeValue,
|
||||||
|
|
||||||
val => {
|
// val => {
|
||||||
tableStore.index()
|
// tableStore.index()
|
||||||
},
|
// },
|
||||||
|
|
||||||
{
|
// {
|
||||||
deep: true
|
// deep: true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/assets/font/iconfont.css';
|
@import '@/assets/font/iconfont.css';
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ const prop = defineProps({
|
|||||||
width: { type: [String, Number] },
|
width: { type: [String, Number] },
|
||||||
height: { type: [String, Number] },
|
height: { type: [String, Number] },
|
||||||
timeKey: { type: [String, Number] },
|
timeKey: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
timeValue: { type: Object },
|
||||||
|
searchKey: { type: [String, Number] }
|
||||||
})
|
})
|
||||||
|
|
||||||
const headerHeight = ref(57)
|
const headerHeight = ref(57)
|
||||||
@@ -183,7 +184,7 @@ const tableStore: any = new TableStore({
|
|||||||
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
||||||
return k.citTotalNum != 0
|
return k.citTotalNum != 0
|
||||||
} else {
|
} else {
|
||||||
return k.citName != '上送国网' && k.citName != '非上送国网'
|
return !k.citName.includes('上送')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -329,22 +330,22 @@ onMounted(() => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.searchKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
// watch(
|
||||||
() => prop.timeValue,
|
// () => prop.timeValue,
|
||||||
|
|
||||||
val => {
|
// val => {
|
||||||
tableStore.index()
|
// tableStore.index()
|
||||||
},
|
// },
|
||||||
|
|
||||||
{
|
// {
|
||||||
deep: true
|
// deep: true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/assets/font/iconfont.css';
|
@import '@/assets/font/iconfont.css';
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
@selectChange="selectChange"
|
@selectChange="selectChange"
|
||||||
datePicker
|
datePicker
|
||||||
v-if="fullscreen"
|
v-if="fullscreen"
|
||||||
></TableHeader>
|
>
|
||||||
|
</TableHeader>
|
||||||
<div
|
<div
|
||||||
class="monitoringPoints"
|
class="monitoringPoints"
|
||||||
:style="{
|
:style="{
|
||||||
@@ -120,7 +121,8 @@ const prop = defineProps({
|
|||||||
width: { type: [String, Number] },
|
width: { type: [String, Number] },
|
||||||
height: { type: [String, Number] },
|
height: { type: [String, Number] },
|
||||||
timeKey: { type: [String, Number] },
|
timeKey: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
timeValue: { type: Object },
|
||||||
|
searchKey: { type: [String, Number] }
|
||||||
})
|
})
|
||||||
|
|
||||||
const headerHeight = ref(57)
|
const headerHeight = ref(57)
|
||||||
@@ -181,7 +183,7 @@ const tableStore: any = new TableStore({
|
|||||||
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
||||||
return k.citTotalNum != 0
|
return k.citTotalNum != 0
|
||||||
} else {
|
} else {
|
||||||
return k.citName != '上送国网' && k.citName != '非上送国网'
|
return !k.citName.includes('上送')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -328,22 +330,22 @@ onMounted(() => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.searchKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
// watch(
|
||||||
() => prop.timeValue,
|
// () => prop.timeValue,
|
||||||
|
|
||||||
val => {
|
// val => {
|
||||||
tableStore.index()
|
// tableStore.index()
|
||||||
},
|
// },
|
||||||
|
|
||||||
{
|
// {
|
||||||
deep: true
|
// deep: true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/assets/font/iconfont.css';
|
@import '@/assets/font/iconfont.css';
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ const prop = defineProps({
|
|||||||
width: { type: [String, Number] },
|
width: { type: [String, Number] },
|
||||||
height: { type: [String, Number] },
|
height: { type: [String, Number] },
|
||||||
timeKey: { type: [String, Number] },
|
timeKey: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
timeValue: { type: Object },
|
||||||
|
searchKey: { type: [String, Number] }
|
||||||
})
|
})
|
||||||
|
|
||||||
const headerHeight = ref(57)
|
const headerHeight = ref(57)
|
||||||
@@ -233,7 +234,7 @@ const tableStore: any = new TableStore({
|
|||||||
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
if (tableStore.table.params.statisticalType.name == '终端厂家') {
|
||||||
return k.count != 0
|
return k.count != 0
|
||||||
} else {
|
} else {
|
||||||
return k.name != '上送国网' && k.name != '非上送国网'
|
return !k.name.includes('上送')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -246,22 +247,28 @@ onMounted(() => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.searchKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
// watch(
|
||||||
() => prop.timeValue,
|
// () => prop.timeKey,
|
||||||
|
// val => {
|
||||||
|
// tableStore.index()
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// watch(
|
||||||
|
// () => prop.timeValue,
|
||||||
|
|
||||||
val => {
|
// val => {
|
||||||
tableStore.index()
|
// tableStore.index()
|
||||||
},
|
// },
|
||||||
|
|
||||||
{
|
// {
|
||||||
deep: true
|
// deep: true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/assets/font/iconfont.css';
|
@import '@/assets/font/iconfont.css';
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ const handlerBar = (options: any) => {
|
|||||||
if (Array.isArray(options.series)) {
|
if (Array.isArray(options.series)) {
|
||||||
options.series.forEach((item: any) => {
|
options.series.forEach((item: any) => {
|
||||||
if (item.type === 'bar') {
|
if (item.type === 'bar') {
|
||||||
item.barMinHeight = 10
|
item.barMinHeight = 0
|
||||||
item.barMaxWidth = 20
|
item.barMaxWidth = 20
|
||||||
item.itemStyle = Object.assign(
|
item.itemStyle = Object.assign(
|
||||||
{
|
{
|
||||||
|
|||||||
322
src/components/echarts/rmsWorker.js
Normal file
322
src/components/echarts/rmsWorker.js
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
// 辅助函数
|
||||||
|
const getMax = (temp, tempA, tempB, tempC) => {
|
||||||
|
temp = temp > tempA ? temp : tempA
|
||||||
|
temp = temp > tempB ? temp : tempB
|
||||||
|
if (tempC !== undefined) {
|
||||||
|
temp = temp > tempC ? temp : tempC
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMaxTwo = (temp, tempA, tempB) => {
|
||||||
|
temp = temp > tempA ? temp : tempA
|
||||||
|
temp = temp > tempB ? temp : tempB
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMin = (temp, tempA, tempB, tempC) => {
|
||||||
|
temp = temp < tempA ? temp : tempA
|
||||||
|
temp = temp < tempB ? temp : tempB
|
||||||
|
if (tempC !== undefined) {
|
||||||
|
temp = temp < tempC ? temp : tempC
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMinOpen = (temp, tempA, tempB) => {
|
||||||
|
temp = temp < tempA ? temp : tempA
|
||||||
|
temp = temp < tempB ? temp : tempB
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据处理函数
|
||||||
|
const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
|
||||||
|
const rmsData = wp.listRmsData
|
||||||
|
const pt = Number(wp.pt) / 1000
|
||||||
|
const ct = Number(wp.ct)
|
||||||
|
const titleList = wp.waveTitle
|
||||||
|
let xishu = pt
|
||||||
|
let aTitle = '',
|
||||||
|
bTitle = '',
|
||||||
|
cTitle = '',
|
||||||
|
unit = '电压'
|
||||||
|
let rmsvFirstX = 0,
|
||||||
|
rmsvFirstY = 0,
|
||||||
|
rmsvSecondX = 0,
|
||||||
|
rmsvSecondY = 0,
|
||||||
|
firstZhou = 'a',
|
||||||
|
secondeZhou = 'a'
|
||||||
|
let ifmax = 0,
|
||||||
|
ifmin = 0,
|
||||||
|
ismax = 0,
|
||||||
|
ismin = 0,
|
||||||
|
rfmax = 0,
|
||||||
|
rfmin = 0,
|
||||||
|
rsmax = 0,
|
||||||
|
rsmin = 0
|
||||||
|
|
||||||
|
const shunshiFA = []
|
||||||
|
const shunshiFB = []
|
||||||
|
const shunshiFC = []
|
||||||
|
const shunshiSA = []
|
||||||
|
const shunshiSB = []
|
||||||
|
const shunshiSC = []
|
||||||
|
const rmsFA = []
|
||||||
|
const rmsFB = []
|
||||||
|
const rmsFC = []
|
||||||
|
const rmsSA = []
|
||||||
|
const rmsSB = []
|
||||||
|
const rmsSC = []
|
||||||
|
|
||||||
|
if (titleList[iphasicValue * step + 1]?.substring(0, 1) !== 'U') {
|
||||||
|
xishu = ct
|
||||||
|
unit = '电流'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= iphasicValue; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
aTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
bTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
cTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmsData[0] && rmsData[0][iphasicValue * step + 1] !== undefined) {
|
||||||
|
rfmax = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rfmin = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rmsvFirstY = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rmsvFirstX = rmsData[0][0]
|
||||||
|
rsmax = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rsmin = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rmsvSecondY = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rmsvSecondX = rmsData[0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let rms = 0; rms < rmsData.length; rms++) {
|
||||||
|
if (!rmsData[rms] || rmsData[rms][iphasicValue * step + 1] === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iphasicValue) {
|
||||||
|
case 1:
|
||||||
|
const rmsFirstA = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA])
|
||||||
|
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA
|
||||||
|
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
firstZhou = 'a'
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA])
|
||||||
|
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA
|
||||||
|
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
secondeZhou = 'a'
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
const rmsFirstA2 = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
const rmsFirstB2 = rmsData[rms][iphasicValue * step + 2] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA2])
|
||||||
|
rmsFB.push([rmsData[rms][0], rmsFirstB2])
|
||||||
|
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2)
|
||||||
|
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2)
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
if (rfmin === rmsFirstA2) {
|
||||||
|
firstZhou = 'a'
|
||||||
|
} else if (rfmin === rmsFirstB2) {
|
||||||
|
firstZhou = 'b'
|
||||||
|
}
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA2 = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
const rmsSecondB2 = rmsData[rms][iphasicValue * step + 2]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA2])
|
||||||
|
rmsSB.push([rmsData[rms][0], rmsSecondB2])
|
||||||
|
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2)
|
||||||
|
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2)
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
if (rsmin === rmsSecondA2) {
|
||||||
|
secondeZhou = 'a'
|
||||||
|
} else if (rsmin === rmsSecondB2) {
|
||||||
|
secondeZhou = 'b'
|
||||||
|
}
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
const rmsFirstA3 = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
const rmsFirstB3 = rmsData[rms][iphasicValue * step + 2] * xishu
|
||||||
|
const rmsFirstC3 = rmsData[rms][iphasicValue * step + 3] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA3])
|
||||||
|
rmsFB.push([rmsData[rms][0], rmsFirstB3])
|
||||||
|
rmsFC.push([rmsData[rms][0], rmsFirstC3])
|
||||||
|
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3)
|
||||||
|
rfmin = isOpen
|
||||||
|
? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3)
|
||||||
|
: getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3)
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
if (rfmin === rmsFirstA3) {
|
||||||
|
firstZhou = 'a'
|
||||||
|
} else if (rfmin === rmsFirstB3) {
|
||||||
|
firstZhou = 'b'
|
||||||
|
} else {
|
||||||
|
firstZhou = 'c'
|
||||||
|
}
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA3 = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
const rmsSecondB3 = rmsData[rms][iphasicValue * step + 2]
|
||||||
|
const rmsSecondC3 = rmsData[rms][iphasicValue * step + 3]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA3])
|
||||||
|
rmsSB.push([rmsData[rms][0], rmsSecondB3])
|
||||||
|
rmsSC.push([rmsData[rms][0], rmsSecondC3])
|
||||||
|
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3)
|
||||||
|
rsmin = isOpen
|
||||||
|
? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3)
|
||||||
|
: getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3)
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
if (rsmin === rmsSecondA3) {
|
||||||
|
secondeZhou = 'a'
|
||||||
|
} else if (rsmin === rmsSecondB3) {
|
||||||
|
secondeZhou = 'b'
|
||||||
|
} else {
|
||||||
|
secondeZhou = 'c'
|
||||||
|
}
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instantF = { max: ifmax, min: ifmin }
|
||||||
|
const instantS = { max: ismax, min: ismin }
|
||||||
|
const RMSF = { max: rfmax, min: rfmin }
|
||||||
|
const RMSS = { max: rsmax, min: rsmin }
|
||||||
|
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou }
|
||||||
|
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou }
|
||||||
|
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
|
||||||
|
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
|
||||||
|
const RMSFWave = { rmsFA, rmsFB, rmsFC }
|
||||||
|
const RMSSWave = { rmsSA, rmsSB, rmsSC }
|
||||||
|
const title = { aTitle, bTitle, cTitle, unit }
|
||||||
|
|
||||||
|
return {
|
||||||
|
instantF,
|
||||||
|
instantS,
|
||||||
|
RMSF,
|
||||||
|
RMSS,
|
||||||
|
RMSFMinDetail,
|
||||||
|
RMSSMinDetail,
|
||||||
|
shunshiF,
|
||||||
|
shunshiS,
|
||||||
|
RMSFWave,
|
||||||
|
RMSSWave,
|
||||||
|
title,
|
||||||
|
unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听消息
|
||||||
|
self.onmessage = function (e) {
|
||||||
|
const { wp, isOpen, value, boxoList, requestId } = e.data
|
||||||
|
|
||||||
|
try {
|
||||||
|
const iphasicValue = wp.iphasic || 1
|
||||||
|
|
||||||
|
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
|
||||||
|
const waveDatas = []
|
||||||
|
|
||||||
|
for (let i = 0; i < picCounts; i++) {
|
||||||
|
const data = fliteWaveData(wp, i, iphasicValue, isOpen, boxoList)
|
||||||
|
waveDatas.push(data)
|
||||||
|
}
|
||||||
|
// 处理标题
|
||||||
|
let titles = ''
|
||||||
|
if (boxoList.systemType == 'pms') {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.powerStationName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.measurementPointName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'ZL') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.equipmentName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
boxoList.evtParamVVaDepth +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.evtParamTm +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'YPT') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.persistTime +
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
titles =
|
||||||
|
' 变电站名称:' +
|
||||||
|
boxoList.subName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
}
|
||||||
|
// 发送处理结果回主线程
|
||||||
|
self.postMessage({
|
||||||
|
requestId,
|
||||||
|
titles: titles,
|
||||||
|
success: true,
|
||||||
|
waveDatas,
|
||||||
|
time: wp.time,
|
||||||
|
type: wp.waveType,
|
||||||
|
severity: wp.yzd,
|
||||||
|
iphasic: iphasicValue
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
self.postMessage({
|
||||||
|
requestId,
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
207
src/components/echarts/shuWorker.js
Normal file
207
src/components/echarts/shuWorker.js
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
// waveData.worker.js
|
||||||
|
self.addEventListener('message', function (e) {
|
||||||
|
const { wp, value, iphasic, isOpen, boxoList, requestId } = e.data
|
||||||
|
|
||||||
|
// 处理波形数据的函数
|
||||||
|
const fliteWaveData = (wp, step) => {
|
||||||
|
// 将原有的fliteWaveData函数实现复制到这里
|
||||||
|
const shunData = wp.listWaveData
|
||||||
|
const pt = Number(wp.pt) / 1000
|
||||||
|
const ct = Number(wp.ct)
|
||||||
|
const titleList = wp.waveTitle
|
||||||
|
let xishu = pt
|
||||||
|
let aTitle = '',
|
||||||
|
bTitle = '',
|
||||||
|
cTitle = '',
|
||||||
|
unit = '电压'
|
||||||
|
let ifmax = 0,
|
||||||
|
ifmin = 0,
|
||||||
|
ismax = 0,
|
||||||
|
ismin = 0
|
||||||
|
|
||||||
|
const shunshiFA = []
|
||||||
|
const shunshiFB = []
|
||||||
|
const shunshiFC = []
|
||||||
|
const shunshiSA = []
|
||||||
|
const shunshiSB = []
|
||||||
|
const shunshiSC = []
|
||||||
|
|
||||||
|
if (shunData.length > 0) {
|
||||||
|
if (titleList[iphasic * step + 1]?.substring(0, 1) !== 'U') {
|
||||||
|
xishu = ct
|
||||||
|
unit = '电流'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= iphasic; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
aTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
bTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
cTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shunData[0][iphasic * step + 1] !== undefined) {
|
||||||
|
ifmax = shunData[0][iphasic * step + 1] * xishu
|
||||||
|
ifmin = shunData[0][iphasic * step + 1] * xishu
|
||||||
|
ismax = shunData[0][iphasic * step + 1]
|
||||||
|
ismin = shunData[0][iphasic * step + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let shun = 0; shun < shunData.length; shun++) {
|
||||||
|
if (shunData[shun][iphasic * step + 1] === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iphasic) {
|
||||||
|
case 1:
|
||||||
|
const shunFirstA = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA)
|
||||||
|
ifmin = Math.min(ifmin, shunFirstA)
|
||||||
|
|
||||||
|
const shunSecondA = shunData[shun][iphasic * step + 1]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA])
|
||||||
|
ismax = Math.max(ismax, shunSecondA)
|
||||||
|
ismin = Math.min(ismin, shunSecondA)
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
const shunFirstA2 = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
const shunFirstB2 = shunData[shun][iphasic * step + 2] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA2])
|
||||||
|
shunshiFB.push([shunData[shun][0], shunFirstB2])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA2, shunFirstB2)
|
||||||
|
ifmin = Math.min(ifmin, shunFirstA2, shunFirstB2)
|
||||||
|
|
||||||
|
const shunSecondA2 = shunData[shun][iphasic * step + 1]
|
||||||
|
const shunSecondB2 = shunData[shun][iphasic * step + 2]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA2])
|
||||||
|
shunshiSB.push([shunData[shun][0], shunSecondB2])
|
||||||
|
ismax = Math.max(ismax, shunSecondA2, shunSecondB2)
|
||||||
|
ismin = Math.min(ismin, shunSecondA2, shunSecondB2)
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
const shunFirstA3 = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
const shunFirstB3 = shunData[shun][iphasic * step + 2] * xishu
|
||||||
|
const shunFirstC3 = shunData[shun][iphasic * step + 3] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA3])
|
||||||
|
shunshiFB.push([shunData[shun][0], shunFirstB3])
|
||||||
|
shunshiFC.push([shunData[shun][0], shunFirstC3])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA3, shunFirstB3, shunFirstC3)
|
||||||
|
ifmin = isOpen
|
||||||
|
? Math.min(ifmin, shunFirstA3, shunFirstC3)
|
||||||
|
: Math.min(ifmin, shunFirstA3, shunFirstB3, shunFirstC3)
|
||||||
|
|
||||||
|
const shunSecondA3 = shunData[shun][iphasic * step + 1]
|
||||||
|
const shunSecondB3 = shunData[shun][iphasic * step + 2]
|
||||||
|
const shunSecondC3 = shunData[shun][iphasic * step + 3]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA3])
|
||||||
|
shunshiSB.push([shunData[shun][0], shunSecondB3])
|
||||||
|
shunshiSC.push([shunData[shun][0], shunSecondC3])
|
||||||
|
ismax = Math.max(ismax, shunSecondA3, shunSecondB3, shunSecondC3)
|
||||||
|
ismin = isOpen
|
||||||
|
? Math.min(ismin, shunSecondA3, shunSecondC3)
|
||||||
|
: Math.min(ismin, shunSecondA3, shunSecondB3, shunSecondC3)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instantF = { max: ifmax, min: ifmin }
|
||||||
|
const instantS = { max: ismax, min: ismin }
|
||||||
|
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
|
||||||
|
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
|
||||||
|
const title = { aTitle, bTitle, cTitle, unit }
|
||||||
|
|
||||||
|
return { instantF, instantS, shunshiF, shunshiS, title, unit }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理标题
|
||||||
|
let titles = ''
|
||||||
|
if (boxoList.systemType == 'pms') {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.powerStationName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.measurementPointName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'ZL') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.equipmentName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
boxoList.evtParamVVaDepth +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.evtParamTm +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'YPT') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.persistTime +
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.subName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
}
|
||||||
|
|
||||||
|
const iphasicValue = wp.iphasic || 1
|
||||||
|
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
|
||||||
|
const waveDatas = []
|
||||||
|
|
||||||
|
for (let i = 0; i < picCounts; i++) {
|
||||||
|
const data = fliteWaveData(wp, i)
|
||||||
|
waveDatas.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = wp.time
|
||||||
|
const type = wp.waveType
|
||||||
|
let severity = wp.yzd
|
||||||
|
|
||||||
|
if (severity < 0) {
|
||||||
|
severity = '/'
|
||||||
|
type = '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将处理结果发送回主线程
|
||||||
|
self.postMessage({
|
||||||
|
requestId,
|
||||||
|
success: true,
|
||||||
|
waveDatas,
|
||||||
|
time,
|
||||||
|
type,
|
||||||
|
severity,
|
||||||
|
titles,
|
||||||
|
iphasic: iphasicValue
|
||||||
|
})
|
||||||
|
})
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
<div v-if="view2">
|
<div v-if="view2">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<span style="font-size: 14px; line-height: 30px">值类型选择:</span>
|
<!-- <span style="font-size: 14px; line-height: 30px">值类型选择:</span>
|
||||||
<el-select
|
<el-select
|
||||||
style="min-width: 200px; width: 200px"
|
style="min-width: 200px; width: 200px"
|
||||||
@change="changeView"
|
@change="changeView"
|
||||||
@@ -15,7 +15,11 @@
|
|||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select> -->
|
||||||
|
<el-radio-group v-model.trim="value" @change="changeView">
|
||||||
|
<el-radio-button label="一次值" :value="1" />
|
||||||
|
<el-radio-button label="二次值" :value="2" />
|
||||||
|
</el-radio-group>
|
||||||
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics">
|
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics">
|
||||||
高级分析
|
高级分析
|
||||||
</el-button> -->
|
</el-button> -->
|
||||||
@@ -24,37 +28,18 @@
|
|||||||
<el-button @click="backbxlb" icon="el-icon-Back" style="float: right">返回</el-button>
|
<el-button @click="backbxlb" icon="el-icon-Back" style="float: right">返回</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div v-loading="loading" style="height: calc(100vh - 190px)">
|
<div v-loading="loading" style="height: calc(100vh - 190px)" class="mt10">
|
||||||
<el-tabs v-if="view4" class="default-main" v-model="bxactiveName" @tab-click="bxhandleClick">
|
<el-tabs v-if="view4" type="border-card" v-model="bxactiveName"
|
||||||
<el-tab-pane
|
@tab-click="bxhandleClick">
|
||||||
label="瞬时波形"
|
<el-tab-pane label="瞬时波形" name="ssbx" class="boxbx pt10 pb10"
|
||||||
name="ssbx"
|
:style="'height:' + bxecharts + ';overflow-y: scroll;'">
|
||||||
class="boxbx pt10 pb10"
|
<shushiboxi ref="shushiboxiRef" v-if="bxactiveName == 'ssbx' && showBoxi" :value="value"
|
||||||
:style="'height:' + bxecharts + ';overflow-y: scroll;'"
|
:parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></shushiboxi>
|
||||||
>
|
|
||||||
<shushiboxi
|
|
||||||
ref="shushiboxiRef"
|
|
||||||
v-if="bxactiveName == 'ssbx' && showBoxi"
|
|
||||||
:value="value"
|
|
||||||
:parentHeight="parentHeight"
|
|
||||||
:boxoList="boxoList"
|
|
||||||
:wp="wp"
|
|
||||||
></shushiboxi>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane
|
<el-tab-pane label="RMS波形" class="boxbx pt10 pb10" name="rmsbx"
|
||||||
label="RMS波形"
|
:style="'height:' + bxecharts + ';overflow-y: scroll;'">
|
||||||
class="boxbx pt10 pb10"
|
<rmsboxi ref="rmsboxiRef" v-if="bxactiveName == 'rmsbx' && showBoxi" :value="value"
|
||||||
name="rmsbx"
|
:parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></rmsboxi>
|
||||||
:style="'height:' + bxecharts + ';overflow-y: scroll;'"
|
|
||||||
>
|
|
||||||
<rmsboxi
|
|
||||||
ref="rmsboxiRef"
|
|
||||||
v-if="bxactiveName == 'rmsbx' && showBoxi"
|
|
||||||
:value="value"
|
|
||||||
:parentHeight="parentHeight"
|
|
||||||
:boxoList="boxoList"
|
|
||||||
:wp="wp"
|
|
||||||
></rmsboxi>
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" />
|
<el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" />
|
||||||
@@ -70,10 +55,12 @@
|
|||||||
import shushiboxi from '@/components/echarts/shushiboxi.vue'
|
import shushiboxi from '@/components/echarts/shushiboxi.vue'
|
||||||
import rmsboxi from '@/components/echarts/rmsboxi.vue'
|
import rmsboxi from '@/components/echarts/rmsboxi.vue'
|
||||||
import analytics from '@/components/echarts/analytics.vue'
|
import analytics from '@/components/echarts/analytics.vue'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, shallowRef } from 'vue'
|
||||||
import { analysis } from '@/api/advance-boot/analyse'
|
import { analysis } from '@/api/advance-boot/analyse'
|
||||||
import { mainHeight } from '@/utils/layout'
|
import { mainHeight } from '@/utils/layout'
|
||||||
import { getMonitorEventAnalyseWave, downloadWaveFile } from '@/api/event-boot/transient'
|
import { getMonitorEventAnalyseWave, downloadWaveFile } from '@/api/event-boot/transient'
|
||||||
|
import { buildWaveStoreKey, registerWaveRaw, buildSlimWp, releaseWaveRaw } from '@/utils/waveRawStore'
|
||||||
|
import { clearWaveCache } from '@/utils/waveCache'
|
||||||
const emit = defineEmits(['backbxlb'])
|
const emit = defineEmits(['backbxlb'])
|
||||||
interface Props {
|
interface Props {
|
||||||
// boxoList: any
|
// boxoList: any
|
||||||
@@ -100,10 +87,10 @@ const options = ref([
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
const shushiboxiRef = ref()
|
const shushiboxiRef = ref()
|
||||||
const bxecharts = ref(mainHeight(95).height as any)
|
const bxecharts = ref(mainHeight(145).height as any)
|
||||||
const view2 = ref(true)
|
const view2 = ref(true)
|
||||||
const boxoList: any = ref(null)
|
const boxoList: any = ref(null)
|
||||||
const wp = ref(null)
|
const wp = shallowRef<any>(null)
|
||||||
const showBoxi = ref(true)
|
const showBoxi = ref(true)
|
||||||
const view3 = ref(false)
|
const view3 = ref(false)
|
||||||
const view4 = ref(false)
|
const view4 = ref(false)
|
||||||
@@ -117,7 +104,9 @@ const open = async (row: any) => {
|
|||||||
if (res != undefined) {
|
if (res != undefined) {
|
||||||
boxoList.value = row
|
boxoList.value = row
|
||||||
boxoList.value.pt = res.data.pt
|
boxoList.value.pt = res.data.pt
|
||||||
wp.value = res.data
|
const storeKey = buildWaveStoreKey(row)
|
||||||
|
registerWaveRaw(storeKey, res.data)
|
||||||
|
wp.value = buildSlimWp(res.data, storeKey)
|
||||||
loading.value = false
|
loading.value = false
|
||||||
view4.value = true
|
view4.value = true
|
||||||
}
|
}
|
||||||
@@ -128,9 +117,6 @@ const open = async (row: any) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const bxhandleClick = (tab: any) => {
|
const bxhandleClick = (tab: any) => {
|
||||||
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
|
|
||||||
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
|
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
if (tab.name == 'ssbx') {
|
if (tab.name == 'ssbx') {
|
||||||
bxactiveName.value = 'ssbx'
|
bxactiveName.value = 'ssbx'
|
||||||
@@ -143,10 +129,12 @@ const bxhandleClick = (tab: any) => {
|
|||||||
// console.log(tab, event);
|
// console.log(tab, event);
|
||||||
}
|
}
|
||||||
const backbxlb = () => {
|
const backbxlb = () => {
|
||||||
|
const storeKey = wp.value?.waveStoreKey
|
||||||
|
releaseWaveRaw(storeKey, 'all')
|
||||||
|
clearWaveCache()
|
||||||
boxoList.value = null
|
boxoList.value = null
|
||||||
wp.value = null
|
wp.value = null
|
||||||
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
|
|
||||||
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
|
|
||||||
|
|
||||||
emit('backbxlb')
|
emit('backbxlb')
|
||||||
}
|
}
|
||||||
@@ -173,8 +161,8 @@ const AdvancedAnalytics = () => {
|
|||||||
view2.value = false
|
view2.value = false
|
||||||
}
|
}
|
||||||
const changeView = () => {
|
const changeView = () => {
|
||||||
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
|
shushiboxiRef.value?.backbxlb?.()
|
||||||
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
|
rmsboxiRef.value?.backbxlb?.()
|
||||||
showBoxi.value = false
|
showBoxi.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
showBoxi.value = true
|
showBoxi.value = true
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 540px">
|
<div :style="{ width: isMinuteData ? '750px' : '610px' }">
|
||||||
<el-select v-model="interval" style="min-width: 90px; width: 90px; margin-right: 10px" @change="timeChange">
|
<el-select v-model="interval" style="min-width: 90px; width: 90px; margin-right: 10px" @change="timeChange" filterable>
|
||||||
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="timeValue"
|
v-model="timeValue"
|
||||||
type="daterange"
|
:type="pickerType"
|
||||||
:disabled="disabledPicker"
|
:disabled="disabledPicker"
|
||||||
:disabled-date="isFutureDate"
|
:disabled-date="isFutureDate"
|
||||||
style="width: 220px; margin-right: 10px"
|
:style="{ width: isMinuteData ? '360px' : '220px', marginRight: '10px' }"
|
||||||
unlink-panels
|
unlink-panels
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
range-separator="至"
|
range-separator="至"
|
||||||
start-placeholder="开始日期"
|
:start-placeholder="isMinuteData ? '开始时间' : '开始日期'"
|
||||||
end-placeholder="结束日期"
|
:end-placeholder="isMinuteData ? '结束时间' : '结束日期'"
|
||||||
value-format="YYYY-MM-DD"
|
:value-format="pickerValueFormat"
|
||||||
:shortcuts="shortcuts"
|
:shortcuts="isMinuteData ? undefined : shortcuts"
|
||||||
/>
|
/>
|
||||||
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
|
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
|
||||||
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
|
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
|
||||||
@@ -26,18 +26,41 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { DArrowLeft, VideoPause, DArrowRight } from '@element-plus/icons-vue'
|
import { DArrowLeft, VideoPause, DArrowRight } from '@element-plus/icons-vue'
|
||||||
import { ref, onMounted, nextTick, watch } from 'vue'
|
import { ref, onMounted, computed, watch } from 'vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
nextFlag?: boolean
|
nextFlag?: boolean
|
||||||
theCurrentTime?: boolean
|
theCurrentTime?: boolean
|
||||||
|
isStatisticData?: number | string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
nextFlag: false,
|
nextFlag: false,
|
||||||
theCurrentTime: false
|
theCurrentTime: false,
|
||||||
|
isStatisticData: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isMinuteData = computed(() => Number(props.isStatisticData) === 1)
|
||||||
|
const pickerType = computed(() => (isMinuteData.value ? 'datetimerange' : 'daterange'))
|
||||||
|
const pickerValueFormat = computed(() => (isMinuteData.value ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'))
|
||||||
|
|
||||||
|
const toDatePart = (value: string) => (value?.includes(' ') ? value.split(' ')[0] : value)
|
||||||
|
|
||||||
|
const toMinuteStart = (date: string) => `${toDatePart(date)} 00:00:00`
|
||||||
|
|
||||||
|
const toMinuteEnd = (date: string) => `${toDatePart(date)} 23:59:59`
|
||||||
|
|
||||||
|
const normalizeRange = (start: string, end: string) => {
|
||||||
|
if (!isMinuteData.value) {
|
||||||
|
return [toDatePart(start), toDatePart(end)]
|
||||||
|
}
|
||||||
|
return [toMinuteStart(start), toMinuteEnd(end)]
|
||||||
|
}
|
||||||
|
|
||||||
|
const setRangeValue = (start: string, end: string) => {
|
||||||
|
timeValue.value = normalizeRange(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
const interval = ref(3)
|
const interval = ref(3)
|
||||||
const timeFlag = ref(1)
|
const timeFlag = ref(1)
|
||||||
const count = ref(0)
|
const count = ref(0)
|
||||||
@@ -95,13 +118,13 @@ const timeChange = (e: number) => {
|
|||||||
if (e == 1) {
|
if (e == 1) {
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
|
|
||||||
timeValue.value = [setTime(1), setTime()]
|
setRangeValue(setTime(1), setTime())
|
||||||
} else if (e == 2) {
|
} else if (e == 2) {
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
timeValue.value = [setTime(2), setTime()]
|
setRangeValue(setTime(2), setTime())
|
||||||
} else if (e == 3) {
|
} else if (e == 3) {
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
timeValue.value = [setTime(3), setTime()]
|
setRangeValue(setTime(3), setTime())
|
||||||
} else if (e == 4) {
|
} else if (e == 4) {
|
||||||
let year = parseInt(setTime().substring(0, 4))
|
let year = parseInt(setTime().substring(0, 4))
|
||||||
let month = parseInt(setTime().substring(5, 7))
|
let month = parseInt(setTime().substring(5, 7))
|
||||||
@@ -111,12 +134,12 @@ const timeChange = (e: number) => {
|
|||||||
var dayOfWeek = start.getDay() == 0 ? 7 : start.getDay() - 1 // 如果为周日,则置为7天
|
var dayOfWeek = start.getDay() == 0 ? 7 : start.getDay() - 1 // 如果为周日,则置为7天
|
||||||
|
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
timeValue.value = [setTime(0, dayOfWeek), setTime(0, -6 + dayOfWeek)]
|
setRangeValue(setTime(0, dayOfWeek), setTime(0, -6 + dayOfWeek))
|
||||||
} else if (e == 5) {
|
} else if (e == 5) {
|
||||||
disabledPicker.value = false
|
disabledPicker.value = false
|
||||||
backDisabled.value = true
|
backDisabled.value = true
|
||||||
preDisabled.value = props.nextFlag ? false : true
|
preDisabled.value = props.nextFlag ? false : true
|
||||||
timeValue.value = [setTime(), setTime()]
|
setRangeValue(setTime(), setTime())
|
||||||
}
|
}
|
||||||
if (e == 1 || e == 2) {
|
if (e == 1 || e == 2) {
|
||||||
timeFlag.value = 0
|
timeFlag.value = 0
|
||||||
@@ -186,7 +209,7 @@ const preClick = () => {
|
|||||||
startTime = year + '-01-01'
|
startTime = year + '-01-01'
|
||||||
endTime = year + '-12-31'
|
endTime = year + '-12-31'
|
||||||
}
|
}
|
||||||
timeValue.value = [startTime, endTime]
|
setRangeValue(startTime, endTime)
|
||||||
|
|
||||||
// 判断向后键的状态
|
// 判断向后键的状态
|
||||||
// var temp = NowgetEndTime()
|
// var temp = NowgetEndTime()
|
||||||
@@ -415,16 +438,27 @@ const next = () => {
|
|||||||
}
|
}
|
||||||
if (!props.nextFlag) {
|
if (!props.nextFlag) {
|
||||||
if (
|
if (
|
||||||
new Date(endTime + ' 00:00:00').getTime() >=
|
new Date(toDatePart(endTime) + ' 00:00:00').getTime() >=
|
||||||
new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()
|
new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()
|
||||||
) {
|
) {
|
||||||
preDisabled.value = props.nextFlag ? false : true
|
preDisabled.value = props.nextFlag ? false : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timeValue.value = [startTime, endTime]
|
setRangeValue(startTime, endTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.isStatisticData,
|
||||||
|
() => {
|
||||||
|
if (timeValue.value?.length === 2) {
|
||||||
|
setRangeValue(timeValue.value[0], timeValue.value[1])
|
||||||
|
} else {
|
||||||
|
timeChange(interval.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const setTime = (flag = 0, e = 0) => {
|
const setTime = (flag = 0, e = 0) => {
|
||||||
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')
|
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default defineComponent({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String,
|
type: [String, Number],
|
||||||
default: '18px'
|
default: '18px'
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
@@ -21,7 +21,7 @@ export default defineComponent({
|
|||||||
setup(props) {
|
setup(props) {
|
||||||
const iconStyle = computed((): CSSProperties => {
|
const iconStyle = computed((): CSSProperties => {
|
||||||
const { size, color } = props
|
const { size, color } = props
|
||||||
let s = `${size.replace('px', '')}px`
|
const s = `${String(size).replace('px', '')}px`
|
||||||
return {
|
return {
|
||||||
fontSize: s,
|
fontSize: s,
|
||||||
color: color
|
color: color
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="isUrl" :style="urlIconStyle" class="url-svg svg-icon icon" />
|
<div v-if="isUrl" :style="urlIconStyle" class="url-svg svg-icon icon" />
|
||||||
<svg v-else class="svg-icon icon" :style="iconStyle">
|
<svg v-else class="svg-icon icon" :style="iconStyle">
|
||||||
<use :href="iconName" />
|
<use :href="iconName" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, type CSSProperties } from 'vue'
|
import { computed, type CSSProperties } from 'vue'
|
||||||
import { isExternal } from '@/utils/common'
|
import { isExternal } from '@/utils/common'
|
||||||
interface Props {
|
interface Props {
|
||||||
name: string
|
name: string
|
||||||
size: string
|
size: string | number
|
||||||
color: string
|
color: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
name: '',
|
name: '',
|
||||||
size: '18px',
|
size: '18px',
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
})
|
})
|
||||||
|
|
||||||
const s = `${props.size.replace('px', '')}px`
|
const s = `${String(props.size).replace('px', '')}px`
|
||||||
const iconName = computed(() => `#${props.name}`)
|
const iconName = computed(() => `#${props.name}`)
|
||||||
const iconStyle = computed((): CSSProperties => {
|
const iconStyle = computed((): CSSProperties => {
|
||||||
return {
|
return {
|
||||||
color: props.color,
|
color: props.color,
|
||||||
fontSize: s,
|
fontSize: s,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const isUrl = computed(() => isExternal(props.name))
|
const isUrl = computed(() => isExternal(props.name))
|
||||||
const urlIconStyle = computed(() => {
|
const urlIconStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
width: s,
|
width: s,
|
||||||
height: s,
|
height: s,
|
||||||
mask: `url(${props.name}) no-repeat 50% 50%`,
|
mask: `url(${props.name}) no-repeat 50% 50%`,
|
||||||
'-webkit-mask': `url(${props.name}) no-repeat 50% 50%`,
|
'-webkit-mask': `url(${props.name}) no-repeat 50% 50%`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,23 +1,41 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
import { defineComponent, createVNode, reactive } from 'vue'
|
import { defineComponent, createVNode, reactive } from 'vue'
|
||||||
import { Column } from 'vxe-table'
|
import { Column } from 'vxe-table'
|
||||||
import { uuid } from '@/utils/random'
|
import { uuid } from '@/utils/random'
|
||||||
|
|
||||||
export default defineComponent({
|
/** storage 开启时列必须有稳定 field;序号/操作等无 field 列按 title 生成 */
|
||||||
name: 'Column',
|
function resolveColumnField(attr: Record<string, any>): string | undefined {
|
||||||
props: {
|
if (attr.field) return attr.field
|
||||||
attr: {
|
if (attr.prop) return attr.prop
|
||||||
type: Object,
|
// checkbox / radio / expand / seq 等类型列由 vxe 内部处理,可不强制 field
|
||||||
required: true
|
if (attr.type && ['checkbox', 'radio', 'expand', 'html'].includes(attr.type)) {
|
||||||
}
|
return undefined
|
||||||
},
|
}
|
||||||
setup(props, { slots }) {
|
if (attr.title != null && attr.title !== '') {
|
||||||
const attr = reactive(props.attr)
|
return `__col_${attr.title}`
|
||||||
attr['align'] = attr['align'] ? attr['align'] : 'center'
|
}
|
||||||
attr['column-key'] = attr['column-key'] ? attr['column-key'] : attr.prop || uuid()
|
return `col_${uuid()}`
|
||||||
return () => {
|
}
|
||||||
return createVNode(Column, attr, slots.default)
|
|
||||||
}
|
export default defineComponent({
|
||||||
}
|
name: 'Column',
|
||||||
})
|
props: {
|
||||||
</script>
|
attr: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const attr = reactive({ ...props.attr })
|
||||||
|
attr['align'] = attr['align'] ? attr['align'] : 'center'
|
||||||
|
const field = resolveColumnField(attr)
|
||||||
|
if (field) {
|
||||||
|
attr.field = field
|
||||||
|
}
|
||||||
|
attr['column-key'] = attr['column-key'] ? attr['column-key'] : attr.field || attr.prop || uuid()
|
||||||
|
return () => {
|
||||||
|
return createVNode(Column, attr, slots.default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ export const defaultAttribute: VxeTableProps = {
|
|||||||
border: true,
|
border: true,
|
||||||
stripe: true,
|
stripe: true,
|
||||||
size: 'small',
|
size: 'small',
|
||||||
columnConfig: { resizable: true },
|
columnConfig: { resizable: true, useKey: true },
|
||||||
rowConfig: { isCurrent: true, isHover: true },
|
rowConfig: { isCurrent: true, isHover: true, },
|
||||||
scrollX: { scrollToLeftOnChange: true },
|
scrollX: { scrollToLeftOnChange: true },
|
||||||
scrollY: { scrollToTopOnChange: true, enabled: true },
|
scrollY: { enabled: false },
|
||||||
treeConfig: {
|
// 注意:全局不要默认开启 treeConfig,会与 stripe 冲突;树表在页面自行配置
|
||||||
reserve: true
|
customConfig: { enabled: true, allowFixed: true, storage: false, showFooter: false, immediate: true ,mode:'default'},
|
||||||
},
|
showOverflow: 'tooltip',
|
||||||
showOverflow: true,
|
showHeaderOverflow: false
|
||||||
showFooter:true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
label-position="left"
|
label-position="left"
|
||||||
:inline="true"
|
:inline="true"
|
||||||
>
|
>
|
||||||
<el-form-item v-if="datePicker" style="grid-column: span 2; max-width: 630px">
|
<el-form-item
|
||||||
|
v-if="datePicker"
|
||||||
|
style="grid-column: span 2"
|
||||||
|
:style="{ maxWidth: isStatisticData == 1 ? '750px' : '610px' }"
|
||||||
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-checkbox v-if="showTimeAll" v-model="timeAll" label="统计时间" />
|
<el-checkbox v-if="showTimeAll" v-model="timeAll" label="统计时间" />
|
||||||
<span v-else>{{ dateLabel }}</span>
|
<span v-else>{{ dateLabel }}</span>
|
||||||
@@ -19,11 +23,17 @@
|
|||||||
v-if="timeAll"
|
v-if="timeAll"
|
||||||
:nextFlag="nextFlag"
|
:nextFlag="nextFlag"
|
||||||
:theCurrentTime="theCurrentTime"
|
:theCurrentTime="theCurrentTime"
|
||||||
|
:isStatisticData="isStatisticData"
|
||||||
></DatePicker>
|
></DatePicker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="区域" v-if="area">
|
<el-form-item label="区域" v-if="area">
|
||||||
<Area ref="areaRef" v-model="tableStore.table.params.deptIndex" @change-value="onAreaChange" />
|
<Area
|
||||||
|
ref="areaRef"
|
||||||
|
v-model="tableStore.table.params.deptIndex"
|
||||||
|
@change-value="onAreaChange"
|
||||||
|
style="width: 200px"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<slot name="select"></slot>
|
<slot name="select"></slot>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -60,6 +70,15 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<slot name="operation"></slot>
|
<slot name="operation"></slot>
|
||||||
|
<el-button
|
||||||
|
class="ml10"
|
||||||
|
v-if="showCustomColumn"
|
||||||
|
:icon="Setting"
|
||||||
|
@mousedown="onCustomColumnMousedown"
|
||||||
|
@click="openCustomColumn"
|
||||||
|
>
|
||||||
|
列设置
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-form
|
<el-form
|
||||||
:style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose"
|
:style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose"
|
||||||
@@ -79,8 +98,7 @@ import DatePicker from '@/components/form/datePicker/index.vue'
|
|||||||
import Area from '@/components/form/area/index.vue'
|
import Area from '@/components/form/area/index.vue'
|
||||||
import { mainHeight } from '@/utils/layout'
|
import { mainHeight } from '@/utils/layout'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import { useDictData } from '@/stores/dictData'
|
||||||
import { Search, RefreshLeft } from '@element-plus/icons-vue'
|
import { Search, RefreshLeft, Setting } from '@element-plus/icons-vue'
|
||||||
import { defineProps } from 'vue'
|
|
||||||
const emit = defineEmits(['selectChange', 'areaChange'])
|
const emit = defineEmits(['selectChange', 'areaChange'])
|
||||||
const tableStore = inject('tableStore') as TableStore
|
const tableStore = inject('tableStore') as TableStore
|
||||||
const tableHeader = ref()
|
const tableHeader = ref()
|
||||||
@@ -100,6 +118,8 @@ interface Props {
|
|||||||
showExport?: boolean //导出控制
|
showExport?: boolean //导出控制
|
||||||
showTimeAll?: boolean //控制时间是否显示
|
showTimeAll?: boolean //控制时间是否显示
|
||||||
dateLabel?: string //设置时间名称
|
dateLabel?: string //设置时间名称
|
||||||
|
isStatisticData?: number | string // 0统计数据 1分钟数据
|
||||||
|
showCustomColumn?: boolean // 列设置
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -111,7 +131,9 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
showReset: true,
|
showReset: true,
|
||||||
showExport: false,
|
showExport: false,
|
||||||
showTimeAll: false,
|
showTimeAll: false,
|
||||||
dateLabel: '统计日期'
|
dateLabel: '统计日期',
|
||||||
|
isStatisticData: 0,
|
||||||
|
showCustomColumn: false
|
||||||
})
|
})
|
||||||
// 动态计算table高度
|
// 动态计算table高度
|
||||||
const resizeObserver = new ResizeObserver(entries => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
@@ -153,7 +175,31 @@ watch(
|
|||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
let customColumnVisibleOnPress = false
|
||||||
|
const onCustomColumnMousedown = () => {
|
||||||
|
const table = tableStore?.table?.ref as any
|
||||||
|
if (!table) return
|
||||||
|
customColumnVisibleOnPress = table.getCustomVisible?.() ?? !!table.reactData?.customStore?.visible
|
||||||
|
if (table.reactData?.customStore) {
|
||||||
|
table.reactData.customStore.activeBtn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const openCustomColumn = () => {
|
||||||
|
const table = tableStore?.table?.ref as any
|
||||||
|
if (!table) return
|
||||||
|
if (table.reactData?.customStore) {
|
||||||
|
table.reactData.customStore.activeBtn = false
|
||||||
|
}
|
||||||
|
if (customColumnVisibleOnPress) {
|
||||||
|
table?.closeCustom?.()
|
||||||
|
} else {
|
||||||
|
table?.openCustom?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (props.showCustomColumn && tableStore?.table) {
|
||||||
|
tableStore.table.customColumnInHeader = true
|
||||||
|
}
|
||||||
timeAll.value = props.showTimeAll ? false : true
|
timeAll.value = props.showTimeAll ? false : true
|
||||||
if (props.datePicker && timeAll.value) {
|
if (props.datePicker && timeAll.value) {
|
||||||
tableStore.table.params.searchBeginTime = datePickerRef.value.timeValue[0]
|
tableStore.table.params.searchBeginTime = datePickerRef.value.timeValue[0]
|
||||||
@@ -297,6 +343,7 @@ defineExpose({
|
|||||||
padding: 13px 15px;
|
padding: 13px 15px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.table-header-operate-text {
|
.table-header-operate-text {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
|
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
|
||||||
<vxe-table ref="tableRef" height="auto" :key="key" :data="tableStore.table.data"
|
<div v-if="showCustomColumn && !tableStore?.table?.customColumnInHeader" class="table-custom-toolbar">
|
||||||
v-loading="tableStore.table.loading" v-bind="Object.assign({}, defaultAttribute, $attrs)"
|
<el-button icon="el-icon-Setting" @mousedown="onCustomColumnMousedown" @click="openCustomColumn">
|
||||||
@checkbox-all="selectChangeEvent" @checkbox-change="selectChangeEvent" :showOverflow="showOverflow"
|
列设置
|
||||||
@sort-change="handleSortChange">
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<vxe-table
|
||||||
|
ref="tableRef"
|
||||||
|
height="auto"
|
||||||
|
:key="key"
|
||||||
|
:data="tableStore.table.data"
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
v-bind="tableBindProps"
|
||||||
|
:id="getTableId()"
|
||||||
|
@checkbox-all="selectChangeEvent"
|
||||||
|
@checkbox-change="selectChangeEvent"
|
||||||
|
@cell-click="onCellClick"
|
||||||
|
>
|
||||||
|
<!-- @sort-change="handleSortChange" -->
|
||||||
<!-- Column 组件内部是 el-table-column -->
|
<!-- Column 组件内部是 el-table-column -->
|
||||||
<template v-if="isGroup">
|
<template v-if="isGroup">
|
||||||
<GroupColumn :column="tableStore.table.column" />
|
<GroupColumn :column="tableStore.table.column" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
|
<Column
|
||||||
:tree-node="item.treeNode">
|
:attr="item"
|
||||||
|
:key="key + '-column'"
|
||||||
|
v-for="(item, key) in tableStore.table.column"
|
||||||
|
:tree-node="item.treeNode"
|
||||||
|
>
|
||||||
<!-- tableStore 预设的列 render 方案 -->
|
<!-- tableStore 预设的列 render 方案 -->
|
||||||
<template v-if="item.render" #default="scope">
|
<template v-if="item.render" #default="scope">
|
||||||
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
|
<FieldRender
|
||||||
'-' +
|
:field="item"
|
||||||
item.render +
|
:row="scope.row"
|
||||||
'-' +
|
:column="scope.column"
|
||||||
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
:index="scope.rowIndex"
|
||||||
" />
|
:key="
|
||||||
|
key +
|
||||||
|
'-' +
|
||||||
|
item.render +
|
||||||
|
'-' +
|
||||||
|
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
||||||
|
"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,17 +52,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="tableStore.showPage" class="table-pagination">
|
<div v-if="tableStore.showPage" class="table-pagination">
|
||||||
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
|
<el-pagination
|
||||||
:page-sizes="pageSizes" background
|
:currentPage="tableStore.table.params!.pageNum"
|
||||||
|
:page-size="tableStore.table.params!.pageSize"
|
||||||
|
:page-sizes="pageSizes"
|
||||||
|
background
|
||||||
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
|
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
|
||||||
:total="tableStore.table.total" @size-change="onTableSizeChange"
|
:total="tableStore.table.total"
|
||||||
@current-change="onTableCurrentChange"></el-pagination>
|
@size-change="onTableSizeChange"
|
||||||
|
@current-change="onTableCurrentChange"
|
||||||
|
></el-pagination>
|
||||||
</div>
|
</div>
|
||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, nextTick, inject, computed, onMounted, watch } from 'vue'
|
import { ref, nextTick, inject, computed, onMounted, watch, useAttrs } from 'vue'
|
||||||
import type { ElTable } from 'element-plus'
|
import type { ElTable } from 'element-plus'
|
||||||
import { VxeTableEvents, VxeTableInstance } from 'vxe-table'
|
import { VxeTableEvents, VxeTableInstance } from 'vxe-table'
|
||||||
import FieldRender from '@/components/table/fieldRender/index.vue'
|
import FieldRender from '@/components/table/fieldRender/index.vue'
|
||||||
@@ -48,22 +78,49 @@ import type TableStoreClass from '@/utils/tableStore'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
inheritAttrs: false
|
||||||
|
})
|
||||||
|
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const tableRef = ref<VxeTableInstance>()
|
const tableRef = ref<VxeTableInstance>()
|
||||||
const tableStore = inject('tableStore') as TableStoreClass
|
const tableStore = inject('tableStore') as TableStoreClass
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const key = ref(0)
|
const key = ref(0)
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'cell-click', params: any): void
|
||||||
|
}>()
|
||||||
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
|
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
|
||||||
isGroup?: boolean
|
isGroup?: boolean
|
||||||
showOverflow?: boolean
|
showOverflow?: boolean | 'ellipsis' | 'title' | 'tooltip'
|
||||||
height?: string | number
|
height?: string | number
|
||||||
|
showCustomColumn?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
isGroup: false,
|
isGroup: false,
|
||||||
showOverflow: true,
|
showOverflow: 'tooltip',
|
||||||
height: undefined
|
height: undefined,
|
||||||
|
showCustomColumn: false
|
||||||
})
|
})
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const tableBindProps = computed(() => {
|
||||||
|
const enableStorage = props.showCustomColumn || !!tableStore?.table?.customColumnInHeader
|
||||||
|
const baseCustomConfig = (defaultAttribute.customConfig || {}) as Record<string, any>
|
||||||
|
const attrsCustomConfig = ((attrs.customConfig as Record<string, any>) || {}) as Record<string, any>
|
||||||
|
return Object.assign({}, defaultAttribute, attrs, {
|
||||||
|
showOverflow: props.showOverflow,
|
||||||
|
showHeaderOverflow: false,
|
||||||
|
customConfig: {
|
||||||
|
...baseCustomConfig,
|
||||||
|
...attrsCustomConfig,
|
||||||
|
storage: enableStorage ? true : !!attrsCustomConfig.storage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const onCellClick: VxeTableEvents.CellClick<any> = params => {
|
||||||
|
emit('cell-click', params)
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.table.ref = tableRef.value as VxeTableInstance
|
tableStore.table.ref = tableRef.value as VxeTableInstance
|
||||||
})
|
})
|
||||||
@@ -93,10 +150,33 @@ const selectChangeEvent: VxeTableEvents.CheckboxChange<any> = ({ checked }) => {
|
|||||||
const records = (tableRef.value as VxeTableInstance).getCheckboxRecords()
|
const records = (tableRef.value as VxeTableInstance).getCheckboxRecords()
|
||||||
tableStore.onTableAction('selection-change', records)
|
tableStore.onTableAction('selection-change', records)
|
||||||
}
|
}
|
||||||
|
let customColumnVisibleOnPress = false
|
||||||
|
const onCustomColumnMousedown = () => {
|
||||||
|
const table = tableRef.value as any
|
||||||
|
if (!table) return
|
||||||
|
customColumnVisibleOnPress = table.getCustomVisible?.() ?? !!table.reactData?.customStore?.visible
|
||||||
|
if (table.reactData?.customStore) {
|
||||||
|
table.reactData.customStore.activeBtn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const openCustomColumn = () => {
|
||||||
|
const table = tableRef.value as any
|
||||||
|
if (!table) return
|
||||||
|
if (table.reactData?.customStore) {
|
||||||
|
table.reactData.customStore.activeBtn = false
|
||||||
|
}
|
||||||
|
if (customColumnVisibleOnPress) {
|
||||||
|
table?.closeCustom?.()
|
||||||
|
} else {
|
||||||
|
table?.openCustom?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
const getRef = () => {
|
const getRef = () => {
|
||||||
return tableRef.value
|
return tableRef.value
|
||||||
}
|
}
|
||||||
|
const getTableId = () => {
|
||||||
|
return tableStore.table.filename || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || ''
|
||||||
|
}
|
||||||
// 排序
|
// 排序
|
||||||
const handleSortChange = ({ column, order }: { column: TableColumn; order: 'asc' | 'desc' | null }) => {
|
const handleSortChange = ({ column, order }: { column: TableColumn; order: 'asc' | 'desc' | null }) => {
|
||||||
// console.log('排序列:', column?.property);
|
// console.log('排序列:', column?.property);
|
||||||
|
|||||||
@@ -3,167 +3,177 @@
|
|||||||
<el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
|
<el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
|
||||||
<el-tab-pane label="监测点详情" name="tab1">
|
<el-tab-pane label="监测点详情" name="tab1">
|
||||||
<el-descriptions :column="3" border label-width="150px">
|
<el-descriptions :column="3" border label-width="150px">
|
||||||
<el-descriptions-item label="项目工程">
|
<el-descriptions-item label="项目工程">
|
||||||
{{ details.areaName }}
|
{{ details.areaName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="项目单位">
|
<el-descriptions-item label="项目单位">
|
||||||
{{ details.gdName }}
|
{{ details.gdName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="所属变电站">
|
<el-descriptions-item label="所属变电站">
|
||||||
{{ details.bdName }}
|
{{ details.bdName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="电压等级">
|
<el-descriptions-item label="监测点名称">
|
||||||
{{ details.scale }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="终端厂家">
|
|
||||||
{{ details.manufacturer }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="终端名称">
|
|
||||||
{{ details.devName }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="网络参数">
|
|
||||||
{{ details.ip }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="监测点名称">
|
|
||||||
{{ details.lineName }}
|
{{ details.lineName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="监测点序号">
|
<el-descriptions-item label="监测点对象名称">
|
||||||
{{ details.id }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="通讯状态">
|
|
||||||
{{ details.comFlag }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="干扰源类型">
|
|
||||||
{{ details.loadType }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="监测点对象名称">
|
|
||||||
{{ details.objName }}
|
{{ details.objName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="接线方式">
|
<el-descriptions-item label="监测点序号">
|
||||||
|
{{ details.id }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="终端厂家">
|
||||||
|
{{ details.manufacturer }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="终端名称">
|
||||||
|
{{ details.devName }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="终端型号">
|
||||||
|
{{ typeArr.find(item => item.id == details.devType)?.name }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="电压等级">
|
||||||
|
{{ details.scale }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="网络参数">
|
||||||
|
{{ details.ip }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="通讯状态">
|
||||||
|
{{ details.comFlag }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="干扰源类型">
|
||||||
|
{{ details.loadType }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="接线方式">
|
||||||
{{ details.ptType }}
|
{{ details.ptType }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="PT变比">
|
<el-descriptions-item label="统计间隔(分钟)">
|
||||||
|
{{ details.timeInterval }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="PT变比">
|
||||||
{{ details.pt }}
|
{{ details.pt }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="CT变比">
|
<el-descriptions-item label="CT变比">
|
||||||
{{ details.ct }}
|
{{ details.ct }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="基准容量(MVA)">
|
<el-descriptions-item label="基准容量(MVA)">
|
||||||
{{ details.standardCapacity }}
|
{{ details.standardCapacity }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="最小短路容量(MVA)">
|
<el-descriptions-item label="供电设备容量(MVA)">
|
||||||
{{ details.shortCapacity }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="供电设备容量(MVA)">
|
|
||||||
{{ details.devCapacity }}
|
{{ details.devCapacity }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="用户协议容量(MVA)">
|
<el-descriptions-item label="最小短路容量(MW)">
|
||||||
|
{{ details.shortCapacity }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="用户协议容量(MW)">
|
||||||
{{ details.dealCapacity }}
|
{{ details.dealCapacity }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="监测点限值" name="tab2">
|
<el-tab-pane label="监测点限值" name="tab2">
|
||||||
<el-descriptions :column="3" border label-width="250px">
|
<el-descriptions :column="3" border label-width="250px">
|
||||||
<el-descriptions-item label="电压偏差上限值(%)">
|
<el-descriptions-item label="电压偏差上限值(%)">
|
||||||
{{ limitValue.voltageDev }}
|
{{ limitValue.voltageDev }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="电压偏差下限值(%)">
|
<el-descriptions-item label="电压偏差下限值(%)">
|
||||||
{{ limitValue.uvoltageDev }}
|
{{ limitValue.uvoltageDev }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="频率偏差限值(Hz)">
|
<el-descriptions-item label="频率偏差限值(Hz)">
|
||||||
{{ limitValue.freqDev }}
|
{{ limitValue.freqDev }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="三相电压不平衡度限值(%)">
|
<el-descriptions-item label="三相电压不平衡度限值(%)">
|
||||||
{{ limitValue.ubalance }}
|
{{ limitValue.ubalance }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="负序电流限值(A)">
|
<el-descriptions-item label="负序电流限值(A)">
|
||||||
{{ limitValue.ineg }}
|
{{ limitValue.ineg }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="长时闪变限值(%)">
|
<el-descriptions-item label="长时闪变限值(%)">
|
||||||
{{ limitValue.flicker }}
|
{{ limitValue.flicker }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="电压总畸变率限值(%)">
|
<el-descriptions-item label="电压总畸变率限值(%)">
|
||||||
{{ limitValue.uaberrance }}
|
{{ limitValue.uaberrance }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="奇次谐波电压含有率限值(%)">
|
<el-descriptions-item label="奇次谐波电压含有率限值(%)">
|
||||||
{{ limitValue.oddHarm }}
|
{{ limitValue.oddHarm }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="偶次谐波电压含有率限值(%)">
|
<el-descriptions-item label="偶次谐波电压含有率限值(%)">
|
||||||
{{ limitValue.evenHarm }}
|
{{ limitValue.evenHarm }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="3次谐波电流幅值限值(A)">
|
<el-descriptions-item label="3次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm3 }}
|
{{ limitValue.iharm3 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="4次谐波电流幅值限值(A)">
|
<el-descriptions-item label="4次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm4 }}
|
{{ limitValue.iharm4 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="5次谐波电流幅值限值(A)">
|
<el-descriptions-item label="5次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm5 }}
|
{{ limitValue.iharm5 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="6次谐波电流幅值限值(A)">
|
<el-descriptions-item label="6次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm6 }}
|
{{ limitValue.iharm6 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="7次谐波电流幅值限值(A)">
|
<el-descriptions-item label="7次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm7 }}
|
{{ limitValue.iharm7 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="8次谐波电流幅值限值(A)">
|
<el-descriptions-item label="8次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm8 }}
|
{{ limitValue.iharm8 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="9次谐波电流幅值限值(A)">
|
<el-descriptions-item label="9次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm9 }}
|
{{ limitValue.iharm9 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="10次谐波电流幅值限值(A)">
|
<el-descriptions-item label="10次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm10 }}
|
{{ limitValue.iharm10 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="11次谐波电流幅值限值(A)">
|
<el-descriptions-item label="11次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm11 }}
|
{{ limitValue.iharm11 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="12次谐波电流幅值限值(A)">
|
<el-descriptions-item label="12次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm12 }}
|
{{ limitValue.iharm12 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="13次谐波电流幅值限值(A)">
|
<el-descriptions-item label="13次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm13 }}
|
{{ limitValue.iharm13 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="14次谐波电流幅值限值(A)">
|
<el-descriptions-item label="14次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm14 }}
|
{{ limitValue.iharm14 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="15次谐波电流幅值限值(A)">
|
<el-descriptions-item label="15次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm15 }}
|
{{ limitValue.iharm15 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="16次谐波电流幅值限值(A)">
|
<el-descriptions-item label="16次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm16 }}
|
{{ limitValue.iharm16 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="17次谐波电流幅值限值(A)">
|
<el-descriptions-item label="17次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm17 }}
|
{{ limitValue.iharm17 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="18次谐波电流幅值限值(A)">
|
<el-descriptions-item label="18次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm18 }}
|
{{ limitValue.iharm18 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="19次谐波电流幅值限值(A)">
|
<el-descriptions-item label="19次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm19 }}
|
{{ limitValue.iharm19 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="20次谐波电流幅值限值(A)">
|
<el-descriptions-item label="20次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm20 }}
|
{{ limitValue.iharm20 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="21次谐波电流幅值限值(A)">
|
<el-descriptions-item label="21次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm21 }}
|
{{ limitValue.iharm21 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="22次谐波电流幅值限值(A)">
|
<el-descriptions-item label="22次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm22 }}
|
{{ limitValue.iharm22 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="23次谐波电流幅值限值(A)">
|
<el-descriptions-item label="23次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm23 }}
|
{{ limitValue.iharm23 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="24次谐波电流幅值限值(A)">
|
<el-descriptions-item label="24次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm24 }}
|
{{ limitValue.iharm24 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="25次谐波电流幅值限值(A)">
|
<el-descriptions-item label="25次谐波电流幅值限值(A)">
|
||||||
{{ limitValue.iharm25 }}
|
{{ limitValue.iharm25 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="0.5-1.5次间谐波电压含有率限值(%)">
|
<el-descriptions-item label="0.5-1.5次间谐波电压含有率限值(%)">
|
||||||
{{ limitValue.inUharm }}
|
{{ limitValue.inUharm }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="2.5-15.5次谐波电压含有率限值(%)">
|
<el-descriptions-item label="2.5-15.5次谐波电压含有率限值(%)">
|
||||||
{{ limitValue.inUharm16 }}
|
{{ limitValue.inUharm16 }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@@ -174,11 +184,14 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, inject } from 'vue'
|
import { ref, inject } from 'vue'
|
||||||
import { getLineOverLimitData, getLineDetailData } from '@/api/device-boot/line'
|
import { getLineOverLimitData, getLineDetailData } from '@/api/device-boot/line'
|
||||||
|
import { useDictData } from '@/stores/dictData'
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
const activeName = ref('tab1')
|
const activeName = ref('tab1')
|
||||||
const details: any = ref([])
|
const details: any = ref([])
|
||||||
|
const dictData = useDictData()
|
||||||
const limitValue: any = ref([])
|
const limitValue: any = ref([])
|
||||||
|
const typeArr = dictData.getBasicData('Dev_Type')
|
||||||
const open = (data: any) => {
|
const open = (data: any) => {
|
||||||
details.value = []
|
details.value = []
|
||||||
limitValue.value = []
|
limitValue.value = []
|
||||||
@@ -187,7 +200,7 @@ const open = (data: any) => {
|
|||||||
|
|
||||||
getLineDetailData(data.id).then(res => {
|
getLineDetailData(data.id).then(res => {
|
||||||
details.value = res.data
|
details.value = res.data
|
||||||
|
res.data.objName ? (title.value = res.data.objName + '_' + title.value) : ''
|
||||||
})
|
})
|
||||||
getLineOverLimitData(data.id).then(res => {
|
getLineOverLimitData(data.id).then(res => {
|
||||||
limitValue.value = res.data
|
limitValue.value = res.data
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<Tree ref="treRef" :data="tree" style="height: 100%" :width="'100%'" :expanded="expanded" />
|
<Tree ref="treRef" :data="tree" style="height: 100%" :width="'100%'" :expanded="expanded" />
|
||||||
</template>
|
</template>
|
||||||
<!-- <div class="mb10">
|
<!-- <div class="mb10">
|
||||||
<el-button type="primary" icon="el-icon-Download" size="small" @click="exportExcelTemplate" :loading="loading">模版下载</el-button>
|
<el-button type="primary" icon="el-icon-Download" size="small" @click="exportExcelTemplate" :loading="loading">模版下载</el-button>
|
||||||
<el-button type="primary" icon="el-icon-Upload" size="small">导入</el-button>
|
<el-button type="primary" icon="el-icon-Upload" size="small">导入</el-button>
|
||||||
<el-button type="primary" icon="el-icon-Download" size="small" @click="ledgerEverywhere" :loading="loading1">导出</el-button>
|
<el-button type="primary" icon="el-icon-Download" size="small" @click="ledgerEverywhere" :loading="loading1">导出</el-button>
|
||||||
@@ -11,7 +10,7 @@
|
|||||||
import { ref, nextTick } from 'vue'
|
import { ref, nextTick } from 'vue'
|
||||||
import Tree from './index.vue'
|
import Tree from './index.vue'
|
||||||
|
|
||||||
import { getTerminalTree,downTerminalTemplate,exportTerminalBase } from '@/api/device-boot/Business'
|
import { getTerminalTree, downTerminalTemplate, exportTerminalBase } from '@/api/device-boot/Business'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
|
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -28,58 +27,108 @@ const info = (id: any) => {
|
|||||||
expanded.value = [id]
|
expanded.value = [id]
|
||||||
getTerminalTree().then(res => {
|
getTerminalTree().then(res => {
|
||||||
// let arr: any[] = []
|
// let arr: any[] = []
|
||||||
if (VITE_FLAG) {
|
// if (VITE_FLAG) {
|
||||||
res.data.forEach((item: any) => {
|
// res.data.forEach((item: any) => {
|
||||||
item.icon = 'el-icon-Menu'
|
// item.icon = 'el-icon-Menu'
|
||||||
item.plevel = item.level
|
// item.plevel = item.level
|
||||||
item.level = 0
|
// item.level = 0
|
||||||
item.children.forEach((item2: any) => {
|
// item.children.forEach((item2: any) => {
|
||||||
item2.icon = 'el-icon-HomeFilled'
|
// item2.icon = 'el-icon-HomeFilled'
|
||||||
|
|
||||||
item2.plevel = item2.level
|
// item2.plevel = item2.level
|
||||||
item2.level = 100
|
// item2.level = 100
|
||||||
expanded.value.push(item2.id)
|
// expanded.value.push(item2.id)
|
||||||
item2.children.forEach((item3: any) => {
|
// item2.children.forEach((item3: any) => {
|
||||||
item3.icon = 'el-icon-CollectionTag'
|
// item3.icon = 'el-icon-CollectionTag'
|
||||||
item3.plevel = item3.level
|
// item3.plevel = item3.level
|
||||||
item3.level = 200
|
// item3.level = 200
|
||||||
item3.children.forEach((item4: any) => {
|
// item3.children.forEach((item4: any) => {
|
||||||
item4.icon = 'el-icon-Flag'
|
// item4.icon = 'el-icon-Flag'
|
||||||
item4.plevel = item4.level
|
// item4.plevel = item4.level
|
||||||
item4.level = 300
|
// item4.level = 300
|
||||||
// arr.push(item4)
|
// // arr.push(item4)
|
||||||
item4.children.forEach((item5: any) => {
|
// item4.children.forEach((item5: any) => {
|
||||||
item5.icon = 'el-icon-OfficeBuilding'
|
// item5.icon = 'el-icon-OfficeBuilding'
|
||||||
item5.plevel = item5.level
|
// item5.plevel = item5.level
|
||||||
item5.level = 300
|
// item5.level = 300
|
||||||
// item5.id = item4.id
|
// // item5.id = item4.id
|
||||||
item5.children.forEach((item6: any) => {
|
// item5.children.forEach((item6: any) => {
|
||||||
item6.icon = 'el-icon-HelpFilled'
|
// item6.icon = 'el-icon-HelpFilled'
|
||||||
item6.plevel = 4
|
// item6.plevel = 4
|
||||||
if (item6.name == '电网侧' && item6.children.length == 0) {
|
// if (item6.name == '电网侧' && item6.children.length == 0) {
|
||||||
item6.level = 400
|
// item6.level = 400
|
||||||
} else {
|
// } else {
|
||||||
item6.level = 400
|
// item6.level = 400
|
||||||
}
|
// }
|
||||||
item6.children.forEach((item7: any) => {
|
// item6.children.forEach((item7: any) => {
|
||||||
item7.icon = 'el-icon-Film'
|
// item7.icon = 'el-icon-Film'
|
||||||
item7.plevel = item7.level
|
// item7.plevel = item7.level
|
||||||
item7.level = 400
|
// item7.level = 400
|
||||||
item7.children.forEach((item8: any) => {
|
// item7.children.forEach((item8: any) => {
|
||||||
item8.icon = 'el-icon-Collection'
|
// item8.icon = 'el-icon-Collection'
|
||||||
item8.plevel = item8.level
|
// item8.plevel = item8.level
|
||||||
item8.level = 500
|
// item8.level = 500
|
||||||
item8.children.forEach((item9: any) => {
|
// item8.children.forEach((item9: any) => {
|
||||||
item9.icon = 'el-icon-Share'
|
// item9.icon = 'el-icon-Share'
|
||||||
item9.plevel = item9.level
|
// item9.plevel = item9.level
|
||||||
item9.level = 600
|
// item9.level = 600
|
||||||
item9.children.forEach((item10: any) => {
|
// item9.children.forEach((item10: any) => {
|
||||||
item10.icon = 'el-icon-Location'
|
// item10.icon = 'el-icon-Location'
|
||||||
item10.plevel = item10.level
|
// item10.plevel = item10.level
|
||||||
item10.level = 700
|
// item10.level = 700
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
res.data.forEach((item: any) => {
|
||||||
|
item.icon = 'el-icon-Menu'
|
||||||
|
item.color = 'var(--el-color-primary)'
|
||||||
|
item.plevel = item.level
|
||||||
|
item.level = (item.level + 1) * 100
|
||||||
|
item.children.forEach((item2: any) => {
|
||||||
|
item2.icon = 'el-icon-HomeFilled'
|
||||||
|
item2.color = 'var(--el-color-primary)'
|
||||||
|
item2.plevel = item2.level
|
||||||
|
item2.level = (item2.level + 1) * 100
|
||||||
|
expanded.value.push(item2.id)
|
||||||
|
item2.children.forEach((item3: any) => {
|
||||||
|
item3.icon = 'el-icon-CollectionTag'
|
||||||
|
item3.color = 'var(--el-color-primary)'
|
||||||
|
item3.plevel = item3.level
|
||||||
|
item3.level = (item3.level + 1) * 100
|
||||||
|
item3.children.forEach((item4: any) => {
|
||||||
|
item4.icon = 'el-icon-Flag'
|
||||||
|
item4.color = 'var(--el-color-primary)'
|
||||||
|
item4.plevel = item4.level
|
||||||
|
item4.level = (item4.level + 1) * 100
|
||||||
|
item4.children.forEach((item5: any) => {
|
||||||
|
item5.icon = 'el-icon-OfficeBuilding'
|
||||||
|
item5.color = 'var(--el-color-primary)'
|
||||||
|
item5.plevel = item5.level
|
||||||
|
item5.level = (item5.level == 7 ? 4 : item5.level + 1) * 100
|
||||||
|
item5.children.forEach((item6: any) => {
|
||||||
|
item6.icon =
|
||||||
|
item6.children?.[0]?.children?.length > 0 ? 'el-icon-Film' : 'el-icon-Share'
|
||||||
|
item6.color = 'var(--el-color-primary)'
|
||||||
|
item6.plevel = item6.level
|
||||||
|
item6.level = (item6.level + 1) * 100
|
||||||
|
item6.children.forEach((item7: any) => {
|
||||||
|
item7.icon = item7.children.length > 0 ? 'el-icon-Share' : 'el-icon-Location'
|
||||||
|
item7.color = 'var(--el-color-primary)'
|
||||||
|
item7.plevel = item7.level
|
||||||
|
item7.level = (item7.level + 1) * 100
|
||||||
|
item7.children.forEach((item8: any) => {
|
||||||
|
item8.icon = 'el-icon-Location'
|
||||||
|
item8.color = 'var(--el-color-primary)'
|
||||||
|
item8.plevel = item8.level
|
||||||
|
item8.level = (item8.level + 1) * 100
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -87,49 +136,8 @@ const info = (id: any) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
})
|
||||||
res.data.forEach((item: any) => {
|
// }
|
||||||
item.icon = 'el-icon-Menu'
|
|
||||||
item.plevel = item.level
|
|
||||||
item.level = (item.level + 1) * 100
|
|
||||||
item.children.forEach((item2: any) => {
|
|
||||||
item2.icon = 'el-icon-HomeFilled'
|
|
||||||
item2.plevel = item2.level
|
|
||||||
item2.level = (item2.level + 1) * 100
|
|
||||||
expanded.value.push(item2.id)
|
|
||||||
item2.children.forEach((item3: any) => {
|
|
||||||
item3.icon = 'el-icon-CollectionTag'
|
|
||||||
item3.plevel = item3.level
|
|
||||||
item3.level = (item3.level + 1) * 100
|
|
||||||
item3.children.forEach((item4: any) => {
|
|
||||||
item4.icon = 'el-icon-Flag'
|
|
||||||
item4.plevel = item4.level
|
|
||||||
item4.level = (item4.level + 1) * 100
|
|
||||||
item4.children.forEach((item5: any) => {
|
|
||||||
item5.icon = 'el-icon-OfficeBuilding'
|
|
||||||
item5.plevel = item5.level
|
|
||||||
item5.level = (item5.level == 7 ? 4 : item5.level + 1) * 100
|
|
||||||
item5.children.forEach((item6: any) => {
|
|
||||||
item6.icon = 'el-icon-Film'
|
|
||||||
item6.plevel = item6.level
|
|
||||||
item6.level = (item6.level + 1) * 100
|
|
||||||
item6.children.forEach((item7: any) => {
|
|
||||||
item7.icon = 'el-icon-Share'
|
|
||||||
item7.plevel = item7.level
|
|
||||||
item7.level = (item7.level + 1) * 100
|
|
||||||
item7.children.forEach((item8: any) => {
|
|
||||||
item8.icon = 'el-icon-Location'
|
|
||||||
item8.plevel = item8.level
|
|
||||||
item8.level = (item8.level + 1) * 100
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
tree.value = res.data
|
tree.value = res.data
|
||||||
|
|
||||||
@@ -149,7 +157,7 @@ const info = (id: any) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 下载模版
|
// 下载模版
|
||||||
const exportExcelTemplate = async() => {
|
const exportExcelTemplate = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
downTerminalTemplate().then((res: any) => {
|
downTerminalTemplate().then((res: any) => {
|
||||||
let blob = new Blob([res], {
|
let blob = new Blob([res], {
|
||||||
@@ -168,7 +176,7 @@ const exportExcelTemplate = async() => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
// 导出台账
|
// 导出台账
|
||||||
const ledgerEverywhere = async() => {
|
const ledgerEverywhere = async () => {
|
||||||
loading1.value = true
|
loading1.value = true
|
||||||
exportTerminalBase().then((res: any) => {
|
exportTerminalBase().then((res: any) => {
|
||||||
let blob = new Blob([res], {
|
let blob = new Blob([res], {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
style="min-width: unset; padding: 10px 10px 0"
|
style="min-width: unset; padding: 10px 10px 0"
|
||||||
@change="loadData"
|
@change="loadData"
|
||||||
v-if="props.showSelect"
|
v-if="props.showSelect"
|
||||||
|
filterable
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in classificationData"
|
v-for="item in classificationData"
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
const config: {
|
|
||||||
base_url: string
|
|
||||||
result_code: number | string
|
|
||||||
default_headers: AxiosHeaders
|
|
||||||
request_timeout: number
|
|
||||||
} = {
|
|
||||||
/**
|
|
||||||
* api请求基础路径
|
|
||||||
*/
|
|
||||||
base_url: import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL,
|
|
||||||
/**
|
|
||||||
* 接口成功返回状态码
|
|
||||||
*/
|
|
||||||
result_code: 200,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接口请求超时时间
|
|
||||||
*/
|
|
||||||
request_timeout: 30000,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认接口请求类型
|
|
||||||
* 可选值:application/x-www-form-urlencoded multipart/form-data
|
|
||||||
*/
|
|
||||||
default_headers: 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
export { config }
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export default {
|
|
||||||
'401': '认证失败,无法访问系统资源',
|
|
||||||
'403': '当前操作没有权限',
|
|
||||||
'404': '访问资源不存在',
|
|
||||||
default: '系统未知错误,请反馈给管理员'
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { service } from './service'
|
|
||||||
|
|
||||||
import { config } from './config'
|
|
||||||
|
|
||||||
const { default_headers } = config
|
|
||||||
|
|
||||||
const request = (option: any) => {
|
|
||||||
const { url, method, params, data, headersType, responseType, ...config } = option
|
|
||||||
return service({
|
|
||||||
url: url,
|
|
||||||
method,
|
|
||||||
params,
|
|
||||||
data,
|
|
||||||
...config,
|
|
||||||
responseType: responseType,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': headersType || default_headers
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
get: async <T = any>(option: any) => {
|
|
||||||
const res = await request({ method: 'GET', ...option })
|
|
||||||
return res.data as unknown as T
|
|
||||||
},
|
|
||||||
post: async <T = any>(option: any) => {
|
|
||||||
const res = await request({ method: 'POST', ...option })
|
|
||||||
return res.data as unknown as T
|
|
||||||
},
|
|
||||||
postOriginal: async (option: any) => {
|
|
||||||
const res = await request({ method: 'POST', ...option })
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
delete: async <T = any>(option: any) => {
|
|
||||||
const res = await request({ method: 'DELETE', ...option })
|
|
||||||
return res.data as unknown as T
|
|
||||||
},
|
|
||||||
put: async <T = any>(option: any) => {
|
|
||||||
const res = await request({ method: 'PUT', ...option })
|
|
||||||
return res.data as unknown as T
|
|
||||||
},
|
|
||||||
download: async <T = any>(option: any) => {
|
|
||||||
const res = await request({ method: 'GET', responseType: 'blob', ...option })
|
|
||||||
return res as unknown as Promise<T>
|
|
||||||
},
|
|
||||||
upload: async <T = any>(option: any) => {
|
|
||||||
option.headersType = 'multipart/form-data'
|
|
||||||
const res = await request({ method: 'POST', ...option })
|
|
||||||
return res as unknown as Promise<T>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
import axios, {
|
|
||||||
AxiosError,
|
|
||||||
AxiosInstance,
|
|
||||||
AxiosRequestHeaders,
|
|
||||||
AxiosResponse,
|
|
||||||
InternalAxiosRequestConfig
|
|
||||||
} from 'axios'
|
|
||||||
|
|
||||||
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
|
|
||||||
import qs from 'qs'
|
|
||||||
import { config } from '@/config/axios/config'
|
|
||||||
import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
|
|
||||||
import errorCode from './errorCode'
|
|
||||||
|
|
||||||
import { deleteUserCache } from '@/hooks/web/useCache'
|
|
||||||
|
|
||||||
const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
|
|
||||||
const { result_code, base_url, request_timeout } = config
|
|
||||||
|
|
||||||
// 需要忽略的提示。忽略后,自动 Promise.reject('error')
|
|
||||||
const ignoreMsgs = [
|
|
||||||
'无效的刷新令牌', // 刷新令牌被删除时,不用提示
|
|
||||||
'刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面
|
|
||||||
]
|
|
||||||
// 是否显示重新登录
|
|
||||||
export const isRelogin = { show: false }
|
|
||||||
// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
|
|
||||||
// 请求队列
|
|
||||||
let requestList: any[] = []
|
|
||||||
// 是否正在刷新中
|
|
||||||
let isRefreshToken = false
|
|
||||||
// 请求白名单,无须token的接口
|
|
||||||
const whiteList: string[] = ['/login', '/refresh-token']
|
|
||||||
|
|
||||||
// 创建axios实例
|
|
||||||
const service: AxiosInstance = axios.create({
|
|
||||||
baseURL: base_url, // api 的 base_url
|
|
||||||
timeout: request_timeout, // 请求超时时间
|
|
||||||
withCredentials: false // 禁用 Cookie 等信息
|
|
||||||
})
|
|
||||||
|
|
||||||
// request拦截器
|
|
||||||
service.interceptors.request.use(
|
|
||||||
(config: InternalAxiosRequestConfig) => {
|
|
||||||
// 是否需要设置 token
|
|
||||||
let isToken = (config!.headers || {}).isToken === false
|
|
||||||
whiteList.some((v) => {
|
|
||||||
if (config.url) {
|
|
||||||
config.url.indexOf(v) > -1
|
|
||||||
return (isToken = false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (getAccessToken() && !isToken) {
|
|
||||||
;(config as Recordable).headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
|
|
||||||
}
|
|
||||||
// 设置租户
|
|
||||||
if (tenantEnable && tenantEnable === 'true') {
|
|
||||||
const tenantId = getTenantId()
|
|
||||||
if (tenantId) (config as Recordable).headers['tenant-id'] = tenantId
|
|
||||||
}
|
|
||||||
const params = config.params || {}
|
|
||||||
const data = config.data || false
|
|
||||||
if (
|
|
||||||
config.method?.toUpperCase() === 'POST' &&
|
|
||||||
(config.headers as AxiosRequestHeaders)['Content-Type'] ===
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
) {
|
|
||||||
config.data = qs.stringify(data)
|
|
||||||
}
|
|
||||||
// get参数编码
|
|
||||||
if (config.method?.toUpperCase() === 'GET' && params) {
|
|
||||||
config.params = {}
|
|
||||||
const paramsStr = qs.stringify(params, { allowDots: true })
|
|
||||||
if (paramsStr) {
|
|
||||||
config.url = config.url + '?' + paramsStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
(error: AxiosError) => {
|
|
||||||
// Do something with request error
|
|
||||||
console.log(error) // for debug
|
|
||||||
Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// response 拦截器
|
|
||||||
service.interceptors.response.use(
|
|
||||||
async (response: AxiosResponse<any>) => {
|
|
||||||
let { data } = response
|
|
||||||
const config = response.config
|
|
||||||
if (!data) {
|
|
||||||
// 返回“[HTTP]请求没有返回值”;
|
|
||||||
throw new Error()
|
|
||||||
}
|
|
||||||
const { t } = useI18n()
|
|
||||||
// 未设置状态码则默认成功状态
|
|
||||||
// 二进制数据则直接返回,例如说 Excel 导出
|
|
||||||
if (
|
|
||||||
response.request.responseType === 'blob' ||
|
|
||||||
response.request.responseType === 'arraybuffer'
|
|
||||||
) {
|
|
||||||
// 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
|
|
||||||
if (response.data.type !== 'application/json') {
|
|
||||||
return response.data
|
|
||||||
}
|
|
||||||
data = await new Response(response.data).json()
|
|
||||||
}
|
|
||||||
const code = data.code || result_code
|
|
||||||
// 获取错误信息
|
|
||||||
const msg = data.msg || errorCode[code] || errorCode['default']
|
|
||||||
if (ignoreMsgs.indexOf(msg) !== -1) {
|
|
||||||
// 如果是忽略的错误码,直接返回 msg 异常
|
|
||||||
return Promise.reject(msg)
|
|
||||||
} else if (code === 401) {
|
|
||||||
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
|
|
||||||
if (!isRefreshToken) {
|
|
||||||
isRefreshToken = true
|
|
||||||
// 1. 如果获取不到刷新令牌,则只能执行登出操作
|
|
||||||
if (!getRefreshToken()) {
|
|
||||||
return handleAuthorized()
|
|
||||||
}
|
|
||||||
// 2. 进行刷新访问令牌
|
|
||||||
try {
|
|
||||||
const refreshTokenRes = await refreshToken()
|
|
||||||
// 2.1 刷新成功,则回放队列的请求 + 当前请求
|
|
||||||
setToken((await refreshTokenRes).data.data)
|
|
||||||
config.headers!.Authorization = 'Bearer ' + getAccessToken()
|
|
||||||
requestList.forEach((cb: any) => {
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
requestList = []
|
|
||||||
return service(config)
|
|
||||||
} catch (e) {
|
|
||||||
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
|
|
||||||
// 2.2 刷新失败,只回放队列的请求
|
|
||||||
requestList.forEach((cb: any) => {
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
// 提示是否要登出。即不回放当前请求!不然会形成递归
|
|
||||||
return handleAuthorized()
|
|
||||||
} finally {
|
|
||||||
requestList = []
|
|
||||||
isRefreshToken = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 添加到队列,等待刷新获取到新的令牌
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
requestList.push(() => {
|
|
||||||
config.headers!.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
|
||||||
resolve(service(config))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if (code === 500) {
|
|
||||||
ElMessage.error(t('sys.api.errMsg500'))
|
|
||||||
return Promise.reject(new Error(msg))
|
|
||||||
} else if (code === 901) {
|
|
||||||
ElMessage.error({
|
|
||||||
offset: 300,
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
message:
|
|
||||||
'<div>' +
|
|
||||||
t('sys.api.errMsg901') +
|
|
||||||
'</div>' +
|
|
||||||
'<div> </div>' +
|
|
||||||
'<div>参考 https://doc.iocoder.cn/ 教程</div>' +
|
|
||||||
'<div> </div>' +
|
|
||||||
'<div>5 分钟搭建本地环境</div>'
|
|
||||||
})
|
|
||||||
return Promise.reject(new Error(msg))
|
|
||||||
} else if (code !== 200) {
|
|
||||||
if (msg === '无效的刷新令牌') {
|
|
||||||
// hard coding:忽略这个提示,直接登出
|
|
||||||
console.log(msg)
|
|
||||||
} else {
|
|
||||||
ElNotification.error({ title: msg })
|
|
||||||
}
|
|
||||||
return Promise.reject('error')
|
|
||||||
} else {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error: AxiosError) => {
|
|
||||||
console.log('err' + error) // for debug
|
|
||||||
let { message } = error
|
|
||||||
const { t } = useI18n()
|
|
||||||
if (message === 'Network Error') {
|
|
||||||
message = t('sys.api.errorMessage')
|
|
||||||
} else if (message.includes('timeout')) {
|
|
||||||
message = t('sys.api.apiTimeoutMessage')
|
|
||||||
} else if (message.includes('Request failed with status code')) {
|
|
||||||
message = t('sys.api.apiRequestFailed') + message.substr(message.length - 3)
|
|
||||||
}
|
|
||||||
ElMessage.error(message)
|
|
||||||
return Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const refreshToken = async () => {
|
|
||||||
axios.defaults.headers.common['tenant-id'] = getTenantId()
|
|
||||||
return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
|
|
||||||
}
|
|
||||||
const handleAuthorized = () => {
|
|
||||||
const { t } = useI18n()
|
|
||||||
if (!isRelogin.show) {
|
|
||||||
// 如果已经到重新登录页面则不进行弹窗提示
|
|
||||||
if (window.location.href.includes('login?redirect=')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isRelogin.show = true
|
|
||||||
ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), {
|
|
||||||
showCancelButton: false,
|
|
||||||
closeOnClickModal: false,
|
|
||||||
showClose: false,
|
|
||||||
confirmButtonText: t('login.relogin'),
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
deleteUserCache() // 删除用户缓存
|
|
||||||
removeToken()
|
|
||||||
isRelogin.show = false
|
|
||||||
// 干掉token后再走一次路由让它过router.beforeEach的校验
|
|
||||||
window.location.href = window.location.href
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return Promise.reject(t('sys.api.timeoutMessage'))
|
|
||||||
}
|
|
||||||
export { service }
|
|
||||||
@@ -1,35 +1,36 @@
|
|||||||
import { i18n } from '@/plugins/vueI18n'
|
import { i18n } from '@/plugins/vueI18n'
|
||||||
import { useLocaleStoreWithOut } from '@/stores/modules/locale'
|
import { useLocaleStoreWithOut } from '@/stores/modules/locale'
|
||||||
import { setHtmlPageLang } from '@/plugins/vueI18n/helper'
|
import { setHtmlPageLang } from '@/plugins/vueI18n/helper'
|
||||||
|
import { loadLocaleMessages } from '@/locales'
|
||||||
const setI18nLanguage = (locale: LocaleType) => {
|
|
||||||
const localeStore = useLocaleStoreWithOut()
|
const setI18nLanguage = (locale: LocaleType) => {
|
||||||
|
const localeStore = useLocaleStoreWithOut()
|
||||||
if (i18n.mode === 'legacy') {
|
|
||||||
i18n.global.locale = locale
|
if (i18n.mode === 'legacy') {
|
||||||
} else {
|
i18n.global.locale = locale
|
||||||
;(i18n.global.locale as any).value = locale
|
} else {
|
||||||
}
|
;(i18n.global.locale as any).value = locale
|
||||||
localeStore.setCurrentLocale({
|
}
|
||||||
lang: locale
|
localeStore.setCurrentLocale({
|
||||||
})
|
lang: locale
|
||||||
setHtmlPageLang(locale)
|
})
|
||||||
}
|
setHtmlPageLang(locale)
|
||||||
|
}
|
||||||
export const useLocale = () => {
|
|
||||||
// Switching the language will change the locale of useI18n
|
export const useLocale = () => {
|
||||||
// And submit to configuration modification
|
// Switching the language will change the locale of useI18n
|
||||||
const changeLocale = async (locale: LocaleType) => {
|
// And submit to configuration modification
|
||||||
const globalI18n = i18n.global
|
const changeLocale = async (locale: LocaleType) => {
|
||||||
|
const globalI18n = i18n.global
|
||||||
const langModule = await import(`../../locales/${locale}.ts`)
|
|
||||||
|
const message = await loadLocaleMessages(locale)
|
||||||
globalI18n.setLocaleMessage(locale, langModule.default)
|
|
||||||
|
globalI18n.setLocaleMessage(locale, message)
|
||||||
setI18nLanguage(locale)
|
|
||||||
}
|
setI18nLanguage(locale)
|
||||||
|
}
|
||||||
return {
|
|
||||||
changeLocale
|
return {
|
||||||
}
|
changeLocale
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
<script lang="tsx">
|
|
||||||
import { computed, defineComponent, unref } from 'vue'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { Backtop } from '@/components/Backtop'
|
|
||||||
import { Setting } from '@/layouts/components/Setting'
|
|
||||||
import { useRenderLayout } from './components/useRenderLayout'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('layout')
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
// 是否是移动端
|
|
||||||
const mobile = computed(() => appStore.getMobile)
|
|
||||||
|
|
||||||
// 菜单折叠
|
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
const handleClickOutside = () => {
|
|
||||||
appStore.setCollapse(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderLayout = () => {
|
|
||||||
switch (unref(layout)) {
|
|
||||||
case 'classic':
|
|
||||||
const { renderClassic } = useRenderLayout()
|
|
||||||
return renderClassic()
|
|
||||||
case 'topLeft':
|
|
||||||
const { renderTopLeft } = useRenderLayout()
|
|
||||||
return renderTopLeft()
|
|
||||||
case 'top':
|
|
||||||
const { renderTop } = useRenderLayout()
|
|
||||||
return renderTop()
|
|
||||||
case 'cutMenu':
|
|
||||||
const { renderCutMenu } = useRenderLayout()
|
|
||||||
return renderCutMenu()
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Layout',
|
|
||||||
setup() {
|
|
||||||
return () => (
|
|
||||||
<section class={[prefixCls, `${prefixCls}__${layout.value}`, 'w-[100%] h-[100%] relative']}>
|
|
||||||
{mobile.value && !collapse.value ? (
|
|
||||||
<div
|
|
||||||
class="absolute left-0 top-0 z-99 h-full w-full bg-[var(--el-color-black)] opacity-30"
|
|
||||||
onClick={handleClickOutside}
|
|
||||||
></div>
|
|
||||||
) : undefined}
|
|
||||||
|
|
||||||
{renderLayout()}
|
|
||||||
|
|
||||||
<Backtop></Backtop>
|
|
||||||
|
|
||||||
<Setting></Setting>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-layout;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
background-color: var(--app-content-bg-color);
|
|
||||||
:deep(.el-scrollbar__view) {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,452 +1,453 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-config-drawer">
|
<div class="layout-config-drawer">
|
||||||
<el-drawer :model-value="configStore.layout.showDrawer" title="布局配置" size="310px" @close="onCloseDrawer">
|
<el-drawer :model-value="configStore.layout.showDrawer" title="布局配置" size="310px" @close="onCloseDrawer">
|
||||||
<el-scrollbar class="layout-mode-style-scrollbar">
|
<el-scrollbar class="layout-mode-style-scrollbar">
|
||||||
<el-form ref="formRef" :model="configStore.layout">
|
<el-form ref="formRef" :model="configStore.layout">
|
||||||
<div class="layout-mode-styles-box">
|
<div class="layout-mode-styles-box">
|
||||||
|
|
||||||
<el-divider border-style="dashed">布局方式</el-divider>
|
<el-divider border-style="dashed">布局方式</el-divider>
|
||||||
<div class="layout-mode-box-style">
|
<div class="layout-mode-box-style">
|
||||||
<el-row class="layout-mode-box-style-row" :gutter="10">
|
<el-row class="layout-mode-box-style-row" :gutter="10">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Default')"
|
@click="setLayoutMode('Default')"
|
||||||
class="layout-mode-style default"
|
class="layout-mode-style default"
|
||||||
:class="configStore.layout.layoutMode == 'Default' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Default' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class="layout-mode-style-box">
|
||||||
<div class="layout-mode-style-aside"></div>
|
<div class="layout-mode-style-aside"></div>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class="layout-mode-style-container-box">
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class="layout-mode-style-header"></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class="layout-mode-style-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">默认</div>
|
<div class="layout-mode-style-name">默认</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Classic')"
|
@click="setLayoutMode('Classic')"
|
||||||
class="layout-mode-style classic"
|
class="layout-mode-style classic"
|
||||||
:class="configStore.layout.layoutMode == 'Classic' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Classic' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class="layout-mode-style-box">
|
||||||
<div class="layout-mode-style-aside"></div>
|
<div class="layout-mode-style-aside"></div>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class="layout-mode-style-container-box">
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class="layout-mode-style-header"></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class="layout-mode-style-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">经典</div>
|
<div class="layout-mode-style-name">经典</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Streamline')"
|
@click="setLayoutMode('Streamline')"
|
||||||
class="layout-mode-style streamline"
|
class="layout-mode-style streamline"
|
||||||
:class="configStore.layout.layoutMode == 'Streamline' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Streamline' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class="layout-mode-style-box">
|
||||||
<div class="layout-mode-style-container-box">
|
<div class="layout-mode-style-container-box">
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class="layout-mode-style-header"></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class="layout-mode-style-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">单栏</div>
|
<div class="layout-mode-style-name">单栏</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<el-divider border-style="dashed">全局</el-divider>
|
<el-divider border-style="dashed">全局</el-divider>
|
||||||
<div class="layout-config-global">
|
<div class="layout-config-global">
|
||||||
<el-form-item label="后台页面切换动画">
|
<el-form-item label="后台页面切换动画">
|
||||||
<el-select
|
<el-select
|
||||||
@change="onCommitState($event, 'mainAnimation')"
|
@change="onCommitState($event, 'mainAnimation')"
|
||||||
:model-value="configStore.layout.mainAnimation"
|
:model-value="configStore.layout.mainAnimation"
|
||||||
:placeholder="'layouts.Please select an animation name'"
|
:placeholder="'layouts.Please select an animation name'"
|
||||||
>
|
filterable
|
||||||
<el-option label="slide-right" value="slide-right"></el-option>
|
>
|
||||||
<el-option label="slide-left" value="slide-left"></el-option>
|
<el-option label="slide-right" value="slide-right"></el-option>
|
||||||
<el-option label="el-fade-in-linear" value="el-fade-in-linear"></el-option>
|
<el-option label="slide-left" value="slide-left"></el-option>
|
||||||
<el-option label="el-fade-in" value="el-fade-in"></el-option>
|
<el-option label="el-fade-in-linear" value="el-fade-in-linear"></el-option>
|
||||||
<el-option label="el-zoom-in-center" value="el-zoom-in-center"></el-option>
|
<el-option label="el-fade-in" value="el-fade-in"></el-option>
|
||||||
<el-option label="el-zoom-in-top" value="el-zoom-in-top"></el-option>
|
<el-option label="el-zoom-in-center" value="el-zoom-in-center"></el-option>
|
||||||
<el-option label="el-zoom-in-bottom" value="el-zoom-in-bottom"></el-option>
|
<el-option label="el-zoom-in-top" value="el-zoom-in-top"></el-option>
|
||||||
</el-select>
|
<el-option label="el-zoom-in-bottom" value="el-zoom-in-bottom"></el-option>
|
||||||
</el-form-item>
|
</el-select>
|
||||||
<el-form-item label="组件主题色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="组件主题色">
|
||||||
@change="onCommitColorState($event, 'elementUiPrimary')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('elementUiPrimary')"
|
@change="onCommitColorState($event, 'elementUiPrimary')"
|
||||||
/>
|
:model-value="configStore.getColorVal('elementUiPrimary')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="表格标题栏背景颜色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="表格标题栏背景颜色">
|
||||||
@change="onCommitColorState($event, 'tableHeaderBackground')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('tableHeaderBackground')"
|
@change="onCommitColorState($event, 'tableHeaderBackground')"
|
||||||
/>
|
:model-value="configStore.getColorVal('tableHeaderBackground')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="表格标题栏文字颜色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="表格标题栏文字颜色">
|
||||||
@change="onCommitColorState($event, 'tableHeaderColor')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('tableHeaderColor')"
|
@change="onCommitColorState($event, 'tableHeaderColor')"
|
||||||
/>
|
:model-value="configStore.getColorVal('tableHeaderColor')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="表格激活栏颜色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="表格激活栏颜色">
|
||||||
@change="onCommitColorState($event, 'tableCurrent')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('tableCurrent')"
|
@change="onCommitColorState($event, 'tableCurrent')"
|
||||||
/>
|
:model-value="configStore.getColorVal('tableCurrent')"
|
||||||
</el-form-item>
|
/>
|
||||||
</div>
|
</el-form-item>
|
||||||
<el-divider border-style="dashed">侧边栏</el-divider>
|
</div>
|
||||||
<div class="layout-config-aside">
|
<el-divider border-style="dashed">侧边栏</el-divider>
|
||||||
<el-form-item label="侧边菜单栏背景色">
|
<div class="layout-config-aside">
|
||||||
<el-color-picker
|
<el-form-item label="侧边菜单栏背景色">
|
||||||
@change="onCommitColorState($event, 'menuBackground')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('menuBackground')"
|
@change="onCommitColorState($event, 'menuBackground')"
|
||||||
/>
|
:model-value="configStore.getColorVal('menuBackground')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="侧边菜单文字颜色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="侧边菜单文字颜色">
|
||||||
@change="onCommitColorState($event, 'menuColor')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('menuColor')"
|
@change="onCommitColorState($event, 'menuColor')"
|
||||||
/>
|
:model-value="configStore.getColorVal('menuColor')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="侧边菜单激活项背景色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="侧边菜单激活项背景色">
|
||||||
@change="onCommitColorState($event, 'menuActiveBackground')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('menuActiveBackground')"
|
@change="onCommitColorState($event, 'menuActiveBackground')"
|
||||||
/>
|
:model-value="configStore.getColorVal('menuActiveBackground')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="侧边菜单激活项文字色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="侧边菜单激活项文字色">
|
||||||
@change="onCommitColorState($event, 'menuActiveColor')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('menuActiveColor')"
|
@change="onCommitColorState($event, 'menuActiveColor')"
|
||||||
/>
|
:model-value="configStore.getColorVal('menuActiveColor')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="显示侧边菜单顶栏(LOGO栏)">
|
</el-form-item>
|
||||||
<el-switch
|
<el-form-item label="显示侧边菜单顶栏(LOGO栏)">
|
||||||
@change="onCommitState($event, 'menuShowTopBar')"
|
<el-switch
|
||||||
:model-value="configStore.layout.menuShowTopBar"
|
@change="onCommitState($event, 'menuShowTopBar')"
|
||||||
></el-switch>
|
:model-value="configStore.layout.menuShowTopBar"
|
||||||
</el-form-item>
|
></el-switch>
|
||||||
<el-form-item label="侧边菜单顶栏背景色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="侧边菜单顶栏背景色">
|
||||||
@change="onCommitColorState($event, 'menuTopBarBackground')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('menuTopBarBackground')"
|
@change="onCommitColorState($event, 'menuTopBarBackground')"
|
||||||
/>
|
:model-value="configStore.getColorVal('menuTopBarBackground')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="侧边菜单宽度(展开时)">
|
</el-form-item>
|
||||||
<el-input
|
<el-form-item label="侧边菜单宽度(展开时)">
|
||||||
@input="onCommitState($event, 'menuWidth')"
|
<el-input
|
||||||
type="number"
|
@input="onCommitState($event, 'menuWidth')"
|
||||||
:step="10"
|
type="number"
|
||||||
:model-value="configStore.layout.menuWidth"
|
:step="10"
|
||||||
>
|
:model-value="configStore.layout.menuWidth"
|
||||||
<template #append>px</template>
|
>
|
||||||
</el-input>
|
<template #append>px</template>
|
||||||
</el-form-item>
|
</el-input>
|
||||||
<!-- <el-form-item label="侧边菜单默认图标">-->
|
</el-form-item>
|
||||||
<!-- <IconSelector-->
|
<!-- <el-form-item label="侧边菜单默认图标">-->
|
||||||
<!-- @change="onCommitMenuDefaultIcon($event, 'menuDefaultIcon')"-->
|
<!-- <IconSelector-->
|
||||||
<!-- :model-value="configStore.layout.menuDefaultIcon"-->
|
<!-- @change="onCommitMenuDefaultIcon($event, 'menuDefaultIcon')"-->
|
||||||
<!-- />-->
|
<!-- :model-value="configStore.layout.menuDefaultIcon"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- />-->
|
||||||
<!-- <el-form-item label="侧边菜单水平折叠">-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-switch-->
|
<!-- <el-form-item label="侧边菜单水平折叠">-->
|
||||||
<!-- @change="onCommitState($event, 'menuCollapse')"-->
|
<!-- <el-switch-->
|
||||||
<!-- :model-value="configStore.layout.menuCollapse"-->
|
<!-- @change="onCommitState($event, 'menuCollapse')"-->
|
||||||
<!-- ></el-switch>-->
|
<!-- :model-value="configStore.layout.menuCollapse"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- ></el-switch>-->
|
||||||
<!-- <el-form-item label="侧边菜单手风琴">-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-switch-->
|
<!-- <el-form-item label="侧边菜单手风琴">-->
|
||||||
<!-- @change="onCommitState($event, 'menuUniqueOpened')"-->
|
<!-- <el-switch-->
|
||||||
<!-- :model-value="configStore.layout.menuUniqueOpened"-->
|
<!-- @change="onCommitState($event, 'menuUniqueOpened')"-->
|
||||||
<!-- ></el-switch>-->
|
<!-- :model-value="configStore.layout.menuUniqueOpened"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- ></el-switch>-->
|
||||||
</div>
|
<!-- </el-form-item>-->
|
||||||
|
</div>
|
||||||
<el-divider border-style="dashed">顶栏</el-divider>
|
|
||||||
<div class="layout-config-aside">
|
<el-divider border-style="dashed">顶栏</el-divider>
|
||||||
<el-form-item label="顶栏背景色">
|
<div class="layout-config-aside">
|
||||||
<el-color-picker
|
<el-form-item label="顶栏背景色">
|
||||||
@change="onCommitColorState($event, 'headerBarBackground')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('headerBarBackground')"
|
@change="onCommitColorState($event, 'headerBarBackground')"
|
||||||
/>
|
:model-value="configStore.getColorVal('headerBarBackground')"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="顶栏文字色">
|
</el-form-item>
|
||||||
<el-color-picker
|
<el-form-item label="顶栏文字色">
|
||||||
@change="onCommitColorState($event, 'headerBarTabColor')"
|
<el-color-picker
|
||||||
:model-value="configStore.getColorVal('headerBarTabColor')"
|
@change="onCommitColorState($event, 'headerBarTabColor')"
|
||||||
/>
|
:model-value="configStore.getColorVal('headerBarTabColor')"
|
||||||
</el-form-item>
|
/>
|
||||||
<!-- <el-form-item label="顶栏悬停时背景色">-->
|
</el-form-item>
|
||||||
<!-- <el-color-picker-->
|
<!-- <el-form-item label="顶栏悬停时背景色">-->
|
||||||
<!-- @change="onCommitColorState($event, 'headerBarHoverBackground')"-->
|
<!-- <el-color-picker-->
|
||||||
<!-- :model-value="configStore.getColorVal('headerBarHoverBackground')"-->
|
<!-- @change="onCommitColorState($event, 'headerBarHoverBackground')"-->
|
||||||
<!-- />-->
|
<!-- :model-value="configStore.getColorVal('headerBarHoverBackground')"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- />-->
|
||||||
<!-- <el-form-item label="顶栏菜单激活项背景色">-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-color-picker-->
|
<!-- <el-form-item label="顶栏菜单激活项背景色">-->
|
||||||
<!-- @change="onCommitColorState($event, 'headerBarTabActiveBackground')"-->
|
<!-- <el-color-picker-->
|
||||||
<!-- :model-value="configStore.getColorVal('headerBarTabActiveBackground')"-->
|
<!-- @change="onCommitColorState($event, 'headerBarTabActiveBackground')"-->
|
||||||
<!-- />-->
|
<!-- :model-value="configStore.getColorVal('headerBarTabActiveBackground')"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- />-->
|
||||||
<!-- <el-form-item label="顶栏菜单激活项文字色">-->
|
<!-- </el-form-item>-->
|
||||||
<!-- <el-color-picker-->
|
<!-- <el-form-item label="顶栏菜单激活项文字色">-->
|
||||||
<!-- @change="onCommitColorState($event, 'headerBarTabActiveColor')"-->
|
<!-- <el-color-picker-->
|
||||||
<!-- :model-value="configStore.getColorVal('headerBarTabActiveColor')"-->
|
<!-- @change="onCommitColorState($event, 'headerBarTabActiveColor')"-->
|
||||||
<!-- />-->
|
<!-- :model-value="configStore.getColorVal('headerBarTabActiveColor')"-->
|
||||||
<!-- </el-form-item>-->
|
<!-- />-->
|
||||||
</div>
|
<!-- </el-form-item>-->
|
||||||
<el-popconfirm @confirm="restoreDefault" title="确定要恢复全部配置到默认值吗?">
|
</div>
|
||||||
<template #reference>
|
<el-popconfirm @confirm="restoreDefault" title="确定要恢复全部配置到默认值吗?">
|
||||||
<div class="ba-center">
|
<template #reference>
|
||||||
<el-button class="w80" type="info">恢复默认</el-button>
|
<div class="ba-center">
|
||||||
</div>
|
<el-button class="w80" type="info">恢复默认</el-button>
|
||||||
</template>
|
</div>
|
||||||
</el-popconfirm>
|
</template>
|
||||||
</div>
|
</el-popconfirm>
|
||||||
</el-form>
|
</div>
|
||||||
</el-scrollbar>
|
</el-form>
|
||||||
</el-drawer>
|
</el-scrollbar>
|
||||||
</div>
|
</el-drawer>
|
||||||
</template>
|
</div>
|
||||||
|
</template>
|
||||||
<script setup lang="ts">
|
|
||||||
import { useConfig } from '@/stores/config'
|
<script setup lang="ts">
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import { useConfig } from '@/stores/config'
|
||||||
import { useRouter } from 'vue-router'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
import IconSelector from '@/components/baInput/components/iconSelector.vue'
|
import { useRouter } from 'vue-router'
|
||||||
import { STORE_CONFIG } from '@/stores/constant/cacheKey'
|
import IconSelector from '@/components/baInput/components/iconSelector.vue'
|
||||||
import { Local, Session } from '@/utils/storage'
|
import { STORE_CONFIG } from '@/stores/constant/cacheKey'
|
||||||
import type { Layout } from '@/stores/interface'
|
import { Local, Session } from '@/utils/storage'
|
||||||
|
import type { Layout } from '@/stores/interface'
|
||||||
const configStore = useConfig()
|
|
||||||
const navTabs = useNavTabs()
|
const configStore = useConfig()
|
||||||
const router = useRouter()
|
const navTabs = useNavTabs()
|
||||||
|
const router = useRouter()
|
||||||
const onCommitState = (value: any, name: any) => {
|
|
||||||
configStore.setLayout(name, value)
|
const onCommitState = (value: any, name: any) => {
|
||||||
}
|
configStore.setLayout(name, value)
|
||||||
|
}
|
||||||
const onCommitColorState = (value: string | null, name: keyof Layout) => {
|
|
||||||
if (value === null) return
|
const onCommitColorState = (value: string | null, name: keyof Layout) => {
|
||||||
const colors = configStore.layout[name] as string[]
|
if (value === null) return
|
||||||
if (configStore.layout.isDark) {
|
const colors = configStore.layout[name] as string[]
|
||||||
colors[1] = value
|
if (configStore.layout.isDark) {
|
||||||
} else {
|
colors[1] = value
|
||||||
colors[0] = value
|
} else {
|
||||||
}
|
colors[0] = value
|
||||||
configStore.setLayout(name, colors)
|
}
|
||||||
}
|
configStore.setLayout(name, colors)
|
||||||
|
}
|
||||||
const setLayoutMode = (mode: string) => {
|
|
||||||
configStore.setLayoutMode(mode)
|
const setLayoutMode = (mode: string) => {
|
||||||
}
|
configStore.setLayoutMode(mode)
|
||||||
|
}
|
||||||
// 修改默认菜单图标
|
|
||||||
const onCommitMenuDefaultIcon = (value: any, name: any) => {
|
// 修改默认菜单图标
|
||||||
configStore.setLayout(name, value)
|
const onCommitMenuDefaultIcon = (value: any, name: any) => {
|
||||||
|
configStore.setLayout(name, value)
|
||||||
const menus = navTabs.state.tabsViewRoutes
|
|
||||||
navTabs.setTabsViewRoutes([])
|
const menus = navTabs.state.tabsViewRoutes
|
||||||
setTimeout(() => {
|
navTabs.setTabsViewRoutes([])
|
||||||
navTabs.setTabsViewRoutes(menus)
|
setTimeout(() => {
|
||||||
}, 200)
|
navTabs.setTabsViewRoutes(menus)
|
||||||
}
|
}, 200)
|
||||||
|
}
|
||||||
const onCloseDrawer = () => {
|
|
||||||
configStore.setLayout('showDrawer', false)
|
const onCloseDrawer = () => {
|
||||||
}
|
configStore.setLayout('showDrawer', false)
|
||||||
|
}
|
||||||
const restoreDefault = () => {
|
|
||||||
Local.remove(STORE_CONFIG)
|
const restoreDefault = () => {
|
||||||
router.go(0)
|
Local.remove(STORE_CONFIG)
|
||||||
}
|
router.go(0)
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
<style scoped lang="scss">
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
.layout-config-drawer :deep(.el-input__inner) {
|
|
||||||
padding: 0 0 0 6px;
|
.layout-config-drawer :deep(.el-input__inner) {
|
||||||
}
|
padding: 0 0 0 6px;
|
||||||
|
}
|
||||||
.layout-config-drawer :deep(.el-input-group__append) {
|
|
||||||
padding: 0 10px;
|
.layout-config-drawer :deep(.el-input-group__append) {
|
||||||
}
|
padding: 0 10px;
|
||||||
|
}
|
||||||
.layout-config-drawer :deep(.el-drawer__header) {
|
|
||||||
margin-bottom: 0 !important;
|
.layout-config-drawer :deep(.el-drawer__header) {
|
||||||
}
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
.layout-config-drawer :deep(.el-drawer__body) {
|
|
||||||
padding: 0;
|
.layout-config-drawer :deep(.el-drawer__body) {
|
||||||
}
|
padding: 0;
|
||||||
|
}
|
||||||
.layout-mode-styles-box {
|
|
||||||
padding: 20px;
|
.layout-mode-styles-box {
|
||||||
}
|
padding: 20px;
|
||||||
|
}
|
||||||
.layout-mode-box-style-row {
|
|
||||||
margin-bottom: 15px;
|
.layout-mode-box-style-row {
|
||||||
}
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
.layout-mode-style {
|
|
||||||
position: relative;
|
.layout-mode-style {
|
||||||
height: 100px;
|
position: relative;
|
||||||
border: 1px solid var(--el-border-color-light);
|
height: 100px;
|
||||||
border-radius: var(--el-border-radius-small);
|
border: 1px solid var(--el-border-color-light);
|
||||||
|
border-radius: var(--el-border-radius-small);
|
||||||
&:hover,
|
|
||||||
&.active {
|
&:hover,
|
||||||
border: 1px solid var(--el-color-primary);
|
&.active {
|
||||||
}
|
border: 1px solid var(--el-color-primary);
|
||||||
|
}
|
||||||
.layout-mode-style-name {
|
|
||||||
position: absolute;
|
.layout-mode-style-name {
|
||||||
display: flex;
|
position: absolute;
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
color: var(--el-color-primary-light-5);
|
justify-content: center;
|
||||||
border-radius: 50%;
|
color: var(--el-color-primary-light-5);
|
||||||
height: 50px;
|
border-radius: 50%;
|
||||||
width: 50px;
|
height: 50px;
|
||||||
border: 1px solid var(--el-color-primary-light-3);
|
width: 50px;
|
||||||
}
|
border: 1px solid var(--el-color-primary-light-3);
|
||||||
|
}
|
||||||
.layout-mode-style-box {
|
|
||||||
display: flex;
|
.layout-mode-style-box {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
width: 100%;
|
justify-content: center;
|
||||||
height: 100%;
|
width: 100%;
|
||||||
}
|
height: 100%;
|
||||||
|
}
|
||||||
&.default {
|
|
||||||
display: flex;
|
&.default {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
.layout-mode-style-aside {
|
|
||||||
width: 18%;
|
.layout-mode-style-aside {
|
||||||
height: 90%;
|
width: 18%;
|
||||||
background-color: var(--el-border-color-lighter);
|
height: 90%;
|
||||||
}
|
background-color: var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
.layout-mode-style-container-box {
|
|
||||||
width: 68%;
|
.layout-mode-style-container-box {
|
||||||
height: 90%;
|
width: 68%;
|
||||||
margin-left: 4%;
|
height: 90%;
|
||||||
|
margin-left: 4%;
|
||||||
.layout-mode-style-header {
|
|
||||||
width: 100%;
|
.layout-mode-style-header {
|
||||||
height: 10%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color-lighter);
|
height: 10%;
|
||||||
}
|
background-color: var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
.layout-mode-style-container {
|
|
||||||
width: 100%;
|
.layout-mode-style-container {
|
||||||
height: 85%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color-extra-light);
|
height: 85%;
|
||||||
margin-top: 5%;
|
background-color: var(--el-border-color-extra-light);
|
||||||
}
|
margin-top: 5%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.classic {
|
|
||||||
display: flex;
|
&.classic {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
.layout-mode-style-aside {
|
|
||||||
width: 18%;
|
.layout-mode-style-aside {
|
||||||
height: 100%;
|
width: 18%;
|
||||||
background-color: var(--el-border-color-lighter);
|
height: 100%;
|
||||||
}
|
background-color: var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
.layout-mode-style-container-box {
|
|
||||||
width: 82%;
|
.layout-mode-style-container-box {
|
||||||
height: 100%;
|
width: 82%;
|
||||||
|
height: 100%;
|
||||||
.layout-mode-style-header {
|
|
||||||
width: 100%;
|
.layout-mode-style-header {
|
||||||
height: 10%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color);
|
height: 10%;
|
||||||
}
|
background-color: var(--el-border-color);
|
||||||
|
}
|
||||||
.layout-mode-style-container {
|
|
||||||
width: 100%;
|
.layout-mode-style-container {
|
||||||
height: 90%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color-extra-light);
|
height: 90%;
|
||||||
}
|
background-color: var(--el-border-color-extra-light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.streamline {
|
|
||||||
display: flex;
|
&.streamline {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
.layout-mode-style-container-box {
|
|
||||||
width: 100%;
|
.layout-mode-style-container-box {
|
||||||
height: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
.layout-mode-style-header {
|
|
||||||
width: 100%;
|
.layout-mode-style-header {
|
||||||
height: 10%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color);
|
height: 10%;
|
||||||
}
|
background-color: var(--el-border-color);
|
||||||
|
}
|
||||||
.layout-mode-style-container {
|
|
||||||
width: 100%;
|
.layout-mode-style-container {
|
||||||
height: 90%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color-extra-light);
|
height: 90%;
|
||||||
}
|
background-color: var(--el-border-color-extra-light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.double {
|
|
||||||
display: flex;
|
&.double {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
.layout-mode-style-aside {
|
|
||||||
width: 18%;
|
.layout-mode-style-aside {
|
||||||
height: 100%;
|
width: 18%;
|
||||||
background-color: var(--el-border-color);
|
height: 100%;
|
||||||
}
|
background-color: var(--el-border-color);
|
||||||
|
}
|
||||||
.layout-mode-style-container-box {
|
|
||||||
width: 82%;
|
.layout-mode-style-container-box {
|
||||||
height: 100%;
|
width: 82%;
|
||||||
|
height: 100%;
|
||||||
.layout-mode-style-header {
|
|
||||||
width: 100%;
|
.layout-mode-style-header {
|
||||||
height: 10%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color);
|
height: 10%;
|
||||||
}
|
background-color: var(--el-border-color);
|
||||||
|
}
|
||||||
.layout-mode-style-container {
|
|
||||||
width: 100%;
|
.layout-mode-style-container {
|
||||||
height: 90%;
|
width: 100%;
|
||||||
background-color: var(--el-border-color-extra-light);
|
height: 90%;
|
||||||
}
|
background-color: var(--el-border-color-extra-light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.w80 {
|
|
||||||
width: 90%;
|
.w80 {
|
||||||
}
|
width: 90%;
|
||||||
</style>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -11,25 +11,25 @@
|
|||||||
:data="eventList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
:data="eventList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
|
||||||
>
|
>
|
||||||
<!-- <vxe-column type="seq" width="70px" title="序号"></vxe-column> -->
|
<!-- <vxe-column type="seq" width="70px" title="序号"></vxe-column> -->
|
||||||
<vxe-column field="time" width="180px" sortable title="发生时刻"></vxe-column>
|
<vxe-column field="time" width="180px" sortable title="暂降发生时刻"></vxe-column>
|
||||||
<vxe-column field="lineName" title="监测点"></vxe-column>
|
|
||||||
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
|
|
||||||
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
|
|
||||||
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
|
|
||||||
<template #default="{ row }">
|
|
||||||
{{ Math.floor(row.persistTime * 1000) / 1000 }}
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<vxe-column field="eventValue" width="160px" sortable title="暂降(骤升)幅值(%)">
|
<vxe-column field="eventValue" width="160px" sortable title="暂降(骤升)幅值(%)">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ Math.floor(row.eventValue * 10000) / 100 }}
|
{{ Math.floor(row.eventValue * 10000) / 100 }}
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
|
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ Math.floor(row.persistTime * 1000) / 1000 }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
<vxe-column field="eventType" width="100px" title="触发类型">
|
<vxe-column field="eventType" width="100px" title="触发类型">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }}
|
{{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }}
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
|
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
|
||||||
|
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
|
||||||
|
<vxe-column field="lineName" title="监测点"></vxe-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
<div class="table-pagination mt10">
|
<div class="table-pagination mt10">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
@@ -99,7 +99,6 @@ const dataSocket = reactive({
|
|||||||
// }
|
// }
|
||||||
const socket = async () => {
|
const socket = async () => {
|
||||||
const url = localStorage.getItem('WebSocketUrl3') || 'null' //'ws://192.168.2.130:10203/event/'
|
const url = localStorage.getItem('WebSocketUrl3') || 'null' //'ws://192.168.2.130:10203/event/'
|
||||||
|
|
||||||
|
|
||||||
// const url = 'ws://192.168.1.68:10203/event/'
|
// const url = 'ws://192.168.1.68:10203/event/'
|
||||||
|
|
||||||
|
|||||||
@@ -8,41 +8,14 @@
|
|||||||
name="el-icon-BellFilled"
|
name="el-icon-BellFilled"
|
||||||
size="18"
|
size="18"
|
||||||
/>
|
/>
|
||||||
<span class="nav-menu-text" v-if="globalPopUpRef?.eventList.length != 0">
|
<span class="nav-menu-text" v-if="globalPopUpRef?.eventList?.length > 0">
|
||||||
{{ (globalPopUpRef?.eventList.length>99? '99+':globalPopUpRef?.eventList.length) || 0 }}
|
{{ globalPopUpRef.eventList.length > 99 ? '99+' : globalPopUpRef.eventList.length }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- <el-tooltip effect="dark" content="截图" placement="bottom">
|
|
||||||
<div @click="savePng" class="nav-menu-item">
|
|
||||||
<Icon
|
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
|
||||||
class="nav-menu-icon"
|
|
||||||
name="el-icon-Camera"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</el-tooltip>
|
|
||||||
<el-tooltip effect="dark" :content="state.isFullScreen ? '缩小' : '放大'" placement="bottom">
|
|
||||||
<div @click="onFullScreen" class="nav-menu-item" :class="state.isFullScreen ? 'hover' : ''">
|
|
||||||
<Icon
|
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
|
||||||
class="nav-menu-icon"
|
|
||||||
v-if="state.isFullScreen"
|
|
||||||
name="fa-solid fa-compress"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
|
||||||
class="nav-menu-icon"
|
|
||||||
v-else
|
|
||||||
name="fa-solid fa-expand"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</el-tooltip> -->
|
|
||||||
<el-dropdown style="height: 100%" @command="handleCommand">
|
<el-dropdown style="height: 100%" @command="handleCommand">
|
||||||
<div class="admin-info" :class="state.currentNavMenu == 'adminInfo' ? 'hover' : ''">
|
<div class="admin-info" :class="state.currentNavMenu === 'adminInfo' ? 'hover' : ''">
|
||||||
<el-avatar :size="25" fit="fill">
|
<el-avatar :size="25" fit="fill">
|
||||||
<img src="@/assets/avatar.png" alt="" />
|
<img src="@/assets/avatar.png" alt="" />
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
@@ -51,105 +24,117 @@
|
|||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item command="adminInfo">个人资料</el-dropdown-item>
|
<el-dropdown-item command="adminInfo">个人资料</el-dropdown-item>
|
||||||
<el-dropdown-item command="changePwd">修改密码</el-dropdown-item>
|
<el-dropdown-item command="changePwd" v-if="!IS_LNQR">修改密码</el-dropdown-item>
|
||||||
<el-dropdown-item command="layout">退出登录</el-dropdown-item>
|
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<!-- <div @click="configStore.setLayout('showDrawer', true)" class="nav-menu-item">
|
|
||||||
<Icon
|
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
|
||||||
class="nav-menu-icon"
|
|
||||||
name="fa fa-cogs"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
</div> -->
|
|
||||||
<Config />
|
<Config />
|
||||||
<PopupPwd ref="popupPwd" />
|
<PopupPwd ref="popupPwd" />
|
||||||
<AdminInfo ref="popupAdminInfo" />
|
<AdminInfo ref="popupAdminInfo" />
|
||||||
<!-- <TerminalVue /> -->
|
|
||||||
<!-- 全局暂降事件 -->
|
|
||||||
<globalPopUp ref="globalPopUpRef" />
|
<globalPopUp ref="globalPopUpRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import screenfull from 'screenfull'
|
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import Config from './config.vue'
|
|
||||||
import { useAdminInfo } from '@/stores/adminInfo'
|
import { useAdminInfo } from '@/stores/adminInfo'
|
||||||
import router from '@/router'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
import globalPopUp from './globalPopUp.vue'
|
import { logout } from '@/api/user-boot/user'
|
||||||
import { routePush } from '@/utils/router'
|
import { Local } from '@/utils/storage'
|
||||||
import html2canvas from 'html2canvas'
|
import Config from './config.vue'
|
||||||
import PopupPwd from './popup/password.vue'
|
import PopupPwd from './popup/password.vue'
|
||||||
import AdminInfo from './popup/adminInfo.vue'
|
import AdminInfo from './popup/adminInfo.vue'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import globalPopUp from './globalPopUp.vue'
|
||||||
|
const { replace } = useRouter()
|
||||||
|
// 环境标识
|
||||||
|
const IS_LNQR = import.meta.env.VITE_NAME === 'LNqr'
|
||||||
|
|
||||||
const adminInfo = useAdminInfo()
|
const adminInfo = useAdminInfo()
|
||||||
const navTabs = useNavTabs()
|
const navTabs = useNavTabs()
|
||||||
const configStore = useConfig()
|
const configStore = useConfig()
|
||||||
|
|
||||||
|
// 引用
|
||||||
const popupPwd = ref()
|
const popupPwd = ref()
|
||||||
const popupAdminInfo = ref()
|
const popupAdminInfo = ref()
|
||||||
const state = reactive({
|
|
||||||
isFullScreen: false,
|
|
||||||
currentNavMenu: '',
|
|
||||||
showLayoutDrawer: false,
|
|
||||||
showAdminInfoPopover: false
|
|
||||||
})
|
|
||||||
const globalPopUpRef = ref()
|
const globalPopUpRef = ref()
|
||||||
const savePng = () => {
|
|
||||||
html2canvas(document.body, {
|
// 状态
|
||||||
scale: 1,
|
const state = reactive({
|
||||||
useCORS: true
|
currentNavMenu: ''
|
||||||
}).then(function (canvas) {
|
})
|
||||||
var link = document.createElement('a')
|
|
||||||
link.href = canvas.toDataURL('image/png')
|
// 打开暂降事件
|
||||||
link.download = 'screenshot.png'
|
const temporaryLandingEvent = () => {
|
||||||
link.click()
|
if (globalPopUpRef.value) {
|
||||||
})
|
globalPopUpRef.value.open()
|
||||||
}
|
|
||||||
const onFullScreen = () => {
|
|
||||||
if (!screenfull.isEnabled) {
|
|
||||||
ElMessage.warning('layouts.Full screen is not supported')
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
screenfull.toggle()
|
|
||||||
screenfull.onchange(() => {
|
|
||||||
state.isFullScreen = screenfull.isFullscreen
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCommand = async(key: string) => {
|
// 下拉菜单命令
|
||||||
console.log(key)
|
const handleCommand = async (key: string) => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'adminInfo':
|
case 'adminInfo':
|
||||||
popupAdminInfo.value.open()
|
popupAdminInfo.value?.open()
|
||||||
break
|
break
|
||||||
case 'changePwd':
|
case 'changePwd':
|
||||||
popupPwd.value.open()
|
popupPwd.value?.open()
|
||||||
break
|
break
|
||||||
case 'layout':
|
case 'logout':
|
||||||
await window.location.reload()
|
await handleLogout()
|
||||||
setTimeout(() => {
|
|
||||||
navTabs.closeTabs()
|
|
||||||
window.localStorage.clear()
|
|
||||||
adminInfo.reset()
|
|
||||||
router.push({ name: 'login' })
|
|
||||||
}, 0)
|
|
||||||
// navTabs.closeTabs()
|
|
||||||
// window.localStorage.clear()
|
|
||||||
// adminInfo.reset()
|
|
||||||
// router.push({ name: 'login' })
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const temporaryLandingEvent = () => {
|
|
||||||
globalPopUpRef.value.open()
|
// 统一登出逻辑
|
||||||
|
const handleLogout = async () => {
|
||||||
|
try {
|
||||||
|
// 1. 调用后端登出接口
|
||||||
|
await logout()
|
||||||
|
// console.log('✅ 后端登出成功')
|
||||||
|
} catch (err) {
|
||||||
|
// console.error('❌ 登出接口异常', err)
|
||||||
|
} finally {
|
||||||
|
// 2. 清理本地所有数据
|
||||||
|
clearLocalData()
|
||||||
|
|
||||||
|
// 3. LNqr 环境跳 CAS 登出
|
||||||
|
if (IS_LNQR) {
|
||||||
|
redirectToCasLogout()
|
||||||
|
} else {
|
||||||
|
// 普通环境直接跳登录页
|
||||||
|
window.location.reload()
|
||||||
|
setTimeout(() => {
|
||||||
|
replace('/login')
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理本地数据
|
||||||
|
const clearLocalData = () => {
|
||||||
|
// 清空 localStorage(保留 VXE 自定义列、DevTools 配置)
|
||||||
|
Local.clear()
|
||||||
|
|
||||||
|
// 清空用户状态
|
||||||
|
adminInfo.reset()
|
||||||
|
|
||||||
|
// 清空标签页
|
||||||
|
navTabs.closeTabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS 登出跳转
|
||||||
|
const redirectToCasLogout = () => {
|
||||||
|
const casLogoutUrl =
|
||||||
|
'http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/logout?service=http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/login?service=http://PQMonitoring.dcloud.ln.dc.sgcc.com.cn'
|
||||||
|
window.location.href = casLogoutUrl
|
||||||
|
// 清 Cookie
|
||||||
|
document.cookie.split(';').forEach(cookie => {
|
||||||
|
const name = cookie.split('=')[0].trim()
|
||||||
|
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -163,7 +148,6 @@ const temporaryLandingEvent = () => {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// height: 100%;
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
background-color: v-bind('configStore.getColorVal("headerBarBackground")');
|
background-color: v-bind('configStore.getColorVal("headerBarBackground")');
|
||||||
|
|
||||||
@@ -219,37 +203,15 @@ const temporaryLandingEvent = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu-box :deep(.el-dropdown-menu__item) {
|
.nav-menu-text {
|
||||||
justify-content: center;
|
position: absolute;
|
||||||
}
|
top: 13px;
|
||||||
|
left: 20px;
|
||||||
.admin-info-base {
|
font-size: 12px;
|
||||||
display: flex;
|
background: #ff0000;
|
||||||
justify-content: center;
|
color: #fff;
|
||||||
flex-wrap: wrap;
|
border-radius: 5px;
|
||||||
padding-top: 10px;
|
padding: 0 3px;
|
||||||
|
|
||||||
.admin-info-other {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 10px 0;
|
|
||||||
|
|
||||||
.admin-info-name {
|
|
||||||
font-size: var(--el-font-size-large);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-info-footer {
|
|
||||||
padding: 10px 0;
|
|
||||||
margin: 0 -12px -12px -12px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pt2 {
|
|
||||||
padding-top: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes twinkle {
|
@keyframes twinkle {
|
||||||
@@ -263,15 +225,4 @@ const temporaryLandingEvent = () => {
|
|||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.nav-menu-text {
|
|
||||||
position: absolute;
|
|
||||||
top: 13px;
|
|
||||||
left: 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #ff0000;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { validatePwd } from '@/utils/common'
|
|||||||
import { useAdminInfo } from '@/stores/adminInfo'
|
import { useAdminInfo } from '@/stores/adminInfo'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
|
import { Local } from '@/utils/storage'
|
||||||
const navTabs = useNavTabs()
|
const navTabs = useNavTabs()
|
||||||
const adminInfo = useAdminInfo()
|
const adminInfo = useAdminInfo()
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
@@ -103,7 +104,7 @@ const submit = () => {
|
|||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navTabs.closeTabs()
|
navTabs.closeTabs()
|
||||||
window.localStorage.clear()
|
Local.clear()
|
||||||
adminInfo.reset()
|
adminInfo.reset()
|
||||||
router.push({ name: 'login' })
|
router.push({ name: 'login' })
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|||||||
@@ -1,128 +1,130 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<component :is="config.layout.layoutMode"></component>
|
<component :is="config.layout.layoutMode"></component>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
import { useAdminInfo } from '@/stores/adminInfo'
|
import { useAdminInfo } from '@/stores/adminInfo'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import { useDictData } from '@/stores/dictData'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import Default from '@/layouts/admin/container/default.vue'
|
import Default from '@/layouts/admin/container/default.vue'
|
||||||
import Classic from '@/layouts/admin/container/classic.vue'
|
import Classic from '@/layouts/admin/container/classic.vue'
|
||||||
import Streamline from '@/layouts/admin/container/streamline.vue'
|
import Streamline from '@/layouts/admin/container/streamline.vue'
|
||||||
import Double from '@/layouts/admin/container/double.vue'
|
import Double from '@/layouts/admin/container/double.vue'
|
||||||
import { onMounted, onBeforeMount } from 'vue'
|
import { onMounted, onBeforeMount } from 'vue'
|
||||||
import { handleAdminRoute, getFirstRoute, routePush } from '@/utils/router'
|
import { handleAdminRoute, getFirstRoute, routePush } from '@/utils/router'
|
||||||
import router from '@/router/index'
|
import router from '@/router/index'
|
||||||
import { useEventListener } from '@vueuse/core'
|
import { useEventListener } from '@vueuse/core'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
import { setNavTabsWidth } from '@/utils/layout'
|
import { setNavTabsWidth } from '@/utils/layout'
|
||||||
import { adminBaseRoutePath } from '@/router/static'
|
import { adminBaseRoutePath } from '@/router/static'
|
||||||
import { getRouteMenu, dictDataCache } from '@/api/auth'
|
import { getRouteMenu, dictDataCache } from '@/api/auth'
|
||||||
import { getAreaList, areaSelect } from '@/api/common'
|
import { getAreaList, areaSelect } from '@/api/common'
|
||||||
import { BasicDictData } from '@/stores/interface'
|
import { BasicDictData } from '@/stores/interface'
|
||||||
import { getAllUserSimpleList, getUserById } from '@/api/user-boot/user'
|
import { getAllUserSimpleList, getUserById } from '@/api/user-boot/user'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
components: { Default, Classic, Streamline, Double }
|
components: { Default, Classic, Streamline, Double }
|
||||||
})
|
})
|
||||||
|
|
||||||
const navTabs = useNavTabs()
|
const navTabs = useNavTabs()
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const adminInfo = useAdminInfo()
|
const adminInfo = useAdminInfo()
|
||||||
const dictData = useDictData()
|
const dictData = useDictData()
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
autoMenuCollapseLock: false
|
autoMenuCollapseLock: false
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// if (!adminInfo.token) return router.push({ name: 'login' })
|
// if (!adminInfo.token) return router.push({ name: 'login' })
|
||||||
|
|
||||||
init()
|
init()
|
||||||
setNavTabsWidth()
|
setNavTabsWidth()
|
||||||
useEventListener(window, 'resize', setNavTabsWidth)
|
useEventListener(window, 'resize', setNavTabsWidth)
|
||||||
})
|
})
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
onAdaptiveLayout()
|
onAdaptiveLayout()
|
||||||
useEventListener(window, 'resize', onAdaptiveLayout)
|
useEventListener(window, 'resize', onAdaptiveLayout)
|
||||||
})
|
})
|
||||||
|
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
await Promise.all([getAreaList(), dictDataCache(), getUserById(), areaSelect(), getAllUserSimpleList()]).then(res => {
|
await Promise.all([getAreaList(), dictDataCache(), getUserById(), areaSelect(), getAllUserSimpleList()]).then(res => {
|
||||||
dictData.state.area = res[0].data
|
dictData.state.area = res[0].data
|
||||||
dictData.state.basic = res[1].data
|
dictData.state.basic = res[1].data
|
||||||
dictData.state.userList = res[4].data
|
dictData.state.userList = res[4].data
|
||||||
adminInfo.dataFill(res[2].data)
|
adminInfo.dataFill(res[2].data)
|
||||||
dictData.state.areaTree = res[3].data
|
dictData.state.areaTree = res[3].data
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
* 后台初始化请求,获取站点配置,动态路由等信息
|
* 后台初始化请求,获取站点配置,动态路由等信息
|
||||||
*/
|
*/
|
||||||
getRouteMenu().then((res: any) => {
|
getRouteMenu().then((res: any) => {
|
||||||
const handlerMenu = (data: any) => {
|
const handlerMenu = (data: any) => {
|
||||||
data.forEach((item: any) => {
|
data.forEach((item: any) => {
|
||||||
item.routePath =
|
item.routePath =
|
||||||
item.routePath[0] == '/' ? item.routePath.substring(1, item.routePath.length) : item.routePath
|
item.routePath[0] == '/' ? item.routePath.substring(1, item.routePath.length) : item.routePath
|
||||||
item.path = item.routePath
|
item.path = item.routePath
|
||||||
item.name = item.routePath
|
item.name = item.routePath
|
||||||
item.keepalive = item.routePath
|
item.keepalive = item.routePath
|
||||||
item.component = item.routeName
|
item.component = item.routeName
|
||||||
? item.routeName.indexOf('/src/views/') > -1
|
? item.routeName.indexOf('/src/views/') > -1
|
||||||
? item.routeName
|
? item.routeName
|
||||||
: `/src/views/${item.routeName}/index.vue`
|
: `/src/views/${item.routeName}/index.vue`
|
||||||
: ''
|
: ''
|
||||||
item.type = item.children && item.children.length > 0 ? 'menu_dir' : 'menu'
|
item.type = item.children && item.children.length > 0 ? 'menu_dir' : 'menu'
|
||||||
item.menu_type = item.children && item.children.length > 0 ? null : 'tab'
|
item.menu_type = item.children && item.children.length > 0 ? null : 'tab'
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
handlerMenu(item.children)
|
handlerMenu(item.children)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
handlerMenu(res.data)
|
handlerMenu(res.data)
|
||||||
handleAdminRoute(res.data)
|
handleAdminRoute(res.data)
|
||||||
if (route.params.to) {
|
if (route.params.to) {
|
||||||
const lastRoute = JSON.parse(route.params.to as string)
|
const lastRoute = JSON.parse(route.params.to as string)
|
||||||
if (lastRoute.path != adminBaseRoutePath) {
|
if (lastRoute.path != adminBaseRoutePath) {
|
||||||
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||||
routePush({ path: lastRoute.path, query: query })
|
routePush({ path: lastRoute.path, query: query })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 跳转到第一个菜单
|
// 仅在 loading 页时跳转到第一个菜单,避免覆盖用户当前页面
|
||||||
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
if (route.name === 'adminMainLoading') {
|
||||||
if (firstRoute) routePush(firstRoute.path)
|
const firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
||||||
})
|
if (firstRoute) routePush(firstRoute.path)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
const onAdaptiveLayout = () => {
|
}
|
||||||
let defaultBeforeResizeLayout = {
|
|
||||||
layoutMode: config.layout.layoutMode,
|
const onAdaptiveLayout = () => {
|
||||||
menuCollapse: config.layout.menuCollapse
|
let defaultBeforeResizeLayout = {
|
||||||
}
|
layoutMode: config.layout.layoutMode,
|
||||||
|
menuCollapse: config.layout.menuCollapse
|
||||||
const clientWidth = document.body.clientWidth
|
}
|
||||||
if (clientWidth < 1024) {
|
|
||||||
/**
|
const clientWidth = document.body.clientWidth
|
||||||
* 锁定窗口改变自动调整 menuCollapse
|
if (clientWidth < 1024) {
|
||||||
* 避免已是小窗且打开了菜单栏时,意外的自动关闭菜单栏
|
/**
|
||||||
*/
|
* 锁定窗口改变自动调整 menuCollapse
|
||||||
if (!state.autoMenuCollapseLock) {
|
* 避免已是小窗且打开了菜单栏时,意外的自动关闭菜单栏
|
||||||
state.autoMenuCollapseLock = true
|
*/
|
||||||
config.setLayout('menuCollapse', true)
|
if (!state.autoMenuCollapseLock) {
|
||||||
}
|
state.autoMenuCollapseLock = true
|
||||||
config.setLayout('shrink', true)
|
config.setLayout('menuCollapse', true)
|
||||||
config.setLayoutMode('Classic')
|
}
|
||||||
} else {
|
config.setLayout('shrink', true)
|
||||||
state.autoMenuCollapseLock = false
|
config.setLayoutMode('Classic')
|
||||||
config.setLayout('menuCollapse', defaultBeforeResizeLayout.menuCollapse)
|
} else {
|
||||||
config.setLayout('shrink', false)
|
state.autoMenuCollapseLock = false
|
||||||
config.setLayoutMode(defaultBeforeResizeLayout.layoutMode)
|
config.setLayout('menuCollapse', defaultBeforeResizeLayout.menuCollapse)
|
||||||
}
|
config.setLayout('shrink', false)
|
||||||
}
|
config.setLayoutMode(defaultBeforeResizeLayout.layoutMode)
|
||||||
</script>
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-main class="layout-main" :style="mainHeight()">
|
<el-main class="layout-main" :style="mainHeight()">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component, route: viewRoute }">
|
||||||
<transition :name="config.layout.mainAnimation" mode="out-in">
|
<transition :name="config.layout.mainAnimation" mode="out-in">
|
||||||
<keep-alive :include="state.keepAliveComponentNameList">
|
<keep-alive :include="state.keepAliveComponentNameList">
|
||||||
<component :is="Component" :key="state.componentKey" />
|
<component
|
||||||
|
:is="Component"
|
||||||
|
v-if="Component"
|
||||||
|
:key="state.componentKey || viewRoute.fullPath"
|
||||||
|
/>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
@@ -32,7 +36,7 @@ const state: {
|
|||||||
componentKey: string
|
componentKey: string
|
||||||
keepAliveComponentNameList: string[]
|
keepAliveComponentNameList: string[]
|
||||||
} = reactive({
|
} = reactive({
|
||||||
componentKey: route.path,
|
componentKey: '',
|
||||||
keepAliveComponentNameList: []
|
keepAliveComponentNameList: []
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -51,9 +55,10 @@ onBeforeMount(() => {
|
|||||||
state.keepAliveComponentNameList = state.keepAliveComponentNameList.filter(
|
state.keepAliveComponentNameList = state.keepAliveComponentNameList.filter(
|
||||||
(name: string) => menu.meta.keepalive !== name
|
(name: string) => menu.meta.keepalive !== name
|
||||||
)
|
)
|
||||||
state.componentKey = ''
|
// 临时换 key 强制卸载,再在 nextTick 恢复为路由 fullPath,避免 keep-alive 缓存错乱
|
||||||
|
state.componentKey = `${menu.fullPath || menu.path}__refresh__${Date.now()}`
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
state.componentKey = menu.path
|
state.componentKey = ''
|
||||||
addKeepAliveComponentName(menu.meta.keepalive as string)
|
addKeepAliveComponentName(menu.meta.keepalive as string)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -79,7 +84,6 @@ onMounted(() => {
|
|||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
() => {
|
() => {
|
||||||
state.componentKey = route.path
|
|
||||||
if (typeof navTabs.state.activeRoute?.meta.keepalive == 'string') {
|
if (typeof navTabs.state.activeRoute?.meta.keepalive == 'string') {
|
||||||
addKeepAliveComponentName(navTabs.state.activeRoute?.meta.keepalive)
|
addKeepAliveComponentName(navTabs.state.activeRoute?.meta.keepalive)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,98 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
v-loading="true"
|
v-loading="true"
|
||||||
element-loading-background="var(--ba-bg-color-overlay)"
|
element-loading-background="var(--ba-bg-color-overlay)"
|
||||||
element-loading-text="加载中"
|
element-loading-text="加载中"
|
||||||
class="default-main ba-main-loading"
|
class="default-main ba-main-loading"
|
||||||
:style="{ height:'calc(100vh - 170px)'}"
|
:style="{ height: 'calc(100vh - 170px)' }"
|
||||||
></div>
|
></div>
|
||||||
<div v-if="state.showReload" class="loading-footer mt10">
|
<div v-if="state.showReload" class="loading-footer mt10">
|
||||||
<el-button @click="refresh" type="warning">重新加载</el-button>
|
<el-button @click="refresh" type="warning">重新加载</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onUnmounted, reactive } from 'vue'
|
import { onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||||
import router from '@/router/index'
|
import { useRoute } from 'vue-router'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import router from '@/router/index'
|
||||||
import { isAdminApp } from '@/utils/common'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
import { getFirstRoute, routePush } from '@/utils/router'
|
import { isAdminApp } from '@/utils/common'
|
||||||
let timer: number
|
import { getFirstRoute, routePush } from '@/utils/router'
|
||||||
|
import { isEmpty } from 'lodash-es'
|
||||||
const navTabs = useNavTabs()
|
import { adminBaseRoutePath } from '@/router/static'
|
||||||
const state = reactive({
|
|
||||||
maximumWait: 1000 * 6,
|
let timer: number
|
||||||
showReload: false,
|
|
||||||
})
|
const route = useRoute()
|
||||||
|
const navTabs = useNavTabs()
|
||||||
const refresh = () => {
|
const state = reactive({
|
||||||
router.go(0)
|
maximumWait: 1000 * 6,
|
||||||
}
|
showReload: false
|
||||||
// if (isAdminApp() && navTabs.state.tabsViewRoutes.length > 0) {
|
})
|
||||||
// let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
|
||||||
// if (firstRoute) routePush(firstRoute.path)
|
const tryRedirect = () => {
|
||||||
// }
|
if (route.params.to) {
|
||||||
|
try {
|
||||||
timer = window.setTimeout(() => {
|
const lastRoute = JSON.parse(route.params.to as string)
|
||||||
state.showReload = true
|
if (lastRoute.path && lastRoute.path !== adminBaseRoutePath) {
|
||||||
}, state.maximumWait)
|
const query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||||
|
routePush({ path: lastRoute.path, query })
|
||||||
onUnmounted(() => {
|
return true
|
||||||
clearTimeout(timer)
|
}
|
||||||
})
|
} catch (error) {
|
||||||
</script>
|
console.error(error)
|
||||||
|
}
|
||||||
<style scoped lang="scss">
|
}
|
||||||
.ba-main-loading {
|
if (isAdminApp() && navTabs.state.tabsViewRoutes.length > 0) {
|
||||||
height: 300px;
|
const firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
||||||
display: flex;
|
if (firstRoute) {
|
||||||
align-items: center;
|
routePush(firstRoute.path)
|
||||||
justify-content: center;
|
return true
|
||||||
}
|
}
|
||||||
.loading-footer {
|
}
|
||||||
display: flex;
|
return false
|
||||||
align-items: center;
|
}
|
||||||
justify-content: center;
|
|
||||||
}
|
const refresh = () => {
|
||||||
</style>
|
if (!tryRedirect()) {
|
||||||
|
router.replace(route.fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (tryRedirect()) return
|
||||||
|
|
||||||
|
const stop = watch(
|
||||||
|
() => navTabs.state.tabsViewRoutes.length,
|
||||||
|
len => {
|
||||||
|
if (len > 0 && tryRedirect()) {
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
timer = window.setTimeout(() => {
|
||||||
|
state.showReload = true
|
||||||
|
}, state.maximumWait)
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearTimeout(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.ba-main-loading {
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.loading-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useTagsViewStore } from '@/stores/modules/tagsView'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { Footer } from '@/layouts/components/Footer'
|
|
||||||
|
|
||||||
defineOptions({ name: 'AppView' })
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
const fixedHeader = computed(() => appStore.getFixedHeader)
|
|
||||||
|
|
||||||
const footer = computed(() => appStore.getFooter)
|
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
|
||||||
|
|
||||||
const getCaches = computed((): string[] => {
|
|
||||||
return tagsViewStore.getCachedViews
|
|
||||||
})
|
|
||||||
|
|
||||||
const tagsView = computed(() => appStore.getTagsView)
|
|
||||||
|
|
||||||
//region 无感刷新
|
|
||||||
const routerAlive = ref(true)
|
|
||||||
// 无感刷新,防止出现页面闪烁白屏
|
|
||||||
const reload = () => {
|
|
||||||
routerAlive.value = false
|
|
||||||
nextTick(() => (routerAlive.value = true))
|
|
||||||
}
|
|
||||||
// 为组件后代提供刷新方法
|
|
||||||
provide('reload', reload)
|
|
||||||
//endregion
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<section
|
|
||||||
:class="[
|
|
||||||
'p-[var(--app-content-padding)] w-[calc(100%-var(--app-content-padding)-var(--app-content-padding))] bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
|
|
||||||
{
|
|
||||||
'!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height))]':
|
|
||||||
(fixedHeader &&
|
|
||||||
(layout === 'classic' || layout === 'topLeft' || layout === 'top') &&
|
|
||||||
footer) ||
|
|
||||||
(!tagsView && layout === 'top' && footer),
|
|
||||||
'!min-h-[calc(100%-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height)-var(--tags-view-height))]':
|
|
||||||
tagsView && layout === 'top' && footer,
|
|
||||||
|
|
||||||
'!min-h-[calc(100%-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-var(--top-tool-height)-var(--app-footer-height))]':
|
|
||||||
!fixedHeader && layout === 'classic' && footer,
|
|
||||||
|
|
||||||
'!min-h-[calc(100%-var(--tags-view-height)-var(--app-content-padding)-var(--app-content-padding)-var(--app-footer-height))]':
|
|
||||||
!fixedHeader && layout === 'topLeft' && footer,
|
|
||||||
|
|
||||||
'!min-h-[calc(100%-var(--top-tool-height)-var(--app-content-padding)-var(--app-content-padding))]':
|
|
||||||
fixedHeader && layout === 'cutMenu' && footer,
|
|
||||||
|
|
||||||
'!min-h-[calc(100%-var(--top-tool-height)-var(--app-content-padding)-var(--app-content-padding)-var(--tags-view-height))]':
|
|
||||||
!fixedHeader && layout === 'cutMenu' && footer
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<router-view v-if="routerAlive">
|
|
||||||
<template #default="{ Component, route }">
|
|
||||||
<keep-alive :include="getCaches">
|
|
||||||
<component :is="Component" :key="route.fullPath" />
|
|
||||||
</keep-alive>
|
|
||||||
</template>
|
|
||||||
</router-view>
|
|
||||||
</section>
|
|
||||||
<Footer v-if="footer" />
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Breadcrumb from './src/Breadcrumb.vue'
|
|
||||||
|
|
||||||
export { Breadcrumb }
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
<script lang="tsx">
|
|
||||||
import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
|
|
||||||
import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { usePermissionStore } from '@/stores/modules/permission'
|
|
||||||
import { filterBreadcrumb } from './helper'
|
|
||||||
import { filter, treeToList } from '@/utils/tree'
|
|
||||||
import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
|
|
||||||
|
|
||||||
import { Icon } from '@/components/Icon'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('breadcrumb')
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
// 面包屑图标
|
|
||||||
const breadcrumbIcon = computed(() => appStore.getBreadcrumbIcon)
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Breadcrumb',
|
|
||||||
setup() {
|
|
||||||
const { currentRoute } = useRouter()
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const levelList = ref<AppRouteRecordRaw[]>([])
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
const menuRouters = computed(() => {
|
|
||||||
const routers = permissionStore.getRouters
|
|
||||||
return filterBreadcrumb(routers)
|
|
||||||
})
|
|
||||||
|
|
||||||
const getBreadcrumb = () => {
|
|
||||||
const currentPath = currentRoute.value.matched.slice(-1)[0].path
|
|
||||||
|
|
||||||
levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
|
|
||||||
return node.path === currentPath
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderBreadcrumb = () => {
|
|
||||||
const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
|
|
||||||
return breadcrumbList.map((v) => {
|
|
||||||
const disabled = !v.redirect || v.redirect === 'noredirect'
|
|
||||||
const meta = v.meta as RouteMeta
|
|
||||||
return (
|
|
||||||
<ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
|
|
||||||
{meta?.icon && breadcrumbIcon.value ? (
|
|
||||||
<div class="flex items-center">
|
|
||||||
<Icon icon={meta.icon} class="mr-[2px]" svgClass="inline-block"></Icon>
|
|
||||||
{t(v?.meta?.title)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
t(v?.meta?.title)
|
|
||||||
)}
|
|
||||||
</ElBreadcrumbItem>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => currentRoute.value,
|
|
||||||
(route: RouteLocationNormalizedLoaded) => {
|
|
||||||
if (route.path.startsWith('/redirect/')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
getBreadcrumb()
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<ElBreadcrumb separator="/" class={`${prefixCls} flex items-center h-full ml-[10px]`}>
|
|
||||||
<TransitionGroup appear enter-active-class="animate__animated animate__fadeInRight">
|
|
||||||
{renderBreadcrumb()}
|
|
||||||
</TransitionGroup>
|
|
||||||
</ElBreadcrumb>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: el-breadcrumb;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
:deep(&__item) {
|
|
||||||
display: flex;
|
|
||||||
.#{$prefix-cls}__inner {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--top-header-text-color);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(&__item):not(:last-child) {
|
|
||||||
.#{$prefix-cls}__inner {
|
|
||||||
color: var(--top-header-text-color);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(&__item):last-child {
|
|
||||||
.#{$prefix-cls}__inner {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--el-text-color-placeholder);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-text-color-placeholder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import { pathResolve } from '@/utils/routerHelper'
|
|
||||||
import type { RouteMeta } from 'vue-router'
|
|
||||||
|
|
||||||
export const filterBreadcrumb = (
|
|
||||||
routes: AppRouteRecordRaw[],
|
|
||||||
parentPath = ''
|
|
||||||
): AppRouteRecordRaw[] => {
|
|
||||||
const res: AppRouteRecordRaw[] = []
|
|
||||||
|
|
||||||
for (const route of routes) {
|
|
||||||
const meta = route?.meta as RouteMeta
|
|
||||||
if (meta.hidden && !meta.canTo) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const data: AppRouteRecordRaw =
|
|
||||||
!meta.alwaysShow && route.children?.length === 1
|
|
||||||
? { ...route.children[0], path: pathResolve(route.path, route.children[0].path) }
|
|
||||||
: { ...route }
|
|
||||||
|
|
||||||
data.path = pathResolve(parentPath, data.path)
|
|
||||||
|
|
||||||
if (data.children) {
|
|
||||||
data.children = filterBreadcrumb(data.children, data.path)
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
res.push(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Collapse from './src/Collapse.vue'
|
|
||||||
|
|
||||||
export { Collapse }
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { Expand,Fold,ZoomIn,Delete} from '@element-plus/icons-vue'
|
|
||||||
|
|
||||||
defineOptions({ name: 'Collapse' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('collapse')
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
color: propTypes.string.def('')
|
|
||||||
})
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
|
||||||
|
|
||||||
const toggleCollapse = () => {
|
|
||||||
const collapsed = unref(collapse)
|
|
||||||
appStore.setCollapse(!collapsed)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="prefixCls" @click="toggleCollapse">
|
|
||||||
<Icon
|
|
||||||
:color="color"
|
|
||||||
:icon="collapse ? Expand: Fold"
|
|
||||||
:size="18"
|
|
||||||
class="cursor-pointer"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import ContextMenu from './src/ContextMenu.vue'
|
|
||||||
import { ElDropdown } from 'element-plus'
|
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
||||||
|
|
||||||
export interface ContextMenuExpose {
|
|
||||||
elDropdownMenuRef: ComponentRef<typeof ElDropdown>
|
|
||||||
tagItem: RouteLocationNormalizedLoaded
|
|
||||||
}
|
|
||||||
|
|
||||||
export { ContextMenu }
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { PropType } from 'vue'
|
|
||||||
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
||||||
import { contextMenuSchema } from '@/types/contextMenu'
|
|
||||||
import type { ElDropdown } from 'element-plus'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ContextMenu' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('context-menu')
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const emit = defineEmits(['visibleChange'])
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
schema: {
|
|
||||||
type: Array as PropType<contextMenuSchema[]>,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
trigger: {
|
|
||||||
type: String as PropType<'click' | 'hover' | 'focus' | 'contextmenu'>,
|
|
||||||
default: 'contextmenu'
|
|
||||||
},
|
|
||||||
tagItem: {
|
|
||||||
type: Object as PropType<RouteLocationNormalizedLoaded>,
|
|
||||||
default: () => ({})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const command = (item: contextMenuSchema) => {
|
|
||||||
item.command && item.command(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
const visibleChange = (visible: boolean) => {
|
|
||||||
emit('visibleChange', visible, props.tagItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
const elDropdownMenuRef = ref<ComponentRef<typeof ElDropdown>>()
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
elDropdownMenuRef,
|
|
||||||
tagItem: props.tagItem
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ElDropdown
|
|
||||||
ref="elDropdownMenuRef"
|
|
||||||
:class="prefixCls"
|
|
||||||
:trigger="trigger"
|
|
||||||
placement="bottom-start"
|
|
||||||
popper-class="v-context-menu-popper"
|
|
||||||
@command="command"
|
|
||||||
@visible-change="visibleChange"
|
|
||||||
>
|
|
||||||
<slot></slot>
|
|
||||||
<template #dropdown>
|
|
||||||
<ElDropdownMenu>
|
|
||||||
<ElDropdownItem
|
|
||||||
v-for="(item, index) in schema"
|
|
||||||
:key="`dropdown${index}`"
|
|
||||||
:command="item"
|
|
||||||
:disabled="item.disabled"
|
|
||||||
:divided="item.divided"
|
|
||||||
>
|
|
||||||
<Icon :icon="item.icon" />
|
|
||||||
{{ t(item.label) }}
|
|
||||||
</ElDropdownItem>
|
|
||||||
</ElDropdownMenu>
|
|
||||||
</template>
|
|
||||||
</ElDropdown>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Footer from './src/Footer.vue'
|
|
||||||
|
|
||||||
export { Footer }
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-reserved-component-names
|
|
||||||
defineOptions({ name: 'Footer' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('footer')
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const title = computed(() => appStore.getTitle)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
:class="prefixCls"
|
|
||||||
class="h-[var(--app-footer-height)] bg-[var(--app-content-bg-color)] text-center leading-[var(--app-footer-height)] text-[var(--el-text-color-placeholder)] dark:bg-[var(--el-bg-color)]"
|
|
||||||
>
|
|
||||||
<span class="text-14px">Copyright ©2022-{{ title }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import LocaleDropdown from './src/LocaleDropdown.vue'
|
|
||||||
|
|
||||||
export { LocaleDropdown }
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useLocaleStore } from '@/stores/modules/locale'
|
|
||||||
import { useLocale } from '@/hooks/web/useLocale'
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
defineOptions({ name: 'LocaleDropdown' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('locale-dropdown')
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
color: propTypes.string.def('')
|
|
||||||
})
|
|
||||||
|
|
||||||
const localeStore = useLocaleStore()
|
|
||||||
|
|
||||||
const langMap = computed(() => localeStore.getLocaleMap)
|
|
||||||
|
|
||||||
const currentLang = computed(() => localeStore.getCurrentLocale)
|
|
||||||
|
|
||||||
const setLang = (lang: LocaleType) => {
|
|
||||||
if (lang === unref(currentLang).lang) return
|
|
||||||
// 需要重新加载页面让整个语言多初始化
|
|
||||||
window.location.reload()
|
|
||||||
localeStore.setCurrentLocale({
|
|
||||||
lang
|
|
||||||
})
|
|
||||||
const { changeLocale } = useLocale()
|
|
||||||
changeLocale(lang)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ElDropdown :class="prefixCls" trigger="click" @command="setLang">
|
|
||||||
<Icon
|
|
||||||
:class="$attrs.class"
|
|
||||||
:color="color"
|
|
||||||
:size="18"
|
|
||||||
class="cursor-pointer !p-0"
|
|
||||||
icon="ion:language-sharp"
|
|
||||||
/>
|
|
||||||
<template #dropdown>
|
|
||||||
<ElDropdownMenu>
|
|
||||||
<ElDropdownItem v-for="item in langMap" :key="item.lang" :command="item.lang">
|
|
||||||
{{ item.name }}
|
|
||||||
</ElDropdownItem>
|
|
||||||
</ElDropdownMenu>
|
|
||||||
</template>
|
|
||||||
</ElDropdown>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Logo from './src/Logo.vue'
|
|
||||||
|
|
||||||
export { Logo }
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { computed, onMounted, ref, unref, watch } from 'vue'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
defineOptions({ name: 'Logo' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('logo')
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const show = ref(true)
|
|
||||||
|
|
||||||
const title = computed(() => appStore.getTitle)
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (unref(collapse)) show.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => collapse.value,
|
|
||||||
(collapse: boolean) => {
|
|
||||||
if (unref(layout) === 'topLeft' || unref(layout) === 'cutMenu') {
|
|
||||||
show.value = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!collapse) {
|
|
||||||
setTimeout(() => {
|
|
||||||
show.value = !collapse
|
|
||||||
}, 400)
|
|
||||||
} else {
|
|
||||||
show.value = !collapse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => layout.value,
|
|
||||||
(layout) => {
|
|
||||||
if (layout === 'top' || layout === 'cutMenu') {
|
|
||||||
show.value = true
|
|
||||||
} else {
|
|
||||||
if (unref(collapse)) {
|
|
||||||
show.value = false
|
|
||||||
} else {
|
|
||||||
show.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<router-link
|
|
||||||
:class="[
|
|
||||||
prefixCls,
|
|
||||||
layout !== 'classic' ? `${prefixCls}__Top` : '',
|
|
||||||
'flex !h-[var(--logo-height)] items-center cursor-pointer pl-8px relative decoration-none overflow-hidden'
|
|
||||||
]"
|
|
||||||
to="/"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
class="h-[calc(var(--logo-height)-10px)] w-[calc(var(--logo-height)-10px)]"
|
|
||||||
src="@/assets/imgs/logo.png"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
v-if="show"
|
|
||||||
:class="[
|
|
||||||
'ml-10px text-16px font-700',
|
|
||||||
{
|
|
||||||
'text-[var(--logo-title-text-color)]': layout === 'classic',
|
|
||||||
'text-[var(--top-header-text-color)]':
|
|
||||||
layout === 'topLeft' || layout === 'top' || layout === 'cutMenu'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
{{ title }}
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Menu from './src/Menu.vue'
|
|
||||||
|
|
||||||
export { Menu }
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
<script lang="tsx">
|
|
||||||
import { PropType } from 'vue'
|
|
||||||
import { ElMenu, ElScrollbar } from 'element-plus'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { usePermissionStore } from '@/stores/modules/permission'
|
|
||||||
import { useRenderMenuItem } from './components/useRenderMenuItem'
|
|
||||||
import { isUrl } from '@/utils/is'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { LayoutType } from '@/types/layout'
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('menu')
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
// eslint-disable-next-line vue/no-reserved-component-names
|
|
||||||
name: 'Menu',
|
|
||||||
props: {
|
|
||||||
menuSelect: {
|
|
||||||
type: Function as PropType<(index: string) => void>,
|
|
||||||
default: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
const { push, currentRoute } = useRouter()
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
|
||||||
// 竖
|
|
||||||
const vertical: LayoutType[] = ['classic', 'topLeft', 'cutMenu']
|
|
||||||
|
|
||||||
if (vertical.includes(unref(layout))) {
|
|
||||||
return 'vertical'
|
|
||||||
} else {
|
|
||||||
return 'horizontal'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const routers = computed(() =>
|
|
||||||
unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
|
|
||||||
)
|
|
||||||
|
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
|
||||||
|
|
||||||
const uniqueOpened = computed(() => appStore.getUniqueOpened)
|
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
|
||||||
const { meta, path } = unref(currentRoute)
|
|
||||||
// if set path, the sidebar will highlight the path you set
|
|
||||||
if (meta.activeMenu) {
|
|
||||||
return meta.activeMenu as string
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
})
|
|
||||||
|
|
||||||
const menuSelect = (index: string) => {
|
|
||||||
if (props.menuSelect) {
|
|
||||||
props.menuSelect(index)
|
|
||||||
}
|
|
||||||
// 自定义事件
|
|
||||||
if (isUrl(index)) {
|
|
||||||
window.open(index)
|
|
||||||
} else {
|
|
||||||
push(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderMenuWrap = () => {
|
|
||||||
if (unref(layout) === 'top') {
|
|
||||||
return renderMenu()
|
|
||||||
} else {
|
|
||||||
return <ElScrollbar>{renderMenu()}</ElScrollbar>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderMenu = () => {
|
|
||||||
return (
|
|
||||||
<ElMenu
|
|
||||||
defaultActive={unref(activeMenu)}
|
|
||||||
mode={unref(menuMode)}
|
|
||||||
collapse={
|
|
||||||
unref(layout) === 'top' || unref(layout) === 'cutMenu' ? false : unref(collapse)
|
|
||||||
}
|
|
||||||
uniqueOpened={unref(layout) === 'top' ? false : unref(uniqueOpened)}
|
|
||||||
backgroundColor="var(--left-menu-bg-color)"
|
|
||||||
textColor="var(--left-menu-text-color)"
|
|
||||||
activeTextColor="var(--left-menu-text-active-color)"
|
|
||||||
onSelect={menuSelect}
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
default: () => {
|
|
||||||
const { renderMenuItem } = useRenderMenuItem(unref(menuMode))
|
|
||||||
return renderMenuItem(unref(routers))
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</ElMenu>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<div
|
|
||||||
id={prefixCls}
|
|
||||||
class={[
|
|
||||||
`${prefixCls} ${prefixCls}__${unref(menuMode)}`,
|
|
||||||
'h-[100%] overflow-hidden flex-col bg-[var(--left-menu-bg-color)]',
|
|
||||||
{
|
|
||||||
'w-[var(--left-menu-min-width)]': unref(collapse) && unref(layout) !== 'cutMenu',
|
|
||||||
'w-[var(--left-menu-max-width)]': !unref(collapse) && unref(layout) !== 'cutMenu'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{renderMenuWrap()}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-menu;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
position: relative;
|
|
||||||
transition: width var(--transition-time-02);
|
|
||||||
|
|
||||||
:deep(.el-menu) {
|
|
||||||
width: 100% !important;
|
|
||||||
border-right: none;
|
|
||||||
|
|
||||||
// 设置选中时子标题的颜色
|
|
||||||
.is-active {
|
|
||||||
& > .el-sub-menu__title {
|
|
||||||
color: var(--left-menu-text-active-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置子菜单悬停的高亮和背景色
|
|
||||||
.el-sub-menu__title,
|
|
||||||
.el-menu-item {
|
|
||||||
&:hover {
|
|
||||||
color: var(--left-menu-text-active-color) !important;
|
|
||||||
background-color: var(--left-menu-bg-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置选中时的高亮背景和高亮颜色
|
|
||||||
.el-menu-item.is-active {
|
|
||||||
color: var(--left-menu-text-active-color) !important;
|
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-menu-item.is-active {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置子菜单的背景颜色
|
|
||||||
.el-menu {
|
|
||||||
.el-sub-menu__title,
|
|
||||||
.el-menu-item:not(.is-active) {
|
|
||||||
background-color: var(--left-menu-bg-light-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 折叠时的最小宽度
|
|
||||||
:deep(.el-menu--collapse) {
|
|
||||||
width: var(--left-menu-min-width);
|
|
||||||
|
|
||||||
& > .is-active,
|
|
||||||
& > .is-active > .el-sub-menu__title {
|
|
||||||
position: relative;
|
|
||||||
background-color: var(--left-menu-collapse-bg-active-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 折叠动画的时候,就需要把文字给隐藏掉
|
|
||||||
:deep(.horizontal-collapse-transition) {
|
|
||||||
// transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
|
|
||||||
.#{$prefix-cls}__title {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 水平菜单
|
|
||||||
&__horizontal {
|
|
||||||
height: calc(var(--top-tool-height)) !important;
|
|
||||||
|
|
||||||
:deep(.el-menu--horizontal) {
|
|
||||||
height: calc(var(--top-tool-height));
|
|
||||||
border-bottom: none;
|
|
||||||
// 重新设置底部高亮颜色
|
|
||||||
& > .el-sub-menu.is-active {
|
|
||||||
.el-sub-menu__title {
|
|
||||||
border-bottom-color: var(--el-color-primary) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-menu-item.is-active {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.#{$prefix-cls}__title {
|
|
||||||
/* stylelint-disable-next-line */
|
|
||||||
max-height: calc(var(--top-tool-height) - 2px) !important;
|
|
||||||
/* stylelint-disable-next-line */
|
|
||||||
line-height: calc(var(--top-tool-height) - 2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
$prefix-cls: v-menu-popper;
|
|
||||||
|
|
||||||
.#{$prefix-cls}--vertical,
|
|
||||||
.#{$prefix-cls}--horizontal {
|
|
||||||
// 设置选中时子标题的颜色
|
|
||||||
.is-active {
|
|
||||||
& > .el-sub-menu__title {
|
|
||||||
color: var(--left-menu-text-active-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置子菜单悬停的高亮和背景色
|
|
||||||
.el-sub-menu__title,
|
|
||||||
.el-menu-item {
|
|
||||||
&:hover {
|
|
||||||
color: var(--left-menu-text-active-color) !important;
|
|
||||||
background-color: var(--left-menu-bg-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置选中时的高亮背景
|
|
||||||
.el-menu-item.is-active {
|
|
||||||
position: relative;
|
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import { ElSubMenu, ElMenuItem } from 'element-plus'
|
|
||||||
import { hasOneShowingChild } from '../helper'
|
|
||||||
import { isUrl } from '@/utils/is'
|
|
||||||
import { useRenderMenuTitle } from './useRenderMenuTitle'
|
|
||||||
import { pathResolve } from '@/utils/routerHelper'
|
|
||||||
|
|
||||||
const { renderMenuTitle } = useRenderMenuTitle()
|
|
||||||
|
|
||||||
export const useRenderMenuItem = () =>
|
|
||||||
// allRouters: AppRouteRecordRaw[] = [],
|
|
||||||
{
|
|
||||||
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
|
|
||||||
return routers
|
|
||||||
.filter((v) => !v.meta?.hidden)
|
|
||||||
.map((v) => {
|
|
||||||
const meta = v.meta ?? {}
|
|
||||||
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
|
|
||||||
const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath<AppRouteRecordRaw>(allRouters, v.path).join('/')
|
|
||||||
|
|
||||||
if (
|
|
||||||
oneShowingChild &&
|
|
||||||
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
|
|
||||||
!meta?.alwaysShow
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<ElMenuItem
|
|
||||||
index={onlyOneChild ? pathResolve(fullPath, onlyOneChild.path) : fullPath}
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta)
|
|
||||||
}}
|
|
||||||
</ElMenuItem>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<ElSubMenu index={fullPath}>
|
|
||||||
{{
|
|
||||||
title: () => renderMenuTitle(meta),
|
|
||||||
default: () => renderMenuItem(v.children!, fullPath)
|
|
||||||
}}
|
|
||||||
</ElSubMenu>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
renderMenuItem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import type { RouteMeta } from 'vue-router'
|
|
||||||
import { Icon } from '@/components/Icon'
|
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
|
||||||
|
|
||||||
export const useRenderMenuTitle = () => {
|
|
||||||
const renderMenuTitle = (meta: RouteMeta) => {
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { title = 'Please set title', icon } = meta
|
|
||||||
|
|
||||||
return icon ? (
|
|
||||||
<>
|
|
||||||
<Icon icon={meta.icon}></Icon>
|
|
||||||
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
|
||||||
{t(title as string)}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<span class="v-menu__title overflow-hidden overflow-ellipsis whitespace-nowrap">
|
|
||||||
{t(title as string)}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
renderMenuTitle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import type { RouteMeta } from 'vue-router'
|
|
||||||
import { findPath } from '@/utils/tree'
|
|
||||||
|
|
||||||
type OnlyOneChildType = AppRouteRecordRaw & { noShowingChildren?: boolean }
|
|
||||||
|
|
||||||
interface HasOneShowingChild {
|
|
||||||
oneShowingChild?: boolean
|
|
||||||
onlyOneChild?: OnlyOneChildType
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAllParentPath = <T = Recordable>(treeData: T[], path: string) => {
|
|
||||||
const menuList = findPath(treeData, (n) => n.path === path) as AppRouteRecordRaw[]
|
|
||||||
return (menuList || []).map((item) => item.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hasOneShowingChild = (
|
|
||||||
children: AppRouteRecordRaw[] = [],
|
|
||||||
parent: AppRouteRecordRaw
|
|
||||||
): HasOneShowingChild => {
|
|
||||||
const onlyOneChild = ref<OnlyOneChildType>()
|
|
||||||
|
|
||||||
const showingChildren = children.filter((v) => {
|
|
||||||
const meta = (v.meta ?? {}) as RouteMeta
|
|
||||||
if (meta.hidden) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
// Temp set(will be used if only has one showing child)
|
|
||||||
onlyOneChild.value = v
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// When there is only one child router, the child router is displayed by default
|
|
||||||
if (showingChildren.length === 1) {
|
|
||||||
return {
|
|
||||||
oneShowingChild: true,
|
|
||||||
onlyOneChild: unref(onlyOneChild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show parent if there are no child router to display
|
|
||||||
if (!showingChildren.length) {
|
|
||||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
|
||||||
return {
|
|
||||||
oneShowingChild: true,
|
|
||||||
onlyOneChild: unref(onlyOneChild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
oneShowingChild: false,
|
|
||||||
onlyOneChild: unref(onlyOneChild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Screenfull from './src/Screenfull.vue'
|
|
||||||
|
|
||||||
export { Screenfull }
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { Icon } from '@/components/Icon'
|
|
||||||
import { useFullscreen } from '@vueuse/core'
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ScreenFull' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('screenfull')
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
color: propTypes.string.def('')
|
|
||||||
})
|
|
||||||
|
|
||||||
const { toggle, isFullscreen } = useFullscreen()
|
|
||||||
|
|
||||||
const toggleFullscreen = () => {
|
|
||||||
toggle()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="prefixCls" @click="toggleFullscreen">
|
|
||||||
<Icon
|
|
||||||
:color="color"
|
|
||||||
:icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
|
|
||||||
:size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import Setting from './src/Setting.vue'
|
|
||||||
|
|
||||||
export { Setting }
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { useClipboard, useCssVar } from '@vueuse/core'
|
|
||||||
|
|
||||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
import { setCssVar, trim } from '@/utils'
|
|
||||||
import { colorIsDark, hexToRGB, lighten } from '@/utils/color'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { ThemeSwitch } from '@/layouts/components/ThemeSwitch'
|
|
||||||
import ColorRadioPicker from './components/ColorRadioPicker.vue'
|
|
||||||
import InterfaceDisplay from './components/InterfaceDisplay.vue'
|
|
||||||
import LayoutRadioPicker from './components/LayoutRadioPicker.vue'
|
|
||||||
|
|
||||||
defineOptions({ name: 'Setting' })
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
const prefixCls = getPrefixCls('setting')
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
const drawer = ref(false)
|
|
||||||
|
|
||||||
// 主题色相关
|
|
||||||
const systemTheme = ref(appStore.getTheme.elColorPrimary)
|
|
||||||
|
|
||||||
const setSystemTheme = (color: string) => {
|
|
||||||
setCssVar('--el-color-primary', color)
|
|
||||||
appStore.setTheme({ elColorPrimary: color })
|
|
||||||
const leftMenuBgColor = useCssVar('--left-menu-bg-color', document.documentElement)
|
|
||||||
setMenuTheme(trim(unref(leftMenuBgColor)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 头部主题相关
|
|
||||||
const headerTheme = ref(appStore.getTheme.topHeaderBgColor || '')
|
|
||||||
|
|
||||||
const setHeaderTheme = (color: string) => {
|
|
||||||
const isDarkColor = colorIsDark(color)
|
|
||||||
const textColor = isDarkColor ? '#fff' : 'inherit'
|
|
||||||
const textHoverColor = isDarkColor ? lighten(color!, 6) : '#f6f6f6'
|
|
||||||
const topToolBorderColor = isDarkColor ? color : '#eee'
|
|
||||||
setCssVar('--top-header-bg-color', color)
|
|
||||||
setCssVar('--top-header-text-color', textColor)
|
|
||||||
setCssVar('--top-header-hover-color', textHoverColor)
|
|
||||||
appStore.setTheme({
|
|
||||||
topHeaderBgColor: color,
|
|
||||||
topHeaderTextColor: textColor,
|
|
||||||
topHeaderHoverColor: textHoverColor,
|
|
||||||
topToolBorderColor
|
|
||||||
})
|
|
||||||
if (unref(layout) === 'top') {
|
|
||||||
setMenuTheme(color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 菜单主题相关
|
|
||||||
const menuTheme = ref(appStore.getTheme.leftMenuBgColor || '')
|
|
||||||
|
|
||||||
const setMenuTheme = (color: string) => {
|
|
||||||
const primaryColor = useCssVar('--el-color-primary', document.documentElement)
|
|
||||||
const isDarkColor = colorIsDark(color)
|
|
||||||
const theme: Recordable = {
|
|
||||||
// 左侧菜单边框颜色
|
|
||||||
leftMenuBorderColor: isDarkColor ? 'inherit' : '#eee',
|
|
||||||
// 左侧菜单背景颜色
|
|
||||||
leftMenuBgColor: color,
|
|
||||||
// 左侧菜单浅色背景颜色
|
|
||||||
leftMenuBgLightColor: isDarkColor ? lighten(color!, 6) : color,
|
|
||||||
// 左侧菜单选中背景颜色
|
|
||||||
leftMenuBgActiveColor: isDarkColor
|
|
||||||
? 'var(--el-color-primary)'
|
|
||||||
: hexToRGB(unref(primaryColor), 0.1),
|
|
||||||
// 左侧菜单收起选中背景颜色
|
|
||||||
leftMenuCollapseBgActiveColor: isDarkColor
|
|
||||||
? 'var(--el-color-primary)'
|
|
||||||
: hexToRGB(unref(primaryColor), 0.1),
|
|
||||||
// 左侧菜单字体颜色
|
|
||||||
leftMenuTextColor: isDarkColor ? '#bfcbd9' : '#333',
|
|
||||||
// 左侧菜单选中字体颜色
|
|
||||||
leftMenuTextActiveColor: isDarkColor ? '#fff' : 'var(--el-color-primary)',
|
|
||||||
// logo字体颜色
|
|
||||||
logoTitleTextColor: isDarkColor ? '#fff' : 'inherit',
|
|
||||||
// logo边框颜色
|
|
||||||
logoBorderColor: isDarkColor ? color : '#eee'
|
|
||||||
}
|
|
||||||
appStore.setTheme(theme)
|
|
||||||
appStore.setCssVarTheme()
|
|
||||||
}
|
|
||||||
if (layout.value === 'top' && !appStore.getIsDark) {
|
|
||||||
headerTheme.value = '#fff'
|
|
||||||
setHeaderTheme('#fff')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听layout变化,重置一些主题色
|
|
||||||
watch(
|
|
||||||
() => layout.value,
|
|
||||||
(n) => {
|
|
||||||
if (n === 'top' && !appStore.getIsDark) {
|
|
||||||
headerTheme.value = '#fff'
|
|
||||||
setHeaderTheme('#fff')
|
|
||||||
} else {
|
|
||||||
setMenuTheme(unref(menuTheme))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 拷贝
|
|
||||||
const copyConfig = async () => {
|
|
||||||
const { copy, copied, isSupported } = useClipboard({
|
|
||||||
source: `
|
|
||||||
// 面包屑
|
|
||||||
breadcrumb: ${appStore.getBreadcrumb},
|
|
||||||
// 面包屑图标
|
|
||||||
breadcrumbIcon: ${appStore.getBreadcrumbIcon},
|
|
||||||
// 折叠图标
|
|
||||||
hamburger: ${appStore.getHamburger},
|
|
||||||
// 全屏图标
|
|
||||||
screenfull: ${appStore.getScreenfull},
|
|
||||||
// 尺寸图标
|
|
||||||
size: ${appStore.getSize},
|
|
||||||
// 多语言图标
|
|
||||||
locale: ${appStore.getLocale},
|
|
||||||
// 消息图标
|
|
||||||
message: ${appStore.getMessage},
|
|
||||||
// 标签页
|
|
||||||
tagsView: ${appStore.getTagsView},
|
|
||||||
// 标签页图标
|
|
||||||
getTagsViewIcon: ${appStore.getTagsViewIcon},
|
|
||||||
// logo
|
|
||||||
logo: ${appStore.getLogo},
|
|
||||||
// 菜单手风琴
|
|
||||||
uniqueOpened: ${appStore.getUniqueOpened},
|
|
||||||
// 固定header
|
|
||||||
fixedHeader: ${appStore.getFixedHeader},
|
|
||||||
// 页脚
|
|
||||||
footer: ${appStore.getFooter},
|
|
||||||
// 灰色模式
|
|
||||||
greyMode: ${appStore.getGreyMode},
|
|
||||||
// layout布局
|
|
||||||
layout: '${appStore.getLayout}',
|
|
||||||
// 暗黑模式
|
|
||||||
isDark: ${appStore.getIsDark},
|
|
||||||
// 组件尺寸
|
|
||||||
currentSize: '${appStore.getCurrentSize}',
|
|
||||||
// 主题相关
|
|
||||||
theme: {
|
|
||||||
// 主题色
|
|
||||||
elColorPrimary: '${appStore.getTheme.elColorPrimary}',
|
|
||||||
// 左侧菜单边框颜色
|
|
||||||
leftMenuBorderColor: '${appStore.getTheme.leftMenuBorderColor}',
|
|
||||||
// 左侧菜单背景颜色
|
|
||||||
leftMenuBgColor: '${appStore.getTheme.leftMenuBgColor}',
|
|
||||||
// 左侧菜单浅色背景颜色
|
|
||||||
leftMenuBgLightColor: '${appStore.getTheme.leftMenuBgLightColor}',
|
|
||||||
// 左侧菜单选中背景颜色
|
|
||||||
leftMenuBgActiveColor: '${appStore.getTheme.leftMenuBgActiveColor}',
|
|
||||||
// 左侧菜单收起选中背景颜色
|
|
||||||
leftMenuCollapseBgActiveColor: '${appStore.getTheme.leftMenuCollapseBgActiveColor}',
|
|
||||||
// 左侧菜单字体颜色
|
|
||||||
leftMenuTextColor: '${appStore.getTheme.leftMenuTextColor}',
|
|
||||||
// 左侧菜单选中字体颜色
|
|
||||||
leftMenuTextActiveColor: '${appStore.getTheme.leftMenuTextActiveColor}',
|
|
||||||
// logo字体颜色
|
|
||||||
logoTitleTextColor: '${appStore.getTheme.logoTitleTextColor}',
|
|
||||||
// logo边框颜色
|
|
||||||
logoBorderColor: '${appStore.getTheme.logoBorderColor}',
|
|
||||||
// 头部背景颜色
|
|
||||||
topHeaderBgColor: '${appStore.getTheme.topHeaderBgColor}',
|
|
||||||
// 头部字体颜色
|
|
||||||
topHeaderTextColor: '${appStore.getTheme.topHeaderTextColor}',
|
|
||||||
// 头部悬停颜色
|
|
||||||
topHeaderHoverColor: '${appStore.getTheme.topHeaderHoverColor}',
|
|
||||||
// 头部边框颜色
|
|
||||||
topToolBorderColor: '${appStore.getTheme.topToolBorderColor}'
|
|
||||||
}
|
|
||||||
`
|
|
||||||
})
|
|
||||||
if (!isSupported) {
|
|
||||||
ElMessage.error(t('setting.copyFailed'))
|
|
||||||
} else {
|
|
||||||
await copy()
|
|
||||||
if (unref(copied)) {
|
|
||||||
ElMessage.success(t('setting.copySuccess'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空缓存
|
|
||||||
const clear = () => {
|
|
||||||
const { wsCache } = useCache()
|
|
||||||
wsCache.delete(CACHE_KEY.LAYOUT)
|
|
||||||
wsCache.delete(CACHE_KEY.THEME)
|
|
||||||
wsCache.delete(CACHE_KEY.IS_DARK)
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
:class="prefixCls"
|
|
||||||
class="fixed right-0 top-[45%] h-40px w-40px cursor-pointer bg-[var(--el-color-primary)] text-center leading-40px"
|
|
||||||
@click="drawer = true"
|
|
||||||
>
|
|
||||||
<Icon color="#fff" icon="ep:setting" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ElDrawer v-model="drawer" :z-index="4000" direction="rtl" size="350px">
|
|
||||||
<template #header>
|
|
||||||
<span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<!-- 主题 -->
|
|
||||||
<ElDivider>{{ t('setting.theme') }}</ElDivider>
|
|
||||||
<ThemeSwitch />
|
|
||||||
|
|
||||||
<!-- 布局 -->
|
|
||||||
<ElDivider>{{ t('setting.layout') }}</ElDivider>
|
|
||||||
<LayoutRadioPicker />
|
|
||||||
|
|
||||||
<!-- 系统主题 -->
|
|
||||||
<ElDivider>{{ t('setting.systemTheme') }}</ElDivider>
|
|
||||||
<ColorRadioPicker
|
|
||||||
v-model="systemTheme"
|
|
||||||
:schema="[
|
|
||||||
'#409eff',
|
|
||||||
'#009688',
|
|
||||||
'#536dfe',
|
|
||||||
'#ff5c93',
|
|
||||||
'#ee4f12',
|
|
||||||
'#0096c7',
|
|
||||||
'#9c27b0',
|
|
||||||
'#ff9800'
|
|
||||||
]"
|
|
||||||
@change="setSystemTheme"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 头部主题 -->
|
|
||||||
<ElDivider>{{ t('setting.headerTheme') }}</ElDivider>
|
|
||||||
<ColorRadioPicker
|
|
||||||
v-model="headerTheme"
|
|
||||||
:schema="[
|
|
||||||
'#fff',
|
|
||||||
'#151515',
|
|
||||||
'#5172dc',
|
|
||||||
'#e74c3c',
|
|
||||||
'#24292e',
|
|
||||||
'#394664',
|
|
||||||
'#009688',
|
|
||||||
'#383f45'
|
|
||||||
]"
|
|
||||||
@change="setHeaderTheme"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 菜单主题 -->
|
|
||||||
<template v-if="layout !== 'top'">
|
|
||||||
<ElDivider>{{ t('setting.menuTheme') }}</ElDivider>
|
|
||||||
<ColorRadioPicker
|
|
||||||
v-model="menuTheme"
|
|
||||||
:schema="[
|
|
||||||
'#fff',
|
|
||||||
'#001529',
|
|
||||||
'#212121',
|
|
||||||
'#273352',
|
|
||||||
'#191b24',
|
|
||||||
'#383f45',
|
|
||||||
'#001628',
|
|
||||||
'#344058'
|
|
||||||
]"
|
|
||||||
@change="setMenuTheme"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 界面显示 -->
|
|
||||||
<ElDivider>{{ t('setting.interfaceDisplay') }}</ElDivider>
|
|
||||||
<InterfaceDisplay />
|
|
||||||
|
|
||||||
<ElDivider />
|
|
||||||
<div>
|
|
||||||
<ElButton class="w-full" type="primary" @click="copyConfig">{{ t('setting.copy') }}</ElButton>
|
|
||||||
</div>
|
|
||||||
<div class="mt-5px">
|
|
||||||
<ElButton class="w-full" type="danger" @click="clear">
|
|
||||||
{{ t('setting.clearAndReset') }}
|
|
||||||
</ElButton>
|
|
||||||
</div>
|
|
||||||
</ElDrawer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-setting;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
border-radius: 6px 0 0 6px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { PropType } from 'vue'
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ColorRadioPicker' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('color-radio-picker')
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
schema: {
|
|
||||||
type: Array as PropType<string[]>,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
modelValue: propTypes.string.def('')
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'change'])
|
|
||||||
|
|
||||||
const colorVal = ref(props.modelValue)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(val: string) => {
|
|
||||||
if (val === unref(colorVal)) return
|
|
||||||
colorVal.value = val
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 监听
|
|
||||||
watch(
|
|
||||||
() => colorVal.value,
|
|
||||||
(val: string) => {
|
|
||||||
emit('update:modelValue', val)
|
|
||||||
emit('change', val)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="prefixCls" class="flex flex-wrap space-x-14px">
|
|
||||||
<span
|
|
||||||
v-for="(item, i) in schema"
|
|
||||||
:key="`radio-${i}`"
|
|
||||||
:class="{ 'is-active': colorVal === item }"
|
|
||||||
:style="{
|
|
||||||
background: item
|
|
||||||
}"
|
|
||||||
class="mb-5px h-20px w-20px cursor-pointer border-2px border-gray-300 rounded-2px border-solid text-center leading-20px"
|
|
||||||
@click="colorVal = item"
|
|
||||||
>
|
|
||||||
<Icon v-if="colorVal === item" :size="16" color="#fff" icon="ep:check" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-color-radio-picker;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
.is-active {
|
|
||||||
border-color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { setCssVar } from '@/utils'
|
|
||||||
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { useWatermark } from '@/hooks/web/useWatermark'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
|
|
||||||
defineOptions({ name: 'InterfaceDisplay' })
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
const { setWatermark } = useWatermark()
|
|
||||||
const prefixCls = getPrefixCls('interface-display')
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const water = ref()
|
|
||||||
|
|
||||||
// 面包屑
|
|
||||||
const breadcrumb = ref(appStore.getBreadcrumb)
|
|
||||||
|
|
||||||
const breadcrumbChange = (show: boolean) => {
|
|
||||||
appStore.setBreadcrumb(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 面包屑图标
|
|
||||||
const breadcrumbIcon = ref(appStore.getBreadcrumbIcon)
|
|
||||||
|
|
||||||
const breadcrumbIconChange = (show: boolean) => {
|
|
||||||
appStore.setBreadcrumbIcon(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 折叠图标
|
|
||||||
const hamburger = ref(appStore.getHamburger)
|
|
||||||
|
|
||||||
const hamburgerChange = (show: boolean) => {
|
|
||||||
appStore.setHamburger(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全屏图标
|
|
||||||
const screenfull = ref(appStore.getScreenfull)
|
|
||||||
|
|
||||||
const screenfullChange = (show: boolean) => {
|
|
||||||
appStore.setScreenfull(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尺寸图标
|
|
||||||
const size = ref(appStore.getSize)
|
|
||||||
|
|
||||||
const sizeChange = (show: boolean) => {
|
|
||||||
appStore.setSize(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 多语言图标
|
|
||||||
const locale = ref(appStore.getLocale)
|
|
||||||
|
|
||||||
const localeChange = (show: boolean) => {
|
|
||||||
appStore.setLocale(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消息图标
|
|
||||||
const message = ref(appStore.getMessage)
|
|
||||||
|
|
||||||
const messageChange = (show: boolean) => {
|
|
||||||
appStore.setMessage(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标签页
|
|
||||||
const tagsView = ref(appStore.getTagsView)
|
|
||||||
|
|
||||||
const tagsViewChange = (show: boolean) => {
|
|
||||||
// 切换标签栏显示时,同步切换标签栏的高度
|
|
||||||
setCssVar('--tags-view-height', show ? '35px' : '0px')
|
|
||||||
appStore.setTagsView(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标签页图标
|
|
||||||
const tagsViewIcon = ref(appStore.getTagsViewIcon)
|
|
||||||
|
|
||||||
const tagsViewIconChange = (show: boolean) => {
|
|
||||||
appStore.setTagsViewIcon(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// logo
|
|
||||||
const logo = ref(appStore.getLogo)
|
|
||||||
|
|
||||||
const logoChange = (show: boolean) => {
|
|
||||||
appStore.setLogo(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 菜单手风琴
|
|
||||||
const uniqueOpened = ref(appStore.getUniqueOpened)
|
|
||||||
|
|
||||||
const uniqueOpenedChange = (uniqueOpened: boolean) => {
|
|
||||||
appStore.setUniqueOpened(uniqueOpened)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 固定头部
|
|
||||||
const fixedHeader = ref(appStore.getFixedHeader)
|
|
||||||
|
|
||||||
const fixedHeaderChange = (show: boolean) => {
|
|
||||||
appStore.setFixedHeader(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页脚
|
|
||||||
const footer = ref(appStore.getFooter)
|
|
||||||
|
|
||||||
const footerChange = (show: boolean) => {
|
|
||||||
appStore.setFooter(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 灰色模式
|
|
||||||
const greyMode = ref(appStore.getGreyMode)
|
|
||||||
|
|
||||||
const greyModeChange = (show: boolean) => {
|
|
||||||
appStore.setGreyMode(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 固定菜单
|
|
||||||
const fixedMenu = ref(appStore.getFixedMenu)
|
|
||||||
|
|
||||||
const fixedMenuChange = (show: boolean) => {
|
|
||||||
appStore.setFixedMenu(show)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置水印
|
|
||||||
const setWater = () => {
|
|
||||||
setWatermark(water.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => layout.value,
|
|
||||||
(n) => {
|
|
||||||
if (n === 'top') {
|
|
||||||
appStore.setCollapse(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="prefixCls">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.breadcrumb') }}</span>
|
|
||||||
<ElSwitch v-model="breadcrumb" @change="breadcrumbChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.breadcrumbIcon') }}</span>
|
|
||||||
<ElSwitch v-model="breadcrumbIcon" @change="breadcrumbIconChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.hamburgerIcon') }}</span>
|
|
||||||
<ElSwitch v-model="hamburger" @change="hamburgerChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.screenfullIcon') }}</span>
|
|
||||||
<ElSwitch v-model="screenfull" @change="screenfullChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.sizeIcon') }}</span>
|
|
||||||
<ElSwitch v-model="size" @change="sizeChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.localeIcon') }}</span>
|
|
||||||
<ElSwitch v-model="locale" @change="localeChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.messageIcon') }}</span>
|
|
||||||
<ElSwitch v-model="message" @change="messageChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.tagsView') }}</span>
|
|
||||||
<ElSwitch v-model="tagsView" @change="tagsViewChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.tagsViewIcon') }}</span>
|
|
||||||
<ElSwitch v-model="tagsViewIcon" @change="tagsViewIconChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.logo') }}</span>
|
|
||||||
<ElSwitch v-model="logo" @change="logoChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.uniqueOpened') }}</span>
|
|
||||||
<ElSwitch v-model="uniqueOpened" @change="uniqueOpenedChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.fixedHeader') }}</span>
|
|
||||||
<ElSwitch v-model="fixedHeader" @change="fixedHeaderChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.footer') }}</span>
|
|
||||||
<ElSwitch v-model="footer" @change="footerChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.greyMode') }}</span>
|
|
||||||
<ElSwitch v-model="greyMode" @change="greyModeChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('setting.fixedMenu') }}</span>
|
|
||||||
<ElSwitch v-model="fixedMenu" @change="fixedMenuChange" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-14px">{{ t('watermark.watermark') }}</span>
|
|
||||||
<ElInput v-model="water" class="right-1 w-20" @change="setWater()" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
defineOptions({ name: 'LayoutRadioPicker' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('layout-radio-picker')
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const layout = computed(() => appStore.getLayout)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="prefixCls" class="flex flex-wrap space-x-14px">
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}__classic`,
|
|
||||||
'relative w-56px h-48px cursor-pointer bg-gray-300',
|
|
||||||
{
|
|
||||||
'is-acitve': layout === 'classic'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@click="appStore.setLayout('classic')"
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}__top-left`,
|
|
||||||
'relative w-56px h-48px cursor-pointer bg-gray-300',
|
|
||||||
{
|
|
||||||
'is-acitve': layout === 'topLeft'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@click="appStore.setLayout('topLeft')"
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}__top`,
|
|
||||||
'relative w-56px h-48px cursor-pointer bg-gray-300',
|
|
||||||
{
|
|
||||||
'is-acitve': layout === 'top'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@click="appStore.setLayout('top')"
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}__cut-menu`,
|
|
||||||
'relative w-56px h-48px cursor-pointer bg-gray-300',
|
|
||||||
{
|
|
||||||
'is-acitve': layout === 'cutMenu'
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@click="appStore.setLayout('cutMenu')"
|
|
||||||
>
|
|
||||||
<div class="absolute left-[10%] top-0 h-full w-[33%] bg-gray-200"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-layout-radio-picker;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
&__classic {
|
|
||||||
border: 2px solid #e5e7eb;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
width: 33%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #273352;
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 25%;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 4px 4px 0;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__top-left {
|
|
||||||
border: 2px solid #e5e7eb;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 33%;
|
|
||||||
background-color: #273352;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 33%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__top {
|
|
||||||
border: 2px solid #e5e7eb;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 33%;
|
|
||||||
background-color: #273352;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__cut-menu {
|
|
||||||
border: 2px solid #e5e7eb;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
height: 33%;
|
|
||||||
background-color: #273352;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 10%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-acitve {
|
|
||||||
border-color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import SizeDropdown from './src/SizeDropdown.vue'
|
|
||||||
|
|
||||||
export { SizeDropdown }
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
|
|
||||||
import { propTypes } from '@/utils/propTypes'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { ElementPlusSize } from '@/types/elementPlus'
|
|
||||||
|
|
||||||
defineOptions({ name: 'SizeDropdown' })
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('size-dropdown')
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
color: propTypes.string.def('')
|
|
||||||
})
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const sizeMap = computed(() => appStore.sizeMap)
|
|
||||||
|
|
||||||
const setCurrentSize = (size: ElementPlusSize) => {
|
|
||||||
appStore.setCurrentSize(size)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ElDropdown :class="prefixCls" trigger="click" @command="setCurrentSize">
|
|
||||||
<Icon :color="color" :size="18" class="cursor-pointer" icon="mdi:format-size" />
|
|
||||||
<template #dropdown>
|
|
||||||
<ElDropdownMenu>
|
|
||||||
<ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">
|
|
||||||
{{ t(`size.${item}`) }}
|
|
||||||
</ElDropdownItem>
|
|
||||||
</ElDropdownMenu>
|
|
||||||
</template>
|
|
||||||
</ElDropdown>
|
|
||||||
</template>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import TabMenu from './src/TabMenu.vue'
|
|
||||||
|
|
||||||
export { TabMenu }
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
<script lang="tsx">
|
|
||||||
import { usePermissionStore } from '@/stores/modules/permission'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
|
|
||||||
import { ElScrollbar } from 'element-plus'
|
|
||||||
import { Menu } from '@/layouts/components/Menu'
|
|
||||||
import { pathResolve } from '@/utils/routerHelper'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
|
||||||
import { filterMenusPath, initTabMap, tabPathMap } from './helper'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { isUrl } from '@/utils/is'
|
|
||||||
|
|
||||||
const { getPrefixCls, variables } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('tab-menu')
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'TabMenu',
|
|
||||||
setup() {
|
|
||||||
const { push, currentRoute } = useRouter()
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const collapse = computed(() => appStore.getCollapse)
|
|
||||||
|
|
||||||
const fixedMenu = computed(() => appStore.getFixedMenu)
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
const routers = computed(() => permissionStore.getRouters)
|
|
||||||
|
|
||||||
const tabRouters = computed(() => unref(routers).filter((v) => !v?.meta?.hidden))
|
|
||||||
|
|
||||||
const setCollapse = () => {
|
|
||||||
appStore.setCollapse(!unref(collapse))
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (unref(fixedMenu)) {
|
|
||||||
const path = `/${unref(currentRoute).path.split('/')[1]}`
|
|
||||||
const children = unref(tabRouters).find(
|
|
||||||
(v) =>
|
|
||||||
(v.meta?.alwaysShow || (v?.children?.length && v?.children?.length > 1)) &&
|
|
||||||
v.path === path
|
|
||||||
)?.children
|
|
||||||
|
|
||||||
tabActive.value = path
|
|
||||||
if (children) {
|
|
||||||
permissionStore.setMenuTabRouters(
|
|
||||||
cloneDeep(children).map((v) => {
|
|
||||||
v.path = pathResolve(unref(tabActive), v.path)
|
|
||||||
return v
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => routers.value,
|
|
||||||
(routers: AppRouteRecordRaw[]) => {
|
|
||||||
initTabMap(routers)
|
|
||||||
filterMenusPath(routers, routers)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const showTitle = ref(true)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => collapse.value,
|
|
||||||
(collapse: boolean) => {
|
|
||||||
if (!collapse) {
|
|
||||||
setTimeout(() => {
|
|
||||||
showTitle.value = !collapse
|
|
||||||
}, 200)
|
|
||||||
} else {
|
|
||||||
showTitle.value = !collapse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 是否显示菜单
|
|
||||||
const showMenu = ref(unref(fixedMenu) ? true : false)
|
|
||||||
|
|
||||||
// tab高亮
|
|
||||||
const tabActive = ref('')
|
|
||||||
|
|
||||||
// tab点击事件
|
|
||||||
const tabClick = (item: AppRouteRecordRaw) => {
|
|
||||||
if (isUrl(item.path)) {
|
|
||||||
window.open(item.path)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const newPath = item.children ? item.path : item.path.split('/')[0]
|
|
||||||
const oldPath = unref(tabActive)
|
|
||||||
tabActive.value = item.children ? item.path : item.path.split('/')[0]
|
|
||||||
if (item.children) {
|
|
||||||
if (newPath === oldPath || !unref(showMenu)) {
|
|
||||||
showMenu.value = unref(fixedMenu) ? true : !unref(showMenu)
|
|
||||||
}
|
|
||||||
if (unref(showMenu)) {
|
|
||||||
permissionStore.setMenuTabRouters(
|
|
||||||
cloneDeep(item.children).map((v) => {
|
|
||||||
v.path = pathResolve(unref(tabActive), v.path)
|
|
||||||
return v
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
push(item.path)
|
|
||||||
permissionStore.setMenuTabRouters([])
|
|
||||||
showMenu.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置高亮
|
|
||||||
const isActive = (currentPath: string) => {
|
|
||||||
const { path } = unref(currentRoute)
|
|
||||||
if (tabPathMap[currentPath].includes(path)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const mouseleave = () => {
|
|
||||||
if (!unref(showMenu) || unref(fixedMenu)) return
|
|
||||||
showMenu.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<div
|
|
||||||
id={`${variables.namespace}-menu`}
|
|
||||||
class={[
|
|
||||||
prefixCls,
|
|
||||||
'relative bg-[var(--left-menu-bg-color)] top-1px layout-border__right',
|
|
||||||
{
|
|
||||||
'w-[var(--tab-menu-max-width)]': !unref(collapse),
|
|
||||||
'w-[var(--tab-menu-min-width)]': unref(collapse)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
onMouseleave={mouseleave}
|
|
||||||
>
|
|
||||||
<ElScrollbar class="!h-[calc(100%-var(--tab-menu-collapse-height)-1px)]">
|
|
||||||
<div>
|
|
||||||
{() => {
|
|
||||||
return unref(tabRouters).map((v) => {
|
|
||||||
const item = (
|
|
||||||
v.meta?.alwaysShow || (v?.children?.length && v?.children?.length > 1)
|
|
||||||
? v
|
|
||||||
: {
|
|
||||||
...(v?.children && v?.children[0]),
|
|
||||||
path: pathResolve(v.path, (v?.children && v?.children[0])?.path as string)
|
|
||||||
}
|
|
||||||
) as AppRouteRecordRaw
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class={[
|
|
||||||
`${prefixCls}__item`,
|
|
||||||
'text-center text-12px relative py-12px cursor-pointer',
|
|
||||||
{
|
|
||||||
'is-active': isActive(v.path)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
onClick={() => {
|
|
||||||
tabClick(item)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
</div>
|
|
||||||
{!unref(showTitle) ? undefined : (
|
|
||||||
<p class="mt-5px break-words px-2px">{t(item.meta?.title)}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</ElScrollbar>
|
|
||||||
<div
|
|
||||||
class={[
|
|
||||||
`${prefixCls}--collapse`,
|
|
||||||
'text-center h-[var(--tab-menu-collapse-height)] leading-[var(--tab-menu-collapse-height)] cursor-pointer'
|
|
||||||
]}
|
|
||||||
onClick={setCollapse}
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<Menu
|
|
||||||
class={[
|
|
||||||
'!absolute top-0 z-11',
|
|
||||||
{
|
|
||||||
'!left-[var(--tab-menu-min-width)]': unref(collapse),
|
|
||||||
'!left-[var(--tab-menu-max-width)]': !unref(collapse),
|
|
||||||
'!w-[calc(var(--left-menu-max-width)+1px)]': unref(showMenu) || unref(fixedMenu),
|
|
||||||
'!w-0': !unref(showMenu) && !unref(fixedMenu)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
style="transition: width var(--transition-time-02), left var(--transition-time-02);"
|
|
||||||
></Menu>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-tab-menu;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
transition: all var(--transition-time-02);
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
color: var(--left-menu-text-color);
|
|
||||||
transition: all var(--transition-time-02);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--left-menu-text-active-color);
|
|
||||||
// background-color: var(--left-menu-bg-active-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--collapse {
|
|
||||||
color: var(--left-menu-text-color);
|
|
||||||
background-color: var(--left-menu-bg-light-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-active {
|
|
||||||
color: var(--left-menu-text-active-color);
|
|
||||||
background-color: var(--left-menu-bg-active-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { getAllParentPath } from '@/layouts/components/Menu/src/helper'
|
|
||||||
import type { RouteMeta } from 'vue-router'
|
|
||||||
import { isUrl } from '@/utils/is'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
|
||||||
|
|
||||||
export type TabMapTypes = {
|
|
||||||
[key: string]: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const tabPathMap = reactive<TabMapTypes>({})
|
|
||||||
|
|
||||||
export const initTabMap = (routes: AppRouteRecordRaw[]) => {
|
|
||||||
for (const v of routes) {
|
|
||||||
const meta = (v.meta ?? {}) as RouteMeta
|
|
||||||
if (!meta?.hidden) {
|
|
||||||
tabPathMap[v.path] = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const filterMenusPath = (
|
|
||||||
routes: AppRouteRecordRaw[],
|
|
||||||
allRoutes: AppRouteRecordRaw[]
|
|
||||||
): AppRouteRecordRaw[] => {
|
|
||||||
const res: AppRouteRecordRaw[] = []
|
|
||||||
for (const v of routes) {
|
|
||||||
let data: Nullable<AppRouteRecordRaw> = null
|
|
||||||
const meta = (v.meta ?? {}) as RouteMeta
|
|
||||||
if (!meta.hidden || meta.canTo) {
|
|
||||||
const allParentPath = getAllParentPath<AppRouteRecordRaw>(allRoutes, v.path)
|
|
||||||
|
|
||||||
const fullPath = isUrl(v.path) ? v.path : allParentPath.join('/')
|
|
||||||
|
|
||||||
data = cloneDeep(v)
|
|
||||||
data.path = fullPath
|
|
||||||
if (v.children && data) {
|
|
||||||
data.children = filterMenusPath(v.children, allRoutes)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
res.push(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allParentPath.length && Reflect.has(tabPathMap, allParentPath[0])) {
|
|
||||||
tabPathMap[allParentPath[0]].push(fullPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import TagsView from './src/TagsView.vue'
|
|
||||||
|
|
||||||
export { TagsView }
|
|
||||||
@@ -1,585 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { onMounted, watch, computed, unref, ref, nextTick } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import type { RouteLocationNormalizedLoaded, RouterLinkProps } from 'vue-router'
|
|
||||||
import { usePermissionStore } from '@/stores/modules/permission'
|
|
||||||
import { useTagsViewStore } from '@/stores/modules/tagsView'
|
|
||||||
import { useAppStore } from '@/stores/modules/app'
|
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
|
||||||
import { filterAffixTags } from './helper'
|
|
||||||
import { ContextMenu, ContextMenuExpose } from '@/layouts/components/ContextMenu'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
import { useTemplateRefsList } from '@vueuse/core'
|
|
||||||
import { ElScrollbar } from 'element-plus'
|
|
||||||
import { useScrollTo } from '@/hooks/event/useScrollTo'
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('tags-view')
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const { currentRoute, push, replace } = useRouter()
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
const routers = computed(() => permissionStore.getRouters)
|
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
|
||||||
|
|
||||||
const visitedViews = computed(() => tagsViewStore.getVisitedViews)
|
|
||||||
|
|
||||||
const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
|
||||||
|
|
||||||
const tagsViewIcon = computed(() => appStore.getTagsViewIcon)
|
|
||||||
|
|
||||||
const isDark = computed(() => appStore.getIsDark)
|
|
||||||
|
|
||||||
// 初始化tag
|
|
||||||
const initTags = () => {
|
|
||||||
affixTagArr.value = filterAffixTags(unref(routers))
|
|
||||||
for (const tag of unref(affixTagArr)) {
|
|
||||||
// Must have tag name
|
|
||||||
if (tag.name) {
|
|
||||||
tagsViewStore.addVisitedView(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedTag = ref<RouteLocationNormalizedLoaded>()
|
|
||||||
|
|
||||||
// 新增tag
|
|
||||||
const addTags = () => {
|
|
||||||
const { name } = unref(currentRoute)
|
|
||||||
if (name) {
|
|
||||||
selectedTag.value = unref(currentRoute)
|
|
||||||
tagsViewStore.addView(unref(currentRoute))
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭选中的tag
|
|
||||||
const closeSelectedTag = (view: RouteLocationNormalizedLoaded) => {
|
|
||||||
if (view?.meta?.affix) return
|
|
||||||
tagsViewStore.delView(view)
|
|
||||||
if (isActive(view)) {
|
|
||||||
toLastView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭全部
|
|
||||||
const closeAllTags = () => {
|
|
||||||
tagsViewStore.delAllViews()
|
|
||||||
toLastView()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭其它
|
|
||||||
const closeOthersTags = () => {
|
|
||||||
tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新加载
|
|
||||||
const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => {
|
|
||||||
if (!view) return
|
|
||||||
tagsViewStore.delCachedView()
|
|
||||||
const { path, query } = view
|
|
||||||
await nextTick()
|
|
||||||
replace({
|
|
||||||
path: '/redirect' + path,
|
|
||||||
query: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭左侧
|
|
||||||
const closeLeftTags = () => {
|
|
||||||
tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭右侧
|
|
||||||
const closeRightTags = () => {
|
|
||||||
tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跳转到最后一个
|
|
||||||
const toLastView = () => {
|
|
||||||
const visitedViews = tagsViewStore.getVisitedViews
|
|
||||||
const latestView = visitedViews.slice(-1)[0]
|
|
||||||
if (latestView) {
|
|
||||||
push(latestView)
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
unref(currentRoute).path === permissionStore.getAddRouters[0].path ||
|
|
||||||
unref(currentRoute).path === permissionStore.getAddRouters[0].redirect
|
|
||||||
) {
|
|
||||||
addTags()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO: You can set another route
|
|
||||||
push('/')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 滚动到选中的tag
|
|
||||||
const moveToCurrentTag = async () => {
|
|
||||||
await nextTick()
|
|
||||||
for (const v of unref(visitedViews)) {
|
|
||||||
if (v.fullPath === unref(currentRoute).path) {
|
|
||||||
moveToTarget(v)
|
|
||||||
if (v.fullPath !== unref(currentRoute).fullPath) {
|
|
||||||
tagsViewStore.updateVisitedView(unref(currentRoute))
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagLinksRefs = useTemplateRefsList<RouterLinkProps>()
|
|
||||||
|
|
||||||
const moveToTarget = (currentTag: RouteLocationNormalizedLoaded) => {
|
|
||||||
const wrap$ = unref(scrollbarRef)?.wrapRef
|
|
||||||
let firstTag: Nullable<RouterLinkProps> = null
|
|
||||||
let lastTag: Nullable<RouterLinkProps> = null
|
|
||||||
|
|
||||||
const tagList = unref(tagLinksRefs)
|
|
||||||
// find first tag and last tag
|
|
||||||
if (tagList.length > 0) {
|
|
||||||
firstTag = tagList[0]
|
|
||||||
lastTag = tagList[tagList.length - 1]
|
|
||||||
}
|
|
||||||
if ((firstTag?.to as RouteLocationNormalizedLoaded).fullPath === currentTag.fullPath) {
|
|
||||||
// 直接滚动到0的位置
|
|
||||||
const { start } = useScrollTo({
|
|
||||||
el: wrap$!,
|
|
||||||
position: 'scrollLeft',
|
|
||||||
to: 0,
|
|
||||||
duration: 500
|
|
||||||
})
|
|
||||||
start()
|
|
||||||
} else if ((lastTag?.to as RouteLocationNormalizedLoaded).fullPath === currentTag.fullPath) {
|
|
||||||
// 滚动到最后的位置
|
|
||||||
const { start } = useScrollTo({
|
|
||||||
el: wrap$!,
|
|
||||||
position: 'scrollLeft',
|
|
||||||
to: wrap$!.scrollWidth - wrap$!.offsetWidth,
|
|
||||||
duration: 500
|
|
||||||
})
|
|
||||||
start()
|
|
||||||
} else {
|
|
||||||
// find preTag and nextTag
|
|
||||||
const currentIndex: number = tagList.findIndex(
|
|
||||||
(item) => (item?.to as RouteLocationNormalizedLoaded).fullPath === currentTag.fullPath
|
|
||||||
)
|
|
||||||
const tgsRefs = document.getElementsByClassName(`${prefixCls}__item`)
|
|
||||||
|
|
||||||
const prevTag = tgsRefs[currentIndex - 1] as HTMLElement
|
|
||||||
const nextTag = tgsRefs[currentIndex + 1] as HTMLElement
|
|
||||||
|
|
||||||
// the tag's offsetLeft after of nextTag
|
|
||||||
const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + 4
|
|
||||||
|
|
||||||
// the tag's offsetLeft before of prevTag
|
|
||||||
const beforePrevTagOffsetLeft = prevTag.offsetLeft - 4
|
|
||||||
|
|
||||||
if (afterNextTagOffsetLeft > unref(scrollLeftNumber) + wrap$!.offsetWidth) {
|
|
||||||
const { start } = useScrollTo({
|
|
||||||
el: wrap$!,
|
|
||||||
position: 'scrollLeft',
|
|
||||||
to: afterNextTagOffsetLeft - wrap$!.offsetWidth,
|
|
||||||
duration: 500
|
|
||||||
})
|
|
||||||
start()
|
|
||||||
} else if (beforePrevTagOffsetLeft < unref(scrollLeftNumber)) {
|
|
||||||
const { start } = useScrollTo({
|
|
||||||
el: wrap$!,
|
|
||||||
position: 'scrollLeft',
|
|
||||||
to: beforePrevTagOffsetLeft,
|
|
||||||
duration: 500
|
|
||||||
})
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否是当前tag
|
|
||||||
const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
|
|
||||||
return route.path === unref(currentRoute).path
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所有右键菜单组件的元素
|
|
||||||
const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
|
|
||||||
|
|
||||||
// 右键菜单装填改变的时候
|
|
||||||
const visibleChange = (visible: boolean, tagItem: RouteLocationNormalizedLoaded) => {
|
|
||||||
if (visible) {
|
|
||||||
for (const v of unref(itemRefs)) {
|
|
||||||
const elDropdownMenuRef = v.elDropdownMenuRef
|
|
||||||
if (tagItem.fullPath !== v.tagItem.fullPath) {
|
|
||||||
elDropdownMenuRef?.handleClose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// elscroll 实例
|
|
||||||
const scrollbarRef = ref<ComponentRef<typeof ElScrollbar>>()
|
|
||||||
|
|
||||||
// 保存滚动位置
|
|
||||||
const scrollLeftNumber = ref(0)
|
|
||||||
|
|
||||||
const scroll = ({ scrollLeft }) => {
|
|
||||||
scrollLeftNumber.value = scrollLeft as number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移动到某个位置
|
|
||||||
const move = (to: number) => {
|
|
||||||
const wrap$ = unref(scrollbarRef)?.wrapRef
|
|
||||||
const { start } = useScrollTo({
|
|
||||||
el: wrap$!,
|
|
||||||
position: 'scrollLeft',
|
|
||||||
to: unref(scrollLeftNumber) + to,
|
|
||||||
duration: 500
|
|
||||||
})
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
initTags()
|
|
||||||
addTags()
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => currentRoute.value,
|
|
||||||
() => {
|
|
||||||
addTags()
|
|
||||||
moveToCurrentTag()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
:id="prefixCls"
|
|
||||||
:class="prefixCls"
|
|
||||||
class="relative w-full flex bg-[#fff] dark:bg-[var(--el-bg-color)]"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:class="`${prefixCls}__tool ${prefixCls}__tool--first`"
|
|
||||||
class="h-[var(--tags-view-height)] w-[var(--tags-view-height)] flex cursor-pointer items-center justify-center"
|
|
||||||
@click="move(-200)"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="ep:d-arrow-left"
|
|
||||||
color="var(--el-text-color-placeholder)"
|
|
||||||
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<div class="flex-1 overflow-hidden">
|
|
||||||
<ElScrollbar ref="scrollbarRef" class="h-full" @scroll="scroll">
|
|
||||||
<div class="h-full flex">
|
|
||||||
<ContextMenu
|
|
||||||
:ref="itemRefs.set"
|
|
||||||
:schema="[
|
|
||||||
{
|
|
||||||
icon: 'ep:refresh',
|
|
||||||
label: t('common.reload'),
|
|
||||||
disabled: selectedTag?.fullPath !== item.fullPath,
|
|
||||||
command: () => {
|
|
||||||
refreshSelectedTag(item)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:close',
|
|
||||||
label: t('common.closeTab'),
|
|
||||||
disabled: !!visitedViews?.length && selectedTag?.meta.affix,
|
|
||||||
command: () => {
|
|
||||||
closeSelectedTag(item)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
divided: true,
|
|
||||||
icon: 'ep:d-arrow-left',
|
|
||||||
label: t('common.closeTheLeftTab'),
|
|
||||||
disabled:
|
|
||||||
!!visitedViews?.length &&
|
|
||||||
(item.fullPath === visitedViews[0].fullPath ||
|
|
||||||
selectedTag?.fullPath !== item.fullPath),
|
|
||||||
command: () => {
|
|
||||||
closeLeftTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:d-arrow-right',
|
|
||||||
label: t('common.closeTheRightTab'),
|
|
||||||
disabled:
|
|
||||||
!!visitedViews?.length &&
|
|
||||||
(item.fullPath === visitedViews[visitedViews.length - 1].fullPath ||
|
|
||||||
selectedTag?.fullPath !== item.fullPath),
|
|
||||||
command: () => {
|
|
||||||
closeRightTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
divided: true,
|
|
||||||
icon: 'ep:discount',
|
|
||||||
label: t('common.closeOther'),
|
|
||||||
disabled: selectedTag?.fullPath !== item.fullPath,
|
|
||||||
command: () => {
|
|
||||||
closeOthersTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:minus',
|
|
||||||
label: t('common.closeAll'),
|
|
||||||
command: () => {
|
|
||||||
closeAllTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
v-for="item in visitedViews"
|
|
||||||
:key="item.fullPath"
|
|
||||||
:tag-item="item"
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}__item`,
|
|
||||||
item?.meta?.affix ? `${prefixCls}__item--affix` : '',
|
|
||||||
{
|
|
||||||
'is-active': isActive(item)
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
@visible-change="visibleChange"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<router-link :ref="tagLinksRefs.set" :to="{ ...item }" custom v-slot="{ navigate }">
|
|
||||||
<div
|
|
||||||
@click="navigate"
|
|
||||||
class="h-full flex items-center justify-center whitespace-nowrap pl-15px"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
v-if="
|
|
||||||
item?.matched &&
|
|
||||||
item?.matched[1] &&
|
|
||||||
item?.matched[1]?.meta?.icon &&
|
|
||||||
tagsViewIcon
|
|
||||||
"
|
|
||||||
:icon="item?.matched[1]?.meta?.icon"
|
|
||||||
:size="12"
|
|
||||||
class="mr-5px"
|
|
||||||
/>
|
|
||||||
{{ t(item?.meta?.title as string) }}
|
|
||||||
<Icon
|
|
||||||
:class="`${prefixCls}__item--close`"
|
|
||||||
color="#333"
|
|
||||||
icon="ep:close"
|
|
||||||
:size="12"
|
|
||||||
@click.prevent.stop="closeSelectedTag(item)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</ContextMenu>
|
|
||||||
</div>
|
|
||||||
</ElScrollbar>
|
|
||||||
</div>
|
|
||||||
<span
|
|
||||||
:class="`${prefixCls}__tool`"
|
|
||||||
class="h-[var(--tags-view-height)] w-[var(--tags-view-height)] flex cursor-pointer items-center justify-center"
|
|
||||||
@click="move(200)"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="ep:d-arrow-right"
|
|
||||||
color="var(--el-text-color-placeholder)"
|
|
||||||
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
:class="`${prefixCls}__tool`"
|
|
||||||
class="h-[var(--tags-view-height)] w-[var(--tags-view-height)] flex cursor-pointer items-center justify-center"
|
|
||||||
@click="refreshSelectedTag(selectedTag)"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="ep:refresh-right"
|
|
||||||
color="var(--el-text-color-placeholder)"
|
|
||||||
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<ContextMenu
|
|
||||||
trigger="click"
|
|
||||||
:schema="[
|
|
||||||
{
|
|
||||||
icon: 'ep:refresh',
|
|
||||||
label: t('common.reload'),
|
|
||||||
command: () => {
|
|
||||||
refreshSelectedTag(selectedTag)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:close',
|
|
||||||
label: t('common.closeTab'),
|
|
||||||
disabled: !!visitedViews?.length && selectedTag?.meta.affix,
|
|
||||||
command: () => {
|
|
||||||
closeSelectedTag(selectedTag!)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
divided: true,
|
|
||||||
icon: 'ep:d-arrow-left',
|
|
||||||
label: t('common.closeTheLeftTab'),
|
|
||||||
disabled: !!visitedViews?.length && selectedTag?.fullPath === visitedViews[0].fullPath,
|
|
||||||
command: () => {
|
|
||||||
closeLeftTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:d-arrow-right',
|
|
||||||
label: t('common.closeTheRightTab'),
|
|
||||||
disabled:
|
|
||||||
!!visitedViews?.length &&
|
|
||||||
selectedTag?.fullPath === visitedViews[visitedViews.length - 1].fullPath,
|
|
||||||
command: () => {
|
|
||||||
closeRightTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
divided: true,
|
|
||||||
icon: 'ep:discount',
|
|
||||||
label: t('common.closeOther'),
|
|
||||||
command: () => {
|
|
||||||
closeOthersTags()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ep:minus',
|
|
||||||
label: t('common.closeAll'),
|
|
||||||
command: () => {
|
|
||||||
closeAllTags()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:class="`${prefixCls}__tool`"
|
|
||||||
class="block h-[var(--tags-view-height)] w-[var(--tags-view-height)] flex cursor-pointer items-center justify-center"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
icon="ep:menu"
|
|
||||||
color="var(--el-text-color-placeholder)"
|
|
||||||
:hover-color="isDark ? '#fff' : 'var(--el-color-black)'"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</ContextMenu>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$prefix-cls: v-tags-view;
|
|
||||||
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
:deep(.el-scrollbar__view) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__tool {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 1px);
|
|
||||||
border-left: 1px solid var(--el-border-color);
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&--first {
|
|
||||||
&::before {
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 1px);
|
|
||||||
border-right: 1px solid var(--el-border-color);
|
|
||||||
border-left: none;
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
height: calc(100% - 6px);
|
|
||||||
padding-right: 25px;
|
|
||||||
margin-left: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
&--close {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 5px;
|
|
||||||
display: none;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
}
|
|
||||||
&:not(.#{$prefix-cls}__item--affix):hover {
|
|
||||||
.#{$prefix-cls}__item--close {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item:not(.is-active) {
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item.is-active {
|
|
||||||
color: var(--el-color-white);
|
|
||||||
background-color: var(--el-color-primary);
|
|
||||||
border: 1px solid var(--el-color-primary);
|
|
||||||
.#{$prefix-cls}__item--close {
|
|
||||||
:deep(span) {
|
|
||||||
color: var(--el-color-white) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
.#{$prefix-cls} {
|
|
||||||
&__tool {
|
|
||||||
&--first {
|
|
||||||
&::after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
border: 1px solid var(--el-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item:not(.is-active) {
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__item.is-active {
|
|
||||||
color: var(--el-color-white);
|
|
||||||
background-color: var(--el-color-primary);
|
|
||||||
border: 1px solid var(--el-color-primary);
|
|
||||||
.#{$prefix-cls}__item--close {
|
|
||||||
:deep(span) {
|
|
||||||
color: var(--el-color-white) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user