@ -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 |
@ -0,0 +1,2 @@ |
|||
VITE_APP_COMPANY=asdzxcasdzxc |
|||
|
@ -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 |
@ -0,0 +1,4 @@ |
|||
# base api |
|||
VITE_APP_BASE_API=/cc-admin |
|||
|
|||
VITE_APP_BASE_URL=http://222.128.25.216:4050 |
@ -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']
|
|||
} |
|||
} |
@ -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 |
@ -0,0 +1,5 @@ |
|||
language: node_js |
|||
node_js: 10 |
|||
script: npm run test |
|||
notifications: |
|||
email: false |
@ -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. |
@ -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. 自定义字体图标(无、不建议使用) |
@ -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,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> |
@ -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' |
|||
} |
@ -0,0 +1,16 @@ |
|||
{ |
|||
"vueCompilerOptions": { |
|||
"target": 2.7 |
|||
}, |
|||
"compilerOptions": { |
|||
"target": "esnext", |
|||
"module": "esnext", |
|||
"moduleResolution": "node", |
|||
|
|||
"baseUrl": "./", |
|||
"paths": { |
|||
"@/*": ["src/*"] |
|||
} |
|||
}, |
|||
"exclude": ["node_modules", "dist"] |
|||
} |
@ -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" |
|||
} |
After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 142 KiB |
@ -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> |
|||
|
@ -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(默认),180,270 三个值 |
|||
*/ |
|||
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.264视频(Safari on iOS不支持) |
|||
* * 不支持 forceNoOffscreen 为 false (开启离屏渲染) |
|||
*/ |
|||
useMSE?: boolean; |
|||
/** |
|||
* 是否开启Webcodecs硬解码 |
|||
* * 视频编码只支持H.264视频 (需在chrome 94版本以上,需要https或者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分辨率下的U、V分量宽度是540/2=270不能被4整除,导致绿屏。 |
|||
*/ |
|||
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; |
|||
|
|||
/** |
|||
* 留给上层用户操作来触发音频恢复的方法。 |
|||
* |
|||
* iPhone,chrome等要求自动播放时,音频必须静音,需要由一个真实的用户交互操作来恢复,不能使用代码。 |
|||
* |
|||
* 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(默认) ,180,270 三个值。 |
|||
* |
|||
* > 可用于实现监控画面小窗和全屏效果,由于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 84及以上有原生亮屏API, 需要是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 可选,默认webm,支持webm 和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; |
@ -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 |
|||
} |
After Width: | Height: | Size: 6.2 KiB |
@ -0,0 +1,11 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<router-view /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App' |
|||
} |
|||
</script> |
@ -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 |
|||
}) |
|||
} |
@ -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 |
|||
}) |
|||
} |
@ -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 |
|||
}) |
|||
} |
|||
|
@ -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); |
|||
}); |
|||
}); |
|||
|
|||
} |
@ -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(); |
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
@ -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, //0通过1驳回 |
|||
|
|||
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, //0通过1驳回 |
|||
|
|||
// 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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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 = ""; |
|||
// 如果端口是80或443,则默认端口,无需显示在 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> |
@ -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", //add或edit |
|||
}; |
|||
}, |
|||
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> |
@ -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", //add或edit |
|||
}; |
|||
}, |
|||
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> |
@ -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", //add或edit |
|||
}; |
|||
}, |
|||
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> |
@ -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> |
@ -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", //add或edit |
|||
}; |
|||
}, |
|||
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> |
@ -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", //add或edit |
|||
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> |
@ -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", //add或edit |
|||
}; |
|||
}, |
|||
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> |
@ -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", //add或edit |
|||
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> |
@ -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> |
@ -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", //add或edit |
|||
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> |
@ -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", //add或edit |
|||
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> |
@ -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", //add或edit |
|||
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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -0,0 +1,12 @@ |
|||
// 元素属性右侧面板默认属性
|
|||
export const defatuleStyle = { |
|||
backgroundColor: '', // 填充色
|
|||
gradientColor: '', // 渐变色
|
|||
borderType: 0, // 边框类型
|
|||
borderColor: '', // 填充颜色
|
|||
borderWidth: 1, // 边框宽度
|
|||
borderStyle: '', // 边框类型
|
|||
fontSize: 12, // 文本大小
|
|||
fontColor: '', // 文本颜色
|
|||
fontWeight: '' // 文本加粗
|
|||
} |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |