Browse Source

前端初始化

master
whyzxhnd 4 weeks ago
parent
commit
0a3e1a40d6
  1. 14
      vite-element-template/.editorconfig
  2. 2
      vite-element-template/.env
  3. 6
      vite-element-template/.env.development
  4. 4
      vite-element-template/.env.production
  5. 271
      vite-element-template/.eslintrc.js
  6. 18
      vite-element-template/.gitignore
  7. 5
      vite-element-template/.travis.yml
  8. 21
      vite-element-template/LICENSE
  9. 84
      vite-element-template/README.md
  10. 11
      vite-element-template/babel.config.js
  11. 0
      vite-element-template/eslint.config.js
  12. 18
      vite-element-template/index.html
  13. 25
      vite-element-template/jest.config.js
  14. 16
      vite-element-template/jsconfig.json
  15. 66
      vite-element-template/package.json
  16. BIN
      vite-element-template/public/NavBackground.png
  17. BIN
      vite-element-template/public/favicon.ico
  18. BIN
      vite-element-template/public/img/IndustrialGateway.png
  19. BIN
      vite-element-template/public/img/OpticalConvergenceSwitch.png
  20. BIN
      vite-element-template/public/img/SerialPortModule.png
  21. BIN
      vite-element-template/public/img/WIFI.png
  22. BIN
      vite-element-template/public/img/accessSwitch.png
  23. BIN
      vite-element-template/public/img/coreSwitch.png
  24. BIN
      vite-element-template/public/img/firewall.png
  25. BIN
      vite-element-template/public/img/host.png
  26. BIN
      vite-element-template/public/img/manageHosts.png
  27. BIN
      vite-element-template/public/img/office_network.png
  28. BIN
      vite-element-template/public/img/router.png
  29. BIN
      vite-element-template/public/img/server.png
  30. 37
      vite-element-template/public/img/status_error.svg
  31. 37
      vite-element-template/public/img/status_success.svg
  32. BIN
      vite-element-template/public/img/tcq.png
  33. 19
      vite-element-template/public/js/EasyWasmPlayer.js
  34. 7718
      vite-element-template/public/js/ZLMRTCClient.js
  35. 1
      vite-element-template/public/js/ZLMRTCClient.js.map
  36. 1
      vite-element-template/public/js/jessibuca/decoder.js
  37. BIN
      vite-element-template/public/js/jessibuca/decoder.wasm
  38. 190
      vite-element-template/public/js/jessibuca/demo.html
  39. 637
      vite-element-template/public/js/jessibuca/jessibuca.d.ts
  40. 1
      vite-element-template/public/js/jessibuca/jessibuca.js
  41. 19
      vite-element-template/public/js/mapConfig.js
  42. BIN
      vite-element-template/public/user.gif
  43. 11
      vite-element-template/src/App.vue
  44. 94
      vite-element-template/src/api/index.js
  45. 64
      vite-element-template/src/api/sys/dictionary/index.js
  46. 122
      vite-element-template/src/api/sys/role/index.js
  47. 62
      vite-element-template/src/api/sys/user/index.js
  48. 1
      vite-element-template/src/api/user.js
  49. 112
      vite-element-template/src/api/video.js
  50. 87
      vite-element-template/src/api/wvp.js
  51. BIN
      vite-element-template/src/assets/404_images/404_cloud.png
  52. BIN
      vite-element-template/src/assets/daping/img3.png
  53. BIN
      vite-element-template/src/assets/home/NumberOfAxialFlowFan.png
  54. BIN
      vite-element-template/src/assets/home/importantDetector.png
  55. 388
      vite-element-template/src/components/activiti/ExamineAndApprove.vue
  56. 162
      vite-element-template/src/components/activiti/ProcessProgress.vue
  57. 146
      vite-element-template/src/components/activiti/applyList/Add.vue
  58. 216
      vite-element-template/src/components/activiti/applyList/Apply.vue
  59. 174
      vite-element-template/src/components/activiti/applyList/Preset.vue
  60. 108
      vite-element-template/src/components/activiticonfig/ModelList/Add.vue
  61. 105
      vite-element-template/src/components/activiticonfig/ModelList/DesignFrame.vue
  62. 241
      vite-element-template/src/components/activiticonfig/ProcessModelList/Edit.vue
  63. 249
      vite-element-template/src/components/activiticonfig/ProcessModelList/EditProcess.vue
  64. 113
      vite-element-template/src/components/activiticonfig/ProcessModelList/ViewForm.vue
  65. 198
      vite-element-template/src/components/activiticonfig/form/leaveForm.vue
  66. 16
      vite-element-template/src/components/common/Breadcrumb/index.vue
  67. 44
      vite-element-template/src/components/common/Hamburger/index.vue
  68. 187
      vite-element-template/src/components/common/Pagination/index.vue
  69. 30
      vite-element-template/src/components/common/SvgIcon/AnyIcon.vue
  70. 62
      vite-element-template/src/components/common/SvgIcon/index.vue
  71. 886
      vite-element-template/src/components/common/player.vue
  72. 126
      vite-element-template/src/components/dust/design/plan/DesignPlanEdit.vue
  73. 169
      vite-element-template/src/components/dust/monitor/DustMonitorItemEdit.vue
  74. 106
      vite-element-template/src/components/dust/monitor/DustSystemEdit.vue
  75. 281
      vite-element-template/src/components/dust/monitor/monitor-chart2.vue
  76. 144
      vite-element-template/src/components/dust/recommend/plan/pipe/config/RecommendPlanPipeConfigEdit.vue
  77. 379
      vite-element-template/src/components/explosion/alarm.vue
  78. 289
      vite-element-template/src/components/explosion/clean.vue
  79. 487
      vite-element-template/src/components/explosion/data.vue
  80. 289
      vite-element-template/src/components/explosion/deviceTree.vue
  81. 373
      vite-element-template/src/components/explosion/dust.vue
  82. 459
      vite-element-template/src/components/explosion/equip.vue
  83. 324
      vite-element-template/src/components/explosion/feedback.vue
  84. 267
      vite-element-template/src/components/flowEdit/Diagram.vue
  85. 81
      vite-element-template/src/components/flowEdit/DiagramSidebar.vue
  86. 208
      vite-element-template/src/components/flowEdit/DiagramToolbar.vue
  87. 398
      vite-element-template/src/components/flowEdit/PropertyPanel.vue
  88. 12
      vite-element-template/src/components/flowEdit/config.js
  89. 38
      vite-element-template/src/components/flowEdit/icon/Actor.vue
  90. 16
      vite-element-template/src/components/flowEdit/icon/AreaSelect.vue
  91. 16
      vite-element-template/src/components/flowEdit/icon/ColorFill.vue
  92. 15
      vite-element-template/src/components/flowEdit/icon/ColorText.vue
  93. 19
      vite-element-template/src/components/flowEdit/icon/Cross.vue
  94. 27
      vite-element-template/src/components/flowEdit/icon/Cylinde.vue
  95. 19
      vite-element-template/src/components/flowEdit/icon/Diamond.vue
  96. 18
      vite-element-template/src/components/flowEdit/icon/DownArrow.vue
  97. 21
      vite-element-template/src/components/flowEdit/icon/Ellipse.vue
  98. 19
      vite-element-template/src/components/flowEdit/icon/Heptagon.vue
  99. 18
      vite-element-template/src/components/flowEdit/icon/HorizontalArrow.vue
  100. 18
      vite-element-template/src/components/flowEdit/icon/LeftArrow.vue

14
vite-element-template/.editorconfig

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

2
vite-element-template/.env

@ -0,0 +1,2 @@
VITE_APP_COMPANY=asdzxcasdzxc

6
vite-element-template/.env.development

@ -0,0 +1,6 @@
# base api
VITE_APP_BASE_API=/api
VITE_APP_WVP_API=/wvp
VITE_APP_PLAY_PORT=8090
VITE_APP_BASE_URL=http://192.168.0.129:8890/cc-admin
VITE_APP_WVP_URL=http://127.0.0.1:18899

4
vite-element-template/.env.production

@ -0,0 +1,4 @@
# base api
VITE_APP_BASE_API=/cc-admin
VITE_APP_BASE_URL=http://222.128.25.216:4050

271
vite-element-template/.eslintrc.js

@ -0,0 +1,271 @@
module.exports = {
root: true,
parser: "vue-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
sourceType: "module",
ecmaFeatures: {
'jsx': true
}
},
env: {
browser: true,
node: true,
es6: true
},
extends: ['plugin:vue/recommended', 'eslint:recommended','prettier'],
// add your custom rules here
// it is base on https://github.com/vuejs/eslint-config-vue
rules: {
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/name-property-casing': 'off',
'vue/no-v-html': 'off',
'vue/multi-word-component-names': 'off',
'vue/max-attributes-per-line': 'off',
// 'accessor-pairs': 2,
// 'arrow-spacing': [
// 2,
// {
// before: true,
// after: true
// }
// ],
// 'block-spacing': [2, 'always'],
// 'brace-style': [
// 2,
// '1tbs',
// {
// allowSingleLine: true
// }
// ],
// camelcase: [
// 0,
// {
// properties: 'always'
// }
// ],
// 'comma-dangle': [2, 'never'],
// 'comma-spacing': [
// 2,
// {
// before: false,
// after: true
// }
// ],
// 'comma-style': [2, 'last'],
// 'constructor-super': 2,
// curly: [2, 'multi-line'],
// 'dot-location': [2, 'property'],
// 'eol-last': 2,
// eqeqeq: ['error', 'always', { null: 'ignore' }],
// 'generator-star-spacing': [
// 2,
// {
// before: true,
// after: true
// }
// ],
// 'handle-callback-err': [2, '^(err|error)$'],
// indent: [
// 2,
// 2,
// {
// SwitchCase: 1
// }
// ],
// 'jsx-quotes': [2, 'prefer-single'],
// 'key-spacing': [
// 2,
// {
// beforeColon: false,
// afterColon: true
// }
// ],
// 'keyword-spacing': [
// 2,
// {
// before: true,
// after: true
// }
// ],
// 'new-cap': [
// 2,
// {
// newIsCap: true,
// capIsNew: false
// }
// ],
// 'new-parens': 2,
// 'no-array-constructor': 2,
// 'no-caller': 2,
// 'no-console': 'off',
// 'no-class-assign': 2,
// 'no-cond-assign': 2,
// 'no-const-assign': 2,
// 'no-control-regex': 0,
// 'no-delete-var': 2,
// 'no-dupe-args': 2,
// 'no-dupe-class-members': 2,
// 'no-dupe-keys': 2,
// 'no-duplicate-case': 2,
// 'no-empty-character-class': 2,
// 'no-empty-pattern': 2,
// 'no-eval': 2,
// 'no-ex-assign': 2,
// 'no-extend-native': 2,
// 'no-extra-bind': 2,
// 'no-extra-boolean-cast': 2,
// 'no-extra-parens': [2, 'functions'],
// 'no-fallthrough': 2,
// 'no-floating-decimal': 2,
// 'no-func-assign': 2,
// 'no-implied-eval': 2,
// 'no-inner-declarations': [2, 'functions'],
// 'no-invalid-regexp': 2,
// 'no-irregular-whitespace': 2,
// 'no-iterator': 2,
// 'no-label-var': 2,
// 'no-labels': [
// 2,
// {
// allowLoop: false,
// allowSwitch: false
// }
// ],
// 'no-lone-blocks': 2,
// 'no-mixed-spaces-and-tabs': 2,
// 'no-multi-spaces': 2,
// 'no-multi-str': 2,
// 'no-multiple-empty-lines': [
// 2,
// {
// max: 1
// }
// ],
// 'no-native-reassign': 2,
// 'no-negated-in-lhs': 2,
// 'no-new-object': 2,
// 'no-new-require': 2,
// 'no-new-symbol': 2,
// 'no-new-wrappers': 2,
// 'no-obj-calls': 2,
// 'no-octal': 2,
// 'no-octal-escape': 2,
// 'no-path-concat': 2,
// 'no-proto': 2,
// 'no-redeclare': 2,
// 'no-regex-spaces': 2,
// 'no-return-assign': [2, 'except-parens'],
// 'no-self-assign': 2,
// 'no-self-compare': 2,
// 'no-sequences': 2,
// 'no-shadow-restricted-names': 2,
// 'no-spaced-func': 2,
// 'no-sparse-arrays': 2,
// 'no-this-before-super': 2,
// 'no-throw-literal': 2,
// 'no-trailing-spaces': 2,
// 'no-undef': 2,
// 'no-undef-init': 2,
// 'no-unexpected-multiline': 2,
// 'no-unmodified-loop-condition': 2,
// 'no-unneeded-ternary': [
// 2,
// {
// defaultAssignment: false
// }
// ],
// 'no-unreachable': 2,
// 'no-unsafe-finally': 2,
// 'no-unused-vars': [
// 2,
// {
// vars: 'all',
// args: 'none'
// }
// ],
// 'no-useless-call': 2,
// 'no-useless-computed-key': 2,
// 'no-useless-constructor': 2,
// 'no-useless-escape': 0,
// 'no-whitespace-before-property': 2,
// 'no-with': 2,
// 'one-var': [
// 2,
// {
// initialized: 'never'
// }
// ],
// 'operator-linebreak': [
// 2,
// 'after',
// {
// overrides: {
// '?': 'before',
// ':': 'before'
// }
// }
// ],
// 'padded-blocks': [2, 'never'],
// quotes: [
// 2,
// 'single',
// {
// avoidEscape: true,
// allowTemplateLiterals: true
// }
// ],
// semi: [2, 'never'],
// 'semi-spacing': [
// 2,
// {
// before: false,
// after: true
// }
// ],
// 'space-before-blocks': [2, 'always'],
// 'space-before-function-paren': [2, 'never'],
// 'space-in-parens': [2, 'never'],
// 'space-infix-ops': 2,
// 'space-unary-ops': [
// 2,
// {
// words: true,
// nonwords: false
// }
// ],
// 'spaced-comment': [
// 2,
// 'always',
// {
// markers: [
// 'global',
// 'globals',
// 'eslint',
// 'eslint-disable',
// '*package',
// '!',
// ','
// ]
// }
// ],
// 'template-curly-spacing': [2, 'never'],
// 'use-isnan': 2,
// 'valid-typeof': 2,
// 'wrap-iife': [2, 'any'],
// 'yield-star-spacing': [2, 'both'],
// yoda: [2, 'never'],
// 'prefer-const': 2,
// 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
// 'object-curly-spacing': [
// 2,
// 'always',
// {
// objectsInObjects: false
// }
// ],
// 'array-bracket-spacing': [2, 'never']
}
}

18
vite-element-template/.gitignore

@ -0,0 +1,18 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
tests/**/coverage/
pnpm-lock.yaml
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
release
dist-electron

5
vite-element-template/.travis.yml

@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

21
vite-element-template/LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 misaka10032
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

84
vite-element-template/README.md

@ -0,0 +1,84 @@
# 依赖
vue2 + elementui2 +vue-router+ axios + pinia
# 开发说明
- `views/` 目录仅存放页面(路由)组件,(因为菜单管理会读取views文件列表)
- `components/` 页面的组件存放在components目录,目录要和views中页面路径一致
- `components/common/` 公共组件存放
- `directive/` 挂载全局指令
- `methods/` 挂载全局函数
- `store/` 状态管理(https://pinia.vuejs.org/zh/)
# vite-admin-template
[原作者,可以参考代码示例](https://panjiachen.gitee.io/vue-admin-template)
[原作者预览地址](https://panjiachen.github.io/vue-element-admin/#)
[原作者文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
[二次改编](https://gitee.com/mi-sa-ka10032/vite-element-template.git)
[本仓库](http://182.92.163.198:3000/18610965287/cc-admin-element-ui.git)
## Build Setup
```bash
# 安装依赖、npm建议替换为pnpm
npm install
# 建议不要直接使用 cnpm 安装,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 启动服务
npm run dev
npm run dev:test
npm run dev:staging
```
浏览器访问 [http://localhost:9528](http://localhost:9528)
## 发布
```bash
# 构建生产环境
npm run build
```
## 其它
```bash
# 预览发布环境效果
npm run preview
# 预览发布环境效果 + 静态资源分析
# npm run preview -- --report
# 代码格式检查
npm run lint
# 代码格式检查并自动修复
npm run lint -- --fix
```
# 图标使用
1. svg图标,放在`src/icons/svg` 目录下
```html
<svg-icon :icon-class="文件名" class-name="disabled" />
```
2. element自带图标
```html
<i :class="'el-icon-图标名'" />
```
3. 合并svg图标、element自带图标
```html
<AnyIcon :icon="svg文件名或者el图标名" :class-name="icon" ></AnyIcon>
<style scoped>
.icon{
font-size: 40px;
color: red;
}
</style>
```
4. 自定义字体图标(无、不建议使用)

11
vite-element-template/babel.config.js

@ -0,0 +1,11 @@
module.exports = {
presets: [['@babel/preset-env', { targets: { node: 'current' }}]],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
}

0
vite-element-template/eslint.config.js

18
vite-element-template/index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title>Vue Admin Template</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="/js/jessibuca/jessibuca.js"></script>
<script type="text/javascript" src="/js/EasyWasmPlayer.js"></script>
<script type="text/javascript" src="/js/ZLMRTCClient.js"></script>
<script type="text/javascript" src="/js/mapConfig.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>

25
vite-element-template/jest.config.js

@ -0,0 +1,25 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': '@vue/vue2-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/',
testEnvironment: 'jsdom'
}

16
vite-element-template/jsconfig.json

@ -0,0 +1,16 @@
{
"vueCompilerOptions": {
"target": 2.7
},
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

66
vite-element-template/package.json

@ -0,0 +1,66 @@
{
"name": "vite-admin-template",
"version": "1.0.0",
"description": "A vite vue admin template with Element UI & axios & iconfont & permission control & lint",
"author": "misaka10032@aliyun.com",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"lint": "eslint --ext .js,.vue src"
},
"dependencies": {
"@logicflow/core": "^1.2.17",
"@logicflow/extension": "^1.2.18",
"@vueuse/core": "^10.6.1",
"axios": "^1.4.0",
"core-js": "3.31.0",
"dayjs": "^1.11.10",
"echarts": "^5.6.0",
"element-ui": "2.15.13",
"js-base64": "^3.7.5",
"lodash-es": "^4.17.21",
"normalize.css": "8.0.1",
"nprogress": "0.2.0",
"path-browserify": "^1.0.1",
"path-to-regexp": "6.2.1",
"pinia": "^2.1.4",
"qs": "^6.11.2",
"uuid": "^9.0.0",
"vue": "^2.7.14",
"vue-color": "^2.8.1",
"vue-router": "3.0.6"
},
"devDependencies": {
"@babel/core": "^7.22.5",
"@babel/eslint-parser": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@typescript-eslint/parser": "^5.61.0",
"@vitejs/plugin-vue2": "^2.2.0",
"@vitejs/plugin-vue2-jsx": "^1.1.0",
"autoprefixer": "9.5.1",
"babel-plugin-dynamic-import-node": "2.3.3",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-vue": "^9.15.1",
"mockjs": "^1.1.0",
"sass": "1.63.6",
"svgo": "1.2.2",
"typescript": "^5.1.6",
"vite": "^4.3.9",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-svg-icons": "^2.0.1",
"vue-template-compiler": "^2.7.14"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"engines": {
"node": ">=8.9",
"npm": ">= 6.0.0"
},
"license": "MIT"
}

BIN
vite-element-template/public/NavBackground.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
vite-element-template/public/favicon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 66 KiB

BIN
vite-element-template/public/img/IndustrialGateway.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
vite-element-template/public/img/OpticalConvergenceSwitch.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
vite-element-template/public/img/SerialPortModule.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
vite-element-template/public/img/WIFI.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
vite-element-template/public/img/accessSwitch.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
vite-element-template/public/img/coreSwitch.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
vite-element-template/public/img/firewall.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
vite-element-template/public/img/host.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
vite-element-template/public/img/manageHosts.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
vite-element-template/public/img/office_network.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
vite-element-template/public/img/router.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
vite-element-template/public/img/server.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

37
vite-element-template/public/img/status_error.svg

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
<g>
<circle cx="32" cy="32" r="12" stroke="#FF0000" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="0s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="0s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle fill="#FF0000" cx="32" cy="32" r="12"/>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#FF0000" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#FF0000" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#FF0000" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

37
vite-element-template/public/img/status_success.svg

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
<g>
<circle cx="32" cy="32" r="12" stroke="#00CC66" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="0s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="0s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle fill="#00CC66" cx="32" cy="32" r="12"/>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#00CC66" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="0.7s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#00CC66" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="1.4s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
<g>
<circle cx="32" cy="32" r="12" stroke="#00CC66" stroke-width="1" fill="none">
<animate attributeName="r" from="12" to="32" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
<animate attributeName="stroke-width" from="2" to="0.5" begin="2.1s" dur="2.8s" repeatCount="indefinite" />
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
vite-element-template/public/img/tcq.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

19
vite-element-template/public/js/EasyWasmPlayer.js

File diff suppressed because one or more lines are too long

7718
vite-element-template/public/js/ZLMRTCClient.js

File diff suppressed because it is too large

1
vite-element-template/public/js/ZLMRTCClient.js.map

File diff suppressed because one or more lines are too long

1
vite-element-template/public/js/jessibuca/decoder.js

File diff suppressed because one or more lines are too long

BIN
vite-element-template/public/js/jessibuca/decoder.wasm

Binary file not shown.

190
vite-element-template/public/js/jessibuca/demo.html

@ -0,0 +1,190 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./jessibuca.js"></script>
<style>
.root {
display: flex;
place-content: center;
margin-top: 3rem;
}
.container-shell {
backdrop-filter: blur(5px);
background: hsla(0, 0%, 50%, 0.5);
padding: 30px 4px 10px 4px;
/* border: 2px solid black; */
width: auto;
position: relative;
border-radius: 5px;
box-shadow: 0 10px 20px;
}
.container-shell:before {
content: "jessibuca demo player";
position: absolute;
color: darkgray;
top: 4px;
left: 10px;
text-shadow: 1px 1px black;
}
#container {
background: rgba(13, 14, 27, 0.7);
width: 640px;
height: 398px;
}
.input {
display: flex;
margin-top: 10px;
color: white;
place-content: stretch;
}
.input2 {
bottom: 0px;
}
.input input {
flex: auto;
}
.err {
position: absolute;
top: 40px;
left: 10px;
color: red;
}
.option {
position: absolute;
top: 4px;
right: 10px;
display: flex;
place-content: center;
font-size: 12px;
}
.option span {
color: white;
}
.page {
background: url('./bg.jpg');
background-repeat: no-repeat;
background-position: top;
}
@media (max-width: 720px) {
#container {
width: 90vw;
height: 52.7vw;
}
}
</style>
</head>
<body class="page">
<div class="root">
<div class="container-shell">
<div id="container"></div>
<div class="input">
<div>输入URL:</div>
<input
autocomplete="on"
id="playUrl"
value=""
/>
<button id="play">播放</button>
<button id="pause" style="display: none">停止</button>
</div>
<div class="input" style="line-height: 30px">
<button id="destroy">销毁</button>
</div>
</div>
</div>
<script>
var $player = document.getElementById('play');
var $pause = document.getElementById('pause');
var $playHref = document.getElementById('playUrl');
var $container = document.getElementById('container');
var $destroy = document.getElementById('destroy');
var showOperateBtns = false; // 是否显示按钮
var forceNoOffscreen = true; //
var jessibuca = null;
function create() {
jessibuca = null;
jessibuca = new Jessibuca({
container: $container,
videoBuffer: 0.2, // 缓存时长
isResize: false,
text: "",
loadingText: "",
useMSE: false,
debug: true,
showBandwidth: showOperateBtns, // 显示网速
operateBtns: {
fullscreen: showOperateBtns,
screenshot: showOperateBtns,
play: showOperateBtns,
audio: false,
recorder: false
},
forceNoOffscreen: forceNoOffscreen,
isNotMute: false,
},);
jessibuca.on('audioInfo', function (audioInfo) {
console.log('audioInfo',audioInfo);
})
jessibuca.on('videoInfo', function (videoInfo) {
console.log('videoInfo',videoInfo);
})
$player.style.display = 'inline-block';
$pause.style.display = 'none';
$destroy.style.display = 'none';
}
create();
$player.addEventListener('click', function () {
var href = $playHref.value;
if (href) {
jessibuca.play(href);
$player.style.display = 'none';
$pause.style.display = 'inline-block';
$destroy.style.display = 'inline-block';
}
}, false)
$pause.addEventListener('click', function () {
$player.style.display = 'inline-block';
$pause.style.display = 'none';
jessibuca.pause();
})
$destroy.addEventListener('click', function () {
if (jessibuca) {
jessibuca.destroy().then(()=>{
create();
});
}
else {
create();
}
})
</script>
</body>
</html>

637
vite-element-template/public/js/jessibuca/jessibuca.d.ts

@ -0,0 +1,637 @@
declare namespace Jessibuca {
/** 超时信息 */
enum TIMEOUT {
/** 当play()的时候,如果没有数据返回 */
loadingTimeout = 'loadingTimeout',
/** 当播放过程中,如果超过timeout之后没有数据渲染 */
delayTimeout = 'delayTimeout',
}
/** 错误信息 */
enum ERROR {
/** 播放错误,url 为空的时候,调用 play 方法 */
playError = 'playError',
/** http 请求失败 */
fetchError = 'fetchError',
/** websocket 请求失败 */
websocketError = 'websocketError',
/** webcodecs 解码 h265 失败 */
webcodecsH265NotSupport = 'webcodecsH265NotSupport',
/** mediaSource 解码 h265 失败 */
mediaSourceH265NotSupport = 'mediaSourceH265NotSupport',
/** wasm 解码失败 */
wasmDecodeError = 'wasmDecodeError',
}
interface Config {
/**
*
* * string document.getElementById('id')
* */
container: HTMLElement | string;
/**
*
*/
videoBuffer?: number;
/**
* worker地址
* * decoder.js文件 decoder.js decoder.wasm文件必须是放在同一个目录下面 */
decoder?: string;
/**
* 使
*/
forceNoOffscreen?: boolean;
/**
* 'visibilityState''hidden'
*/
hiddenAutoPause?: boolean;
/**
* `false`
*/
hasAudio?: boolean;
/**
* 0()180270
*/
rotate?: boolean;
/**
* 1. `true`,canvas区域,, `setScaleMode(1)`
* 2. `false`canvas区域, `setScaleMode(0)`
*/
isResize?: boolean;
/**
* 1. `true`,canvas区域,,, `setScaleMode(2)`
*/
isFullResize?: boolean;
/**
* 1. `true`ws协议不检验是否以.flv为依据
*/
isFlv?: boolean;
/**
*
*/
debug?: boolean;
/**
* 1. ,
* 2. (loading)(heart),,timeout事件
*/
timeout?: number;
/**
* 1. ,
* 2. ,,timeout事件
*/
heartTimeout?: number;
/**
* 1. ,
* 2. ,,timeout事件
*/
loadingTimeout?: number;
/**
*
*/
supportDblclickFullscreen?: boolean;
/**
*
*/
showBandwidth?: boolean;
/**
*
*/
operateBtns?: {
/** 是否显示全屏按钮 */
fullscreen?: boolean;
/** 是否显示截图按钮 */
screenshot?: boolean;
/** 是否显示播放暂停按钮 */
play?: boolean;
/** 是否显示声音按钮 */
audio?: boolean;
/** 是否显示录制按 */
record?: boolean;
};
/**
* , canvas标签渲染视频并不会像video标签那样保持屏幕常亮
*/
keepScreenOn?: boolean;
/**
*
*/
isNotMute?: boolean;
/**
*
*/
loadingText?: string;
/**
*
*/
background?: string;
/**
* MediaSource硬解码
* * H.264Safari on iOS不支持
* * forceNoOffscreen false ()
*/
useMSE?: boolean;
/**
* Webcodecs硬解码
* * H.264 (chrome 94https或者localhost环境)
* * forceNoOffscreen false )
* */
useWCS?: boolean;
/**
*
* esc -> 退arrowUp -> arrowDown ->
*/
hotKey?: boolean;
/**
* 使MSE或者Webcodecs H265的时候wasm模式
* false Error true wasm模式播放
*/
autoWasm?: boolean;
/**
* heartTimeout ,
*/
heartTimeoutReplay?: boolean,
/**
* heartTimeoutReplay
*/
heartTimeoutReplayTimes?: number,
/**
* loadingTimeout loading之后自动再播放,
*/
loadingTimeoutReplay?: boolean,
/**
* heartTimeoutReplay
*/
loadingTimeoutReplayTimes?: number
/**
* wasm解码报错之后
*/
wasmDecodeErrorReplay?: boolean,
/**
* https://github.com/langhuihui/jessibuca/issues/152 解决方案
* WebGL图像预处理默认每次取4字节的数据540x960分辨率下的UV分量宽度是540/2=2704绿
*/
openWebglAlignment?: boolean
}
}
declare class Jessibuca {
constructor(config?: Jessibuca.Config);
/**
*
@example
// 开启
jessibuca.setDebug(true)
// 关闭
jessibuca.setDebug(false)
*/
setDebug(flag: boolean): void;
/**
*
@example
jessibuca.mute()
*/
mute(): void;
/**
*
@example
jessibuca.cancelMute()
*/
cancelMute(): void;
/**
*
*
* iPhonechrome等要求自动播放时使
*
* https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
*/
audioResume(): void;
/**
*
* ,
* ,,timeout事件
@example
jessibuca.setTimeout(10)
jessibuca.on('timeout',function(){
//
});
*/
setTimeout(): void;
/**
* @param mode
* 0 canvas区域, `isResize` false
*
* 1 ,canvas区域,, `isResize` true
*
* 2 ,canvas区域,,, `isFullResize` true
@example
jessibuca.setScaleMode(0)
jessibuca.setScaleMode(1)
jessibuca.setScaleMode(2)
*/
setScaleMode(mode: number): void;
/**
*
*
* pause `play()`
@example
jessibuca.pause().then(()=>{
console.log('pause success')
jessibuca.play().then(()=>{
}).catch((e)=>{
})
}).catch((e)=>{
console.log('pause error',e);
})
*/
pause(): Promise<void>;
/**
* ,
@example
jessibuca.close();
*/
close(): void;
/**
*
@example
jessibuca.destroy()
*/
destroy(): void;
/**
*
@example
jessibuca.clearView()
*/
clearView(): void;
/**
*
@example
jessibuca.play('url').then(()=>{
console.log('play success')
}).catch((e)=>{
console.log('play error',e)
})
//
jessibuca.play()
*/
play(url?: string): Promise<void>;
/**
*
*/
resize(): void;
/**
*
*
* `videoBuffer`
*
@example
// 设置 200ms 缓冲
jessibuca.setBufferTime(0.2)
*/
setBufferTime(time: number): void;
/**
* 0() 180270
*
* > iOS没有全屏API *
@example
jessibuca.setRotate(0)
jessibuca.setRotate(90)
jessibuca.setRotate(270)
*/
setRotate(deg: number): void;
/**
*
* 0 1
*
* > mute cancelMute setVolume(0) mute方法mute setVolume(0)0
* @param volume 0;1
@example
jessibuca.setVolume(0.2)
jessibuca.setVolume(0)
jessibuca.setVolume(1)
*/
setVolume(volume: number): void;
/**
*
@example
var result = jessibuca.hasLoaded()
console.log(result) // true
*/
hasLoaded(): boolean;
/**
* , canvas标签渲染视频并不会像video标签那样保持屏幕常亮
* H5目前在chrome\edge 84, android chrome 84API, https页面
*
@example
jessibuca.setKeepScreenOn()
*/
setKeepScreenOn(): boolean;
/**
* ()
@example
jessibuca.setFullscreen(true)
//
jessibuca.setFullscreen(false)
*/
setFullscreen(flag: boolean): void;
/**
*
*
* @param filename , , `时间戳`
* @param format , png或jpeg或者webp , `png`
* @param quality , jpeg或者webp时0 ~ 1 , `0.92`
* @param type , download或者base64或者blob`download`
@example
jessibuca.screenshot("test","png",0.5)
const base64 = jessibuca.screenshot("test","png",0.5,'base64')
const fileBlob = jessibuca.screenshot("test",'blob')
*/
screenshot(filename?: string, format?: string, quality?: number, type?: string): void;
/**
*
* @param fileName
* @param fileType webmwebm mp4
@example
jessibuca.startRecord('xxx','webm')
*/
startRecord(fileName: string, fileType: string): void;
/**
*
@example
jessibuca.stopRecordAndSave()
*/
stopRecordAndSave(): void;
/**
*
@example
var result = jessibuca.isPlaying()
console.log(result) // true
*/
isPlaying(): boolean;
/**
*
@example
var result = jessibuca.isMute()
console.log(result) // true
*/
isMute(): boolean;
/**
*
@example
var result = jessibuca.isRecording()
console.log(result) // true
*/
isRecording(): boolean;
/**
* jessibuca
* @example
* jessibuca.on("load",function(){console.log('load')})
*/
on(event: 'load', callback: () => void): void;
/**
* ms
* @example
* jessibuca.on('timeUpdate',function (ts) {console.log('timeUpdate',ts);})
*/
on(event: 'timeUpdate', callback: () => void): void;
/**
* 2
* @example
* jessibuca.on("videoInfo",function(data){console.log('width:',data.width,'height:',data.width)})
*/
on(event: 'videoInfo', callback: (data: {
/** 视频宽 */
width: number;
/** 视频高 */
height: number;
}) => void): void;
/**
* 2
* @example
* jessibuca.on("audioInfo",function(data){console.log('numOfChannels:',data.numOfChannels,'sampleRate',data.sampleRate)})
*/
on(event: 'audioInfo', callback: (data: {
/** 声频通道 */
numOfChannels: number;
/** 采样率 */
sampleRate: number;
}) => void): void;
/**
*
* @example
* jessibuca.on("log",function(data){console.log('data:',data)})
*/
on(event: 'log', callback: () => void): void;
/**
*
* @example
* jessibuca.on("error",function(error){
if(error === Jessibuca.ERROR.fetchError){
//
}
else if(error === Jessibuca.ERROR.webcodecsH265NotSupport){
//
}
console.log('error:',error)
})
*/
on(event: 'error', callback: (err: Jessibuca.ERROR) => void): void;
/**
* KB 1,
* @example
* jessibuca.on("kBps",function(data){console.log('kBps:',data)})
*/
on(event: 'kBps', callback: (value: number) => void): void;
/**
*
* @example
* jessibuca.on("start",function(){console.log('start render')})
*/
on(event: 'start', callback: () => void): void;
/**
* ,
* @example
* jessibuca.on("timeout",function(error){console.log('timeout:',error)})
*/
on(event: 'timeout', callback: (error: Jessibuca.TIMEOUT) => void): void;
/**
* play()
* @example
* jessibuca.on("loadingTimeout",function(){console.log('timeout')})
*/
on(event: 'loadingTimeout', callback: () => void): void;
/**
* timeout之后没有数据渲染
* @example
* jessibuca.on("delayTimeout",function(){console.log('timeout')})
*/
on(event: 'delayTimeout', callback: () => void): void;
/**
*
* @example
* jessibuca.on("fullscreen",function(flag){console.log('is fullscreen',flag)})
*/
on(event: 'fullscreen', callback: () => void): void;
/**
*
* @example
* jessibuca.on("play",function(flag){console.log('play')})
*/
on(event: 'play', callback: () => void): void;
/**
*
* @example
* jessibuca.on("pause",function(flag){console.log('pause')})
*/
on(event: 'pause', callback: () => void): void;
/**
* boolean值
* @example
* jessibuca.on("mute",function(flag){console.log('is mute',flag)})
*/
on(event: 'mute', callback: () => void): void;
/**
* 1
* @example
* jessibuca.on("stats",function(s){console.log("stats is",s)})
*/
on(event: 'stats', callback: (stats: {
/** 当前缓冲区时长,单位毫秒 */
buf: number;
/** 当前视频帧率 */
fps: number;
/** 当前音频码率,单位byte */
abps: number;
/** 当前视频码率,单位byte */
vbps: number;
/** 当前视频帧pts,单位毫秒 */
ts: number;
}) => void): void;
/**
* 1
* @param performance 0: 表示卡顿,1: 表示流畅,2: 表示非常流程
* @example
* jessibuca.on("performance",function(performance){console.log("performance is",performance)})
*/
on(event: 'performance', callback: (performance: 0 | 1 | 2) => void): void;
/**
*
* @example
* jessibuca.on("recordStart",function(){console.log("record start")})
*/
on(event: 'recordStart', callback: () => void): void;
/**
*
* @example
* jessibuca.on("recordEnd",function(){console.log("record end")})
*/
on(event: 'recordEnd', callback: () => void): void;
/**
* 1s一次
* @example
* jessibuca.on("recordingTimestamp",function(timestamp){console.log("recordingTimestamp is",timestamp)})
*/
on(event: 'recordingTimestamp', callback: (timestamp: number) => void): void;
/**
* play方法 -> -> -> ->
* @param event
* @param callback
*/
on(event: 'playToRenderTimes', callback: (times: {
playInitStart: number, // 1 初始化
playStart: number, // 2 初始化
streamStart: number, // 3 网络请求
streamResponse: number, // 4 网络请求
demuxStart: number, // 5 解封装
decodeStart: number, // 6 解码
videoStart: number, // 7 渲染
playTimestamp: number,// playStart- playInitStart
streamTimestamp: number,// streamStart - playStart
streamResponseTimestamp: number,// streamResponse - streamStart
demuxTimestamp: number, // demuxStart - streamResponse
decodeTimestamp: number, // decodeStart - demuxStart
videoTimestamp: number,// videoStart - decodeStart
allTimestamp: number // videoStart - playInitStart
}) => void): void
/**
*
*
@example
jessibuca.on("load",function(){console.log('load')})
*/
on(event: string, callback: Function): void;
}
export default Jessibuca;

1
vite-element-template/public/js/jessibuca/jessibuca.js

File diff suppressed because one or more lines are too long

19
vite-element-template/public/js/mapConfig.js

@ -0,0 +1,19 @@
// map组件全局参数, 注释此内容可以关闭地图功能
window.mapParam = {
// 开启/关闭地图功能
enable: true,
// 坐标系 GCJ-02 WGS-84,
coordinateSystem: "GCJ-02",
// 地图瓦片地址
tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
// 瓦片大小
tileSize: 256,
// 默认层级
zoom:10,
// 默认地图中心点
center:[116.41020, 39.915119],
// 地图最大层级
maxZoom:18,
// 地图最小层级
minZoom: 3
}

BIN
vite-element-template/public/user.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

11
vite-element-template/src/App.vue

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

94
vite-element-template/src/api/index.js

@ -1,62 +1,51 @@
// import { Message } from 'element-ui'
import request from "@/utils/request";
import request from '@/utils/request'
export function uploadFile(data) {
return request({
url: "/sys/common/upload",
method: "post",
data: data,
});
url: '/sys/common/upload',
method: 'post',
data: data
})
}
export function downloadFile(url, params, FileName) {
return request({
url: url,
method: "get",
method: 'get',
params: params,
responseType: "blob",
}).then((data) => {
responseType: 'blob'
}).then(data => {
if (!data) {
return;
}
var fileName;
var fileSuffix;
if (!data.headers["content-disposition"]) {
if (!FileName) {
console.log("未获取到文件信息");
return;
}
} else {
console.log('data.headers["content-disposition"]',data.headers["content-disposition"]);
var serverFileName = decodeURIComponent(
data.headers["content-disposition"]
.replaceAll(" ", "")
.replaceAll('"', "")
.replaceAll("'", "")
.replaceAll("attachment;filename=", "")
);
fileSuffix = serverFileName.split(".")[1];
fileName = serverFileName;
}
if (FileName && fileSuffix) {
fileName = FileName + "." + fileSuffix;
} else if(FileName){
fileName = FileName;
var serverFileName = decodeURIComponent(
data.headers['content-disposition']
.replaceAll(' ', '')
.replaceAll('"', '')
.replaceAll("'", '')
.replaceAll('attachment;filename=', '')
)
let fileSuffix=serverFileName.split('.')[1]
let fileName=serverFileName
if(FileName){
fileName=FileName+'.'+fileSuffix
}
if (typeof window.navigator.msSaveBlob !== "undefined") {
window.navigator.msSaveBlob(new Blob([data.data]), fileName);
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data.data]), fileName)
} else {
const url = window.URL.createObjectURL(new Blob([data.data]));
const link = document.createElement("a");
link.style.display = "none";
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // 下载完成移除元素
window.URL.revokeObjectURL(url); // 释放掉blob对象
const url = window.URL.createObjectURL(new Blob([data.data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
});
})
}
/**
@ -66,19 +55,8 @@ export function downloadFile(url, params, FileName) {
*/
export function getDictById(id) {
return request({
url: "/sys/dictItem/selectItemsByDefId",
url: '/sys/dictItem/selectItemsByDefId',
params: { defId: id },
method: "get",
});
}
/**
* 根据字典编码获取字段
*/
export function getDictByCode(code) {
return request({
url: "/sys/dictItem/selectItemsByDictCode",
params: { dictCode: code },
method: "get",
});
method: 'get'
})
}

64
vite-element-template/src/api/sys/dictionary/index.js

@ -0,0 +1,64 @@
import request from '@/utils/request'
export function getDictList(params) {
return request({
url: '/sys/dict/list',
method: 'get',
params
})
}
export function getDictInfoList(params) {
return request({
url: '/sys/dictItem/list',
method: 'get',
params
})
}
export function addDict(data) {
return request({
url: '/sys/dict/add',
method: 'post',
data
})
}
export function deleteDict(params) {
return request({
url: '/sys/dict/delete',
method: 'delete',
params
})
}
export function deleteDictItem(params) {
return request({
url: '/sys/dictItem/delete',
method: 'delete',
params
})
}
export function editDict(data) {
return request({
url: '/sys/dict/edit',
method: 'put',
data
})
}
export function changeStatus(data) {
return request({
url: '/sys/dictItem/status',
method: 'put',
data
})
}
export function addDictItem(data) {
return request({
url: '/sys/dictItem/add',
method: 'post',
data
})
}
export function editDictItem(data) {
return request({
url: '/sys/dictItem/edit',
method: 'put',
data
})
}

122
vite-element-template/src/api/sys/role/index.js

@ -0,0 +1,122 @@
import request from '@/utils/request'
export function fetchRoleList(params) {
return request({
url: '/sys/role/list',
method: 'get',
params
})
}
export function addRole(data) {
return request({
url: '/sys/role/add',
method: 'post',
data
})
}
export function editRole(data) {
return request({
url: '/sys/role/edit',
method: 'put',
data
})
}
export function batchDeleteRoles(params) {
return request({
url: '/sys/role/deleteBatch',
method: 'delete',
params
})
}
export function deleteRole(params) {
return request({
url: '/sys/role/delete',
method: 'delete',
params
})
}
export function getRolePermission(params) {
return request({
url: '/sys/permission/queryRolePermission',
method: 'get',
params
})
}
/**
* @description 修改用户权限
* @param {Object} data
* @param {String} data.lastpermissionIds 上次permission
* @param {String} data.permissionIds 本次permission
* @param {String} data.roleId
* @returns
*/
export function editRolePermission(data) {
return request({
url: '/sys/permission/saveRolePermission',
method: 'post',
data
})
}
export function getMenuList() {
return request({
url: '/sys/permission/list',
method: 'get',
})
}
/**
* @description 获取是否拥有该权限的用户
* @param {Object} params
* @param {String} params.roleId 角色id
* @param {boolean} params.selected 是否拥有该角色
* @param {String} params.key 查询关键字
* @param {String} params.pageNo
* @param {String} params.pageSize
* @returns
*/
export function getPermissionUsers(params) {
return request({
url: '/sys/userRole/list',
method: 'get',
params
})
}
/**
* @description 添加拥有该权限的用户
* @param {Array<{userId:String,roleId:String}>} data [{userId,userId}]
* @returns
*/
export function addPermissionUsers(data) {
return request({
url: '/sys/userRole/add',
method: 'post',
data
})
}
/**
* @description 批量删除拥有该权限的用户
* @param {Array<{userId:String,roleId:String}>} data [{userId,userId}]
* @returns
*/
export function BatchDeletePermissionUsers(data) {
return request({
url: '/sys/userRole/deleteBatch',
method: 'post',
data
})
}
/**
* @description 删除拥有该权限的用户
* @param {Object} params
* @param {String} params.userId
* @param {String} params.roleId
* @returns
*/
export function deletePermissionUsers(params) {
return request({
url: 'sys/userRole/delete',
method: 'delete',
params
})
}

62
vite-element-template/src/api/sys/user/index.js

@ -0,0 +1,62 @@
import request from '@/utils/request'
export function fetchUserList(params) {
return request({
url: '/sys/user/list',
method: 'get',
params: params
})
}
export function addUser(data) {
return request({
url: '/sys/user/add',
method: 'post',
data: data
})
}
export function editUser(data) {
return request({
url: '/sys/user/edit',
method: 'put',
data: data
})
}
export function deleteBatchUsers(params) {
return request({
url: '/sys/user/deleteBatch',
method: 'delete',
params: params
})
}
export function deleteUser(params) {
return request({
url: '/sys/user/delete',
method: 'delete',
params: params
})
}
/**
* @description 修改角色权限
* @param {Object} params {userId:String,selectedRoles:String}
* @param {String} params.userId
* @param {String} params.selectedRoles
* @returns
*/
export function editUserRoles(params) {
return request({
url: '/sys/user/setUserRoles',
method: 'put',
params
})
}
export function changePassword(data) {
return request({
url: 'sys/user/changePassword',
method: 'put',
data: data
})
}

1
vite-element-template/src/api/user.js

@ -42,7 +42,6 @@ export function VerificationCode() {
method: 'post'
})
}
// 修改用户信息密码
export function change_password(data) {
return request({

112
vite-element-template/src/api/video.js

@ -0,0 +1,112 @@
import request from "@/utils/request";
//获取所有通道列表
export function getAllChannel() {
return request({
url: '/nvr/channel/list',
method: 'get',
params: {
pageSize: 99999,
pageNo: 1
}
})
}
//根据取通道列表
/**
*
* @param {*} params
* @param {String} params.siteId 区域
* @param {String} params.equipmentId 主机
* @param {String} params.name 名称
* @param {String} params.pageNo 页码
* @param {String} params.pageSize 页大小
* @returns
*/
export function getChannel(params) {
// 区域 主机 名称
return request({
url: '/nvr/channel/list',
method: 'get',
params: params
})
}
/**
*
* @param {*} params
* @param {String} params.siteId 区域
*/
// 根据区域获取巡航列表
export function getCruiseList(params) {
return request({
url: '/nvr/cruise/list',
method: 'get',
params: params
})
}
// 获取巡航映射
export function getCruiseMap(params) {
return request({
url: '/nvr/cruise/presetList',
method: 'get',
params: params
})
}
// 通道云台控制
/**
* @param {String} params.cameraIp ip
* @param {String} params.speed 速度
* @param {String} params.direction 方向
*/
export function setChannelPTZ(params) {
// 原有系统的云台控制
return request({
url: '/nvr/cruise/movePTZ',
method: 'get',
params: params
})
}
// 通道预置位控制
/**
* @param {String} params.cameraIp ip
* @param {String} params.preset 预置位
*/
export function setChannelPreset(params) {
// 原有系统的预置位控制
return request({
url: '/nvr/cruise/movePreset',
method: 'get',
params: params
})
}
export function setZoom({
ip, command, deviceType, deviceSerial, accessToken, channelNo
}) {
let cmd;
// 原有系统的缩放控制
if (command > 0) {
cmd = 'zoomin';
} else if (command < 0) {
cmd = 'zoomout';
}
command = Math.abs(command);
// 发送command秒命令
return new Promise((res, rej) => {
return setChannelPTZ({ cameraIp: ip, command: cmd }).then(() => {
setTimeout(() => {
setChannelPTZ({
cameraIp: ip,
command: 'stop'
}).then(() => {
res();
}).catch((err) => {
rej(err);
});
}, command * 1000);
});
});
}

87
vite-element-template/src/api/wvp.js

@ -0,0 +1,87 @@
class WvpService {
constructor() {
this.baseURL = import.meta.env.VITE_APP_WVP_API;
this.token = '';
this.login()
}
login() {
return fetch(`${this.baseURL}/api/user/login?username=admin&password=21232f297a57a5a743894a0e4a801fc3`)
.then(response => response.json())
.then(({ data }) => {
this.token = data.accessToken;
})
.catch(error => {
console.error('Error:', error);
});
}
async deviceList() {
if (!this.token) {
await this.login();
}
return fetch(`${this.baseURL}/api/device/query/devices?page=1&count=100`, {
headers: {
'Access-Token': `${this.token}`
}
})
.then(response => response.json())
.then(data => {
if (data.code === 401) {
// this.login();
} else {
return data.data.list;
}
})
.catch(error => {
console.error('Error:', error);
});
}
getTree(deviceId, parentId, onlyCatalog, callback, endCallback, errorCallback) {
let currentPage = 1;
let count = 100;
let catalogList = []
this.getTreeIteration(deviceId, parentId, onlyCatalog, catalogList, currentPage, count, callback, endCallback, errorCallback)
}
getTreeIteration(deviceId, parentId, onlyCatalog, catalogList, currentPage, count, callback, endCallback, errorCallback) {
this.getTreeInfo(deviceId, parentId, onlyCatalog, currentPage, count, (data) => {
console.log(data)
if (data.code === 0 && data.data.list) {
if (typeof (callback) == "function") callback(data.data.list)
catalogList = catalogList.concat(data.data.list);
if (catalogList.length < data.data.total) {
currentPage++
this.getTreeIteration(deviceId, parentId, onlyCatalog, catalogList, currentPage, count, callback, endCallback, errorCallback)
} else {
if (typeof (endCallback) == "function") endCallback(catalogList)
}
}
}, errorCallback)
}
getTreeInfo(deviceId, parentId, onlyCatalog, currentPage, count, callback, errorCallback) {
if (onlyCatalog == null || typeof onlyCatalog === "undefined") {
onlyCatalog = false;
}
return fetch(`${this.baseURL}/api/device/query/tree/${deviceId}?page=${currentPage}&count=${count}&parentId=${parentId}&onlyCatalog=${onlyCatalog}`, {
headers: {
'Access-Token': `${this.token}`
}
})
.then(response => response.json())
.then((res) => {
if (typeof (callback) == "function") callback(res)
}).catch(errorCallback);
}
startPlay(deviceId, channelId) {
return fetch(`${this.baseURL}/api/play/start/${deviceId}/${channelId}`, {
headers: {
'Access-Token': `${this.token}`
}
})
.then(response => response.json())
}
}
export default new WvpService();

BIN
vite-element-template/src/assets/404_images/404_cloud.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
vite-element-template/src/assets/daping/img3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

BIN
vite-element-template/src/assets/home/NumberOfAxialFlowFan.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
vite-element-template/src/assets/home/importantDetector.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

388
vite-element-template/src/components/activiti/ExamineAndApprove.vue

@ -0,0 +1,388 @@
<!-- 审批 -->
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
>
<el-form
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="100px"
>
<el-form-item label="审批意见" prop="comment" :rules="[requiredTest]">
<el-input
v-model="form.comment"
type="textarea"
placeholder="请输入审批意见"
style="width: 100%"
clearable
></el-input>
</el-form-item>
<el-form-item
v-if="showAssign"
label="下一审批人"
prop="assignees"
:rules="[requiredTest]"
>
<el-select
v-model="form.assignees"
filterable
multiple
placeholder="请选择"
style="width: 100%"
clearable
>
<el-option
v-for="item in assigneeList"
:key="item.username"
:label="item.realname"
:value="item.username"
></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="isGateway" label="下一审批人" :rules="[requiredTest]">
分支网关处不支持自定义选择下一审批人将自动下发给所有可审批人
</el-form-item>
<div v-show="form.type == 1">
<el-form-item label="驳回至" :rules="[requiredTest]">
<el-select
v-model="form.backTaskKey"
filterable
placeholder="请选择"
style="width: 100%"
clearable
@change="changeBackTask"
>
<el-option
v-for="item in backList"
:key="item.key"
:value="item.key"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item
v-show="form.backTaskKey != -1"
label="指定原节点审批人"
:rules="[requiredTest]"
>
<el-select
v-model="form.assignees"
filterable
multiple
placeholder="请选择"
style="width: 100%"
clearable
>
<el-option
v-for="item in assigneeList"
:key="item.username"
:value="item.username"
:label="item.realname"
></el-option>
</el-select>
</el-form-item>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
import { requiredTest } from "@/utils/inputTest.js";
export default {
name: "ExamineAndApprove",
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
requiredTest,
dialogVisible: false,
loading: false,
isGateway: false, //
showAssign: false, //
assigneeList: [],
backList: [], //
form: {
id: "",
procDefId: "",
title: "",
priority: 0, //
firstGateway: false,
assignees: [],
},
};
},
computed: {
showTitle() {
return this.form.type==1?"驳回":"审批通过";
},
},
methods: {
reset() {
this.loading = false;
this.isGateway = false;
this.showAssign = false;
this.assigneeList = [];
this.backList = [];
this.form = this.$options.data().form;
},
changeBackTask(v) {
if (v == "-1") {
return;
}
this.$axios
.get("act/zNodePreset/getCurrentNodeUser", {
params: {
businessId: this.form.businessKey,
procDefId: this.form.procDefId,
nodeId: v,
},
})
.then((res) => {
if (!res.success) {
return this.$message.error("请求错误");
}
this.assigneeList = res.result.users;
const ids = [];
res.result.users.forEach((e) => {
ids.push(e.username);
});
this.form.assignees = ids;
});
},
backTask(v) {
this.reset();
const form = {
id: v.id,
procInstId: v.procInstId,
procDefId: v.procDefId,
title: "",
priority: v.priority, //
type: 1, //01
businessKey: v.businessKey,
tableName: v.tableName,
tableId: v.tableId,
backTaskKey: "-1",
};
this.showAssign = false;
//
this.backList = [
{
key: "-1",
name: "发起人",
},
];
this.$axios
.get(this.url.getBackList + v.procInstId)
.then((res) => {
if (!res.success) {
return this.$message.error("请求错误");
}
res.result.forEach((e) => {
this.backList.push(e);
});
if (res.result.length) {
form.backTaskKey = res.result[0].key;
this.changeBackTask(form.backTaskKey);
}
this.form = form;
this.dialogVisible = true;
})
.catch(() => {
this.$message.error("请求驳回节点错误");
});
},
passTask(v) {
this.reset();
if (!v.procDefId || v.procDefId == "null") {
this.$message.error("流程定义为空");
return;
}
const form = {
id: v.id,
procInstId: v.procInstId,
procDefId: v.procDefId,
title: "",
priority: v.priority, //
type: 0, //01
// firstGateway: false,
// assignees: [], //id
};
this.$axios
.get("act/zNodePreset/getNodeUser", {
params: {
businessId: v.businessKey,
procDefId: v.procDefId,
nodeId: v.key,
},
})
.then((res) => {
if (!res.success) {
return this.$message.error("请求错误");
}
// if (res.result.type == 3 || res.result.type == 4) {
if (res.result.type == 4) {
this.isGateway = true; //
this.showAssign = false; //
this.form = form;
this.dialogVisible = true;
return;
}
if (res.result.type == 2) {
this.isGateway = false;
this.showAssign = false;
this.form = form;
this.dialogVisible = true;
return;
}
this.isGateway = false;
if (res.result.users && res.result.users.length > 0) {
this.assigneeList = res.result.users;
//
let ids = [];
res.result.users.forEach((e) => {
ids.push(e.username);
});
form.assignees = ids;
this.showAssign = true;
this.dialogVisible = true;
} else {
form.assignees = [];
this.showAssign = true;
this.$message.error(
`审批节点“${res.result.title}”未分配候选审批人员,请联系管理员!`
);
}
this.form = form;
})
.catch(() => {
this.$message.error("请求错误");
});
return;
},
/*审批提交的方法*/
onSubmit() {
// this.submitLoading = true;
var formData = Object.assign({}, this.form);
formData.assignees = formData.assignees.join(",");
if (formData.type == 0) {
//
if (this.showAssign && formData.assignees.length < 1) {
this.$message.error("请至少选择一个审批人");
// this.submitLoading = false;
return;
}
this.$axios
.post(this.url.pass, null, {
params: formData,
})
.then((res) => {
// this.submitLoading = false;
if (res.success) {
this.$message.success("操作成功");
this.close();
this.$emit("refresh");
}
});
} else if (formData.type == 1) {
//
if (formData.backTaskKey == "-1") {
//
this.$axios
.post(this.url.back, null, {
params: formData,
}).then((res) => {
// this.submitLoading = false;
if (res.success) {
this.$message.success("操作成功");
this.close();
this.$emit("refresh");
}
});
} else {
//
if (formData.backTaskKey != "-1" && formData.assignees.length < 1) {
this.$message.error("请至少选择一个审批人");
// this.submitLoading = false;
return;
} else {
this.error = "";
}
this.$axios
.post(this.url.backToTask, null, {
params: formData,
}).then((res) => {
// this.submitLoading = false;
if (res.success) {
this.$message.success("操作成功");
this.close();
this.$emit("refresh");
}
});
}
} else if (formData.type == 2) {
//
if (!formData.userId) {
this.$message.error("请选择一委托人");
// this.submitLoading = false;
return;
}
this.$axios
.post(this.url.delegate, null, {
params: formData,
}).then((res) => {
// this.submitLoading = false;
if (res.success) {
this.$message.success("操作成功");
this.close();
this.$emit("refresh");
}
});
}
},
close() {
this.dialogVisible = false;
this.$emit("close");
},
},
};
</script>

162
vite-element-template/src/components/activiti/ProcessProgress.vue

@ -0,0 +1,162 @@
<template>
<div class="ProcessProgress">
<div @click="show">
<slot>
<el-link type="primary">审批历史</el-link>
</slot>
</div>
<el-drawer
title="流程审批进度历史"
append-to-body
:visible.sync="drawerShow"
position="right"
size="700px"
>
<el-table :data="data" border fit size="mini" highlight-current-row>
<el-table-column
align="center"
label="任务名称"
prop="name"
></el-table-column>
<el-table-column align="center" label="处理人" prop="assignees">
<template slot-scope="scope">
<span v-for="(item, index) in scope.row.assignees" :key="index">
<span v-if="item.isExecutor" style="color: #00db00">
{{ item.username }}
</span>
<span v-else style="color: #999">{{ item.username }}</span>
</span>
</template>
</el-table-column>
<el-table-column
align="center"
label="审批操作"
prop="deleteReason"
></el-table-column>
<el-table-column
align="center"
label="审批意见"
prop="comment"
></el-table-column>
<el-table-column
align="center"
label="耗时"
prop="duration"
></el-table-column>
<el-table-column
align="center"
label="创建时间"
prop="createTime"
></el-table-column>
<el-table-column
align="center"
label="完成时间"
prop="endTime"
></el-table-column>
<el-table-column
align="center"
label="状态"
prop="status"
></el-table-column>
</el-table>
<div class="progress">
<img :src="imgUrl" alt />
</div>
</el-drawer>
</div>
</template>
<script>
export default {
props: {
rid: {
type: String,
default: "",
},
},
data() {
return {
drawerShow: false,
data: [],
url: {
historicFlow: "/actTask/historicFlow/",
getHighlightImg: `${import.meta.env.VITE_APP_BASE_URL}${
import.meta.env.VITE_APP_BASE_API
}/activiti/models/getHighlightImg/`,
},
imgUrl: "",
};
},
methods: {
millsToTime(mills) {
if (!mills) {
return "";
}
const s = mills / 1000;
if (s < 60) {
return `${s.toFixed(0)}`;
}
const m = s / 60;
if (m < 60) {
return `${m.toFixed(0)} 分钟`;
}
const h = m / 60;
if (h < 24) {
return `${h.toFixed(0)} 小时`;
}
const d = h / 24;
if (d < 30) {
return `${d.toFixed(0)}`;
}
const month = d / 30;
if (month < 12) {
return `${month.toFixed(0)} 个月`;
}
const year = month / 12;
return `${year.toFixed(0)}`;
},
show() {
if (!this.rid) {
this.$message.error("未指定数据");
} else {
this.drawerShow = true;
this.imgUrl = `${
this.url.getHighlightImg + this.rid
}?time=${new Date()}`;
this.getDataList();
}
},
getDataList() {
this.$axios.get(this.url.historicFlow + this.rid).then((res) => {
this.loading = false;
if (res.success) {
this.data = res.result;
if (!res.result || res.result.length === 0) {
this.$message.error(
"未找到该记录审批历史数据,历史数据可能已被删除"
);
}
} else {
this.$message.error(res.message);
}
});
},
submit() {},
},
};
</script>
<style lang="scss" scoped>
.ProcessProgress {
display: inline-block;
}
.progress {
img {
width: 100%;
}
}
</style>

146
vite-element-template/src/components/activiti/applyList/Add.vue

@ -0,0 +1,146 @@
<template>
<el-drawer
title="选择流程"
:visible.sync="drawerShow"
position="right"
size="600px"
>
<el-table
v-for="value of activeKeyAll"
:key="value"
:data="processDataMap[value]"
border
fit
size="mini"
highlight-current-row
>
<el-table-column
align="center"
:label="filterDictText(dictOptions, value) || '未分类'"
>
<el-table-column
align="center"
label="任务名称"
prop="name"
></el-table-column>
<el-table-column
align="center"
label="版本"
prop="version"
></el-table-column>
<el-table-column
align="center"
label="说明"
prop="description"
></el-table-column>
<el-table-column align="center" label="说明" prop="description">
<template #default="scope">
<a href="javascript:void (0)" @click="chooseProcess(scope.row)"
>发起申请</a
>
</template>
</el-table-column>
</el-table-column>
</el-table>
<ViewForm ref="viewForm" @refresh="refresh"></ViewForm>
</el-drawer>
</template>
<script>
import { groupBy } from "lodash-es";
import ViewForm from "@/components/activiticonfig/ProcessModelList/ViewForm.vue";
export default {
components: {
ViewForm,
},
data() {
return {
drawerShow: false,
activeKeyAll: [],
processDataMap: {},
dictOptions: [],
data: [],
url: {
list: "/actBusiness/listData",
delete: "/actBusiness/delByIds",
deleteBatch: "/actBusiness/delByIds",
getProcessDataList: "/activiti_process/listData",
getFirstNode: "/actProcessIns/getFirstNode",
applyBusiness: "/actBusiness/apply",
cancelApply: "/actBusiness/cancel",
},
};
},
methods: {
show() {
this.drawerShow = true;
this.getProcessList();
this.initDictConfig();
},
initDictConfig() {
// -
this.$axios.get("/sys/dict/getDictItems/bpm_process_type").then((res) => {
if (res.success) {
this.dictOptions = res.result;
}
});
},
filterDictText(dictOptions, text) {
if (dictOptions instanceof Array) {
for (let dictItem of dictOptions) {
if (text === dictItem.value) {
return dictItem.text;
}
}
}
return text || text == "null" ? "" : text;
},
getProcessList() {
this.$axios
.get("/activiti_process/listData", {
params: { status: 1, roles: true },
})
.then((res) => {
this.activeKeyAll = [];
if (res.success) {
var result = res.result || [];
if (result.length > 0) {
this.processDataMap = groupBy(result, "categoryId");
for (const categoryId in this.processDataMap) {
this.activeKeyAll.push(categoryId);
}
this.activeKey = this.activeKeyAll;
}
this.processModalVisible = true;
} else {
this.$message.error(res.message);
}
})
.finally(() => (this.addApplyLoading = false));
},
chooseProcess(v) {
if (!v.routeName) {
this.$message.error("该流程信息未配置表单,请联系开发人员!");
return;
}
this.$refs.viewForm.show({
routeName:v.routeName,
title:"发起流程:" + v.name,
isNew:true,
processData:v,
disabled:false,
});
console.log("发起", v);
},
refresh() {
this.drawerShow = false;
this.$emit("refresh");
},
submit() {},
},
};
</script>

216
vite-element-template/src/components/activiti/applyList/Apply.vue

@ -0,0 +1,216 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
>
<el-form
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="100px"
>
<el-form-item
v-if="showAssign"
label="审批人"
prop="assignees"
:rules="[requiredTest]"
>
<el-select
v-model="form.assignees"
filterable
multiple
placeholder="请选择"
style="width: 100%"
clearable
>
<el-option
v-for="item in assigneeList"
:key="item.username"
:label="item.realname"
:value="item.username"
></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="isGateway" label="下一审批人" :rules="[requiredTest]">
分支网关处不支持自定义选择下一审批人将自动下发给所有可审批人
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select
v-model="form.priority"
filterable
placeholder="请选择"
style="width: 100%"
clearable
>
<el-option label="普通" :value="0"></el-option>
<el-option label="重要" :value="1"></el-option>
<el-option label="紧急" :value="2"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
import { requiredTest } from "@/utils/inputTest.js";
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
emits: ["refresh"],
data() {
return {
requiredTest,
dialogVisible: false,
loading: false,
isGateway: false, //
showAssign: false, //
assigneeList: [],
form: {
id: "",
procDefId: "",
title: "",
priority: 0, //
firstGateway: false,
assignees: [],
},
};
},
computed: {
showTitle() {
return "提交申请";
},
},
methods: {
reset() {
this.loading = false;
this.isGateway = false;
this.showAssign = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
// this.form = { ...this.$options.data().form, ...form };
this.apply(form);
}
// this.dialogVisible = true;
},
apply(v) {
if (!v.procDefId || v.procDefId == "null") {
this.$message.error("流程定义为空");
return;
}
const form = {
id: v.id,
procDefId: v.procDefId,
title: v.title,
priority: 0,
firstGateway: false,
assignees: [], //id
};
this.$axios
.get("act/zNodePreset/getNodeUser", {
params: {
businessId: v.id,
procDefId: v.procDefId,
},
})
.then((res) => {
if (!res.success) {
return this.$message.error("需要先设置审核用户");
}
if (res.result.type == 3 || res.result.type == 4) {
form.firstGateway = true;
this.isGateway = true; //
this.showAssign = false; //
this.form = form;
this.dialogVisible = true;
return;
}
if (res.result.users && res.result.users.length > 0) {
this.assigneeList = res.result.users;
//
let ids = [];
res.result.users.forEach((e) => {
ids.push(e.username);
});
form.assignees = ids;
this.showAssign = true;
} else {
form.assignees = [];
this.showAssign = true;
this.$message.error(
`审批节点“${res.result.title}”未分配候选审批人员,请联系管理员!`
);
}
this.form = form;
this.dialogVisible = true;
});
return;
},
onSubmit() {
if (this.showAssign && this.form.assignees.length < 1) {
this.$error("请至少选择一个审批人");
return;
}
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
var form = { ...this.form };
console.log("form", form);
form.assignees = form.assignees.join(",");
this.$axios
.post(this.url.applyBusiness, null, {
params: form,
})
.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
})
.finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped></style>

174
vite-element-template/src/components/activiti/applyList/Preset.vue

@ -0,0 +1,174 @@
<template>
<span>
<el-link type="primary" @click="getNodeData">审批用户</el-link>
<el-dialog
v-el-drag-dialog
title="审批用户"
width="500px"
:visible.sync="showProcessNode"
append-to-body
>
<el-form>
<el-form-item label="提示:" style="color: red"
>所有输入框请只保留一个审批人</el-form-item
>
<el-form-item
v-for="(item, i) in nodeList"
:key="i"
:label="item.title"
>
<el-select v-model="item.userId" multiple style="width: 100%">
<el-option
v-for="v in item.users"
:key="v.id"
:value="v.id"
:label="v.realname"
></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="closeNode"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="confirm">
确定
</el-button>
</div>
</el-dialog>
</span>
</template>
<script>
export default {
props: {
row: {
type: Object,
default: () => ({}),
},
},
data() {
return {
showProcessNode: false,
nodeList: [],
nodeId: "",
loading: false,
url: {
PresetList: "act/zNodePreset/listAll",
add: "act/zNodePreset/add",
edit: "act/zNodePreset/edit",
getNodeData: "/actBusiness/getApprovalUser",
},
PresetList: [],
};
},
methods: {
closeNode() {
this.showProcessNode = false;
},
confirm() {
this.add();
},
handleChange(v, item) {
console.log(v, item);
item.userId = v;
},
add() {
let haveMultiple = false; //
let haveNull = false; //
const data = this.nodeList.map((v) => {
if (!v.userId || v.userId.length === 0) {
haveNull = true;
}
if (v.userId && v.userId.length > 1) {
haveMultiple = true;
}
return {
id: v.PresetId,
businessId: this.row.id,
procDefId: v.procDefId,
nodeId: v.id,
userId: v.userId && v.userId.length === 1 ? v.userId[0] : "",
};
});
if (haveNull) {
this.$message.error("所有节点都需要选择审批人");
return;
}
if (haveMultiple) {
this.$message.error("所有节点只能选择一个审批人");
return;
}
console.log(data);
if (this.PresetList.length) {
this.$axios.put(this.url.edit, data).then((res) => {
if (res.code === 200) {
// this.nodeList = res.data;
this.$message.info(res.message);
} else {
this.$message.error(res.message);
}
this.closeNode();
});
} else {
this.$axios.post(this.url.add, data).then((res) => {
if (res.code === 200) {
// this.nodeList = res.data;
this.$message.info(res.message);
} else {
this.$message.error(res.message);
}
this.closeNode();
});
}
},
async getPresetList() {
const res = await this.$axios.get(this.url.PresetList, {
params: {
businessId: this.row.id,
},
});
if (res.code === 200) {
console.log("获取user");
this.PresetList = res.result;
// this.$message.info(res.message);
}
},
async getNodeData() {
await this.getPresetList();
console.log("获取NodeData");
this.$axios
.get(`${this.url.getNodeData}?id=${this.row.id}`, {
id: this.row.id,
})
.then((res) => {
if (res.success) {
res.result.forEach((v) => {
this.PresetList.forEach((p) => {
if (v.id === p.nodeId) {
v.userId = [p.userId];
v.PresetId = p.id;
}
});
});
res.result.forEach((v) => {
let ids = [];
if (v.users) {
ids = v.users.map((user) => user.id);
}
if (!v.userId) {
v.userId = ids;
}
});
this.nodeList = res.result || [];
console.log("this.nodeList", this.nodeList);
this.showProcessNode = true;
} else {
this.$message.error(res.message);
}
});
},
},
};
</script>
<style></style>

108
vite-element-template/src/components/activiticonfig/ModelList/Add.vue

@ -0,0 +1,108 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="false"
width="500px"
top="5vh"
>
<el-form
v-if="dialogVisible"
ref="editForm"
size="mini"
:rules="rules"
:model="form"
label-position="right"
label-width="100px"
>
<el-form-item label="模型名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="模型描述" prop="description">
<el-input v-model="form.description" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
import { useAppStore } from "@/store";
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
appStore: useAppStore(),
dialogVisible: false,
loading: false,
form: {
id: "",
name: "",
description: "",
},
rules: {
// icon: [{ required: false, message: "", trigger: "blur" }],
name: [{ required: true, message: "名称必填", trigger: "blur" }],
description: [
{ required: true, message: "描述必填", trigger: "change" },
],
},
// componentOptions:[],
};
},
computed: {
showTitle() {
return this.form.id ? "编辑" + this.title : "新增" + this.title;
},
},
methods: {
reset() {
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.dialogVisible = false;
this.$emit("refresh", this.form.name, this.form.description);
});
},
},
};
</script>
<style lang="scss" scoped>
.tips {
font-size: 12px;
}
</style>

105
vite-element-template/src/components/activiticonfig/ModelList/DesignFrame.vue

@ -0,0 +1,105 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="false"
width="90%"
top="20px"
>
<iframe
:src="iframeUrl"
frameborder="0"
width="100%"
height="600px"
scrolling="auto"
style="background-color: #fff"
></iframe>
<!-- <div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div> -->
</el-dialog>
</template>
<script>
import { useAppStore } from "@/store";
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
appStore: useAppStore(),
dialogVisible: false,
loading: false,
iframeUrl: "",
rules: {
// icon: [{ required: false, message: "", trigger: "blur" }],
name: [{ required: true, message: "名称必填", trigger: "blur" }],
},
// componentOptions:[],
};
},
computed: {
showTitle() {
return "编辑";
},
},
methods: {
reset() {
this.form = this.$options.data().form;
},
show(iframeUrl) {
this.reset();
if (iframeUrl) {
this.iframeUrl = iframeUrl;
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
// const url = this.form.id ? this.url.edit : this.url.add;
// this.loading = true;
// this.$axios
// .post(url, this.form)
// .then(({ message }) => {
// this.$message({ type: "info", message: message });
// this.dialogVisible = false;
// this.$emit("refresh");
// })
// .finally(() => {
// this.loading = false;
// });
});
},
},
};
</script>
<style lang="scss" scoped>
.tips {
font-size: 12px;
}
</style>

241
vite-element-template/src/components/activiticonfig/ProcessModelList/Edit.vue

@ -0,0 +1,241 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="false"
width="800px"
top="20px"
>
<el-form
v-if="dialogVisible"
ref="editForm"
size="mini"
:rules="rules"
:model="form"
label-position="right"
label-width="100px"
>
<el-form-item label="流程分类" prop="categoryId">
<el-select
v-model="form.categoryId"
filterable
placeholder="请选择"
style="width: 100%"
clearable
>
<el-option
v-for="item in categoryOptions"
:key="item.itemValue"
:label="item.itemText"
:value="item.itemValue"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="关联表单" prop="routeName">
<el-select
v-model="form.routeName"
filterable
placeholder="请选择"
style="width: 100%"
clearable
@change="changeRouteName"
>
<el-option
v-for="item in activeStore.allFormComponent"
:key="item.routeName"
:label="item.text"
:value="item.routeName"
></el-option>
</el-select>
<span style="cursor: pointer;" @click="viewForm()">预览表单</span>
</el-form-item>
<el-form-item label="角色授权" prop="roles">
<el-select v-model="form.roles" multiple placeholder="请选择">
<el-option
v-for="item in rolesOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="form.sort" :step="1"></el-input-number>
</el-form-item>
<el-form-item label="备注描述" prop="description">
<el-input v-model="form.description" autosize />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
<el-dialog
append-to-body
v-el-drag-dialog
:title="preview.showTitle"
:visible.sync="preview.dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="true"
width="800px"
top="20px"
>
<component :is="preview.formComponent" :disabled="true" isNew></component>
</el-dialog>
</el-dialog>
</template>
<script>
import { useAppStore, useActiveStore } from "@/store";
import qs from "qs";
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
preview: {
dialogVisible: false,
formComponent: null,
showTitle: null,
},
appStore: useAppStore(),
activeStore: useActiveStore(),
dialogVisible: false,
loading: false,
categoryOptions: [],
allFormComponent: [],
rolesOptions: [],
form: {
id: "",
categoryId: "",
routeName: "",
description: "",
sort: 0,
roles: [],
},
rules: {
// icon: [{ required: false, message: "", trigger: "blur" }],
categoryId: [
{ required: true, message: "分类必选", trigger: "change" },
],
routeName: [{ required: true, message: "表单必选", trigger: "change" }],
},
};
},
computed: {
showTitle() {
return this.form.id ? "编辑" + this.title : "新增" + this.title;
},
},
mounted() {
this.getClass();
this.getRoleList();
},
methods: {
reset() {
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
let row = { ...form };
if (row.roles) {
row.roles = row.roles.split(",");
}
this.form = { ...this.$options.data().form, ...row };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
let formData = Object.assign({}, this.form);
if (formData.roles) {
formData.roles = formData.roles.join(",");
}
this.$axios
.post(this.url.updateInfo + "?" + qs.stringify(formData))
.then((res) => {
if (res.success) {
this.$message.info("操作成功");
this.dialogVisible = false;
this.$emit("refresh");
} else {
this.$message.error(res.message);
}
})
.finally(() => (this.confirmLoading = false));
});
},
viewForm() {
if (this.form.routeName) {
var row = this.activeStore.getFormComponent(this.form.routeName);
this.preview.formComponent = row.component;
this.preview.showTitle = row.text;
this.preview.dialogVisible = true;
}
},
changeRouteName(routeName) {
if (!routeName) {
this.form.businessTable = "";
return;
}
console.log("changeRouteName", routeName);
let row = this.activeStore.getFormComponent(routeName);
this.form.businessTable = row.businessTable;
},
//
getRoleList() {
return this.$axios.get("/sys/role/queryall").then((r) => {
this.rolesOptions = r.result.map((v) => {
return {
value: v.roleCode,
label: v.roleName,
};
});
});
},
//
getClass() {
return this.$axios
.get("/sys/dictItem/list", {
params: {
dictId: "d6e1152968b02d69ff358c75b48a6ee1",
},
})
.then((r) => {
this.categoryOptions = r.result.records.map((v) => v);
})
.finally(() => {});
},
},
};
</script>
<style lang="scss" scoped>
.tips {
font-size: 12px;
}
</style>

249
vite-element-template/src/components/activiticonfig/ProcessModelList/EditProcess.vue

@ -0,0 +1,249 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="false"
width="800px"
top="20px"
>
<el-row :gutter="20">
<el-col :span="6" style="height: 100%">
<el-steps direction="vertical" :active="current">
<el-step v-for="(item, i) in nodeList" :key="i" :title="item.title">
<div
slot="title"
style="cursor: pointer"
@click.prevent="setStep(item, i)"
>
{{ item.title }}
</div>
</el-step>
</el-steps>
</el-col>
<el-col :key="current" :span="18">
<el-alert
title="温馨提示:若流程运行至未分配审批人员的审批节点时,流程将自动中断取消!"
type="warning"
/>
<el-form
ref="editForm"
size="mini"
:rules="rules"
:model="editNode"
label-position="right"
label-width="100px"
>
<el-form-item label="节点名称:" prop="title">
{{ editNode.title }}
</el-form-item>
<el-form-item label="节点类型:" prop="type">
{{ dictNodeType[editNode.type] }}
</el-form-item>
<el-alert
title="每个节点设置,如有修改都请保存一次,跳转节点后数据不会自动保存!"
type="warning"
/>
<el-form-item
v-if="editNode.type == 1"
label="角色授权:"
prop="roleIds"
>
<el-select
v-model="editNode.roleIds"
multiple
placeholder="请选择"
style="width: 100%"
>
<el-option
v-for="item in rolesOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-col>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button
v-if="editNode.type !== 0 && editNode.type != 2"
type="primary"
:loading="loading"
@click="onSubmit"
>
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
import { useAppStore, useActiveStore } from "@/store";
import qs from "qs";
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
appStore: useAppStore(),
activeStore: useActiveStore(),
dialogVisible: false,
loading: false,
nodeList: [],
current: 0,
editNode: {
id: "",
procDefId: "",
title: "",
type: 0,
roleIds: [],
},
rolesOptions: [],
parentRow: {},
rules: {
// icon: [{ required: false, message: "", trigger: "blur" }],
roleIds: [{ required: true, message: "角色必选", trigger: "change" }],
},
dictNodeType: {
0: "开始节点",
1: "审批节点",
2: "结束节点",
},
};
},
computed: {
showTitle() {
return this.parentRow.id ? "编辑" + this.title : "新增" + this.title;
},
},
mounted() {
this.getRoleList();
},
methods: {
reset() {
this.editNode= this.$options.data().editNode;
this.parentRow = this.$options.data().parentRow;
},
show(row) {
this.reset();
if (row) {
this.parentRow = { ...this.$options.data().parentRow, ...row };
this.getNodeData(this.parentRow);
}
this.dialogVisible = true;
},
//
getNodeData(row) {
this.$axios
.post(this.url.getProcessNode + `?id=${row.id}`, {
id: row.id,
})
.then((res) => {
if (res.success) {
// null""
let nodeList = res.result || [];
if (nodeList.length > 0) {
nodeList.forEach((v) => {
if (v.roles) {
v.roleIds = v.roles.map((v) => v.roleCode);
} else {
v.roleIds = [];
}
});
this.nodeList = nodeList;
this.setStep(this.nodeList[0], 0);
} else {
this.nodeList = [];
}
} else {
this.nodeList = [];
this.$message.error(res.message);
}
});
},
setStep(node, i) {
console.log("setStep", node, i);
this.editNode = node;
this.current = i;
},
//
getRoleList() {
return this.$axios.get("/sys/role/queryall").then((r) => {
this.rolesOptions = r.result.map((v) => {
return {
value: v.roleCode,
label: v.roleName,
};
});
});
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
var send = {
nodeId: this.editNode.id,
procDefId: this.editNode.procDefId,
chooseDepHeader: "",
chooseSponsor: "",
userIds: "",
departmentIds: "",
departmentManageIds: "",
formVariables: "",
formVariable: "",
// roleIds: this.editNode.roleIds.join(","),
};
if (this.editNode.roleIds.length) {
send.roleIds = this.editNode.roleIds.join(",");
}
this.$axios
.post(this.url.editNodeUser + "?" + qs.stringify(send))
.then((res) => {
if (res.success) {
this.$message.info("操作成功");
/*保存成功后回显数据*/
this.getNodeData(this.parentRow);
} else {
this.$message.error(res.message);
}
})
.finally(() => (this.loading = false));
});
},
},
};
</script>
<style lang="scss" scoped>
.tips {
font-size: 12px;
}
</style>

113
vite-element-template/src/components/activiticonfig/ProcessModelList/ViewForm.vue

@ -0,0 +1,113 @@
<template>
<div>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
append-to-body
:title="preview.title"
:visible.sync="dialogVisible"
:destroy-on-close="true"
:close-on-click-modal="false"
width="800px"
>
<component
:is="preview.formComponent"
v-if="preview.formComponent"
:disabled="preview.disabled"
:is-new="preview.isNew"
:task="preview.isTask"
:process-data="preview.processData"
@onSave="onSave"
@passTask="passTask"
@backTask="backTask"
@close="close"
></component>
</el-dialog>
<ExamineAndApprove ref="ExamineAndApprove" :url="url" @refresh="refresh" @close="close"></ExamineAndApprove>
</div>
</template>
<script>
import { useActiveStore } from "@/store";
import ExamineAndApprove from "@/components/activiti/ExamineAndApprove.vue";
export default {
name: "ViewForm",
components: { ExamineAndApprove },
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
},
emits:["refresh","close"],
data() {
return {
activeStore: useActiveStore(),
dialogVisible: false,
preview: {
formComponent: null,
title: null,
isNew: false,
isTask: false,
processData: null,
},
};
},
methods: {
reset() {
this.preview = this.$options.data().preview;
},
/**
* 显示表单
* @param {Object} preview
* @param {String} preview.routeName 表单组件名称
* @param {String} preview.title 表单标题
* @param {Boolean} preview.isNew 是否是新增
*/
show(preview = {}) {
this.reset();
if (!preview.routeName) {
return;
}
var formComponent = this.activeStore.getFormComponent(preview.routeName);
if (!formComponent) {
this.$message.error("表单组件不存在");
return;
}
this.preview = {
...this.preview,
...preview,
formComponent: formComponent.component,
};
this.dialogVisible = true;
},
onSave() {
this.close();
this.$emit("refresh");
},
passTask() {
// this.close();
console.log("pass");
this.$refs.ExamineAndApprove.passTask(this.preview.processData);
},
backTask() {
this.$refs.ExamineAndApprove.backTask(this.preview.processData);
// this.close();
},
refresh(){
this.$emit("refresh");
},
close() {
this.dialogVisible = false;
this.reset();
this.$emit("close");
},
},
};
</script>

198
vite-element-template/src/components/activiticonfig/form/leaveForm.vue

@ -0,0 +1,198 @@
<template>
<!--流程业务表单-->
<div class="form-main">
<el-card :bordered="false">
<el-form ref="editForm" :model="form" @submit="handleSubmit">
<el-form-item label="年度">
<el-input
v-model="form.annual"
:disabled="disabled"
placeholder="请输入年度"
/>
</el-form-item>
<el-form-item label="组织">
<SelectDepart v-model="form.departId" :disabled="!form.id"></SelectDepart>
</el-form-item>
<el-form-item label="请假事由">
<el-input
v-model="form.name"
:disabled="disabled"
placeholder="请输入请假事由"
/>
</el-form-item>
<el-form-item label="catalogId">
<el-input
v-model="form.catalogId"
:disabled="disabled"
placeholder="请输入catalog_id"
/>
</el-form-item>
<el-form-item v-if="!disabled" style="text-align: center">
<el-button
type="primary"
:disabled="disabled || btndisabled"
@click="handleSubmit"
>保存</el-button
>
<el-button
style="margin-left: 8px"
:disabled="disabled"
@click="close"
>取消</el-button
>
</el-form-item>
<el-form-item v-if="task" style="text-align: center">
<el-button type="primary" @click="passTask">通过</el-button>
<el-button style="margin-left: 8px" @click="backTask">驳回</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import qs from "qs";
import SelectDepart from "@/components/sys/depart/SelectDepart.vue";
export default {
name: "LeaveForm",
components: {
SelectDepart,
},
props: {
/* 全局禁用,可表示查看 */
disabled: {
type: Boolean,
default: false,
required: false,
},
/* 流程数据 */
processData: {
type: Object,
default: () => ({}),
required: false,
},
/* 是否新增 */
isNew: { type: Boolean, default: false, required: false },
/* 是否处理流程 */
task: { type: Boolean, default: false, required: false },
},
emits: ["onSave", "close", "passTask", "backTask"],
data() {
return {
url: {
getForm: "/actBusiness/getForm",
addApply: "/actBusiness/add",
editForm: "/actBusiness/editForm",
},
// form
form: {
// id: "",
departId: [],
annual: "",
name: "",
catalogId: "",
},
/* 表单回显数据 */
data: {},
btndisabled: false,
departList: [],
};
},
created() {
console.log("流程数据", this.processData);
if (!this.isNew) {
this.init();
}
},
methods: {
/* 回显数据 */
init() {
this.btndisabled = true;
const r = this.processData;
this.$axios
.get(this.url.getForm, {
params: {
tableId: r.tableId,
tableName: r.tableName,
},
})
.then((res) => {
if (res.success) {
const formData = res.result;
formData.tableName = r.tableName;
this.data = formData;
console.log("表单回显数据", this.data);
this.$nextTick(() => {
this.form = {
name: this.data.name,
departId: String(this.data.departId).split(","),
catalogId: this.data.catalogId,
annual: this.data.annual,
};
});
this.btndisabled = false;
} else {
this.$message.error(res.message);
}
});
},
// handler
handleSubmit(e) {
e.preventDefault();
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
const formData = Object.assign(this.data || {}, this.form);
formData.procDefId = this.processData.id;
formData.procDeTitle = this.processData.name;
if (formData.departId) {
formData.departId = formData.departId.join(",");
}
if (!formData.tableName) {
formData.tableName = this.processData.businessTable;
}
formData.filedNames = Object.keys(this.form).join(",");
console.log("formData", this.form);
let url = this.url.addApply;
if (!this.isNew) {
url = this.url.editForm;
}
this.btndisabled = true;
this.$axios
.post(url + "?" + qs.stringify(formData))
.then((res) => {
if (res.success) {
this.$message.success("保存成功!");
// todo
this.$emit("onSave", formData);
} else {
this.$message.error(res.message);
}
})
.finally(() => {
this.btndisabled = false;
});
});
},
close() {
// todo
this.$emit("close");
},
/* 通过审批 */
passTask() {
this.$emit("passTask");
},
/* 驳回审批 */
backTask() {
this.$emit("backTask");
},
},
};
</script>

16
vite-element-template/src/components/common/Breadcrumb/index.vue

@ -44,13 +44,27 @@ export default {
let matched = this.$route.matched.filter(
(item) => item.meta && item.meta.title
)
// const first = matched[0]
// if (!this.isDashboard(first)) {
// matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(
// matched
// )
// }
this.levelList = matched.filter(
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
)
},
// isDashboard(route) {
// const name = route && route.name
// if (!name) {
// return false
// }
// return (
// name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
// )
// },
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route

44
vite-element-template/src/components/common/Hamburger/index.vue

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

187
vite-element-template/src/components/common/Pagination/index.vue

@ -0,0 +1,187 @@
<template>
<div :class="{'hidden':hidden}" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to.js'
export default {
name: 'Pagination',
props: {
total: {
required: true,
type: Number
},
page: {
type: Number,
default: 1
},
limit: {
type: Number,
default: 10
},
pageSizes: {
type: Array,
default() {
return [5,10, 20, 30, 50,100,200]
}
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true
},
autoScroll: {
type: Boolean,
default: true
},
hidden: {
type: Boolean,
default: false
}
},
computed: {
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style lang="scss" scoped>
/* 自定义滚动条样式 */
:deep(*) {
/* 整个滚动条 */
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
background: rgba(15, 12, 97, 0.2);
border-radius: 4px;
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(75, 72, 178, 0.6);
border-radius: 4px;
&:hover {
background: rgba(75, 72, 178, 0.8);
}
}
/* 滚动条边角 */
&::-webkit-scrollbar-corner {
background: rgba(15, 12, 97, 0.2);
}
}
.pagination-container {
background: transparent;
padding: 15px 0;
text-align: right;
&.hidden {
display: none;
}
:deep(.el-pagination) {
color: #c0c4cc;
.btn-prev,
.btn-next {
background-color: rgba(25, 22, 104, 0.7);
color: #c0c4cc;
&:disabled {
background-color: rgba(25, 22, 104, 0.4);
color: rgba(192, 196, 204, 0.5);
}
}
.el-pager li {
background-color: rgba(25, 22, 104, 0.7);
color: #c0c4cc;
&.active {
background-color: #1976d2;
color: #ffffff;
}
&:hover {
color: #64b5f6;
}
}
.el-pagination__total,
.el-pagination__jump {
color: #c0c4cc;
}
.el-pagination__sizes {
.el-input {
.el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #c0c4cc;
}
}
}
.el-pagination__editor {
&.el-input {
.el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #c0c4cc;
}
}
}
}
}
</style>

30
vite-element-template/src/components/common/SvgIcon/AnyIcon.vue

@ -0,0 +1,30 @@
<template>
<i v-if="isElIcon" :class="[icon, className]" ></i>
<svg-icon v-else :icon-class="icon" :class-name="className" />
</template>
<script>
export default {
name: "AnyIcons",
props: {
icon: {
type: String,
default: "",
},
className: {
type: String,
default: "",
},
},
computed: {
isElIcon() {
return this.icon.indexOf("el-icon-") == 0;
},
},
};
</script>
<style lang="scss" scoped></style>

62
vite-element-template/src/components/common/SvgIcon/index.vue

@ -0,0 +1,62 @@
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover!important;
display: inline-block;
}
</style>

886
vite-element-template/src/components/common/player.vue

@ -0,0 +1,886 @@
<template>
<div
ref="container" class="container"
style="width: 100%; height: 100%; background-color: #000000; margin: 0 auto" @dblclick="fullscreenSwich">
<div id="buttonsBox" class="buttons-box">
<div class="buttons-box-left">
<i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
<i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
<i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i>
</div>
<div class="buttons-box-right">
<i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
</div>
</div>
<div v-if="ptzControl" class="ptzControl" @dblclick.stop>
<div class="control-wrapper">
<template>
<div
ref="tooltipWrap" class="control-btn control-top" @mousedown="ptzCamera('up')"
@mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="向上移动" placement="top-start">
<i class="el-icon-caret-top"></i>
</el-tooltip>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-left" @mousedown="ptzCamera('left')" @mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="向左移动" placement="left-start">
<i class="el-icon-caret-left"></i>
</el-tooltip>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-bottom" @mousedown="ptzCamera('down')" @mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="向下移动" placement="bottom-start">
<i class="el-icon-caret-bottom"></i>
</el-tooltip>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-right" @mousedown="ptzCamera('right')" @mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="向右移动" placement="right-start">
<i class="el-icon-caret-right"></i>
</el-tooltip>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-round">
<div class="control-round-inner">
<i class="fa fa-pause-circle"></i>
</div>
</div>
</template>
<div
style="position: absolute; left: 8.25rem; top: 0rem; color: #78aee4" @mousedown="ptzCamera('zoomin')"
@mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="放大" placement="right">
<i class="el-icon-zoom-in control-zoom-btn" style="font-size: 1.875rem"></i>
</el-tooltip>
</div>
<div
style="position: absolute; left: 8.25rem; top: 4rem; font-size: 1.875rem; color: #78aee4"
@mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')">
<el-tooltip class="item" effect="dark" content="缩小" placement="right">
<i class="el-icon-zoom-out control-zoom-btn"></i>
</el-tooltip>
</div>
<el-tooltip class="item" effect="dark" content="移动速度控制" placement="top">
<div class="contro-speed" style="position: absolute; left: 100px; top: 0rem; width: 1rem; height: 7rem">
<el-slider v-model="controSpeed" vertical height="6rem" :max="100" type="vertical"></el-slider>
</div>
</el-tooltip>
</div>
</div>
</div>
</template>
<script>
import { setChannelPTZ } from "@/api/video.js";
function getCurrentIPAndPortOrDomain() {
var ipAndPort = "";
// 80443 URL
if (window.location.port === "80" || window.location.port === "443") {
ipAndPort = window.location.hostname;
} else {
ipAndPort = window.location.hostname + ":" + window.location.port;
}
return ipAndPort;
}
let jessibucaPlayer = {};
export default {
name: "Player",
props: {
video: {
type: Object,
default: () => ({}),
},
},
data() {
return {
playing: false,
fullscreen: false,
loaded: false,
speed: 0,
performance: "", //
videoUrl: "",
btnDom: null,
volume: 1,
rotate: 0,
ptzControl: false,
forceNoOffscreen: false,
controSpeed: 30,
};
},
watch: {
video: {
handler(val) {
if (val.deviceId) {
this.$nextTick(() => {
this.play();
});
}
},
deep: true,
},
},
mounted() {
this.$nextTick(() => {
this.updatePlayerDomSize();
window.onresize = () => {
this.updatePlayerDomSize();
};
this.btnDom = document.getElementById("buttonsBox");
this.play();
});
},
async destroyed() {
if (jessibucaPlayer[this._uid]) {
await jessibucaPlayer[this._uid].destroy();
}
this.playing = false;
this.loaded = false;
this.performance = "";
},
methods: {
updatePlayerDomSize() {
let dom = this.$refs.container;
let width = dom.parentNode.clientWidth;
let height = (9 / 16) * width;
const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight);
if (height > clientHeight) {
height = clientHeight;
width = (16 / 9) * height;
}
dom.style.width = width + "px";
dom.style.height = height + "px";
},
create() {
this._uid = this.video.deviceId;
let options = {};
jessibucaPlayer[this._uid] = new window.Jessibuca(
Object.assign(
{
container: this.$refs.container,
videoBuffer: 0.2, //
isResize: true,
decoder: "./js/jessibuca/decoder.js",
useWCS: false,
useMSE: false,
autoWasm: true, //
useSIMD: true,
showBandwidth: false,
isFlv: true,
loadingText: "",
debug: false,
supportDblclickFullscreen: false, //
operateBtns: {
fullscreen: false,
screenshot: false,
play: false,
audio: false,
recorder: false,
},
record: "record",
vod: true,
forceNoOffscreen: true,
isNotMute: false,
timeout: 10,
},
options
)
);
let jessibuca = jessibucaPlayer[this._uid];
jessibuca.on("error", async (err) => {
console.log(err);
await this.destroy();
this.play();
});
jessibuca.on("timeout", async (err) => {
console.log(err);
await this.destroy();
this.play();
});
},
playBtnClick() {
this.play();
},
async play() {
const ipAndPort = getCurrentIPAndPortOrDomain();
// 使
this.videoUrl = "ws://" + ipAndPort + "/play/" + this.video.deviceId + '_' + this.video.channelId + ".live.flv";
this.create();
jessibucaPlayer[this._uid].on("play", () => {
this.playing = true;
this.loaded = true;
});
if (jessibucaPlayer[this._uid].hasLoaded()) {
jessibucaPlayer[this._uid].play(this.videoUrl);
} else {
jessibucaPlayer[this._uid].on("load", () => {
jessibucaPlayer[this._uid].play(this.videoUrl);
});
}
},
pause() {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].pause();
}
this.playing = false;
this.err = "";
this.performance = "";
},
async destroy() {
if (jessibucaPlayer[this._uid]) {
await jessibucaPlayer[this._uid].destroy();
}
if (document.getElementById("buttonsBox") == null) {
this.$refs.container.appendChild(this.btnDom);
}
jessibucaPlayer[this._uid] = null;
this.playing = false;
this.err = "";
this.performance = "";
},
fullscreenSwich() {
let isFull = this.isFullscreen();
jessibucaPlayer[this._uid].setFullscreen(!isFull);
this.fullscreen = !isFull;
this.ptzControl = false;
if (isFull) {
this.$emit('outFullscreen', this.index);
}
},
isFullscreen() {
return (
document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement ||
false
);
},
changePTZControl() {
this.ptzControl = !this.ptzControl;
},
ptzCamera(command) {
if (this.isEzvizDevice) {
//
setChannelPTZ({
deviceType: 'ezviz',
accessToken: this.accessToken,
deviceSerial: this.deviceSerial,
direction: command,
speed: this.controSpeed
});
} else {
//
setChannelPTZ({
cameraIp: this.video.ip,
direction: command,
speed: this.controSpeed,
});
}
},
},
};
</script>
<style>
.jessibuca-btn {
width: 20px;
color: rgb(255, 255, 255);
line-height: 27px;
margin: 0px 10px;
padding: 0px 2px;
cursor: pointer;
text-align: center;
font-size: 0.8rem !important;
}
.buttons-box-right {
position: absolute;
right: 0;
}
.container {
width: 100%;
height: 100%;
.buttons-box {
width: 100%;
height: 28px;
position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
left: 0;
bottom: 0;
user-select: none;
z-index: 10;
overflow: hidden;
}
}
.turn-left {
position: absolute;
left: 0;
top: 10%;
width: 10%;
height: 80%;
cursor: pointer;
z-index: 999;
background-color: transparent;
/* 初始背景色为透明 */
transition: background-color 0.3s ease;
/* 平滑的过渡效果 */
overflow: hidden;
/* 隐藏超出部分 */
}
.turn-left::after {
content: "";
/* 伪元素需要content属性 */
border: 10px solid transparent;
/* 创建箭头形状 */
border-right-color: transparent;
/* 初始状态透明 */
position: absolute;
left: 50%;
/* 位置调整到正中 */
top: 50%;
/* 位置调整到正中 */
transform: translate(-50%, -50%) rotate(180deg);
/* 精确居中调整 */
transition: border-right-color 0.3s;
/* 箭头颜色渐变 */
}
.turn-left:hover {
background-color: rgba(255, 255, 255, 0.5);
}
.turn-left:hover::after {
border-left-color: black;
/* 悬停时显示箭头 */
}
.turn-right {
position: absolute;
right: 0;
top: 10%;
width: 10%;
height: 80%;
background-color: transparent;
/* 初始背景色为透明 */
transition: background-color 0.3s ease;
/* 平滑的过渡效果 */
cursor: pointer;
z-index: 999;
}
.turn-right::after {
content: "";
/* 伪元素需要content属性 */
border: 10px solid transparent;
/* 创建箭头形状 */
border-left-color: transparent;
/* 初始状态透明 */
position: absolute;
right: 50%;
/* 位置调整到正中 */
top: 50%;
/* 位置调整到正中 */
transform: translate(50%, -50%);
/* 精确居中调整 */
transition: border-left-color 0.3s;
/* 箭头颜色渐变 */
}
.turn-right:hover {
background-color: rgba(255, 255, 255, 0.5);
}
.turn-right:hover::after {
border-left-color: black;
/* 悬停时显示箭头 */
}
.control-btn {
display: flex;
justify-content: center;
position: absolute;
width: 44%;
height: 44%;
border-radius: 5px;
border: 1px solid #78aee4;
box-sizing: border-box;
transition: all 0.3s linear;
}
.control-btn:hover {
cursor: pointer;
}
.control-btn i {
font-size: 20px;
color: #78aee4;
display: flex;
justify-content: center;
align-items: center;
}
.control-btn i:hover {
cursor: pointer;
}
.control-wrapper {
/* background-color: #fff; */
position: relative;
width: 6.25rem;
height: 6.25rem;
max-width: 6.25rem;
max-height: 6.25rem;
border-radius: 100%;
margin-top: 1.5rem;
margin-left: 0.5rem;
float: left;
}
.ptzControl {
position: absolute;
bottom: 10%;
left: 10%;
width: 100%;
height: 30%;
background-color: rgba(0, 0, 0, 0);
display: flex;
/* justify-content: center; */
align-items: center;
z-index: 999;
}
.control-wrapper {
position: relative;
width: 6.25rem;
height: 6.25rem;
max-width: 6.25rem;
max-height: 6.25rem;
border-radius: 100%;
margin-top: 1.5rem;
margin-left: 0.5rem;
float: left;
}
.control-panel {
position: relative;
top: 0;
left: 5rem;
height: 11rem;
max-height: 11rem;
}
.control-btn {
display: flex;
justify-content: center;
position: absolute;
width: 44%;
height: 44%;
border-radius: 5px;
border: 1px solid #78aee4;
box-sizing: border-box;
transition: all 0.3s linear;
}
.control-btn:hover {
cursor: pointer;
}
.control-btn i {
font-size: 20px;
color: #78aee4;
display: flex;
justify-content: center;
align-items: center;
}
.control-btn i:hover {
cursor: pointer;
}
.control-zoom-btn:hover {
cursor: pointer;
}
.control-round {
position: absolute;
top: 21%;
left: 21%;
width: 58%;
height: 58%;
/* background: #fff; */
border-radius: 100%;
}
.control-round-inner {
position: absolute;
left: 13%;
top: 13%;
display: flex;
justify-content: center;
align-items: center;
width: 70%;
height: 70%;
font-size: 40px;
color: #78aee4;
border: 1px solid #78aee4;
border-radius: 100%;
transition: all 0.3s linear;
}
.control-inner-btn {
position: absolute;
width: 60%;
height: 60%;
background: rgba(0, 0, 0, 0);
visibility: hidden;
}
.control-top {
top: -8%;
left: 27%;
transform: rotate(-45deg);
border-radius: 5px 100% 5px 0;
}
.control-top i {
transform: rotate(45deg);
border-radius: 5px 100% 5px 0;
}
.control-top .control-inner {
left: -1px;
bottom: 0;
border-top: 1px solid #78aee4;
border-right: 1px solid #78aee4;
border-radius: 0 100% 0 0;
}
.control-top .fa {
transform: rotate(45deg) translateY(-7px);
}
.control-left {
top: 27%;
left: -8%;
transform: rotate(45deg);
border-radius: 5px 0 5px 100%;
}
.control-left i {
transform: rotate(-45deg);
}
.control-left .control-inner {
right: -1px;
top: -1px;
border-bottom: 1px solid #78aee4;
border-left: 1px solid #78aee4;
border-radius: 0 0 0 100%;
}
.control-left .fa {
transform: rotate(-45deg) translateX(-7px);
}
.control-right {
top: 27%;
right: -8%;
transform: rotate(45deg);
border-radius: 5px 100% 5px 0;
}
.control-right i {
transform: rotate(-45deg);
}
.control-right .control-inner {
left: -1px;
bottom: -1px;
border-top: 1px solid #78aee4;
border-right: 1px solid #78aee4;
border-radius: 0 100% 0 0;
}
.control-right .fa {
transform: rotate(-45deg) translateX(7px);
}
.control-bottom {
left: 27%;
bottom: -8%;
transform: rotate(45deg);
border-radius: 0 5px 100% 5px;
}
.control-bottom i {
transform: rotate(-45deg);
}
.control-bottom .control-inner {
top: -1px;
left: -1px;
border-bottom: 1px solid #78aee4;
border-right: 1px solid #78aee4;
border-radius: 0 0 100% 0;
}
.control-bottom .fa {
transform: rotate(-45deg) translateY(7px);
}
.trank {
width: 80%;
height: 180px;
text-align: left;
padding: 0 10%;
overflow: auto;
}
.trankInfo {
width: 80%;
padding: 0 10%;
}
.location {
position: absolute;
display: flex;
width: 100%;
text-align: center;
align-items: center;
justify-content: center;
top: 0;
left: 0;
color: #fff;
font-size: 1rem;
padding: 0.5rem;
background-color: rgba(0, 0, 0, 0.1);
z-index: 999;
.cruise-name {
flex: 1;
}
.current-cruise {
color: #fff;
background-color: rgb(255, 234, 0);
}
.past-cruise {
color: #fff;
background-color: rgba(73, 196, 77, 0.5);
}
.future-cruise {
color: #fff;
background-color: rgba(255, 255, 255, 0.3);
}
}
.cruise {
position: absolute;
bottom: 30px;
right: 10px;
color: #fff;
font-size: 1rem;
padding: 0.5rem;
z-index: 999;
}
.report {
position: absolute;
z-index: 9;
right: 30px;
bottom: 30px;
color: #fff;
}
.rules {
border: 1px solid #78aee4;
padding: 10px;
position: absolute;
z-index: 999;
right: 30px;
top: 60px;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
}
.undoTask {
position: absolute;
z-index: 99999;
right: 140px;
bottom: 160px;
background-color: rgba(0, 0, 0, 0.7);
width: 300px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
transition: all 0.3s ease;
border: 1px solid rgba(120, 174, 228, 0.5);
overflow: hidden;
.undoTask-header {
padding: 8px 12px;
background-color: rgba(120, 174, 228, 0.2);
color: #fff;
font-size: 14px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(120, 174, 228, 0.3);
&:hover {
background-color: rgba(120, 174, 228, 0.3);
}
i {
font-size: 16px;
transition: transform 0.3s;
}
}
.undoTask-content {
max-height: 250px;
overflow-y: auto;
/* 自定义滚动条样式 */
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: rgba(120, 174, 228, 0.7);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(120, 174, 228, 1);
}
}
.undoTask-item {
border-bottom: 1px solid rgba(120, 174, 228, 0.2);
padding: 8px 0;
&:last-child {
border-bottom: none;
}
}
.undoTask-item-title {
display: flex;
align-items: center;
padding: 4px 12px;
color: #fff;
font-size: 13px;
}
.undoTask-item-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 12px 4px;
font-size: 12px;
}
.undoTask-time {
color: #bbb;
}
.undoTask-status {
padding: 1px 6px;
border-radius: 10px;
font-size: 11px;
&.status-pending {
background-color: #E6A23C;
color: #fff;
}
&.status-processing {
background-color: #409EFF;
color: #fff;
}
}
.undoTask-empty {
padding: 20px;
text-align: center;
color: #999;
font-size: 14px;
}
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s, max-height 0.3s ease;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
max-height: 0;
}
.popper-class-top {
color: red !important;
transform: rotate(45deg);
}
.fullscreen-loading {
z-index: 9999999 !important;
}
.fullscreen-loading .el-loading-mask {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
}
/* 自定义loading样式 */
.custom-loading-mask {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 999999999;
}
.custom-loading-spinner {
text-align: center;
}
.custom-loading-spinner i {
color: #fff;
font-size: 32px;
}
.custom-loading-text {
color: #fff;
margin-top: 10px;
font-size: 14px;
}
</style>

126
vite-element-template/src/components/dust/design/plan/DesignPlanEdit.vue

@ -1,126 +0,0 @@
<template>
<el-dialog :close-on-click-modal="false" v-if="dialogVisible" v-el-drag-dialog :title="showTitle" :visible.sync="dialogVisible">
<el-form v-if="dialogVisible" ref="editForm" :rules="rules" size="mini" :model="form" label-position="right"
label-width="100px">
<el-form-item label="方案名称" prop="name">
<el-input v-model="form.name" type="text" />
</el-form-item>
<el-form-item label="管径配置" prop="pipeDiameterId">
<el-select v-model="form.pipeDiameterId" placeholder="请选择">
<el-option v-for="item in options.pipeDiameterConfigOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" type="text" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="text" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id: "",
name: "",
totalFlow: "",
sortOrder: "",
remark: "",
delFlag: "",
createBy: "",
createTime: "",
updateBy: "",
updateTime: "",
},
rules: {
name: [
{ required: true, message: "请输入方案名称", trigger: "blur" },
{ min: 1, max: 50, message: "长度在 1 到 50 个字符", trigger: "blur" },
],
pipeDiameterId: [
{ required: true, message: "请选择管径配置", trigger: "blur" },
],
},
editType: "add", //addedit
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped></style>

169
vite-element-template/src/components/dust/monitor/DustMonitorItemEdit.vue

@ -1,169 +0,0 @@
<template>
<el-dialog v-if="dialogVisible" v-el-drag-dialog :title="showTitle" :visible.sync="dialogVisible">
<el-form v-if="dialogVisible" ref="editForm" size="mini" :model="form" label-position="right" label-width="100px"
:rules="rules">
<el-form-item label="所属系统" prop="systemId">
<el-select v-model="form.systemId" placeholder="请选择所属系统">
<el-option v-for="item in options.systemOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="除尘器进口压力" prop="inletPressureDataTagId">
<el-select v-model="form.inletPressureDataTagId" placeholder="请选择除尘器进口压力">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="除尘器出口压力" prop="outletPressureDataTagId">
<el-select v-model="form.outletPressureDataTagId" placeholder="请选择除尘器出口压力">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="风机速度" prop="fanSpeedDataTagId">
<el-select v-model="form.fanSpeedDataTagId" placeholder="请选择风机速度">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="电机电流" prop="motorCurrentDataTagId">
<el-select v-model="form.motorCurrentDataTagId" placeholder="请选择电机电流">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="烟囱CEMS风量" prop="cemsAirVolumeDataTagId">
<el-select v-model="form.cemsAirVolumeDataTagId" placeholder="请选择烟囱CEMS风量">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="粉尘浓度" prop="dustConcentrationDataTagId">
<el-select v-model="form.dustConcentrationDataTagId" placeholder="请选择粉尘浓度">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="风机运行状态" prop="fanStatusDataTagId">
<el-select v-model="form.fanStatusDataTagId" placeholder="请选择风机运行状态">
<el-option v-for="item in options.allTagOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" type="number" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="text" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
systemId: "",
inletPressureDataTagId: "",
outletPressureDataTagId: "",
fanSpeedDataTagId: "",
motorCurrentDataTagId: "",
cemsAirVolumeDataTagId: "",
dustConcentrationDataTagId: "",
fanStatusDataTagId: "",
sortOrder: "",
remark: "",
createTime: "",
createBy: "",
updateTime: "",
updateBy: "",
},
rules: {
systemId: [{ required: true, message: "请选择所属系统", trigger: "blur" }],
inletPressureDataTagId: [{ required: true, message: "请选择除尘器进口压力", trigger: "blur" }],
outletPressureDataTagId: [{ required: true, message: "请选择除尘器出口压力", trigger: "blur" }],
fanSpeedDataTagId: [{ required: true, message: "请选择风机速度", trigger: "blur" }],
motorCurrentDataTagId: [{ required: true, message: "请选择电机电流", trigger: "blur" }],
cemsAirVolumeDataTagId: [{ required: true, message: "请选择烟囱CEMS风量", trigger: "blur" }],
dustConcentrationDataTagId: [{ required: true, message: "请选择粉尘浓度", trigger: "blur" }],
fanStatusDataTagId: [{ required: true, message: "请选择风机运行状态", trigger: "blur" }],
},
editType: "add", //addedit
};
},
computed: {
showTitle() {
return this.editType == 'edit' ? "编辑" + this.title : "新增" + this.title;
},
},
methods: {
reset() {
this.editType = 'add'
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = 'edit'
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == 'edit') {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped></style>

106
vite-element-template/src/components/dust/monitor/DustSystemEdit.vue

@ -1,106 +0,0 @@
<template>
<el-dialog v-if="dialogVisible" v-el-drag-dialog :title="showTitle" :visible.sync="dialogVisible">
<el-form v-if="dialogVisible" ref="editForm" size="mini" :model="form" label-position="right" label-width="100px">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" type="text" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" type="text" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="text" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
name: "",
sortOrder: "",
remark: "",
createTime: "",
createBy: "",
updateTime: "",
updateBy: "",
},
editType: "add", //addedit
};
},
computed: {
showTitle() {
return this.editType == 'edit' ? "编辑" + this.title : "新增" + this.title;
},
},
methods: {
reset() {
this.editType = 'add'
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = 'edit'
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == 'edit') {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped></style>

281
vite-element-template/src/components/dust/monitor/monitor-chart2.vue

@ -1,281 +0,0 @@
<template>
<div class="monitor-chart2">
<!-- 旁通阀 -->
<div class="bypass-valve">
<div class="valve-container">
<div class="valve-label">旁通阀</div>
<div class="valve-icon green">
<img :src="openStatus[0] ? valveOpen : valveClose" />
</div>
</div>
</div>
<div class="dashed-line horizontal-line top-line"></div>
<!-- 入口阀门 -->
<div class="entry-valve">
<div class="text-box">副原料除尘</div>
<div class="valve-container">
<div class="valve-label">入口阀门</div>
<div class="valve-icon green">
<img :src="openStatus[1] ? valveOpen : valveClose" />
</div>
</div>
</div>
<div class="dashed-line horizontal-line bottom-line"></div>
<!-- 垂直连接线 -->
<div class="dashed-line vertical-line"></div>
</div>
</template>
<script>
import valveOpen from '@/assets/monitor/valve-open.svg'
import valveClose from '@/assets/monitor/valve-close.svg'
export default {
name: 'MonitorChart2',
props: {
openStatus: {
type: Array,
default: () => []
}
},
data() {
return {
valveOpen,
valveClose
}
}
}
</script>
<style scoped>
.monitor-chart2 {
width: 100%;
height: 100%;
position: relative;
padding: 2%;
box-sizing: border-box;
min-height: 350px;
}
.bypass-valve {
position: absolute;
top: 15%;
right: 15%;
display: flex;
flex-direction: column;
align-items: center;
z-index: 3;
transition: all 0.3s ease;
}
.bypass-valve:hover {
transform: translateY(-3px);
}
.entry-valve {
position: absolute;
bottom: 30%;
left: 5%;
display: flex;
align-items: center;
z-index: 3;
transition: all 0.3s ease;
}
.entry-valve:hover {
transform: translateX(3px);
}
.text-box {
background-color: #f0f0f8;
color: #1a237e;
padding: 2% 3%;
border-radius: 4px;
font-weight: bold;
font-size: 0.9rem;
margin-right: 8%;
min-width: 150px;
max-width: 180px;
text-align: center;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.text-box:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
background-color: #e8e8f5;
}
.valve-container {
display: flex;
flex-direction: column;
align-items: center;
}
.valve-icon {
width: 3.5rem;
height: 3.5rem;
max-width: 60px;
max-height: 60px;
z-index: 5;
padding: 3px;
background-color: #1d2061;
border-radius: 50%;
transition: all 0.3s ease;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
position: relative;
overflow: hidden;
}
.valve-icon:hover {
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.valve-icon::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 70%);
opacity: 0;
transition: opacity 0.3s ease;
}
.valve-icon:hover::after {
opacity: 1;
}
.valve-icon img {
width: 100%;
height: 100%;
transition: transform 0.5s ease, filter 0.5s ease;
}
.green img {
filter: brightness(1.2) drop-shadow(0 0 3px rgba(0, 255, 0, 0.5));
}
.red img {
filter: hue-rotate(180deg) drop-shadow(0 0 3px rgba(255, 0, 0, 0.5));
}
.valve-label {
color: white;
font-size: 0.85rem;
margin-bottom: 5px;
text-align: center;
transition: all 0.3s ease;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.valve-icon:hover + .valve-label,
.valve-label:hover {
transform: scale(1.05);
color: #a5c7fe;
}
.dashed-line {
position: absolute;
border: 2px dashed rgba(255, 255, 255, 0.7);
z-index: 1;
transition: all 0.5s ease;
}
.horizontal-line {
height: 0;
}
.horizontal-line.bottom-line {
position: absolute;
top: 63%;
left: 35%;
width: 30%;
}
.horizontal-line.top-line {
position: absolute;
top: 30%;
left: 65%;
width: 15%;
}
.vertical-line {
width: 0;
height: 34.3%;
left: 65%;
top: 30%;
}
@keyframes flowAnimation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.dashed-line {
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 100%);
background-size: 200% 100%;
animation: flowAnimation 4s infinite;
}
/* 响应式布局 */
@media screen and (max-width: 768px) {
.monitor-chart2 {
padding: 10px;
}
.text-box {
font-size: 0.8rem;
padding: 5px 4px;
min-width: 100px;
max-width: 150px;
}
.valve-icon {
width: 2.5rem;
height: 2.5rem;
}
.valve-label {
font-size: 0.75rem;
}
}
@media screen and (max-width: 480px) {
.bypass-valve {
right: 20%;
}
.entry-valve {
flex-direction: column;
align-items: flex-start;
left: 5%;
}
.text-box {
margin-bottom: 15px;
margin-right: 0;
}
.entry-valve .valve-container {
margin-left: 20%;
}
.vertical-line {
left: 28%;
}
}
</style>

144
vite-element-template/src/components/dust/recommend/plan/pipe/config/RecommendPlanPipeConfigEdit.vue

@ -1,144 +0,0 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
>
<el-form
v-if="dialogVisible"
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="100px"
>
<el-form-item label="推荐方案" prop="recommendPlanId">
<el-select v-model="form.recommendPlanId" placeholder="请选择推荐方案">
<el-option
v-for="item in options.recommendPlanOtions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="管道" prop="pipeId">
<el-select v-model="form.pipeId" placeholder="请选择管道">
<el-option
v-for="item in options.rootDesignPipeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="节点阀门打开度(%)" prop="valveOpening">
<el-input-number
v-model="form.valveOpening"
:min="0"
:max="100"
:step="10"
/>
</el-form-item>
<el-form-item label="管道风量" prop="pipeFlow">
<el-input v-model="form.pipeFlow" type="text" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id: "",
recommendPlanId: "",
pipeId: "",
valveOpening: "",
pipeFlow: "",
delFlag: "",
createBy: "",
createTime: "",
updateBy: "",
updateTime: "",
},
editType: "add", //addedit
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped></style>

379
vite-element-template/src/components/explosion/alarm.vue

@ -0,0 +1,379 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="650px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
:rules="rules"
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="120px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指标类别" prop="targetType">
<el-select
show-search
v-model="form.targetType"
placeholder="请选择指标类别"
style="width: 100%"
>
<el-option
v-for="item in options.targetTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指标名称" prop="targetName">
<el-input v-model="form.targetName" placeholder="请输入指标名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指标编码" prop="targetCode">
<el-input v-model="form.targetCode" placeholder="请输入指标编码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报警等级" prop="rank">
<el-select
v-model="form.rank"
placeholder="请选择报警等级"
style="width: 100%"
>
<el-option
v-for="item in options.rankOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报警状态" prop="warnStatus">
<el-select
v-model="form.warnStatus"
placeholder="请选择报警状态"
style="width: 100%"
>
<el-option
v-for="item in options.warnStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报警开始时间" prop="startTime">
<el-date-picker
value-format="yyyy-MM-dd HH:mm:ss"
v-model="form.startTime"
type="datetime"
placeholder="选择报警开始时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报警结束时间" prop="endTime">
<el-date-picker
value-format="yyyy-MM-dd HH:mm:ss"
v-model="form.endTime"
type="datetime"
placeholder="选择报警结束时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="处置情况" prop="processStatus">
<el-select
v-model="form.processStatus"
placeholder="请选择处置情况"
style="width: 100%"
>
<el-option
v-for="item in options.processStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效标记" prop="actived">
<el-select
v-model="form.actived"
placeholder="请选择有效标记"
style="width: 100%"
>
<el-option
v-for="item in options.activedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="报警描述" prop="message">
<el-input
v-model="form.message"
type="textarea"
placeholder="请输入报警描述"
:rows="3"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {
};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
targetType: "",
targetName: "",
targetCode: "",
targetPlace: "",
equipinfoId: "",
warnUnit: "",
dataId: "",
rank: "",
startTime: "",
warnStatus: "0", //
endTime: "",
message: "",
processStatus: "0", //
actived: "1", //
creatorName: "",
createTime: "",
updatorName: "",
updateTime: "",
},
editType: "add", //addedit
rules: {
targetType: [
{ required: true, message: "请选择指标类别", trigger: "change" },
],
targetName: [
{ required: true, message: "请输入指标名称", trigger: "blur" },
],
targetCode: [
{ required: true, message: "请输入指标编码", trigger: "blur" },
],
rank: [
{ required: true, message: "请选择报警等级", trigger: "change" },
],
startTime: [
{ required: true, message: "请选择报警开始时间", trigger: "change" },
],
warnStatus: [
{ required: true, message: "请选择报警状态", trigger: "change" },
],
message: [
{ required: true, message: "请输入报警描述", trigger: "blur" },
],
processStatus: [
{ required: true, message: "请选择处置情况", trigger: "change" },
],
},
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

289
vite-element-template/src/components/explosion/clean.vue

@ -0,0 +1,289 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="650px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="100px"
>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="清理项目" prop="clearItemName">
<el-select v-model="form.clearItemName" placeholder="请选择清理项目" style="width: 100%;">
<el-option
v-for="item in options.clearItems"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="完成情况" prop="taskProcess">
<el-select v-model="form.taskProcess" placeholder="请选择完成情况" style="width: 100%;">
<el-option
v-for="item in options.taskProcesses"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="执行人" prop="taskPerson">
<el-input v-model="form.taskPerson" type="text"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="执行日期" prop="taskTime">
<el-date-picker
value-format="yyyy-MM-dd HH:mm:ss"
v-model="form.taskTime"
type="datetime"
placeholder="请选择执行日期"
style="width: 100%;"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="有效标志" prop="actived">
<el-select v-model="form.actived" placeholder="请选择有效标志" style="width: 100%;">
<el-option
v-for="item in options.activedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-if="editType != 'edit'">
<el-col :span="24">
<el-form-item label="创建人" prop="creatorName">
<el-input v-model="form.creatorName" type="text"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-if="editType == 'edit'">
<el-col :span="24">
<el-form-item label="修改人" prop="updatorName">
<el-input v-model="form.updatorName" type="text"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id:"",
dataId:"",
clearItemName:"",
taskProcess:"",
taskPerson:"",
taskTime:"",
actived:"",
creatorName:"",
createTime:"",
updatorName:"",
updateTime:"",
},
editType:"add", //addedit
};
},
computed: {
showTitle() {
return this.editType=='edit' ? "编辑" + this.title : "新增" + this.title;
},
},
methods: {
reset() {
this.editType='add'
// this.$refs.elForm.resetFields();
this.loading=false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType='edit'
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType=='edit') {
q = this.$axios.put( this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

487
vite-element-template/src/components/explosion/data.vue

@ -0,0 +1,487 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="650px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
ref="editForm"
:rules="rules"
size="mini"
:model="form"
label-position="right"
label-width="130px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指标编码" prop="targetCode">
<el-input
v-model="form.targetCode"
placeholder="设备编码+3位流水编码"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指标名称" prop="targetName">
<el-input v-model="form.targetName" placeholder="请输入指标名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="除尘系统" prop="equipId">
<el-select @change="handleEquipChange" v-model="form.equipId" placeholder="请选择除尘系统" style="width: 100%">
<el-option v-for="item in options.equipList" :key="item.id" :label="item.equipName" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指标类别" prop="targetType">
<el-select
v-model="form.targetType"
placeholder="请选择指标类别"
style="width: 100%"
>
<el-option
v-for="item in options.targetTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="信号类型" prop="signalType">
<el-select
v-model="form.signalType"
placeholder="请选择信号类型"
style="width: 100%"
@change="handleSignalTypeChange"
>
<el-option
v-for="item in options.signalTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="采集点位置" prop="targetPlace">
<el-input
v-model="form.targetPlace"
placeholder="请输入指标采集点位置"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="位号" prop="bitNo">
<el-input v-model="form.bitNo" placeholder="请输入位号" />
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.signalType === '02'" :gutter="20">
<el-col :span="12">
<el-form-item label="开关量报警值" prop="alarmValue">
<el-select
v-model="form.alarmValue"
placeholder="请选择报警值"
style="width: 100%"
>
<el-option label="0" value="0" />
<el-option label="1" value="1" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<template v-if="form.signalType === '01'">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="计量单位" prop="targetUnit">
<el-input v-model="form.targetUnit" placeholder="模拟量必填" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="阈值上限" prop="thresholdUpLimit">
<el-input-number
v-model="form.thresholdUpLimit"
:controls="false"
placeholder="高报阈值"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="阈值上上限" prop="thresholdUpUpLimit">
<el-input-number
v-model="form.thresholdUpUpLimit"
:controls="false"
placeholder="高高报阈值"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="阈值下限" prop="thresholdDownLimit">
<el-input-number
v-model="form.thresholdDownLimit"
:controls="false"
placeholder="低报阈值"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="阈值下下限" prop="thresholdDownDownLimit">
<el-input-number
v-model="form.thresholdDownDownLimit"
:controls="false"
placeholder="低低报阈值"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="量程上限" prop="rangeUp" >
<el-input-number v-model="form.rangeUp" :controls="false" placeholder="模拟量指标需填写" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="量程下限" prop="rangeDown">
<el-input-number
v-model="form.rangeDown"
:controls="false"
placeholder="模拟量指标需填写"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报警保持时间(秒)" prop="alarmTime">
<el-input
v-model="form.alarmTime"
placeholder="请输入报警保持时间"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="报警保持次数" prop="alarmDataRepeatedly">
<el-input
v-model="form.alarmDataRepeatedly"
placeholder="请输入报警保持次数"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="指标状态" prop="targetStatus">
<el-select
v-model="form.targetStatus"
placeholder="请选择指标状态"
style="width: 100%"
>
<el-option
v-for="item in options.targetStatuses"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效标记" prop="actived">
<el-select
v-model="form.actived"
placeholder="请选择有效标记"
style="width: 100%"
>
<el-option
v-for="item in options.activedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="描述" prop="targetDescription">
<el-input
v-model="form.targetDescription"
type="textarea"
placeholder="请输入描述内容"
:rows="3"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {
signalTypes: [],
targetStatuses: [],
activedOptions: [],
targetTypes: [],
equipList: [],
};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
targetCode: "",
equipCode: "",
equipId: "",
targetName: "",
targetType: "",
targetPlace: "",
targetUnit: "",
thresholdUpLimit: "",
thresholdUpUpLimit: "",
thresholdDownLimit: "",
thresholdDownDownLimit: "",
rangeUp: "",
rangeDown: "",
targetDescription: "",
bitNo: "",
signalType: "",
alarmValue: "",
targetStatus: "1", //
actived: "1", //
creatorName: "",
createTime: "",
updatorName: "",
updateTime: "",
},
editType: "add", //addedit
rules: {
targetCode: [
{ required: true, message: "请输入指标编码", trigger: "blur" },
],
targetName: [
{ required: true, message: "请输入指标名称", trigger: "blur" },
],
equipCode: [
{ required: true, message: "请输入除尘系统编码", trigger: "blur" },
],
equipId: [
{ required: true, message: "请输入除尘系统ID", trigger: "blur" },
],
targetType: [
{ required: true, message: "请选择指标类别", trigger: "blur" },
],
signalType: [
{ required: true, message: "请选择信号类型", trigger: "blur" },
],
targetPlace: [
{ required: true, message: "请输入指标采集点位置", trigger: "blur" },
],
bitNo: [{ required: true, message: "请输入位号", trigger: "blur" }],
targetUnit: [
{ required: true, message: "请输入计量单位", trigger: "blur" },
],
},
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
handleSignalTypeChange(value) {
this.form.alarmValue = "";
this.form.alarmTime = "";
this.form.alarmDataRepeatedly = "";
this.form.thresholdUpLimit = "";
this.form.thresholdUpUpLimit = "";
this.form.thresholdDownLimit = "";
this.form.thresholdDownDownLimit = "";
this.form.rangeUp = "";
this.form.rangeDown = "";
},
handleEquipChange(value) {
this.form.equipId = value;
this.form.equipCode = this.options.equipList.find(item => item.id === value).equipCode;
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

289
vite-element-template/src/components/explosion/deviceTree.vue

@ -0,0 +1,289 @@
<template>
<div id="DeviceTree" class="device-tree-container">
<el-container>
<el-header class="device-tree-header">设备列表</el-header>
<el-main class="device-tree-main">
<div class="device-tree-main-box">
<el-tree
ref="gdTree"
:props="defaultProps"
:load="loadNode"
lazy
node-key="id"
class="custom-tree"
@node-click="handleNodeClick"
@node-contextmenu="handleContextMenu"
>
<span slot-scope="{ node }" class="custom-tree-node">
<span v-if="node.data.type === 0 && node.data.online" title="在线设备" class="device-online iconfont icon-jiedianleizhukongzhongxin2"></span>
<span v-if="node.data.type === 0 && !node.data.online " title="离线设备" class="device-offline iconfont icon-jiedianleizhukongzhongxin2"></span>
<span v-if="node.data.type === 2 && node.data.online" title="目录" class="device-online iconfont icon-jiedianleilianjipingtai"></span>
<span v-if="node.data.type === 2 && !node.data.online" title="目录" class="device-offline iconfont icon-jiedianleilianjipingtai"></span>
<span v-if="node.data.type === 3 && node.data.online " title="在线通道" class="device-online iconfont icon-shebeileijiankongdian"></span>
<span v-if="node.data.type === 3 && !node.data.online" title="在线通道" class="device-offline iconfont icon-shebeileijiankongdian"></span>
<span v-if="node.data.type === 4 && node.data.online " title="在线通道-球机" class="device-online iconfont icon-shebeileiqiuji"></span>
<span v-if="node.data.type === 4 && !node.data.online" title="在线通道-球机" class="device-offline iconfont icon-shebeileiqiuji"></span>
<span v-if="node.data.type === 5 && node.data.online " title="在线通道-半球" class="device-online iconfont icon-shebeileibanqiu"></span>
<span v-if="node.data.type === 5 && !node.data.online" title="在线通道-半球" class="device-offline iconfont icon-shebeileibanqiu"></span>
<span v-if="node.data.type === 6 && node.data.online " title="在线通道-枪机" class="device-online iconfont icon-shebeileiqiangjitongdao"></span>
<span v-if="node.data.type === 6 && !node.data.online" title="在线通道-枪机" class="device-offline iconfont icon-shebeileiqiangjitongdao"></span>
<span v-if="node.data.online" class="device-online device-label">{{ node.label }}</span>
<span v-if="!node.data.online" class="device-offline device-label">{{ node.label }}</span>
<span>
<i v-if="node.data.hasGPS && node.data.online" class="device-online iconfont icon-dizhi gps-icon"></i>
<i v-if="node.data.hasGPS && !node.data.online" class="device-offline iconfont icon-dizhi gps-icon"></i>
</span>
</span>
</el-tree>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
import WvpService from "@/api/wvp.js";
export default {
name: 'DeviceTree',
props: ['device', 'onlyCatalog', 'clickEvent', 'contextMenuEvent'],
data() {
return {
wvpService: WvpService,
defaultProps: {
children: 'children',
label: 'name',
isLeaf: 'isLeaf'
}
};
},
destroyed() {
// if (this.jessibuca) {
// this.jessibuca.destroy();
// }
// this.playing = false;
// this.loaded = false;
// this.performance = "";
},
methods: {
handleNodeClick(data) {
let deviceNode = this.$refs.gdTree.getNode(data.userData.deviceId)
if(typeof (this.clickEvent) == "function") {
this.clickEvent(deviceNode.data.userData, data.userData, data.type === 2)
}
},
handleContextMenu(event, data) {
console.log("右键点击事件")
let deviceNode = this.$refs.gdTree.getNode(data.userData.deviceId)
if(typeof (this.contextMenuEvent) == "function") {
this.contextMenuEvent(deviceNode.data.userData, event, data.userData, data.type === 2)
}
},
loadNode: function(node, resolve){
if (node.level === 0) {
if (this.device) {
let node = {
name: this.device.name || this.device.deviceId,
isLeaf: false,
id: this.device.deviceId,
type: this.device.online,
online: this.device.online === 1,
userData: this.device
}
resolve([node])
}else {
this.wvpService.deviceList().then((data)=>{
if (data.length > 0) {
let nodeList = []
for (let i = 0; i < data.length; i++) {
let node = {
name: data[i].name || data[i].deviceId,
isLeaf: false,
id: data[i].deviceId,
type: data[i].online,
online: data[i].online === 1,
userData: data[i]
}
nodeList.push(node);
}
resolve(nodeList)
}else {
resolve([])
}
})
}
}else {
let channelArray = []
this.wvpService.getTree(node.data.userData.deviceId, node.data.id, this.onlyCatalog, catalogData =>{
console.log(catalogData)
channelArray = channelArray.concat(catalogData)
this.channelDataHandler(channelArray, resolve)
},() => {
//
})
}
},
channelDataHandler: function (data, resolve) {
if (data.length > 0) {
let nodeList = []
for (let i = 0; i <data.length; i++) {
let item = data[i];
let type = 3;
if (item.id.length <= 10) {
type = 2;
}else {
if (item.id.length > 14) {
let channelType = item.id.substring(10, 13)
console.log("channelType: " + channelType)
if (channelType === '215' || channelType === '216') {
type = 2;
}
console.log(type)
if (item.basicData.ptzType === 1 ) { // 1-;2-;3-;4-
type = 4;
}else if (item.basicData.ptzType === 2) {
type = 5;
}else if (item.basicData.ptzType === 3 || item.basicData.ptzType === 4) {
type = 6;
}
}else {
if (item.basicData.subCount > 0 || item.basicData.parental === 1) {
type = 2;
}
}
}
let node = {
name: item.name || item.basicData.channelId,
isLeaf: type !== 2,
id: item.id,
deviceId: item.deviceId,
type: type,
online: item.basicData.status === 1,
hasGPS: item.basicData.longitude*item.basicData.latitude !== 0,
userData: item.basicData
}
nodeList.push(node);
}
resolve(nodeList)
}else {
resolve([])
}
},
reset: function (){
this.$forceUpdate();
}
},
}
</script>
<style lang="scss" scoped>
.device-tree-container {
width: 100%;
height: 100%;
background-color: rgba(1, 10, 71, 0.9);
overflow: auto;
border-radius: 8px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
border: 1px solid rgb(0, 60, 151);
}
.device-tree-header {
background-color: rgba(0, 19, 86, 0.9);
color: white;
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
border-bottom: 1px solid rgba(0, 80, 255, 0.3);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
text-shadow: 0 0 10px rgba(0, 200, 255, 0.4);
}
.device-tree-main {
background-color: rgba(24, 26, 45, 0.7);
padding: 10px;
}
.device-tree-main-box {
text-align: left;
}
.custom-tree {
background-color: transparent;
color: white;
}
.custom-tree-node {
width: 100%;
display: flex;
align-items: center;
padding: 2px 0;
}
.device-online {
color: rgb(0, 255, 128);
margin-right: 5px;
&.iconfont {
font-size: 16px;
}
}
.device-offline {
color: #727272;
margin-right: 5px;
&.iconfont {
font-size: 16px;
}
}
.device-label {
padding-left: 1px;
flex: 1;
}
.gps-icon {
font-size: 14px;
margin-left: 5px;
}
/* 覆盖Element-UI树的默认样式 */
:deep(.el-tree) {
background-color: transparent;
color: white;
}
:deep(.el-tree-node__content) {
background-color: transparent;
border-bottom: 1px solid rgba(0, 60, 151, 0.2);
padding: 5px 0;
transition: all 0.3s;
&:hover {
background-color: rgba(0, 60, 151, 0.3);
}
&:active, &.is-current {
background-color: rgba(0, 100, 255, 0.3);
}
}
:deep(.el-tree-node__expand-icon) {
color: rgba(0, 200, 255, 0.8);
}
:deep(.el-tree-node__expand-icon.is-leaf) {
color: transparent;
}
:deep(.el-tree-node__expand-icon.expanded) {
transform: rotate(90deg);
}
:deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: rgba(0, 100, 255, 0.3);
}
</style>

373
vite-element-template/src/components/explosion/dust.vue

@ -0,0 +1,373 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="780px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
ref="editForm"
:rules="rules"
size="mini"
:model="form"
label-position="right"
label-width="130px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="企业ID" prop="companyinfoId">
<el-input v-model="form.companyinfoId" placeholder="请输入企业ID" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="企业行业类型" prop="industryType">
<el-select
v-model="form.industryType"
placeholder="请选择行业类型"
style="width: 100%"
>
<el-option label="金属制品加工" value="1" />
<el-option label="农副产品加工" value="2" />
<el-option label="木制品加工" value="3" />
<el-option label="纸制品加工" value="4" />
<el-option label="纺织品加工" value="5" />
<el-option label="橡胶和塑料制品加工" value="6" />
<el-option label="冶金/有色/建材行业煤粉制备" value="7" />
<el-option label="其他" value="8" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="主要粉尘类型" prop="dustType">
<el-cascader
v-model="form.dustType"
:options="options.dustTypeOptionsTree"
placeholder="请选择主要粉尘类型"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="粉尘高风险工艺" prop="dustTechnology">
<el-select
v-model="form.dustTechnology"
placeholder="可多选"
multiple
style="width: 100%"
>
<el-option label="铝镁金属打磨抛光" value="1" />
<el-option label="铝镁金属喷砂抛丸" value="2" />
<el-option label="其他金属打磨抛光" value="3" />
<el-option label="其他金属喷砂抛丸" value="4" />
<el-option label="木材砂光" value="5" />
<el-option label="静电喷涂" value="6" />
<el-option label="粉碎研磨" value="7" />
<el-option label="造粒" value="8" />
<el-option label="无" value="9" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="日产尘量" prop="dailyDustOutput">
<el-input v-model="form.dailyDustOutput" type="number" placeholder="单位:Kg">
<template slot="append">Kg</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="单班最高涉粉人数" prop="dustInvolvedPersonNo">
<el-input-number
v-model="form.dustInvolvedPersonNo"
placeholder="每日单班最高涉粉作业人数"
:min="0"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="其他涉及粉尘信息" prop="otheRdust">
<el-input
v-model="form.otheRdust"
type="textarea"
:rows="3"
placeholder="格式:粉尘种类,日产尘量Kg;多记录分号分隔,例如A2,100;A3,300;A5,150"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="有效标记" prop="actived">
<el-select
v-model="form.actived"
placeholder="请选择是否有效"
style="width: 100%"
>
<el-option label="无效" value="0" />
<el-option label="有效" value="1" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" >
<el-col v-if="editType !== 'edit'" :span="12">
<el-form-item label="创建人" prop="creatorName">
<el-input v-model="form.creatorName" disabled />
</el-form-item>
</el-col>
<el-col v-if="editType === 'edit'" :span="12">
<el-form-item label="修改人" prop="updatorName">
<el-input v-model="form.updatorName" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
companyinfoId: "",
industryType: "",
dustTechnology: "",
dustType: "",
dailyDustOutput: "",
otheRdust: "",
dustInvolvedPersonNo: "",
actived: "1", //
creatorName: "",
createTime: "",
updatorName: "",
updateTime: "",
},
editType: "add", //addedit
rules: {
companyinfoId: [
{ required: true, message: "请输入企业ID", trigger: "blur" },
],
industryType: [
{ required: true, message: "请选择企业行业类型", trigger: "change" },
],
dustTechnology: [
{
required: true,
message: "请选择粉尘高风险工艺",
trigger: "change",
},
],
dustType: [
{ required: true, message: "请输入主要粉尘类型", trigger: "blur" },
],
dailyDustOutput: [
{ required: true, message: "请输入日产尘量", trigger: "blur" },
],
dustInvolvedPersonNo: [
{
required: true,
message: "请输入单班最高涉粉人数",
trigger: "blur",
},
],
actived: [
{ required: true, message: "请选择是否有效", trigger: "change" },
],
},
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, {
...this.form,
dustTechnology: this.form.dustTechnology.join(","),
dustType: this.form.dustType[1],
});
} else {
q = this.$axios.post(this.url.add, {
...this.form,
dustTechnology: this.form.dustTechnology.join(","),
dustType: this.form.dustType[1],
});
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner,
::v-deep .el-input-number__decrease,
::v-deep .el-input-number__increase {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

459
vite-element-template/src/components/explosion/equip.vue

@ -0,0 +1,459 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="650px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
ref="editForm"
:rules="rules"
size="mini"
:model="form"
label-position="right"
label-width="120px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="设备编号" prop="equipCode">
<el-input
v-model="form.equipCode"
placeholder="数据接入标识(10位)+3位流水编码"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备名称" prop="equipName">
<el-input v-model="form.equipName" placeholder="请输入设备名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="企业ID" prop="companyinfoId">
<el-input v-model="form.companyinfoId" placeholder="请输入企业ID" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="场所编码" prop="placeCode">
<el-input
v-model="form.placeCode"
placeholder="场所在系统中原属车间"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="设备类型" prop="equipType">
<el-select
v-model="form.equipType"
placeholder="请选择设备类型"
style="width: 100%"
>
<el-option label="干式集中式除尘系统" value="1" />
<el-option label="湿式集中式除尘系统" value="2" />
<el-option label="湿式单机除系统" value="3" />
<el-option label="干式单机除系统" value="4" />
<el-option label="其它" value="5" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备厂家" prop="equipFactory">
<el-input
v-model="form.equipFactory"
placeholder="请输入设备厂家"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="安装日期" prop="setDate">
<el-date-picker
value-format="yyyy-MM-dd HH:mm:ss"
v-model="form.setDate"
type="datetime"
placeholder="选择安装日期"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="安装区域" prop="installArea">
<el-select
v-model="form.installArea"
placeholder="请选择安装区域"
style="width: 100%"
>
<el-option label="室内" value="1" />
<el-option label="室外" value="2" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="相关控制措施" prop="bombControl">
<el-select
v-model="form.bombControl"
placeholder="可多选"
multiple
style="width: 100%"
>
<el-option label="泄爆" value="1" />
<el-option label="抑爆" value="2" />
<el-option label="隔爆" value="3" />
<el-option label="惰化" value="4" />
<el-option label="其他" value="5" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="除去粉尘种类" prop="dustType">
<el-cascader
v-model="form.dustType"
:options="options.dustTypeOptionsTree"
placeholder="请选择粉尘种类"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="除尘涉及人数" prop="workersNumber">
<el-input-number
v-model="form.workersNumber"
placeholder="单班最高作业人数"
:min="0"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="涉及云量工艺" prop="dustTechnology">
<el-select
v-model="form.dustTechnology"
placeholder="可多选"
multiple
style="width: 100%"
>
<el-option
v-for="item in options.dustTechnologyOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="单日产尘量" prop="dailyDustOutput">
<el-input v-model="form.dailyDustOutput" placeholder="单位:Kg" type="number">
<template slot="append">Kg</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="系统状态" prop="equipStatus">
<el-select
v-model="form.equipStatus"
placeholder="请选择系统状态"
style="width: 100%"
>
<el-option
v-for="item in options.equipStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="有效标志" prop="active">
<el-select
v-model="form.active"
placeholder="请选择是否有效"
style="width: 100%"
>
<el-option
v-for="item in options.activeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col v-if="editType === 'add'" :span="12">
<el-form-item label="创建人" prop="creatorName">
<el-input v-model="form.creatorName" />
</el-form-item>
</el-col>
<el-col v-if="editType === 'edit'" :span="12">
<el-form-item label="修改人" prop="updatorName">
<el-input v-model="form.updatorName" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id: "",
equipCode: "",
equipName: "",
companyinfoId: "",
placeCode: "",
equipType: "",
equipFactory: "",
setDate: "",
bombControl: "",
installArea: "",
dustType: "",
workersNumber: "",
dustTechnology: "",
dailyDustOutput: "",
equipStatus: "1", //
active: "1", //
creatorName: "",
createTime: "",
updatorName: "",
updateTime: "",
delFlag: "0", //
},
editType: "add", //addedit
rules: {
equipCode: [
{ required: true, message: "请输入设备编号", trigger: "blur" },
],
equipName: [
{ required: true, message: "请输入设备名称", trigger: "blur" },
],
companyinfoId: [
{ required: true, message: "请输入企业ID", trigger: "blur" },
],
equipType: [
{ required: true, message: "请选择设备类型", trigger: "change" },
],
installArea: [
{ required: true, message: "请选择安装区域", trigger: "change" },
],
dustType: [
{ required: true, message: "请输入粉尘种类", trigger: "blur" },
],
equipStatus: [
{ required: true, message: "请选择系统状态", trigger: "change" },
],
active: [
{ required: true, message: "请选择是否有效", trigger: "change" },
],
},
};
},
computed: {
showTitle() {
return this.editType == "edit"
? "编辑" + this.title
: "新增" + this.title;
},
},
methods: {
reset() {
this.editType = "add";
// this.$refs.elForm.resetFields();
this.loading = false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType = "edit";
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType == "edit") {
q = this.$axios.put(this.url.edit, {
...this.form,
bombControl: this.form.bombControl.join(","),
dustTechnology: this.form.dustTechnology.join(","),
dustType: this.form.dustType[1],
});
} else {
q = this.$axios.post(this.url.add, {
...this.form,
bombControl: this.form.bombControl.join(","),
dustTechnology: this.form.dustTechnology.join(","),
dustType: this.form.dustType[1],
});
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner,
::v-deep .el-input-number__decrease,
::v-deep .el-input-number__increase {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

324
vite-element-template/src/components/explosion/feedback.vue

@ -0,0 +1,324 @@
<template>
<el-dialog
v-if="dialogVisible"
v-el-drag-dialog
:title="showTitle"
:visible.sync="dialogVisible"
width="650px"
class="custom-dialog"
>
<el-form
v-if="dialogVisible"
:rules="rules"
ref="editForm"
size="mini"
:model="form"
label-position="right"
label-width="120px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="预警编号" prop="id">
<el-input v-model="form.id" placeholder="主键,唯一"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="系统ID" prop="equipinfoId">
<el-input v-model="form.equipinfoId" placeholder="请输入系统ID"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="数据接入标识" prop="dataId">
<el-input v-model="form.dataId" placeholder="请输入数据接入标识"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预警等级" prop="warningRank">
<el-select v-model="form.warningRank" placeholder="请选择预警等级" style="width: 100%;">
<el-option
v-for="item in options.rankOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="反馈时间" prop="realTime">
<el-date-picker
v-model="form.realTime"
type="datetime"
placeholder="选择反馈时间"
style="width: 100%;"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="填报人" prop="fillBy">
<el-input v-model="form.fillBy" placeholder="请输入填报人"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="有效标记" prop="actived">
<el-select v-model="form.actived" placeholder="请选择有效标记" style="width: 100%;">
<el-option
v-for="item in options.activedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="删除标记" prop="delFlag">
<el-select v-model="form.delFlag" placeholder="请选择删除标记" style="width: 100%;">
<el-option
v-for="item in options.delFlagOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="创建人" prop="creatorName">
<el-input v-model="form.creatorName" placeholder="请输入创建人"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="修改人" prop="updatorName">
<el-input v-model="form.updatorName" placeholder="请输入修改人"/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="企业反馈信息" prop="warnFeedback">
<el-input v-model="form.warnFeedback" type="textarea" placeholder="请输入企业反馈信息" :rows="3"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> 取消 </el-button>
<el-button type="primary" :loading="loading" @click="onSubmit">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
url: {
type: Object,
default: () => {
return {};
},
},
options: {
type: Object,
default: () => {
return {
};
},
},
},
data() {
return {
dialogVisible: false,
loading: false,
form: {
id:"",
equipinfoId:"",
dataId:"",
warningRank:"",
warnFeedback:"",
realTime:"",
fillBy:"",
actived:"1", //
creatorName:"",
createTime:"",
updatorName:"",
updateTime:"",
},
editType:"add", //addedit
rules: {
equipinfoId: [
{ required: true, message: '请输入系统ID', trigger: 'blur' }
],
dataId: [
{ required: true, message: '请输入数据接入标识', trigger: 'blur' }
],
warningRank: [
{ required: true, message: '请选择预警等级', trigger: 'change' }
],
warnFeedback: [
{ required: true, message: '请输入企业反馈信息', trigger: 'blur' }
],
realTime: [
{ required: true, message: '请选择反馈时间', trigger: 'change' }
],
fillBy: [
{ required: true, message: '请输入填报人', trigger: 'blur' }
]
}
};
},
computed: {
showTitle() {
return this.editType=='edit' ? "编辑" + this.title : "新增" + this.title;
},
},
methods: {
reset() {
this.editType='add'
// this.$refs.elForm.resetFields();
this.loading=false;
this.form = this.$options.data().form;
},
show(form) {
this.reset();
if (form) {
this.editType='edit'
this.form = { ...this.$options.data().form, ...form };
}
this.dialogVisible = true;
},
onSubmit() {
this.$refs.editForm.validate((valid) => {
if (!valid) {
return false;
}
this.loading = true;
let q;
if (this.editType=='edit') {
q = this.$axios.put( this.url.edit, this.form);
} else {
q = this.$axios.post(this.url.add, this.form);
}
q.then(({ message }) => {
this.$message({ type: "info", message: message });
this.dialogVisible = false;
this.$emit("refresh");
}).finally(() => {
this.loading = false;
});
});
},
},
};
</script>
<style lang="scss" scoped>
.custom-dialog {
::v-deep .el-dialog {
background-color: rgba(4, 0, 79, 0.98);
border: 1px solid rgba(75, 72, 178, 0.5);
border-radius: 4px;
.el-dialog__header {
background-color: rgba(0, 8, 59, 0.9);
padding: 15px 20px;
border-bottom: 1px solid rgba(75, 72, 178, 0.5);
.el-dialog__title {
color: #e0e0ff;
font-weight: bold;
font-size: 16px;
}
.el-dialog__headerbtn .el-dialog__close {
color: #e0e0ff;
}
}
.el-dialog__body {
padding: 20px;
color: #e0e0ff;
}
.el-dialog__footer {
padding: 10px 20px;
border-top: 1px solid rgba(75, 72, 178, 0.5);
background-color: rgba(0, 8, 59, 0.7);
}
}
.el-form-item {
margin-bottom: 15px;
::v-deep .el-form-item__label {
color: #c0c4cc;
font-size: 13px;
}
::v-deep .el-input__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-textarea__inner {
background-color: rgba(25, 22, 104, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&::placeholder {
color: rgba(195, 195, 219, 0.5);
}
}
::v-deep .el-select .el-input .el-select__caret {
color: #e0e0ff;
}
}
.dialog-footer {
text-align: right;
.el-button {
background-color: rgba(30, 27, 110, 0.7);
border-color: rgba(75, 72, 178, 0.5);
color: #e0e0ff;
&:hover {
background-color: rgba(40, 36, 124, 0.8);
}
&[type="primary"] {
background-color: #1976d2;
border-color: #1565c0;
color: #ffffff;
&:hover {
background-color: #1e88e5;
}
}
}
}
}
</style>

267
vite-element-template/src/components/flowEdit/Diagram.vue

@ -0,0 +1,267 @@
<template>
<div class="diagram">
<diagram-toolbar
v-if="lf"
class="diagram-toolbar"
:lf="lf"
:active-edges="activeEdges"
@changeNodeFillColor="$_changeNodeFill"
@saveGraph="$_saveGraph"
@importData="importData"
/>
<div class="diagram-main">
<diagram-sidebar class="diagram-sidebar" @dragInNode="$_dragInNode" @exportXML="$_saveGraph" />
<div ref="container" class="diagram-container">
<div class="diagram-wrapper">
<div ref="diagram" class="lf-diagram"></div>
</div>
</div>
</div>
<!-- 右侧属性面板 -->
<PropertyPanel
v-show="activeNodes.length > 0 || activeEdges.length > 0"
class="diagram-panel"
:only-edge="activeNodes.length === 0"
:elements-style="properties"
@setStyle="$_setStyle"
@setZIndex="$_setZIndex"
/>
</div>
</template>
<script>
import LogicFlow from "@logicflow/core";
import { SelectionSelect, Menu } from "@logicflow/extension";
import "@logicflow/core/dist/style/index.css";
import "@logicflow/extension/lib/style/index.css";
import DiagramToolbar from "./DiagramToolbar.vue";
import DiagramSidebar from "./DiagramSidebar.vue";
import PropertyPanel from "./PropertyPanel.vue";
import { registerCustomElement } from "./node";
// import { Control } from "@logicflow/extension";
export default {
name: "Diagram",
components: {
DiagramToolbar,
DiagramSidebar,
PropertyPanel,
},
data() {
return {
sidebarWidth: 200,
diagramWidth: 0,
diagramHeight: 0,
lf: "",
filename: "",
activeNodes: [],
activeEdges: [],
properties: {},
};
},
mounted() {
let data = "";
this.filename = "export.json";
const d = window.sessionStorage.getItem(this.filename);
if (d) {
data = JSON.parse(d);
}
this.initLogicFlow(data);
},
methods: {
initLogicFlow(data) {
//
LogicFlow.use(SelectionSelect);
LogicFlow.use(Menu);
const lf = new LogicFlow({
container: this.$refs.diagram,
overlapMode: 1,
autoWrap: true,
metaKeyMultipleSelected: true,
keyboard: {
enabled: true,
},
grid: {
visible: true,
size: 10,
type: "mesh",
config: {
color: "rgba(255,255,255,0.1)",
thickness: 1,
},
},
background: {
backgroundColor: "rgba(29, 32, 98, 1)",
// backgroundImage: 'url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImdyaWQiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTSAwIDEwIEwgNDAgMTAgTSAxMCAwIEwgMTAgNDAgTSAwIDIwIEwgNDAgMjAgTSAyMCAwIEwgMjAgNDAgTSAwIDMwIEwgNDAgMzAgTSAzMCAwIEwgMzAgNDAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QwZDBkMCIgb3BhY2l0eT0iMC4yIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNIDQwIDAgTCAwIDAgMCA0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDBkMGQwIiBzdHJva2Utd2lkdGg9IjEiLz48L3BhdHRlcm4+PC9kZWZzPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JpZCkiLz48L3N2Zz4=")',
// backgroundRepeat: 'repeat'
},
});
lf.setTheme({
baseEdge: { strokeWidth: 1 },
baseNode: { strokeWidth: 1 },
nodeText: { overflowMode: "autoWrap", lineHeight: 1.5 },
edgeText: { overflowMode: "autoWrap", lineHeight: 1.5 },
});
//
registerCustomElement(lf);
lf.setDefaultEdgeType("pro-polyline");
lf.render(data);
this.lf = lf;
this.lf.on("selection:selected,node:click,blank:click,edge:click", () => {
this.$nextTick(() => {
const { nodes, edges } = this.lf.getSelectElements();
this.$set(this, "activeNodes", nodes);
this.activeNodes = nodes;
this.activeEdges = edges;
this.$_getProperty();
});
});
// lf.renderRawData( )
},
importData(text) {
this.lf.renderRawData(text);
},
//
$_getProperty() {
let properties = {};
const { nodes, edges } = this.lf.getSelectElements();
console.log("nodes", nodes);
nodes.forEach((node) => {
console.log(this.lf.getProperties(node.id));
properties = { ...properties, ...node.properties };
});
edges.forEach((edge) => {
properties = { ...properties, ...edge.properties };
});
this.properties = properties;
return properties;
},
$_dragInNode(type) {
this.lf.dnd.startDrag({
type,
});
},
$_changeNodeFill(color) {
const { nodes } = this.lf.graphModel.getSelectElements();
nodes.forEach(({ id }) => {
this.lf.setProperties(id, {
fill: color,
});
});
},
$_setStyle(item) {
this.activeNodes.forEach(({ id }) => {
this.lf.setProperties(id, item);
});
this.activeEdges.forEach(({ id }) => {
this.lf.setProperties(id, item);
});
this.$_getProperty();
},
$_setZIndex(type) {
this.activeNodes.forEach(({ id }) => {
this.lf.setElementZIndex(id, type);
});
this.activeEdges.forEach(({ id }) => {
this.lf.setElementZIndex(id, type);
});
},
$_saveGraph() {
const data = this.lf.getGraphData();
this.download(this.filename, JSON.stringify(data));
},
download(filename, text) {
window.sessionStorage.setItem(filename, text);
const element = document.createElement("a");
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
element.setAttribute("download", filename);
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
},
},
};
</script>
<style scoped>
.diagram {
width: 100%;
height: 100%;
}
.diagram * {
box-sizing: border-box;
}
.diagram-toolbar {
position: absolute;
top: 0;
left: 200px;
height: 40px;
padding: 0 10px;
/* width: 310px; */
display: flex;
align-items: center;
/* border-bottom: 1px solid #e5e5e5; */
z-index: 10;
background: #fff;
}
.diagram-main {
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
}
.diagram-sidebar {
width: 200px;
height: 100%;
}
.diagram-panel {
width: 300px;
background: #fff;
position: absolute;
right: 0px;
top: 40px;
bottom: 40px;
overflow: auto;
border: 1px solid #dadce0;
}
.diagram-container {
flex: 1;
}
/* 由于背景图和gird不对齐,需要css处理一下 */
.diagram /deep/ .lf-background {
left: -9px;
}
.diagram-wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
}
.lf-diagram {
box-shadow: 0px 0px 4px #838284;
width: 100%;
height: 100%;
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
background: white;
border-left: 1px solid #e8e8e8;
}
::-webkit-scrollbar-thumb {
border-width: 1px;
border-style: solid;
border-color: #fff;
border-radius: 6px;
background: #c9c9c9;
}
::-webkit-scrollbar-thumb:hover {
background: #b5b5b5;
}
</style>

81
vite-element-template/src/components/flowEdit/DiagramSidebar.vue

@ -0,0 +1,81 @@
<template>
<div class="diagram-sidebar">
<div
class="image-node"
v-for="(item, index) of list"
:key="index"
@mousedown.stop.prevent="dragInNode(item.type)"
>
<img :src="item.imgUrl" alt="" srcset="" />
<div>
{{ item.name }}
</div>
</div>
<div class="image-node" @mousedown.stop.prevent="dragInNode('pro-text')">
<div>TEXT</div>
<div>文本节点</div>
</div>
<!-- <div @click="exportXML">导出</div> -->
</div>
</template>
<script>
// import IconCircle from './icon/Circle.vue'
import { List } from "./node";
console.log("List", List);
export default {
name: "DiagramSidebar",
data() {
return {
list: List.map((item) => {
return {
type: item.type,
...item.info,
};
}),
};
},
methods: {
dragInNode(type) {
console.log("dragInNode", type);
this.$emit("dragInNode", type);
},
exportXML() {
this.$emit("exportXML");
},
},
// components: {
// // IconCircle,
// }
};
</script>
<style scoped>
.diagram-sidebar {
user-select: none;
text-align: center;
overflow: auto;
}
.image-node {
display: inline-block;
width: 50%;
margin: 10px 0;
cursor: pointer;
background-size: contain;
background-repeat: no-repeat;
user-select: none;
}
.image-node img {
max-width: 26px;
max-height: 26px;
user-select: none;
}
.image-node div {
font-size: 12px;
user-select: none;
}
</style>

208
vite-element-template/src/components/flowEdit/DiagramToolbar.vue

@ -0,0 +1,208 @@
<template>
<div>
<div class="toolbar-item" :class="{ 'selection-active': selectionOpened }" @click="$_selectionSelect()">
<area-select size="18" />
</div>
<!-- <div class="toolbar-item toolbar-color-picker">
<el-popover
placement="top-start"
title="填充样式"
width="220"
trigger="click"
>
<sketch-picker :value="fillColor" @input="$_changeFillColor"/>
<color-fill size="24" slot="reference" />
</el-popover>
</div> -->
<!-- <div class="toolbar-item">
<color-text size="20" />
</div>
<div class="toolbar-item">
<icon-font size="18" />
</div>
<div class="toolbar-item">
<icon-blod size="18" />
</div>
<div class="toolbar-item">
<icon-line size="18" />
</div> -->
<div class="toolbar-item" @click="$_zoomIn()">
<zoom-in size="18" />
</div>
<div class="toolbar-item" @click="$_zoomOut()">
<zoom-out size="18" />
</div>
<div class="toolbar-item" :class="{ disabled: !undoAble }" @click="$_undo()">
<step-back size="18" />
</div>
<div class="toolbar-item" :class="{ disabled: !redoAble }" @click="$_redo()">
<step-foward size="18" />
</div>
<div class="toolbar-item" @click="$import">导入</div>
<div class="toolbar-item" @click="$_saveGraph">导出</div>
<div>
<el-select v-model="linetype" size="mini" @change="$_changeLineType">
<el-option v-for="item in lineOptions" :key="item.value" :value="item.value" :label="item.label"></el-option>
</el-select>
</div>
</div>
</template>
<script>
// import { Sketch } from 'vue-color'
// import ColorFill from './icon/ColorFill.vue'
// import ColorText from './icon/ColorText.vue'
// import IconFont from './icon/Font.vue'
// import IconBlod from './icon/Blod.vue'
// import IconLine from './icon/Line.vue'
import ZoomIn from "./icon/ZoomIn.vue";
import ZoomOut from "./icon/ZoomOut.vue";
import StepBack from "./icon/StepBack.vue";
import StepFoward from "./icon/StepFoward.vue";
import AreaSelect from "./icon/AreaSelect.vue";
let fileHandle;
async function getFile() {
[fileHandle] = await window.showOpenFilePicker();
console.log("fileHandle", fileHandle);
}
async function getText() {
const file = await fileHandle.getFile();
const text = await file.text();
console.log(text);
return text;
}
async function writeFile() {
const writable = await fileHandle.createWritable();
await writable.write("测试一下");
await writable.close();
}
export default {
props: {
lf: Object,
activeEdges: Array,
fillColor: {
type: String,
default: "",
},
},
data() {
return {
selectionOpened: false,
undoAble: false,
redoAble: false,
colors: "#345678",
linetype: "pro-polyline",
lineOptions: [
{
value: "pro-polyline",
label: "折线",
},
{
value: "pro-line",
label: "直线",
},
{
value: "pro-bezier",
label: "曲线",
},
],
};
},
mounted() {
this.$props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
this.$data.redoAble = redoAble;
this.$data.undoAble = undoAble;
});
},
methods: {
async $import() {
try {
await getFile();
let text = await getText();
if(JSON.parse(text)){
this.$emit("importData",JSON.parse(text));
}
} catch (error) {
this.$message.error("文件读取错误");
}
},
$_changeFillColor(val) {
this.$emit("changeNodeFillColor", val.hex);
},
$_saveGraph() {
this.$emit("saveGraph");
},
$_zoomIn() {
this.$props.lf.zoom(true);
},
$_zoomOut() {
this.$props.lf.zoom(false);
},
$_undo() {
if (this.$data.undoAble) {
this.$props.lf.undo();
}
},
$_redo() {
if (this.$data.redoAble) {
this.$props.lf.redo();
}
},
$_selectionSelect() {
this.selectionOpened = !this.selectionOpened;
if (this.selectionOpened) {
this.lf.extension.selectionSelect.openSelectionSelect();
} else {
this.lf.extension.selectionSelect.closeSelectionSelect();
}
},
$_changeLineType(value) {
const { lf, activeEdges } = this.$props;
const { graphModel } = lf;
lf.setDefaultEdgeType(value);
if (activeEdges && activeEdges.length > 0) {
activeEdges.forEach((edge) => {
graphModel.changeEdgeType(edge.id, value);
});
}
},
},
components: {
// ColorFill,
// ColorText,
// IconFont,
// IconBlod,
// IconLine,
ZoomIn,
ZoomOut,
StepBack,
StepFoward,
AreaSelect,
// SketchPicker: Sketch
},
};
</script>
<style scoped>
.toolbar-item {
/* width: 18px;
height: 18px; */
float: left;
margin: 12px 6px;
cursor: pointer;
}
.toolbar-color-picker {
width: 24px;
height: 24px;
margin: 8px 4px;
}
.selection-active {
background: #33a3dc;
}
</style>

398
vite-element-template/src/components/flowEdit/PropertyPanel.vue

@ -0,0 +1,398 @@
<template>
<div class="diagram-panel">
<div class="setting-block">
<div>快捷样式</div>
<div class="short-styles">
<div
v-for="(item, index) in shortStyles"
:key="index"
:style="{
backgroundColor: item.backgroundColor,
borderColor: item.borderColor,
borderWidth: item.borderWidth,
}"
@click="setStyle(item)"
></div>
</div>
</div>
<div class="setting-block">
<div class="setting-item">
<span>背景色</span>
<el-popover
placement="top-start"
title="填充样式"
width="220"
trigger="click"
>
<sketch-picker
:value="style.backgroundColor"
@input="(c) => $_changeColorProperty(c, 'backgroundColor')"
/>
<div
class="border-color"
:style="{ backgroundColor: style.backgroundColor }"
slot="reference"
></div>
</el-popover>
<span>背景渐变色</span>
<el-popover
placement="top-start"
title="填充样式"
width="220"
trigger="click"
>
<sketch-picker
:value="style.gradientColor"
@input="(c) => $_changeColorProperty(c, 'gradientColor')"
/>
<div
class="border-color"
:style="{ backgroundColor: style.gradientColor }"
slot="reference"
></div>
</el-popover>
</div>
<div class="setting-item">
<span>线条样式</span>
<el-select
v-model="style.borderStyle"
size="small"
@change="$_selectBorder"
>
<el-option value="hidden" label="不显示"></el-option>
<el-option
v-for="(border, index) in borderStyles"
:value="border.value"
:key="index"
>
<div
class="border-style"
:style="{ borderBottomStyle: border.value }"
></div>
</el-option>
</el-select>
</div>
<div class="setting-item">
<span>线条颜色</span>
<el-popover
placement="top-start"
title="填充样式"
width="220"
trigger="click"
>
<sketch-picker
:value="style.borderColor"
@input="(c) => $_changeColorProperty(c, 'borderColor')"
/>
<div
class="border-color"
:style="{ backgroundColor: style.borderColor }"
slot="reference"
></div>
</el-popover>
</div>
<div class="setting-item">
<span>线条宽度</span>
<el-select v-model="style.borderWidth" @change="$_changeBorderWidth">
<el-option
v-for="item in borderWidthOptions"
:key="item"
:label="`${item}px`"
:value="item"
></el-option>
</el-select>
</div>
<div class="setting-item">
<span>文本颜色</span>
<el-popover
placement="top-start"
title="填充样式"
width="220"
trigger="click"
>
<sketch-picker
:value="style.fontColor"
@input="(c) => $_changeColorProperty(c, 'fontColor')"
/>
<div
class="border-color"
:style="{ backgroundColor: style.fontColor }"
slot="reference"
></div>
</el-popover>
</div>
<div class="setting-item">
<span>文本大小</span>
<el-input-number
v-model="style.fontSize"
controls-position="right"
size="mini"
@change="$_changeFontSize"
:min="12"
:max="30"
>
</el-input-number>
<span>px</span>
</div>
<div class="setting-item">
<span>文本字体</span>
<el-select
v-model="style.fontFamily"
size="small"
@change="$_changeFontFamily"
>
<el-option
v-for="(fontFamily, index) in fontFamilies"
:value="fontFamily.value"
:key="index"
></el-option>
</el-select>
</div>
<div class="setting-item">
<span>行高</span>
<el-select
v-model="style.lineHeight"
size="small"
@change="$_changeLineHeight"
>
<el-option
v-for="(item, index) in lineHeightOptions"
:key="index"
:label="`${item}`"
:value="item"
></el-option>
</el-select>
</div>
<div class="setting-item">
<span>对齐</span>
<el-radio-group
v-model="style.textAlign"
size="small"
@change="$_changeTextAlign"
>
<el-radio-button label="left">左对齐</el-radio-button>
<el-radio-button label="center">居中</el-radio-button>
<el-radio-button label="right">右对齐</el-radio-button>
</el-radio-group>
</div>
<div class="setting-item">
<span>文本样式</span>
<el-button size="small" @click="$_changeFontWeight">B</el-button>
<el-button size="small" @click="$_changeTextDecoration">U</el-button>
<el-button size="small" @click="$_changeFontStyle">I</el-button>
</div>
<div class="setting-item">
<span>设备id</span>
<el-input
v-model="style.deviceID"
controls-position="right"
size="mini"
@input="$_changeDeviceID"
>
</el-input>
<span>监控项id</span>
<el-input
v-model="style.itemID"
controls-position="right"
size="mini"
@input="$_changeItemID"
>
</el-input>
</div>
<div>
<el-button @click="$emit('setZIndex', 'top')">置为顶部</el-button>
<el-button @click="$emit('setZIndex', 'bottom')">置为底部</el-button>
</div>
</div>
</div>
</template>
<script>
import { Sketch } from "vue-color";
import { shortStyles, borderStyles, fontFamilies } from "./constant";
export default {
props: {
elementsStyle: Object,
onlyEdge: Boolean, //
},
data() {
return {
shortStyles,
borderStyles,
fontFamilies,
style: {
backgroundColor: "", //
gradientColor: "", //
borderType: 0, // 线
borderColor: "", //
borderWidth: 1, // 线
borderStyle: "", // 线
fontSize: 12, //
fontColor: "", //
fontWeight: "", //
fontFamily: "", //
lineHeight: "", //
textAlign: "", //
deviceID:"" // id
},
borderWidthOptions: Array(11)
.fill()
.map((_, i) => i),
SketchPicker: Sketch,
fontWeight: "", //
lineHeightOptions: Array(5)
.fill(1)
.map((_, i) => _ + i * 0.5),
};
},
watch: {
elementsStyle: {
handler(val) {
this.style = { ...this.$options.data().style, ...val };
},
immediate: true,
deep: true,
},
},
methods: {
setStyle(item) {
this.$emit("setStyle", item);
},
$_selectBorder(val) {
this.$emit("setStyle", {
borderStyle: val,
});
},
$_changeColorProperty({ rgba: { r, g, b, a } }, type) {
const color = `rgba(${r},${g},${b},${a})`;
this[type] = color;
this.$emit("setStyle", {
[type]: color,
});
},
$_changeFontSize(val) {
this.$emit("setStyle", {
fontSize: val,
});
},
$_changeBorderWidth(val) {
this.$emit("setStyle", {
borderWidth: val,
});
},
$_changeFontFamily(val) {
this.$emit("setStyle", {
fontFamily: val,
});
},
$_changeLineHeight(val) {
this.$emit("setStyle", {
lineHeight: val,
});
},
$_changeFontWeight() {
if (this.style.fontWeight === "bold") {
this.$emit("setStyle", {
fontWeight: "normal",
});
} else {
this.$emit("setStyle", {
fontWeight: "bold",
});
}
},
$_changeTextDecoration() {
if (this.style.textDecoration === "underline") {
this.$emit("setStyle", {
textDecoration: "none",
});
} else {
this.$emit("setStyle", {
textDecoration: "underline",
});
}
},
$_changeDeviceID(val){
this.$emit("setStyle", {
deviceID: val,
});
},
$_changeItemID(val){
this.$emit("setStyle", {
itemID: val,
});
},
$_changeFontStyle() {
if (this.style.fontStyle === "italic") {
this.$emit("setStyle", {
fontStyle: "normal",
});
} else {
this.$emit("setStyle", {
fontStyle: "italic",
});
}
},
$_changeTextAlign(val) {
this.$emit("setStyle", {
textAlign: val,
});
},
},
components: {
SketchPicker: Sketch,
},
};
</script>
<style scoped>
.diagram-panel {
padding: 20px;
}
.short-styles {
width: 240px;
}
.short-styles > div {
width: 20px;
height: 20px;
margin: 0 10px 5px 0;
box-sizing: border-box;
float: left;
border: 1px solid #fff;
cursor: pointer;
}
.border-style {
width: 150px;
height: 0px;
margin-top: 18px;
border-bottom-width: 1px;
border-bottom-color: black;
}
.setting-block {
overflow: hidden;
}
.setting-item {
line-height: 12px;
font-size: 12px;
display: flex;
vertical-align: middle;
align-items: center;
margin-top: 10px;
}
.setting-item > span {
width: 50px;
margin-right: 10px;
text-align: right;
flex-shrink: 0;
flex-grow: 0;
}
.border-color {
width: 40px;
height: 30px;
display: inline-block;
border: 1px solid #eaeaeb;
}
</style>

12
vite-element-template/src/components/flowEdit/config.js

@ -0,0 +1,12 @@
// 元素属性右侧面板默认属性
export const defatuleStyle = {
backgroundColor: '', // 填充色
gradientColor: '', // 渐变色
borderType: 0, // 边框类型
borderColor: '', // 填充颜色
borderWidth: 1, // 边框宽度
borderStyle: '', // 边框类型
fontSize: 12, // 文本大小
fontColor: '', // 文本颜色
fontWeight: '' // 文本加粗
}

38
vite-element-template/src/components/flowEdit/icon/Actor.vue

@ -0,0 +1,38 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<ellipse
cx="15.75"
cy="4.73"
rx="3.375"
ry="3.375"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></ellipse>
<path
d="M 15.75 8.1 L 15.75 19.35 M 15.75 10.35 L 9 10.35 M 15.75 10.35 L 22.5 10.35 M 15.75 19.35 L 9 28.35 M 15.75 19.35 L 22.5 28.35"
fill="none"
stroke="white"
stroke-width="9.3"
stroke-miterlimit="10"
pointer-events="stroke"
visibility="hidden"
></path>
<path
d="M 15.75 8.1 L 15.75 19.35 M 15.75 10.35 L 9 10.35 M 15.75 10.35 L 22.5 10.35 M 15.75 19.35 L 9 28.35 M 15.75 19.35 L 22.5 28.35"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

16
vite-element-template/src/components/flowEdit/icon/AreaSelect.vue

@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M933.647059 0h-210.82353v90.352941h180.705883a30.117647 30.117647 0 0 1 30.117647 30.117647v180.705883h90.352941V90.352941a90.352941 90.352941 0 0 0-90.352941-90.352941zM361.411765 0h301.17647v90.352941H361.411765zM933.647059 361.411765h90.352941v301.17647h-90.352941zM361.411765 933.647059h301.17647v90.352941H361.411765zM0 361.411765h90.352941v301.17647H0zM90.352941 903.529412v-180.705883H0v210.82353a90.352941 90.352941 0 0 0 90.352941 90.352941h210.82353v-90.352941H120.470588a30.117647 30.117647 0 0 1-30.117647-30.117647zM933.647059 903.529412a30.117647 30.117647 0 0 1-30.117647 30.117647h-180.705883v90.352941h210.82353a90.352941 90.352941 0 0 0 90.352941-90.352941v-210.82353h-90.352941zM0 90.352941v210.82353h90.352941V120.470588a30.117647 30.117647 0 0 1 30.117647-30.117647h180.705883V0H90.352941a90.352941 90.352941 0 0 0-90.352941 90.352941z" p-id="1890">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

16
vite-element-template/src/components/flowEdit/icon/ColorFill.vue

@ -0,0 +1,16 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path fill="currentColor" d="M810.666667 618.666667s-85.333333 93.866667-85.333334 149.333333c0 46.933333 38.4 85.333333 85.333334 85.333333s85.333333-38.4 85.333333-85.333333c0-55.466667-85.333333-149.333333-85.333333-149.333333M221.866667 554.666667L426.666667 349.866667l204.8 204.8m76.8-46.933334L324.266667 128 264.533333 187.733333l102.4 102.4-221.866666 217.6c-25.6 25.6-25.6 64 0 89.6l234.666666 234.666667c25.6 25.6 64 25.6 89.6 0l234.666667-234.666667c25.6-21.333333 29.866667-64 4.266667-89.6z" p-id="4284">
</path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

15
vite-element-template/src/components/flowEdit/icon/ColorText.vue

@ -0,0 +1,15 @@
<template>
<svg class="icon" viewBox="0 0 1024 1024" :width="size" :height="size">
<path d="M512 725.333333a128 128 0 1 1 0 256 128 128 0 0 1 0-256zM469.333333 85.333333L234.666667 682.666667h96l47.786666-128h266.666667l47.786667 128h96L554.666667 85.333333h-85.333334z m-58.88 384L512 199.253333 613.546667 469.333333H410.453333z" p-id="4479"></path>
</svg>
</template>
<script>
export default {
props: {
size: {
default: '24'
}
}
}
</script>

19
vite-element-template/src/components/flowEdit/icon/Cross.vue

@ -0,0 +1,19 @@
<template>
<!-- 加号 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,9 9,9 9,0 18,0 18,9 27,9 27,18 18,18 18,27 9,27 9,18 0,18"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

27
vite-element-template/src/components/flowEdit/icon/Cylinde.vue

@ -0,0 +1,27 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 5.78 6.46 C 5.78 3.64 10.35 1.36 15.98 1.36 C 18.69 1.36 21.28 1.9 23.19 2.85 C 25.11 3.81 26.18 5.11 26.18 6.46 L 26.18 23.46 C 26.18 26.28 21.61 28.56 15.98 28.56 C 10.35 28.56 5.78 26.28 5.78 23.46 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
<path
d="M 26.18 6.46 C 26.18 9.28 21.61 11.56 15.98 11.56 C 10.35 11.56 5.78 9.28 5.78 6.46"
fill="none"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

19
vite-element-template/src/components/flowEdit/icon/Diamond.vue

@ -0,0 +1,19 @@
<template>
<svg>
<g transform="translate(0.5,0.5)" style="visibility: visible">
<path
d="M 15.98 1.36 L 29.58 14.96 L 15.98 28.56 L 2.38 14.96 Z"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
stroke-miterlimit="10"
pointer-events="all"
></path>
</g>
</svg>
</template>
<script>
export default {
}
</script>

18
vite-element-template/src/components/flowEdit/icon/DownArrow.vue

@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="10,0 20,0 20,18 30,18 15,28 0,18 10,18"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

21
vite-element-template/src/components/flowEdit/icon/Ellipse.vue

@ -0,0 +1,21 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<ellipse
cx="15.84"
cy="14.88"
rx="14.399999999999999"
ry="9.6"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></ellipse>
</g>
</svg>
</template>
<script>
export default {
}
</script>

19
vite-element-template/src/components/flowEdit/icon/Heptagon.vue

@ -0,0 +1,19 @@
<template>
<!-- 八边形 -->
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="19.74,0 28,8.26 28,19.74 19.74,28 8.26,28 0,19.74 0,8.26 8.26,0"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

18
vite-element-template/src/components/flowEdit/icon/HorizontalArrow.vue

@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,13.6 9,2.2 9,11.2 18,11.2 18,2.2 27,13.6 18,27.2 18,18.2 9,18.2 9,27.2"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

18
vite-element-template/src/components/flowEdit/icon/LeftArrow.vue

@ -0,0 +1,18 @@
<template>
<svg class="svg-node">
<g transform="translate(0.5,0.5)" style="visibility: visible">
<polygon
points="0,15 10,0 10,10 30,10 30,20 10,20 10,30"
fill="#ffffff"
stroke="#000000"
stroke-width="1.3"
pointer-events="all"
></polygon>
</g>
</svg>
</template>
<script>
export default {
}
</script>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save