!118 ♥️发布 5.2.0-BETA 公测版本
Merge pull request !118 from 疯狂的狮子Li/dev
已修改133个文件
已添加90个文件
已重命名2个文件
已删除4个文件
| | |
| | | # çæ§å°å |
| | | VITE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/applications' |
| | | |
| | | # powerjob æ§å¶å°å°å |
| | | VITE_APP_POWERJOB_ADMIN = 'http://localhost:7700/' |
| | | # SnailJob æ§å¶å°å°å |
| | | VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job' |
| | | |
| | | VITE_APP_PORT = 80 |
| | | |
| | | # æ¥å£å å¯åè½å¼å
³(å¦éå
³é å端ä¹å¿
须对åºå
³é) |
| | | VITE_APP_ENCRYPT = true |
| | | # æ¥å£å å¯ä¼ è¾ RSA å
¬é¥ä¸å端解å¯ç§é¥å¯¹åº 妿´æ¢éåå端ä¸åæ´æ¢ |
| | | VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' |
| | | # æ¥å£ååºè§£å¯ RSA ç§é¥ä¸å端å å¯å
¬é¥å¯¹åº 妿´æ¢éåå端ä¸åæ´æ¢ |
| | |
| | | # 客æ·ç«¯id |
| | | VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' |
| | | |
| | | # websocket å¼å
³(å¼åç¯å¢é»è®¤å
³éws å viteçbug导è´å¦wsæ æ³è¿æ¥åä¼å´©æº) |
| | | VITE_APP_WEBSOCKET = false |
| | | # websocket å¼å
³ |
| | | VITE_APP_WEBSOCKET = true |
| | |
| | | # çæ§å°å |
| | | VITE_APP_MONITRO_ADMIN = '/admin/applications' |
| | | |
| | | # powerjob æ§å¶å°å°å |
| | | VITE_APP_POWERJOB_ADMIN = '/powerjob' |
| | | # SnailJob æ§å¶å°å°å |
| | | VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job' |
| | | |
| | | # ç产ç¯å¢ |
| | | VITE_APP_BASE_API = '/prod-api' |
| | |
| | | |
| | | VITE_APP_PORT = 80 |
| | | |
| | | # æ¥å£å å¯åè½å¼å
³(å¦éå
³é å端ä¹å¿
须对åºå
³é) |
| | | VITE_APP_ENCRYPT = true |
| | | # æ¥å£å å¯ä¼ è¾ RSA å
¬é¥ä¸å端解å¯ç§é¥å¯¹åº 妿´æ¢éåå端ä¸åæ´æ¢ |
| | | VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' |
| | | # æ¥å£ååºè§£å¯ RSA ç§é¥ä¸å端å å¯å
¬é¥å¯¹åº 妿´æ¢éåå端ä¸åæ´æ¢ |
| | |
| | | .husky |
| | | .local |
| | | /bin |
| | | .eslintrc.js |
| | | .eslintrc.cjs |
| | | prettier.config.js |
| | | src/assets |
| | | tailwind.config.js |
| | | tailwind.config.js |
ÎļþÃû´Ó .eslintrc.js ÐÞ¸Ä |
| | |
| | | module.exports = { |
| | | env: { |
| | | browser: true, |
| | | es2021: true, |
| | | node: true |
| | | node: true, |
| | | es6: true |
| | | }, |
| | | parser: 'vue-eslint-parser', |
| | | extends: [ |
| | | 'eslint:recommended', |
| | | 'plugin:vue/vue3-essential', |
| | | 'plugin:@typescript-eslint/recommended', |
| | | 'plugin:vue/vue3-recommended', |
| | | './.eslintrc-auto-import.json', |
| | | 'plugin:@typescript-eslint/recommended', |
| | | 'prettier', |
| | | 'plugin:prettier/recommended' |
| | | ], |
| | | parserOptions: { |
| | | ecmaVersion: '2020', |
| | | sourceType: 'module', |
| | | project: './tsconfig.*?.json', |
| | | parser: '@typescript-eslint/parser' |
| | | }, |
| | | plugins: ['vue', '@typescript-eslint'], |
| | | plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'], |
| | | rules: { |
| | | 'vue/multi-word-component-names': 'off', |
| | | '@typescript-eslint/no-empty-function': 'off', |
| | | '@typescript-eslint/no-explicit-any': 'off', |
| | | '@typescript-eslint/no-unused-vars': 'off', |
| | | '@typescript-eslint/no-this-alias': 'off', |
| | | |
| | | // vue |
| | | 'vue/multi-word-component-names': 'off', |
| | | 'vue/valid-define-props': 'off', |
| | | 'vue/no-v-model-argument': 'off', |
| | | 'prefer-rest-params': 'off', |
| | | // prettier |
| | | 'prettier/prettier': 'error', |
| | | '@typescript-eslint/ban-types': [ |
| | | 'error', |
| | | { |
| | |
| | | |
| | | package-lock.json |
| | | yarn.lock |
| | | pnpm-lock.yaml |
| | | |
| | | # ç¼è¯çæçæä»¶ |
| | | auto-imports.d.ts |
¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "printWidth": 150, |
| | | "tabWidth": 2, |
| | | "useTabs": false, |
| | | "semi": true, |
| | | "singleQuote": true, |
| | | "quoteProps": "preserve", |
| | | "jsxSingleQuote": false, |
| | | "bracketSameLine": false, |
| | | "trailingComma": "none", |
| | | "bracketSpacing": true, |
| | | "embeddedLanguageFormatting": "auto", |
| | | "arrowParens": "always", |
| | | "requirePragma": false, |
| | | "insertPragma": false, |
| | | "proseWrap": "preserve", |
| | | "htmlWhitespaceSensitivity": "css", |
| | | "vueIndentScriptAndStyle": false, |
| | | "endOfLine": "auto" |
| | | } |
| | |
| | | ## å¹³å°ç®ä» |
| | | |
| | | * æ¬ä»åºä¸ºåç«¯ææ¯æ [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) çæ¬ã |
| | | * é
å¥å端代ç ä»åºå°å |
| | | * [RuoYi-Vue-Plus 5.X(注æçæ¬å·)](https://gitee.com/dromara/RuoYi-Vue-Plus) |
| | | * [RuoYi-Cloud-Plus 2.X(注æçæ¬å·)](https://gitee.com/dromara/RuoYi-Cloud-Plus) |
| | | - æ¬ä»åºä¸ºåç«¯ææ¯æ [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) çæ¬ã |
| | | - æå项ç®: åºäº vben(ant-design-vue) çåç«¯é¡¹ç® [ruoyi-plus-vben](https://gitee.com/dapppp/ruoyi-plus-vben) |
| | | - é
å¥å端代ç ä»åºå°å |
| | | - [RuoYi-Vue-Plus 5.X(注æçæ¬å·)](https://gitee.com/dromara/RuoYi-Vue-Plus) |
| | | - [RuoYi-Cloud-Plus 2.X(注æçæ¬å·)](https://gitee.com/dromara/RuoYi-Cloud-Plus) |
| | | |
| | | ## å端è¿è¡ |
| | | |
| | |
| | | # å¯å¨æå¡ |
| | | npm run dev |
| | | |
| | | # æå»ºç产ç¯å¢ |
| | | # æå»ºç产ç¯å¢ |
| | | npm run build:prod |
| | | |
| | | # å端访é®å°å http://localhost:80 |
| | |
| | | |
| | | ## æ¬æ¡æ¶ä¸RuoYiçä¸å¡å·®å¼ |
| | | |
| | | | ä¸å¡ | åè½è¯´æ | æ¬æ¡æ¶ | RuoYi | |
| | | |--------|-----------------------------------------|-----|------------------| |
| | | | ç§æ·ç®¡ç | ç³»ç»å
ç§æ·ç管ç å¦:ç§æ·å¥é¤ãè¿ææ¶é´ãç¨æ·æ°éãä¼ä¸ä¿¡æ¯ç | æ¯æ | æ | |
| | | | ç§æ·å¥é¤ç®¡ç | ç³»ç»å
ç§æ·æè½ä½¿ç¨çå¥é¤ç®¡ç å¦:å¥é¤å
æå
å«çèåç | æ¯æ | æ | |
| | | | ç¨æ·ç®¡ç | ç¨æ·ç管çé
ç½® å¦:æ°å¢ç¨æ·ãåé
ç¨æ·æå±é¨é¨ãè§è²ãå²ä½ç | æ¯æ | æ¯æ | |
| | | | é¨é¨ç®¡ç | é
置系ç»ç»ç»æºæï¼å
¬å¸ãé¨é¨ãå°ç»ï¼ æ ç»æå±ç°æ¯ææ°æ®æé | æ¯æ | æ¯æ | |
| | | | å²ä½ç®¡ç | é
置系ç»ç¨æ·æå±æ
ä»»èå¡ | æ¯æ | æ¯æ | |
| | | | èå管ç | é
置系ç»èåãæä½æéãæé®æéæ è¯ç | æ¯æ | æ¯æ | |
| | | | è§è²ç®¡ç | è§è²èåæéåé
ã设置è§è²ææºæè¿è¡æ°æ®èå´æéåå | æ¯æ | æ¯æ | |
| | | | åå
¸ç®¡ç | 对系ç»ä¸ç»å¸¸ä½¿ç¨çä¸äºè¾ä¸ºåºå®çæ°æ®è¿è¡ç»´æ¤ | æ¯æ | æ¯æ | |
| | | | åæ°ç®¡ç | 对系ç»å¨æé
置常ç¨åæ° | æ¯æ | æ¯æ | |
| | | | éç¥å
¬å | ç³»ç»éç¥å
¬åä¿¡æ¯åå¸ç»´æ¤ | æ¯æ | æ¯æ | |
| | | | æä½æ¥å¿ | ç³»ç»æ£å¸¸æä½æ¥å¿è®°å½åæ¥è¯¢ ç³»ç»å¼å¸¸ä¿¡æ¯æ¥å¿è®°å½åæ¥è¯¢ | æ¯æ | æ¯æ | |
| | | | ç»å½æ¥å¿ | ç³»ç»ç»å½æ¥å¿è®°å½æ¥è¯¢å
å«ç»å½å¼å¸¸ | æ¯æ | æ¯æ | |
| | | | æä»¶ç®¡ç | ç³»ç»æä»¶å±ç¤ºãä¸ä¼ ãä¸è½½ãå é¤ç管ç | æ¯æ | æ | |
| | | | æä»¶é
置管ç | ç³»ç»æä»¶ä¸ä¼ ãä¸è½½æéè¦çé
置信æ¯å¨ææ·»å ãä¿®æ¹ãå é¤ç管ç | æ¯æ | æ | |
| | | | å¨çº¿ç¨æ·ç®¡ç | å·²ç»å½ç³»ç»çå¨çº¿ç¨æ·ä¿¡æ¯çæ§ä¸å¼ºå¶è¸¢åºæä½ | æ¯æ | æ¯æ | |
| | | | 宿¶ä»»å¡ | è¿è¡æ¥è¡¨ãä»»å¡ç®¡ç(æ·»å ãä¿®æ¹ãå é¤)ãæ¥å¿ç®¡çãæ§è¡å¨ç®¡çç | æ¯æ | ä»
æ¯æä»»å¡ä¸æ¥å¿ç®¡ç | |
| | | | 代ç çæ | 夿°æ®æºåå端代ç ççæï¼javaãhtmlãxmlãsqlï¼æ¯æCRUDä¸è½½ | æ¯æ | ä»
æ¯æåæ°æ®æº | |
| | | | ç³»ç»æ¥å£ | æ ¹æ®ä¸å¡ä»£ç èªå¨çæç¸å
³çapiæ¥å£ææ¡£ | æ¯æ | æ¯æ | |
| | | | æå¡çæ§ | çè§é群系ç»CPUãå
åãç£çãå æ ãå¨çº¿æ¥å¿ãSpringç¸å
³é
ç½®ç | æ¯æ | ä»
æ¯æåæºCPUãå
åãç£ççæ§ | |
| | | | ç¼åçæ§ | 对系ç»çç¼åä¿¡æ¯æ¥è¯¢ï¼å½ä»¤ç»è®¡çã | æ¯æ | æ¯æ | |
| | | | å¨çº¿æå»ºå¨ | æå¨è¡¨åå
ç´ çæç¸åºçHTML代ç ã | æ¯æ | æ¯æ | |
| | | | ä½¿ç¨æ¡ä¾ | ç³»ç»çä¸äºåè½æ¡ä¾ | æ¯æ | 䏿¯æ | |
| | | | ä¸å¡ | åè½è¯´æ | æ¬æ¡æ¶ | RuoYi | |
| | | | ------------ | ------------------------------------------------------------- | ------ | ----------------------------- | |
| | | | ç§æ·ç®¡ç | ç³»ç»å
ç§æ·ç管ç å¦:ç§æ·å¥é¤ãè¿ææ¶é´ãç¨æ·æ°éãä¼ä¸ä¿¡æ¯ç | æ¯æ | æ | |
| | | | ç§æ·å¥é¤ç®¡ç | ç³»ç»å
ç§æ·æè½ä½¿ç¨çå¥é¤ç®¡ç å¦:å¥é¤å
æå
å«çèåç | æ¯æ | æ | |
| | | | ç¨æ·ç®¡ç | ç¨æ·ç管çé
ç½® å¦:æ°å¢ç¨æ·ãåé
ç¨æ·æå±é¨é¨ãè§è²ãå²ä½ç | æ¯æ | æ¯æ | |
| | | | é¨é¨ç®¡ç | é
置系ç»ç»ç»æºæï¼å
¬å¸ãé¨é¨ãå°ç»ï¼ æ ç»æå±ç°æ¯ææ°æ®æé | æ¯æ | æ¯æ | |
| | | | å²ä½ç®¡ç | é
置系ç»ç¨æ·æå±æ
ä»»èå¡ | æ¯æ | æ¯æ | |
| | | | èå管ç | é
置系ç»èåãæä½æéãæé®æéæ è¯ç | æ¯æ | æ¯æ | |
| | | | è§è²ç®¡ç | è§è²èåæéåé
ã设置è§è²ææºæè¿è¡æ°æ®èå´æéåå | æ¯æ | æ¯æ | |
| | | | åå
¸ç®¡ç | 对系ç»ä¸ç»å¸¸ä½¿ç¨çä¸äºè¾ä¸ºåºå®çæ°æ®è¿è¡ç»´æ¤ | æ¯æ | æ¯æ | |
| | | | åæ°ç®¡ç | 对系ç»å¨æé
置常ç¨åæ° | æ¯æ | æ¯æ | |
| | | | éç¥å
¬å | ç³»ç»éç¥å
¬åä¿¡æ¯åå¸ç»´æ¤ | æ¯æ | æ¯æ | |
| | | | æä½æ¥å¿ | ç³»ç»æ£å¸¸æä½æ¥å¿è®°å½åæ¥è¯¢ ç³»ç»å¼å¸¸ä¿¡æ¯æ¥å¿è®°å½åæ¥è¯¢ | æ¯æ | æ¯æ | |
| | | | ç»å½æ¥å¿ | ç³»ç»ç»å½æ¥å¿è®°å½æ¥è¯¢å
å«ç»å½å¼å¸¸ | æ¯æ | æ¯æ | |
| | | | æä»¶ç®¡ç | ç³»ç»æä»¶å±ç¤ºãä¸ä¼ ãä¸è½½ãå é¤ç管ç | æ¯æ | æ | |
| | | | æä»¶é
置管ç | ç³»ç»æä»¶ä¸ä¼ ãä¸è½½æéè¦çé
置信æ¯å¨ææ·»å ãä¿®æ¹ãå é¤ç管ç | æ¯æ | æ | |
| | | | å¨çº¿ç¨æ·ç®¡ç | å·²ç»å½ç³»ç»çå¨çº¿ç¨æ·ä¿¡æ¯çæ§ä¸å¼ºå¶è¸¢åºæä½ | æ¯æ | æ¯æ | |
| | | | 宿¶ä»»å¡ | è¿è¡æ¥è¡¨ãä»»å¡ç®¡ç(æ·»å ãä¿®æ¹ãå é¤)ãæ¥å¿ç®¡çãæ§è¡å¨ç®¡çç | æ¯æ | ä»
æ¯æä»»å¡ä¸æ¥å¿ç®¡ç | |
| | | | 代ç çæ | 夿°æ®æºåå端代ç ççæï¼javaãhtmlãxmlãsqlï¼æ¯æCRUDä¸è½½ | æ¯æ | ä»
æ¯æåæ°æ®æº | |
| | | | ç³»ç»æ¥å£ | æ ¹æ®ä¸å¡ä»£ç èªå¨çæç¸å
³çapiæ¥å£ææ¡£ | æ¯æ | æ¯æ | |
| | | | æå¡çæ§ | çè§é群系ç»CPUãå
åãç£çãå æ ãå¨çº¿æ¥å¿ãSpringç¸å
³é
ç½®ç | æ¯æ | ä»
æ¯æåæºCPUãå
åãç£ççæ§ | |
| | | | ç¼åçæ§ | 对系ç»çç¼åä¿¡æ¯æ¥è¯¢ï¼å½ä»¤ç»è®¡çã | æ¯æ | æ¯æ | |
| | | | å¨çº¿æå»ºå¨ | æå¨è¡¨åå
ç´ çæç¸åºçHTML代ç ã | æ¯æ | æ¯æ | |
| | | | ä½¿ç¨æ¡ä¾ | ç³»ç»çä¸äºåè½æ¡ä¾ | æ¯æ | 䏿¯æ | |
| | | |
| | | ## æ¼ç¤ºå¾ä¾ |
| | | |
| | | | | | |
| | | |--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | | | | |
| | | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | | |  |  | |
| | |
| | | <!DOCTYPE html> |
| | | <!doctype html> |
| | | <html lang="zh-CN"> |
| | | <head> |
| | | <meta charset="UTF-8" /> |
| | |
| | | <meta name="renderer" content="webkit" /> |
| | | <base target="_blank" /> |
| | | <style type="text/css"> |
| | | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0} |
| | | a{text-decoration:none;color:#0072c6;}a:hover{text-decoration:none;color:#004d8c;} |
| | | body{width:960px;margin:0 auto;padding:10px;font-size:14px;line-height:24px;color:#454545;font-family:'Microsoft YaHei UI','Microsoft YaHei',DengXian,SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif;overflow-y:scroll} |
| | | h1{font-size:40px;line-height:80px;font-weight:100;margin-bottom:10px;} |
| | | h2{font-size:20px;line-height:25px;font-weight:100;margin:10px 0;} |
| | | em{color:red} |
| | | p{margin-bottom:10px;} |
| | | hr{margin:20px 0;border:0;border-top:1px solid #dadada} |
| | | span{display:block;font-size:12px;line-height:12px;} |
| | | .clean{clear:both;} |
| | | .browser{padding:10px 10px;} |
| | | .browser li{width:auto;padding:0 80px;margin-top:30px;height:34px;line-height:22px;float:left;list-style:none;background:url(data:image/png;base64,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) no-repeat;padding-left:40px} |
| | | .browser .browser-firefox{background-position:0 -34px} |
| | | .browser .browser-ie{background-position:0 -68px;margin-left:0px} |
| | | .browser .browser-360{background-position:0 -170px;margin-left: -27px} |
| | | html, |
| | | body, |
| | | div, |
| | | span, |
| | | applet, |
| | | object, |
| | | iframe, |
| | | h1, |
| | | h2, |
| | | h3, |
| | | h4, |
| | | h5, |
| | | h6, |
| | | p, |
| | | blockquote, |
| | | pre, |
| | | a, |
| | | abbr, |
| | | acronym, |
| | | address, |
| | | big, |
| | | cite, |
| | | code, |
| | | del, |
| | | dfn, |
| | | em, |
| | | img, |
| | | ins, |
| | | kbd, |
| | | q, |
| | | s, |
| | | samp, |
| | | small, |
| | | strike, |
| | | strong, |
| | | sub, |
| | | sup, |
| | | tt, |
| | | var, |
| | | b, |
| | | u, |
| | | i, |
| | | center, |
| | | dl, |
| | | dt, |
| | | dd, |
| | | ol, |
| | | ul, |
| | | li, |
| | | fieldset, |
| | | form, |
| | | label, |
| | | legend, |
| | | table, |
| | | caption, |
| | | tbody, |
| | | tfoot, |
| | | thead, |
| | | tr, |
| | | th, |
| | | td, |
| | | article, |
| | | aside, |
| | | canvas, |
| | | details, |
| | | embed, |
| | | figure, |
| | | figcaption, |
| | | footer, |
| | | header, |
| | | hgroup, |
| | | menu, |
| | | nav, |
| | | output, |
| | | ruby, |
| | | section, |
| | | summary, |
| | | time, |
| | | mark, |
| | | audio, |
| | | video { |
| | | border: 0; |
| | | font-size: 100%; |
| | | font: inherit; |
| | | vertical-align: baseline; |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | article, |
| | | aside, |
| | | details, |
| | | figcaption, |
| | | figure, |
| | | footer, |
| | | header, |
| | | hgroup, |
| | | menu, |
| | | nav, |
| | | section { |
| | | display: block; |
| | | } |
| | | body { |
| | | line-height: 1; |
| | | } |
| | | ol, |
| | | ul { |
| | | list-style: none; |
| | | } |
| | | blockquote, |
| | | q { |
| | | quotes: none; |
| | | } |
| | | blockquote:before, |
| | | blockquote:after, |
| | | q:before, |
| | | q:after { |
| | | content: none; |
| | | } |
| | | table { |
| | | border-collapse: collapse; |
| | | border-spacing: 0; |
| | | } |
| | | a { |
| | | text-decoration: none; |
| | | color: #0072c6; |
| | | } |
| | | a:hover { |
| | | text-decoration: none; |
| | | color: #004d8c; |
| | | } |
| | | body { |
| | | width: 960px; |
| | | margin: 0 auto; |
| | | padding: 10px; |
| | | font-size: 14px; |
| | | line-height: 24px; |
| | | color: #454545; |
| | | font-family: 'Microsoft YaHei UI', 'Microsoft YaHei', DengXian, SimSun, 'Segoe UI', Tahoma, Helvetica, sans-serif; |
| | | overflow-y: scroll; |
| | | } |
| | | h1 { |
| | | font-size: 40px; |
| | | line-height: 80px; |
| | | font-weight: 100; |
| | | margin-bottom: 10px; |
| | | } |
| | | h2 { |
| | | font-size: 20px; |
| | | line-height: 25px; |
| | | font-weight: 100; |
| | | margin: 10px 0; |
| | | } |
| | | em { |
| | | color: red; |
| | | } |
| | | p { |
| | | margin-bottom: 10px; |
| | | } |
| | | hr { |
| | | margin: 20px 0; |
| | | border: 0; |
| | | border-top: 1px solid #dadada; |
| | | } |
| | | span { |
| | | display: block; |
| | | font-size: 12px; |
| | | line-height: 12px; |
| | | } |
| | | .clean { |
| | | clear: both; |
| | | } |
| | | .browser { |
| | | padding: 10px 10px; |
| | | } |
| | | .browser li { |
| | | width: auto; |
| | | padding: 0 80px; |
| | | margin-top: 30px; |
| | | height: 34px; |
| | | line-height: 22px; |
| | | float: left; |
| | | list-style: none; |
| | | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAADMCAYAAAAWCXEwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAC7ESURBVHja5Lx5dFRV1rBfgHwYRQQVtB26ZWhtabtfeUGxGxFbUGZF8RMHGkVbRkekVYiKisicVhE0gEwBokgDAhEMMSSQkAECwcxkrlRSqVTqJqnxzs/vj5t7qUyAvr9e37fWV2vtleSm6p6n9t5nn733OVU2RaUaEP5PiqJSbeMXPBTA5/Xhzk9Vnd9vo3HFx21E2LYJX9IRgh6npvyCe9uaqS4K4C3IpXHFx9S99CTuJ8Z0KLVjRlA7ZgTuJ8ZgXxmJL+kIlwAkXBQk6HFq9pWRVA8fSvXwodYgdS892a6EA1UNvouqwXdR99KTeAtyfz2IL+kI1cOHYh9wqwVwKWJqpXbMCOv19gG3Imzb1JF2OgZxfr/NukH4jcNVfyEAE8IU+4BbKet1PfaVke3BtA/i/H6b8aIBt7a4mWmaC0nr55vmqRp8F5V33Mm5LhHtwbQF8SUdsSDCb1I1+K42g1xIWgOYYh9wK+e6RCBs29QxSIWus37aJM51iWjx4so77mwD1d5AHQ1eecedlN9yuyVlva6nrNf14Q7cEmRn4W7u3T2E9ME3UX7L7W1uZg5Weced1s3sA2613ql5LXzQjuRclwjcT4wxTXQeRHC7GLdnHPeensiCVwa3e0PznZk3EbZtwluQa0kofz8NcVNxr++Ce30XnNuv61Bcu7viXt8Fvyu7JYipjfGHxzD+8Bh2j+7fAiZcC+Y0zPDIbCyD6DyV6DyVeDcIQR2C39J4oieNJ3oSOnkVcnZ35Ozu6MVdDHF0N6S4C43OqJYg/0ydzb27hzDx0FjuPT2R+asfa6OVsl7X40s6QoWus/CQk6fWZPHChhxe3lbMCxtyrN9TyxSQSwidvMoC0XK6tRGybPjSRmOuNUKVo4Zxe8YxIu4+Jh4ay/jDY7j39MQWWjnXJYLGFR9Toes8tSaLiavTrIHDxfxfapkCwW8hy9YuhCmhk1fR1FRnaCS1NM4yy8RDYy2tjIkZRXq/HtYsCnqc2sJDTkYsTrU00J6YkEJQR7M/eEGY0MmrcOenqjZA2JmyzTJLuJiOe65LBHUvPUmGR2bE4lQmrk7jqTVZHcrE1WkMWpRIdJ4KnpUXBCHLRl3e16EWIOEaMU00/vAY9na/gsYVH/NdgYe+8w9bMBeSQYsSWXjICcFvL2ga+dhlFwcJ10rjio/ZklprgbSWiavTWvzdd/5hXt5W/OtATC201sq9u4eQ+PVijmSW0nf+YQYtSmTQosR2gUYsTmXQokT6zj9saeRCpmkJ0hxD2gOZeGgsI+Lu45+ps7FXlFmDmDDtSd/5h+k7/zCpZQpa9cwOQciyIR+77LyzFhXlMyZmFOP2jLP8orVWRsTdR2ppHFtSa+k6ZZM1WHvSdcomwyxySceayO4OWTY88TdirygzUkWf18eL2//RQiutYcwYE/Q4tagDOUQ8uo6uUzbRZ3qMJV2nbCLi0XU8tSbrolNXzu6OfOyylgEN4NOkaO5acw/j9ozr0ET37h5imehIZimPL91rAfSZHsOQBfuISS7E7vaTETeX0MmrOoQInbwK+dhlNKWsahni0zPSuGvNPW1M1BrI1NrOwt0WkCn2ijJSS+MYt2ccuQk3oxd36RCi8URPY+HLT1VbgGiSzPsx71laCddMe2Yygf6ZOtuScXvG0XfJn/n8YL+LQnjibyQ34WZ8Xl/bfKSoKL+FVi4EYwKZcu/uIQzaPoExMaPQcrq1ADFX33AI1+6u1OV9HVI6ShU/TYqm75I/dwjTHtDEQ2MZt2ccg7ZPaGGScIDWEBlxc42UoSMQ00StYdoDCgcbtH0Cbx+8p40ZTIBwiFM7RmB3+y+exZvT2YRpDdR6ZoVrw1xRWwN44m/Euf06A6Ki7NLrmnDNmH7TEdSg7RP4/GA/yLK1GdwEKNzSk1M7RlDlqPl1JefOlG2MXTGmXaAxMaMsB/XE34h4tH+7ANlrB7T2iV8OAlDlqOH9mPcsIBPKlF3R16Ad7GwlxoVberYAKCrKv1ghfmkg5sPldLIzZVsLqLErxpC9doAlp3aMICNurlGyVpRdSAu/HqS1Q58rd1JUlI87P1UtKsrHXlGG3e1HCOoov+x2wiX3RxT+o49L1IgutXxVUCfDIxNfLraQDI+M3e3/NdCXbhohqBNfLrIsVzZqmoT6dmXG0SBLTrmJLxd/CVRLECXcDGFaSC1TmHE0yKg4B0P2uxiy38WoOAePHaptAfHYoVqG7HcxcGc5o+IcfFfgsbQUPoYoSa213BbE78oGucTSwpJTbobFFjNgbQHdvi6g8/Z6Om+vZ8h+VxsQE7T/97UMWFvA+Og0UvIryfDIZBQ4CeXvt8a5IAhAY/RImlJWUaHrPHaolhuXFXHN+8e58qNcbomq5P6t3xG973WePLzPgnnsUG0LiP7f1zJwZzk3LisyctfSOFxOJ4lfLzYToQubxu/KpmpWBFWzInguOokrP8ql7/zDRMxLpFfUabasHwlZNnITbmbgznI6b6+3Bu7/fa2lrW5fF9Ar6jQD1hYwLLaYx5fupdi+EiGok748koa4qa010xKkKWUV2UM7kd6vB7tH9yfpnUFkLzQiZOGWnmgHO9N4oie9ok5bA4YPbkqvqNNc8/5xIuYl8tSaLOLLRXambENXF+PxNJD0ziAanVHhYaEliH1lJD/1iqD0qSsIzu2M/N550TZ3QjvYmS3rR1qDtwdhgpgwnabGMj46zRjQsxJdXYw7P1X1pY0GuaRjkMKxPah5qxuV8y6nct7l1LzVDfdyo6miHexM+ou9mblwKfdv/Y77t37HNe8fbwMQDhIxL5FOU2PZklqLJjUYdU7wWxBuN+ricBAF0KQG6pcNovZpw0fCQao/MEBcu7tSOLYHjnu7EZzbmeDczqyfNokrP8ptMXi4XDnzAJ0n72TIgn1oUoMB4VlpgIjj24I0payi9KkrqHj+Ssth2wM5c38f8p68D2nbHKRtc3h86d42A/eZHsOVMw9Y0nXKJmxDvyS1NA70z8Gz0qh5hNvbzpr6ZYMofzyiBUwLkOVdjfR/eVcao0dSl/d1aHx0GhHzEi0TXDnzAJ2mxtJpaixdp2yypM/0GLrcs5D3Y94ztNDsK7qjuxmzDBBz2rYGqZoVQc1b3dr4yfppk+g8eWeLd91aAxGPrqPbyKV0G7mUiEfXMWdz+nmQ0Jsgn1AbT/SkMXrkeZC6vK9DpU9d0S5I5bzLqf6gq6UV7WBn5q9+zDJBuEQ8us4SE6LLPQvpcs9CjmSW4ndlo1XPNBxWLiE34WbSX+wNapEBEsrfT/njERSO7WGBmDA1b3Wj9KkrSO/Xg1WjBjJl/CT+8sQ8a0BT/eGDhwN0uWchXe94ia07YkE+oSLc3gxyQt2yfiSrRg0E+YRqgRSO7UHh2B4UT7ragqmcdznFk67mp14ROO7txpTxk7AN/bLFgN1GLsU29EvrejiACdG59xQjKgu3GzVP9UwIvcmCVwYb102NmBHVBDFNVDUrgjP39yF98E0E5xox5Dcj5lsDhwOYQObg4dK59xR2RV8D4njEo/0NIEd3dkVfgy9t9HkfMTWSO6pXG63kjupF8aSrqXj+SoJzO1M573KmjJ/Eb0bM5y9PzGPBK4Mp3GKUEFvWj+Q3I+a3AOjcewp/eWKesUQ0T1mz2att7oSU9+F5EE2SqXvpSbKHdrIGNmHCoapmRVgh33LezZ3QNncyloGDnVnwyuA2IFvWj0Q+dplREzu6Wy0r9/KubVvg9pWRpPfrwZn7+1haMSHCxdSM/J4RWWufjiC9Xw/m9PgtN9w0uo1JbrhpNI0njAXTrAIbT/TEvb4LjdEj2641vqQjpPfrQfrgm1qYKHxKlz51BbmjerFj4G2WtAYwtWDKglcGG2ZoXrldu43AWDUrAmnbnLaRVZMayHvyPn7qZThoa38pfeoKap+OIDi3M6tGDeSGm0a3GTT82g03jeaGm0bj3H4d8rHLrN0I93LDpDsG3kb68si2a425hfZTrwjSB9/UBiZcM+YM6ghoyvhJpL/Ym+yFhknc67tYQVF+z3gjc3r8Fuf32zpOFTMeHXpRGDNfMYF2j+7PqlEDWTVqIOkv9rZ8SNvcCff6LlTOu9yK1Okv9mZOj9+S8ehQNKmBDhs17vxU9adeES1gwoHKH49oFyhcwhfKynmXWzOu4vkryR7aieyhnQjl7+84QzNNJGzbxN7uV1gw7WmntYZaLw2mmNdrn44ge2gnztzfx9od7zBnDa9t0pdHtgsTDhRustaaCndwEyLj0aG481PVS9r3FSUJj6eBrConMZHvnodpntrh2gkHCgcLl/TBN7G3+xXGLMlIo0LXjU7ixeoaUZIQ3C7OlTtJya8kJvJddgy8DctvWgGFaylcHPd2Y2/3K5jT47esGjWQrTtiyapy4nI6jUrvUmpfUytFRfmkZ6SxdUcs66dNYsfA2ywNtQBrJeb/dgy8jZjId/kx4YgF4fP6Ln1L3uyhhWvnSGYpOw6lEBP5LuunTWLDAw+x4YGHrAi74YGHWD9tEuunTSIm8l227ohtAyBK0i8/pNDagTVJxuf1YXf7OVfuJKvKMF16RhrpGWkcySwlJb+SrCqn1awRgjqaJP9nO0b/Zxo1v+ahS0ZqKJ9QCX5rJMyhN42aRj6h/udB5BKjiAp+i64uNrJ2M0Vs3rUiy4aU92G42X49iCYZDZjUMoX4ctFIcILfGgVU6E0LwEyCxKP98aWNxpc2GvFof+RjlyHlfdjxWnOxh93tJya5kIWHnDx2qJbnopP4NCmaYvtKC0LL6WYkQps70RA3laaUVbjzU1V7RRn2ijK8BbkWUJsM7VIAog7k8MyuPKtD1AJA/9zQQpYN9/oubFk/kpkLl7J4a0KbtrdZa/vSRrfMWS8GcSSzlGd25TH5VIjptTpR9T5SS+OMsrHZD3RHd7SDnTm1YwSzY2KsTtL46DSei07iSGZpm/tKeR8a5gnf0+vI8zfE5zAstpjptTrvifBJeeZ5LTQDkGXDtbsr0fte59mjDmaWaUyv1ZlZpvH3XJlRcQ6Grj5OTHJhy/t7VhrpwMVAog7kMCrOwcs+nZWaccak2L7S0oLpC6d2jGDJiUyWN8E6FVZqsLwJ5ruwYO5O9jFoUSIb4nPOT+/gtxf3kZjkQobFFreAaHRGGZoQbm+hhWd25fHsUQevHilgbo7bAmoNM2S/i6Grj3Mks9Tolcgn1Hb39MzHuXInw9edZrJd4z3xPISuLrYgCrf0ZOuOWKLzVFLLFDIKmlfr5EJmHMxhfoWvDczkUyELxl5RduFUUZNkIvdm8+BpkZd9eocQPyYc6XDnocpRQ+TebObmuFmptdTK5FMhBqwt4K1vMi4cWTMKnIyKczDZrvFJeWaHEBdrbVc5aphxMIflTR1rJaPA2TFI1IEc7k72tZwdYRCLtyZc6h4MMcmF7WrlwRSRAWsLiNyb3T6Iz+vjmV15jIpztIHwxN/I7JgY4svFS47CHk9DG62Y5hm4s5zx0Wntb0CnlikMiy3m06ToFpFSO9iZnSnbeGZXHkcyS8kocF6SHMksZc7m9AuaJyW/si3IltRaZsfEGNM09KZVs2bEzWV5EyzLlXn1SEG7MuNgTruy5JS73dlzd7IvPMi1BIlJLmRnyjbLJFawar7ZHi5NdrSS9jRyd7KPXlGnzQDXyjSlcYY2mk1SuKUnS05kslI7f9M9/HKgdaoh74nn/cR02NV7M9t2A9A/t/qf2uZOvB/zHvNdxk3Mm0bV+36VzK8wxHTWVutPmEbkE6q1hjQ3/yefCvGeeB7k1SPGlLsUeeubDOtnezJnczpvfZPBuXJnGEjzAqSri9FyulG4pSf3b/3OCvErNQNmxsEczpU70ST5kuWXJc9yiZXemQ3du5N9TK/VedmnW1qZm+M+v3r+gpTS42nA42nA5XRa4vE0hFd8zSDBb63cInvtAAYtSuTuZB+T7ZoFYy7tz+zK6+igQZtHRoGTyL3ZLab4M7vyGB+dxpAF+1i8NaEliLmWyNndsa+MZPi60/T/vpaJhTKT7ZqllZWaoZW3vsnA42m4IMS5cifPRScxN8fNeyK87NOZXqszsdDITa55/3i4dgVb0OPUTG2IR/vjzk9Vt6Qau5R3J/uYWCi3MJEJM2dzOkcyS80Q3WKrPia50IIIX2cmnwrxYIpIr6jTPBed1Mo0apFgpv0NcVMR3C5ESWLO5nS6fV3Ag6fFdmHmV/iYcTCHyL3ZRB3IsSRybzbP7MpjfoWvXYj+39cyZME+c7aEgTQ36smy0RA31dostrv9DF193IIJ9xcTxgSam+O2xAQwg9fMMo2JhTIPnjYgBi1KbC+RPq8REyR8iT9X7rRgWptpvssYLBwqHGB6rc7fc2ULYsh+F4MWJbLjUErH09c8ytcaxNTMCxtyGLC2oIUDT6/VO5TJdkMLJsTAneUMWpTYNotvE0eaj3rKxy6zun2t69mdKdt4fOley4lN35ls11pIOIC51D8XnWQu9xcGUQCteibyscuM5n31TKNqD5fm1H9DfA7PRScxdPVxhsUWMyy22Dq4MGS/i2GxxQxfd9oC2HEopb1WVcdtCU2Sqcv7OmTWpGbRLOV9SCh/P0GPUwvPvDIKnMQkFxK5N5s5m9N5LjqJ56KTeOubDFbvzSQlv7LN1P5FxzZ8Xp918v8SWk5WsWStLbr0a5oLHRdY/+GjPP8vtq7+0yCiJOHz+hDcLlxOJ2bzxeV0Irhdlk/9x0B8Xh9VjhoEt6s5rZTaFU1qQHC7qHLU/PpZ05EGqhw1uJxO0CVESSIlv5KoAznM2ZxufTJgzuZ0og7kkJJfaR1mcjmdVDlqflkc6ahSs1eUWdMzJrmQQYsSrYMJNy4raiHmYQWzD2IC2SvKLpa/dAzi8/qsc6cZBU6GLNjHlTMPcEtUJVMSdd45qRGdp7KxDOvDPu+c1JhxNMgtUZVcOfMAQxbss0K7vaLsQqbq+GCtCbEhPodOU2O58qNcZhwNsrMK4t0Xlp1VMONokCs/yqXT1FgrE7sATPvbJK0hblxWxDsnNWugvc7zcqFry3JlbomqbANzSdskpk9kFDjpOmWTpQnzne6sMgbbWWWYY8kpN0tOuYnOU1v8z9TcOyc1blxWRNcpmwwz6dLFjxr7vD5rY+eO13YSMS+Rh/co1iAby4wBluXKLDnl5rsCD1lVxk7FdwUelpxysyxXbvHcjWUwYb9CxLxE7nhtp7X10spELUHMMiHqQA6dJ+9k8KYaJh1u6ZRLTrnZklrb+hS3lURtSa1lySm39fyNZTAlUWfwpho6T95p1rqtS5LzICapJsmWNkbEBpiSqLMs1/gY3DsntfAuT4tDlkrYtci92bxzUmNjmaG9KYk6I2IDbbTStsBqjhma1EBKfiVdp2xiwNoCHt6jMOmwxjsnNev46KWUkaIksfCQk2W5Mu+c1Jh0WGPCfoUBawvoOmWT1d4Miy3nQczIuXpvJp2mxjJ4Uw0T9hsg09KM6fhcdBIxyYWXJM9FJzHjaJBpaTDpsAEzeFMNnabGGhVec+RtA1LlqAFd4vGley0Q8wZTEnWmpWGdWX3sUC3PHnW0K+b/n0qoZ1oaTEszfCQc5PGle0GXwv0k7PxI87S9EMjMMo35rvMdILPDbErrzlA4iOmw4SBh0/iXgUxLg8mnQvw9V2Zmmdau/D1XtpoxpiYe3qPw8B6FW6IqreOCvwpkWhqMinMwaFEi46PTfrFMXG38HLr6OHe8ttPykXZNYzrr4q0JdJoay4C1BS2cdfCmGuZsTrd6Hv/T5ozZJ7no9L1xWZE1fU0bD193unXx3GESFZNcyIb4nDazaUN8Dh6PkTy1O307CmgT9itM2K9YWnkuOumi26wTV6dZR43NXOXKj3LpPHknEY+us0DaDWiWnwCr92bSdcomBm+q4eE9ShsThTXh2jRn5mxOZ/CmmjYzZkRsgE5TY40Q33bhu/iiF66VcJjh604TuTfbUnnk3myGrzttQZgzZtJhzQrvfabHWGNccNELnz2tfSUcJjxADVhbwIC1BdYsMyOp+fyH9yhWGnAks/TS0gDTV4qK8q2NxU5TY7klqrIFTDhQ6+gZ/hwzdoSbpKgo/9LPj5hnR8yUwEwVw810MRkRG7BSRXPpLyrKv/RUsT2YI5mlLZLnEbEBK1q2lhGxASt5vuO1nZY5ioryL5TJX7icENwuioryjV1rr4+oAzkMWbDvouXEkAX7iDqQg8/rQ5MaLgZxaQWWJslWSWkWWBkFzl9UYP2PvgjFPNrj8/osM/2YcIQfE46QnpFmfL7K7SLocWpBj1Mz6+D0jLQWzzPb3b/6aI8SVnCbvXTTVOZxno6kqCjfKlPNUH4pIP9XPGz/N319UFnrf2iKLGi6LmggqCBoIOi6JuiqIqCrgqIrgqyrgoYu6JpiiK4LKgigCpquCCEdQdVVAU0VdP2iMGW29tplmtbcQNQ1QEXXNDQdQGsWHZBbvdQsKkTQfaiaBJrc/PyLPpQ2zqqbL9U10GV0TUbTZUCyQAoaJPaVinx5RmbVKZnVWRpf56r8WKlQFww2Q4bf8VdMXwsEtfkdGb97xSAb8yRG7df4zYYQ3deEsK2WsK1UsK1U6LIqxJWfKQzcEODVw0GS7KbG1F8Pout6C7WuL5Dpv1PBtlLEFgWXfyHTY61Ery91rvkiwLWfB7h6jcxV/5LoskLF9gl0+tjLI7FesuuxzKnrHeqneQdL143Bjacj6wqg4ZFUph8JYvusCdsXIldvhGvXi/T+SuS6dQrXrZO4fp3Ib76UuH5NiD6fi1z/mcgNnwa5epWMbbHG1StEvsoSjbeoq2i60h6MYNN1XTAhNF1vdlBoVFSG7/Nh+1Ti2o1Brl8v03uDyDVfN3DDVz5u+FKh15cKvdbp9FoHvT5X6PW5wjVr4LrPda6NkugTJdL1EwXbIpkVx5sdGaXZ8S9gGgNIJ6ipPHgghO3TED23h+ixTafXZpmb1ofos0ml+9dw1VcaV3wapMvKIF1WSVz+qULPzxV6faZw9Wc613yq0Xt1iN9Ehei+WMG2QObz03JHDtxsGk07P2XRmZ/hx7ZG5rqtMjdubqTHFonrNov8doPMZRvA9pmPqz8X+MNWhb/tkrg/VuGWaJXLPmmk85Imen6m0+sz6BMlcsNqP9etVujysU63jwIcrwy1N6UFm6Zrgma4KKBxrE7lyq999PnaT58dcMNWjV5bFa7d6sP2lcj/+szP6/FNHK2SqQtpSKqIKItUN2psyJH52yYXtkV+uq9UuP5fMj1XqVy9WuWGFSE6LQgxbHMQv6kVXW92B12wKZouSEjGNNMVJvwgYdugcGOsym+2q/TZqnD9dh3bVz5u3h4guVJtnpJa808zkJlBMMS7SQG6vB/gimUKvVdK9Fmu0nu5zLXLZGzvaWzLDhggmoysqwYIKoKqG+rKqVO5douP62JUfvutxg2xCn1iZTpv0rgpRuF0XQAIgRJElSUURUWWZWRZRpFlgrIKeIEg7yaC7X2FXkslei+XDVkmY1sQ4pFNDaA3hwcdNF0XbGjNZwNQWXZaxrZV5XexMjftFLnpW4ne34rYNvjZUywBQUJqEEkMoEk6oqIgySqipCCKEt6Qis8fRNEaAB+TtijYInV6Lwtx7VKRPstkIj5S6PGBRGFtwFCgApquCDYFTQANXZeZkiARsVPnlu9kfhcr0/cbiYivA4w94DM0oet4VQVJUQiJGiFRIiTKBEMSAX+QhoBIvU/C1SQCfpIKGrl8kZerFitcu0Tkuk9ErlsiYXtDYuMpYyobE0gVbIouC6DiDsgMiwtx406Z/rs0+u6WGPCNSI8tIZbnSoCCEvITkBRkWSMUkAgEJbz+EE2+IA3eAPUNjTR6fNTWSni9PuoFN/d8KtBpkcg1n3jp82GQ3h/6sc33seAHb/P6pYOmCTY0VQCNEkHhrgMhfrdL5k/fafT/XqT/boU+sRI/2r0AhESFYFDCF1TwBSWa/CE8TQHcjQFcDX6cdQGq63w43PWU1AoEmup4emMjtvl+enzop/d7Aa57N4Btvo/Z37jCHBzBpuqaAHDOHWDo/iD99in8+XuZO/er/H6fxsB/h0irDgGqoYGAhOAL0eALUd/oo87TRK2nCUddI3anQKXTTUl1DUVVNXga6nh2mwvb6066L3Bz3btOekU2YXtd5MVNDmuVVtEFm6brAmiUu4OMPODnjv0idx+UGHpQ4q6DEnf928+h0iCg0egN0OgXqW8MUCd4cXm81LgbqHIJlDs9lFd5KK90U1hWQ3GlgLOqlrs/rsQ2q45rFjq57q0yukc6sL3iYc62akBDR0fRNcGmq5oAQYSAyuQEibsPhnjgkMYD8T4ePOTnv/ZrfJrtBTWE4A3ibvRTJ3hx1jdRXddApbOeMoebEruL3Ao3p8vqOVVSR1JuDZkFtbywvgDb0zl0eqmanm+Wct2bFdhmlvP2Po/hH6qIrmiCTdNUAVVElTVeyfTz10My435UGHNE5JGfJIYf1ZiV4kFo8uILBKirD+LwBHC43Dhq6ymurqfAUU9ORS05RSU0NHmQVRW/JCMqOho6354U6DEri04z8+nxWim2fxSx8ZgLEAlJCqoiCzZZUwVZVECDjUVNDD8s8sRRlSmJOs8mwbPHZJ466iO2yI8aDNJU56a8tpGqaicOZx2FVfWcLa8lq7CMBn8IHfAGZQKSik/SQAoBOjEZtdiezqTTS/l0fzmPrFIBNB9CUCcoSYJN0TTBKymgS5TXBXn8pwCTj8lMT1WZmarx+nGR2Rk680+GOFleh9/bgMtZR3V1HYWVLvJKajiTV0pVjRsV8IVEgrLaLApeERSCAAx5/xS2+48zZvlZAmKIQFMTHq+PppAi2DRdFQIyyKIfRImoMz6ePO7lpUyJl08r/PN0iMjTEh9kS6zNEUgp92GvaaDAXstZh4DLG0JoChAMyviDMn5Jxi/K+EISIVnFr0h4JWPZ33a8mNteSCI6vhpZbMDhaqChyYfHHxRsmhYURBECoRDoMvkukVfTFN7IlHk7W+aDXIlVOSHW5ob4qhi2F4v8WNLIiSov5wLgkVVERSUYMqa2LyTjF1UCkkpQ1vGLImJAxCsai2SdKFJQ6aG0ooqK+gBuVxOCTxBsuq4IkqQSFCVCkgyqzg8lXt5J9/H+WViVJ7G+KMSOEoVdJSp77DJxdRrH3Rq5goLDJyMERRqCIt6QbPiHqBAQFSRJJSCrhGSZJklDUs/nIefsNRRXe3DWefE0NjUf21BURFEiGDRWVH9I5Nu8Rt7Pk/lXocbWIpFvKzT2VSr8YJdIcEqk1Svke2TsPhV3SMYTEmkISngDCr6QTFBSCUkqQUnFL2kEJUNLflFF1aGuyUepow6HuxG34DdyVkVRkCQFUVLxBWR0ScEfFPmuuIG1hTIxpSr/rpA46FBIqJHJdGmcqVPJa1Co9MrUBiTcQQlPQKYhoNAUUvCJCn5JJSApBCTZEr8oEVJU/IpKiaOOmnov9Q1+QyOqqiErGqKiIYk6/mAATQ4QalRItPvZU+EnvkrmxxqJRJdIVp1KTr1GQaNChVei2idTE9BwBRTqAzKeoEyjKNMkKvglhaCkNAMZogAeX4DS6npcDQE8jYHmM0aajqLqyLJOSNbwSTJev0woEKCxyU9OdZCEkgAJ1UGSBYWsBo3cRihq0qj0KVT5ZBwBjdqQRn1IRhBVGiWVRlklqOiIikZQ1hAV4ytjJE2n0ummqt6LU/AjNAYEm64jaBqoqo6iaEiKhiirBESVhkAQr9eH0ChSUu3nVGkdGY4mUmt8ZLoC5DWoFDUplHpVKnw6VT6ZWn+IuqCEJ6TQEFINzUgSflXFJ8nUe304XALVdQ3UNwaob/TT5A0ZILoO4TCyrBKSZHxBGcEfxNPgpdETwO32U+ZoIKesnrPlHrLtbn6urCfPXk+B3U2R3cO5qgbOVTVQUilwrkKgtEqguLKe4sp6yhwNlNg9VLkEhKYgjd4QTX6RYFA+X2Dpuo6maaiqiqqqKIqGKKn4QwrekERjIIC70YenMUBjk0S9EKK23our3ovb48Xj8SI0BfD4ROq9IdyNQeoa/Lg8AZxuPzV1PuobRASfguAN0egP4Q1KBEMykqwKNkAxMnpDNM1oSxhQGrKiI6oqTapIkyTiDYUIiDLBkEwoICOGjHghKxqKqqCoEooqEVJFgkqIkBIiKIsEpBB+MYA/FMAXkgiICiHRmK2KoilWo6bZRIKu61bjRdd1QdEQVBVBkzRBlVRBFhVBVTRBUXRBknVB1hAUECQQNF0XUHVB13RB0XRBVDRBUjRBUTVBUlRBlBRBlGQhJGuCJOuCouiCpuqCqqpl/7Eemqor5HnS2Ja/hPezpvCP1PuYlfo3vvo5EnfA0baH9qs+CKZpBIIh7DUuyuw1lNprqHDU4mnwoqoamq5xyn2YVTkv8cKJO3n+TH+eTB7Ao/H9eSr+TnbmrfyfgdiddZzKKaK0yklhuYN6oWVfvabay+6Tu3gzaSJPpPZm9E9XMmnvH1n60wKSanZypuEg35WuZlrCMLb9vPSXgzicdWTkFLX7vya5Dq/spk62s8v1AW+cu53ns29kSd6z/Fi9mZ/L8tpqVFfZeHYxBe7MSwdJy85v8Xd1oJwDFRtZlTeTD88+wcKsMSzMGsv8rL8wNbMnc7LuJN6xg6AcsF6TW1xBkzfQct9P8pDrSkfT1QuDKKrKz8UV1t+V3kKi89/m1YyhvHlyMPOz/ouFZ4fwYe59fJAzjLfO3s66wuep8p7jbF0iUTkzOe76/rzZ6jxUVteGtch06gL2C4PIikJFtcv6e3/ZeuamDOHNU//NivwxfFY8jnXlE/iyYiKflz/Eh4WD2Gv/CL/YQIJjI2+dvJvXTt7FtJS+LPt5OvVBY383KEoUlFaGzSz5wqb5ubC0WSsyG3PfZUbKnXzw8wOsKX6EdWUT+NI+nq8cY1nrGMnikjuJd0Xhld1sr3iTt37+IyuLHmZN0WMszxnPzLSBvJnxMMWNPxv7vUITLrdw8VlzMswnNud+xD+O3cGy3LF8ce5R1pZN4IuKsXzlGM0X1SP4uPJ2jgpraJAcfFb+CJHnbuOz8pF8UT6OL0om8nnRJFblPcrLaXfxxolROHzGd2idq7xIHBEavTQFQwAcLNvMP5Lu5JOcsawpmsRnJROIKnuYtVWjWVP9Vz6q7McRz0pUTSa2Zh6LSgeytOJPfGa/j3UVY1lTMoFPz01kdcEjLM95hNmp/8UHmU+j6MYnlrJyz3UMknHW0IbDW8rLyfexIGs4nxU8zqqi8Xx07gGiKkfyheN+ltnvJEFYGdYOFWlUqjniWcGK8iFElQ1jTek4Pi2awOqCR1iZ9wgfnx3Hs4l9+aHc+BqH2voGRFFqC+JpaEKSjOR2Y84iZqX8majcx1ieN57Xc+/hvXPD+aziAZaX30VGY0yH0/1s00E+KR7KquL7+ezceFbnT2BFzkSW5Uzg7VP38UbKQ3hCdc1aKWoLktHsG06/nbnJ9/H+6VGsyJnIC9l38kreMNaUPsKSkkHsdy26aABMcK3lw4L/5l9FY1mdP56lOeP55Ox4Psh+mOeT7+BAyUZj17O8qiWIKMkUlNoBOFQaw4zkQSw+M5bZp+7in7mPsKnkFVade4DPSsfTJNVeFCSk+lhbPIVl+Q+wMnccS8+OY/GZsXxwZjTTj9/OkqwXACi3O/H5A+dBKhy1lFQac33t2bf5R/KdvJnxFxadnkSyYzuf5j3BssIR/Kt4DBvLp/NF2dOsqXiSNRVPsKbyCeNnxZN8XjaFz4ufJrr4Bf5V8Agr8h5iWc5YPs4ey4enR/P+6YeYnfZn3kh9CAUfqgz2Gtd5kLOFpZTYjUMHH516jmlJA3jjxHCO2XexteBtFpwZyqqC0awo+huLCv7Eu4W38V7x73mvtD/vl/Xl/bJ+vFfye94tuo2F+X/g3dw/szT/b6zIHcMnZ0fz0ZmHWXT6ISKzRvJq5mBeSh5MSeNZyzyyrBggWTlFlNsNssiMKYz9oQe7i/9FmmM/r6bezZKfx7Is5yGW5f+NFYUjWHXuflaXDmN12V+JKhtGVNkwVpX9lZXFw1lRNILl+Q/ySc6DfHRmFIuyRhF5ciRvZ/6NNzPvZ3baIJ5N+AM/1xsfXcg9V47XH2wLMidpFE/9eAcVQg7Lsp7j9fShfHTmIT4+M4rIrKG8ljGAeSf78eaZfszP7sc/z/bln9n9mH+mH29m9eO1jP7MPfF7ZibfxvSE3zP1UD+eiruVxw/cxIT9fRj+764Mje3M6bqjAOQVl+MPhgyQvHPllFQapnkhfgRf5y7haNV3PJvwe945+QDvnnyAf2bcQ0zR22S7fySzbj+Z7n2cdO/jZP1eTtbvI9O9j8y6fWS49pHm3Edq9T6OV+0luXIPRyt2k1C+i/jybzhYupUfSrfjV40wX1zhQNN0A8RR66bEbjjr5p+Xc9IRz9snJvJ88h94O/N+3s64j1dS7mJLXuT/v0e/vT6qa93nnVXXdXLOlRtJi6qSWLmL8Yd682rGvcxLG8qbJ4byRuoQXj56L+UNuRcdoDHk5kDJNvaXbuZA2Rb2l21hX9nX7C3byNaCKJKr4pqnbw3+QLBlQDttxn4dPsh4hseP3sjcjP/m5dRBvJYymNdTBjMtvh8rT865KMja0wsZvqsr4/f3ZNyBnjx88CpGxV3BiAM2bt5iY8PPKwz/KKlsG1lDooTgCRJAYPKR/jyb2pcZaQOZdfyPzDn+J145/l/MSfojU364lW05yzuE2F30FU/80JcZSQN5+fifmH38Tmam3MGM1Dt4LOE6pv90DyHFCGLZ+SXtL3pn88rJCR5hbPy1TEq6jqnJv2XGsduZdfwPzD52By8n/5FZSX9g8sGbeDflGU7VHMUTqKMhVM/Z2hMsSZ/JY3G38I/E25l77I/MOv4HZhy/nRkptzE1+Rbu+beNhMrvjLEKSi+cj0T+8AaPZfTi2eQ/8Gj89fz96C3MSB7AjOTfMzPpNmYn3c7MowN4/IdrmXKoPy8l3MtLP/2Fpw7fxiMHr+HFxH7MTrqNmUm/56XkAbyY3I/pyb/jr/tsRJ542hqnOGydaRdkxv6J/DXBxvflX/Fd0Rru2W3jmYTrmZnUnxlJ/ZhxtB+zjg5g1tH+vJBwM1Pjr+fZ+Ot5PuFmZiX2Y9ZR43kvJfXlpeR+PJ90M3/da2Nm4gME5MZ2c5F2QV5OeYA/7rZxrOYgANE/f8S933ViTFxXZiX1ZfbRvsxK7MusxFuZnXgrs8JkZuKtzEi8lZlHf8espL48Gd+Lu3fbeDVpLA1BY+kvc7T7ZTktQUQlyLQjg/nzv20cyo+zrsdX7OKR/bcybLeNp368hpd+uok5ib9lbuKtzfI75ib+jtmJv2PGT7fwfMJveOj7zty/O4JPs+YjKsYUdTc04Wloav/YRusLz/04lAeTIsgsPENewfnc0is1EH32Qx47MICH913F+O//F+O/t/H4wW7877gIHtnfhXHfd2Hs91cyZl9v3k19lgLPaev15TV1NDR6Oz4/0vrC26ceYVhcL45X/GB4d2Eljf7Q+cJI9pHqiGPVqVeZd+wRZicOZ0bCvbyS9DAfpD3PnnNfUuO3ny9NVI2T+eVI8oVPGrUB2ZsfzX1HehJTtMK6FgyJZOYW0+gXf1EIz8wro9LhvKTn2lrugkMoFOS5n/7C0APXYK8tb3GepMrh5HB8Cmknz5JbXEpBSQVlFbVU2N0UlVWRW1RK1s95/JCQzMkzPyPLMpqm4ff7CQQChEIhJElCURQ0TcPsVOm6fn6tCT+oUOkq4bGE27n/qzv4KeMIwVCQQCBAbV0ttXW1VFRWkJ19lrS0DJKSj5F4NInk5OOcPHmK/Px8amtrcbvd1NTU4HQ6cbvdNDU1WTCyLKOqaguYDmvfgNzE4bIYdpWv4UT5EezuMkQl9B877PT/DQC7cLwx8LR3hQAAAABJRU5ErkJggg==) |
| | | no-repeat; |
| | | padding-left: 40px; |
| | | } |
| | | .browser .browser-firefox { |
| | | background-position: 0 -34px; |
| | | } |
| | | .browser .browser-ie { |
| | | background-position: 0 -68px; |
| | | margin-left: 0px; |
| | | } |
| | | .browser .browser-360 { |
| | | background-position: 0 -170px; |
| | | margin-left: -27px; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body style="margin-top:50px"> |
| | | <body style="margin-top: 50px"> |
| | | <h1>请å级æ¨çæµè§å¨ï¼ä»¥ä¾¿æä»¬æ´å¥½çä¸ºæ¨æä¾æå¡ï¼</h1> |
| | | <p>æ¨æ£å¨ä½¿ç¨ Internet Explorer çæ©æçæ¬ï¼IE11以ä¸çæ¬æä½¿ç¨è¯¥å
æ ¸çæµè§å¨ï¼ãè¿æå³çå¨å级æµè§å¨åï¼æ¨å°æ æ³è®¿é®æ¤ç½ç«ã</p> |
| | | <hr /> |
| | |
| | | <!DOCTYPE html> |
| | | <!doctype html> |
| | | <html> |
| | | <head> |
| | | <meta charset="utf-8" /> |
| | |
| | | <title>RuoYi-Vue-Pluså¤ç§æ·ç®¡çç³»ç»</title> |
| | | <!--[if lt IE 11 |
| | | ]><script> |
| | | window.location.href='/html/ie.html'; |
| | | window.location.href = '/html/ie.html'; |
| | | </script><! |
| | | [endif]--> |
| | | <style> |
| | |
| | | margin: -75px 0 0 -75px; |
| | | border-radius: 50%; |
| | | border: 3px solid transparent; |
| | | border-top-color: #FFF; |
| | | border-top-color: #fff; |
| | | -webkit-animation: spin 2s linear infinite; |
| | | -ms-animation: spin 2s linear infinite; |
| | | -moz-animation: spin 2s linear infinite; |
| | |
| | | } |
| | | |
| | | #loader:before { |
| | | content: ""; |
| | | content: ''; |
| | | position: absolute; |
| | | top: 5px; |
| | | left: 5px; |
| | |
| | | bottom: 5px; |
| | | border-radius: 50%; |
| | | border: 3px solid transparent; |
| | | border-top-color: #FFF; |
| | | border-top-color: #fff; |
| | | -webkit-animation: spin 3s linear infinite; |
| | | -moz-animation: spin 3s linear infinite; |
| | | -o-animation: spin 3s linear infinite; |
| | |
| | | } |
| | | |
| | | #loader:after { |
| | | content: ""; |
| | | content: ''; |
| | | position: absolute; |
| | | top: 15px; |
| | | left: 15px; |
| | |
| | | bottom: 15px; |
| | | border-radius: 50%; |
| | | border: 3px solid transparent; |
| | | border-top-color: #FFF; |
| | | border-top-color: #fff; |
| | | -moz-animation: spin 1.5s linear infinite; |
| | | -o-animation: spin 1.5s linear infinite; |
| | | -ms-animation: spin 1.5s linear infinite; |
| | | -webkit-animation: spin 1.5s linear infinite; |
| | | animation: spin 1.5s linear infinite; |
| | | } |
| | | |
| | | |
| | | @-webkit-keyframes spin { |
| | | 0% { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | #loader-wrapper .loader-section { |
| | | position: fixed; |
| | | top: 0; |
| | | width: 51%; |
| | | height: 100%; |
| | | background: #7171C6; |
| | | background: #7171c6; |
| | | z-index: 1000; |
| | | -webkit-transform: translateX(0); |
| | | -ms-transform: translateX(0); |
| | |
| | | right: 0; |
| | | } |
| | | |
| | | |
| | | .loaded #loader-wrapper .loader-section.section-left { |
| | | -webkit-transform: translateX(-100%); |
| | | -ms-transform: translateX(-100%); |
| | | transform: translateX(-100%); |
| | | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); |
| | | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); |
| | | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | } |
| | | |
| | | .loaded #loader-wrapper .loader-section.section-right { |
| | | -webkit-transform: translateX(100%); |
| | | -ms-transform: translateX(100%); |
| | | transform: translateX(100%); |
| | | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); |
| | | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000); |
| | | -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); |
| | | } |
| | | |
| | | .loaded #loader { |
| | |
| | | |
| | | #loader-wrapper .load_title { |
| | | font-family: 'Open Sans'; |
| | | color: #FFF; |
| | | color: #fff; |
| | | font-size: 19px; |
| | | width: 100%; |
| | | text-align: center; |
| | |
| | | font-weight: normal; |
| | | font-style: italic; |
| | | font-size: 13px; |
| | | color: #FFF; |
| | | color: #fff; |
| | | opacity: 0.5; |
| | | } |
| | | </style> |
| | |
| | | { |
| | | "name": "ruoyi-vue-plus", |
| | | "version": "5.1.2", |
| | | "version": "5.2.0-BETA", |
| | | "description": "RuoYi-Vue-Pluså¤ç§æ·ç®¡çç³»ç»", |
| | | "author": "LionLi", |
| | | "license": "MIT", |
| | | "type": "module", |
| | | "scripts": { |
| | | "dev": "vite serve --mode development", |
| | | "build:prod": "vite build --mode production &&vue-tsc --noEmit", |
| | | "build:prod": "vite build --mode production", |
| | | "build:dev": "vite build --mode development", |
| | | "preview": "vite preview", |
| | | "lint": "eslint src/**/*.{ts,js,vue} --fix", |
| | | "prepare": "husky install", |
| | | "lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ", |
| | | "prettier": "prettier --write ." |
| | | }, |
| | | "repository": { |
| | |
| | | "url": "https://gitee.com/JavaLionLi/plus-ui.git" |
| | | }, |
| | | "dependencies": { |
| | | "@element-plus/icons-vue": "2.1.0", |
| | | "@element-plus/icons-vue": "2.3.1", |
| | | "@highlightjs/vue-plugin": "2.1.0", |
| | | "@lezer/common": "1.2.1", |
| | | "@vueup/vue-quill": "1.2.0", |
| | | "@vueuse/core": "9.5.0", |
| | | "@vueuse/core": "10.9.0", |
| | | "animate.css": "4.1.1", |
| | | "await-to-js": "^3.0.0", |
| | | "axios": "^1.3.4", |
| | | "echarts": "5.4.0", |
| | | "element-plus": "2.2.27", |
| | | "await-to-js": "3.0.0", |
| | | "axios": "1.6.8", |
| | | "bpmn-js": "16.4.0", |
| | | "camunda-bpmn-js-behaviors": "1.2.2", |
| | | "camunda-bpmn-moddle": "7.0.1", |
| | | "crypto-js": "4.2.0", |
| | | "diagram-js": "12.3.0", |
| | | "didi": "9.0.2", |
| | | "echarts": "5.5.0", |
| | | "element-plus": "2.7.2", |
| | | "file-saver": "2.0.5", |
| | | "fuse.js": "6.6.2", |
| | | "js-cookie": "3.0.1", |
| | | "jsencrypt": "3.3.1", |
| | | "crypto-js": "^4.1.1", |
| | | "fuse.js": "7.0.0", |
| | | "highlight.js": "11.9.0", |
| | | "image-conversion": "^2.1.1", |
| | | "js-cookie": "3.0.5", |
| | | "jsencrypt": "3.3.2", |
| | | "moddle": "6.2.3", |
| | | "nprogress": "0.2.0", |
| | | "path-browserify": "1.0.1", |
| | | "path-to-regexp": "6.2.0", |
| | | "pinia": "2.0.22", |
| | | "screenfull": "6.0.0", |
| | | "vform3-builds": "3.0.8", |
| | | "vue": "3.2.45", |
| | | "vue-cropper": "1.0.3", |
| | | "vue-i18n": "9.2.2", |
| | | "vue-router": "4.1.4", |
| | | "vue-types": "^5.0.3" |
| | | "path-to-regexp": "6.2.1", |
| | | "pinia": "2.1.7", |
| | | "preact": "10.19.7", |
| | | "screenfull": "6.0.2", |
| | | "vform3-builds": "3.0.10", |
| | | "vue": "3.4.25", |
| | | "vue-cropper": "1.1.1", |
| | | "vue-i18n": "9.10.2", |
| | | "vue-router": "4.3.2", |
| | | "vue-types": "5.1.1", |
| | | "vxe-table": "4.5.22", |
| | | "zeebe-bpmn-moddle": "1.0.0" |
| | | }, |
| | | "devDependencies": { |
| | | "@iconify/json": "^2.2.40", |
| | | "@intlify/unplugin-vue-i18n": "0.8.2", |
| | | "@types/crypto-js": "^4.1.1", |
| | | "@types/file-saver": "2.0.5", |
| | | "@types/js-cookie": "3.0.3", |
| | | "@types/node": "18.14.2", |
| | | "@types/nprogress": "0.2.0", |
| | | "@types/path-browserify": "^1.0.0", |
| | | "@typescript-eslint/eslint-plugin": "5.56.0", |
| | | "@typescript-eslint/parser": "5.56.0", |
| | | "@unocss/preset-attributify": "^0.50.6", |
| | | "@unocss/preset-icons": "^0.50.6", |
| | | "@unocss/preset-uno": "^0.50.6", |
| | | "@vitejs/plugin-vue": "4.0.0", |
| | | "@vue/compiler-sfc": "3.2.45", |
| | | "autoprefixer": "10.4.14", |
| | | "eslint": "8.36.0", |
| | | "eslint-config-prettier": "8.8.0", |
| | | "eslint-plugin-prettier": "4.2.1", |
| | | "eslint-plugin-vue": "9.9.0", |
| | | "fast-glob": "^3.2.11", |
| | | "husky": "7.0.4", |
| | | "postcss": "^8.4.21", |
| | | "prettier": "2.8.6", |
| | | "sass": "1.56.1", |
| | | "typescript": "4.9.5", |
| | | "unocss": "^0.50.6", |
| | | "unplugin-auto-import": "0.13.0", |
| | | "unplugin-icons": "0.15.1", |
| | | "unplugin-vue-components": "0.23.0", |
| | | "vite": "4.3.1", |
| | | "@iconify/json": "2.2.201", |
| | | "@intlify/unplugin-vue-i18n": "3.0.1", |
| | | "@types/crypto-js": "4.2.2", |
| | | "@types/file-saver": "2.0.7", |
| | | "@types/js-cookie": "3.0.6", |
| | | "@types/node": "18.18.2", |
| | | "@types/nprogress": "0.2.3", |
| | | "@types/path-browserify": "1.0.2", |
| | | "@typescript-eslint/eslint-plugin": "7.3.1", |
| | | "@typescript-eslint/parser": "7.3.1", |
| | | "@unocss/preset-attributify": "0.58.6", |
| | | "@unocss/preset-icons": "0.58.6", |
| | | "@unocss/preset-uno": "0.58.6", |
| | | "@vitejs/plugin-vue": "5.0.4", |
| | | "@vue/compiler-sfc": "3.4.23", |
| | | "autoprefixer": "10.4.18", |
| | | "eslint": "8.57.0", |
| | | "eslint-config-prettier": "9.1.0", |
| | | "eslint-define-config": "2.1.0", |
| | | "eslint-plugin-prettier": "5.1.3", |
| | | "eslint-plugin-promise": "6.1.1", |
| | | "eslint-plugin-node": "11.1.0", |
| | | "eslint-plugin-import": "2.29.1", |
| | | "eslint-plugin-vue": "9.23.0", |
| | | "fast-glob": "3.3.2", |
| | | "postcss": "8.4.36", |
| | | "prettier": "3.2.5", |
| | | "sass": "1.72.0", |
| | | "typescript": "5.4.5", |
| | | "unocss": "0.58.6", |
| | | "unplugin-auto-import": "0.17.5", |
| | | "unplugin-icons": "0.18.5", |
| | | "unplugin-vue-components": "0.26.0", |
| | | "unplugin-vue-setup-extend-plus": "1.0.1", |
| | | "vite": "5.2.10", |
| | | "vite-plugin-compression": "0.5.1", |
| | | "vite-plugin-svg-icons": "2.0.1", |
| | | "unplugin-vue-setup-extend-plus": "0.4.9", |
| | | "vitest": "^0.29.7", |
| | | "vue-eslint-parser": "9.1.0", |
| | | "vue-tsc": "0.35.0" |
| | | "vitest": "1.5.0", |
| | | "vue-eslint-parser": "9.4.2", |
| | | "vue-tsc": "2.0.13" |
| | | } |
| | | } |
| | |
| | | <template> |
| | | <el-config-provider :locale="appStore.locale" :size="size"> |
| | | <el-config-provider :locale="appStore.locale" :size="appStore.size"> |
| | | <router-view /> |
| | | </el-config-provider> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import { handleThemeStyle } from '@/utils/theme' |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import { handleThemeStyle } from '@/utils/theme'; |
| | | import useAppStore from '@/store/modules/app'; |
| | | |
| | | const appStore = useAppStore(); |
| | | const size = computed(() => appStore.size as any); |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | // åå§å䏻颿 ·å¼ |
| | | handleThemeStyle(useSettingsStore().theme) |
| | | }) |
| | | }) |
| | | handleThemeStyle(useSettingsStore().theme); |
| | | }); |
| | | }); |
| | | </script> |
| | |
| | | url: '/auth/login', |
| | | headers: { |
| | | isToken: false, |
| | | isEncrypt: true |
| | | isEncrypt: true, |
| | | repeatSubmit: false |
| | | }, |
| | | method: 'post', |
| | | data: params |
| | |
| | | url: '/auth/register', |
| | | headers: { |
| | | isToken: false, |
| | | isEncrypt: true |
| | | isEncrypt: true, |
| | | repeatSubmit: false |
| | | }, |
| | | method: 'post', |
| | | data: params |
| | |
| | | method: 'delete' |
| | | }); |
| | | } |
| | | |
| | | // è·åå½åç¨æ·ç»å½å¨çº¿è®¾å¤ |
| | | export function getOnline() { |
| | | return request({ |
| | | url: '/monitor/online', |
| | | method: 'get' |
| | | }); |
| | | } |
| | | |
| | | // å é¤å½åå¨çº¿è®¾å¤ |
| | | export function delOnline(tokenId: string) { |
| | | return request({ |
| | | url: '/monitor/online/' + tokenId, |
| | | method: 'post' |
| | | }); |
| | | } |
| | |
| | | |
| | | /** |
| | | * ç¶æä¿®æ¹ |
| | | * @param id ID |
| | | * @param clientId 客æ·ç«¯id |
| | | * @param status ç¶æ |
| | | */ |
| | | export function changeStatus(id: number | string, status: string) { |
| | | export function changeStatus(clientId: string, status: string) { |
| | | const data = { |
| | | id, |
| | | clientId, |
| | | status |
| | | }; |
| | | return request({ |
| | |
| | | /** |
| | | * 客æ·ç«¯id |
| | | */ |
| | | clientId: string | number; |
| | | clientId: string; |
| | | |
| | | /** |
| | | * 客æ·ç«¯key |
| | |
| | | } |
| | | |
| | | // æ ¹æ®åæ°é®åæ¥è¯¢åæ°å¼ |
| | | export function getConfigKey(configKey: string): AxiosPromise<String> { |
| | | export function getConfigKey(configKey: string): AxiosPromise<string> { |
| | | return request({ |
| | | url: '/system/config/configKey/' + configKey, |
| | | method: 'get' |
| | |
| | | */ |
| | | export interface DeptQuery extends PageQuery { |
| | | deptName?: string; |
| | | deptCategory?: string; |
| | | status?: number; |
| | | } |
| | | |
| | |
| | | children: DeptVO[]; |
| | | deptId: number | string; |
| | | deptName: string; |
| | | deptCategory: string; |
| | | orderNum: number; |
| | | leader: string; |
| | | phone: string; |
| | |
| | | children?: DeptForm[]; |
| | | deptId?: number | string; |
| | | deptName?: string; |
| | | deptCategory?: string; |
| | | orderNum?: number; |
| | | leader?: string; |
| | | phone?: string; |
| | |
| | | }); |
| | | } |
| | | |
| | | // è·åå²ä½éæ©æ¡å表 |
| | | export function optionselect(deptId?: number | string, postIds?: (number | string)[]): AxiosPromise<PostVO[]> { |
| | | return request({ |
| | | url: '/system/post/optionselect', |
| | | method: 'get', |
| | | params: { |
| | | postIds: postIds, |
| | | deptId: deptId |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢å²ä½ |
| | | export function addPost(data: PostForm) { |
| | | return request({ |
| | |
| | | export interface PostVO extends BaseEntity { |
| | | postId: number | string; |
| | | deptId: number | string; |
| | | postCode: string; |
| | | postName: string; |
| | | postCategory: string; |
| | | deptName: string; |
| | | postSort: number; |
| | | status: string; |
| | | remark: string; |
| | |
| | | |
| | | export interface PostForm { |
| | | postId: number | string | undefined; |
| | | deptId: number | string | undefined; |
| | | postCode: string; |
| | | postName: string; |
| | | postCategory: string; |
| | | postSort: number; |
| | | status: string; |
| | | remark: string; |
| | | } |
| | | |
| | | export interface PostQuery extends PageQuery { |
| | | deptId: number | string; |
| | | belongDeptId: number | string; |
| | | postCode: string; |
| | | postName: string; |
| | | postCategory: string; |
| | | status: string; |
| | | } |
| | |
| | | }; |
| | | |
| | | /** |
| | | * éè¿roleIdsæ¥è¯¢è§è² |
| | | * @param roleIds |
| | | */ |
| | | export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => { |
| | | return request({ |
| | | url: '/system/role/optionselect?roleIds=' + roleIds, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è§è²è¯¦ç» |
| | | */ |
| | | export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => { |
| | |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | export default { |
| | | optionSelect, |
| | | listRole |
| | | }; |
| | |
| | | url: '/system/tenant', |
| | | method: 'post', |
| | | headers: { |
| | | isEncrypt: true |
| | | isEncrypt: true, |
| | | repeatSubmit: false |
| | | }, |
| | | data: data |
| | | }); |
| | |
| | | }; |
| | | |
| | | /** |
| | | * éè¿ç¨æ·idsæ¥è¯¢ç¨æ· |
| | | * @param userIds |
| | | */ |
| | | export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => { |
| | | return request({ |
| | | url: '/system/user/optionselect?userIds=' + userIds, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·åç¨æ·è¯¦æ
|
| | | * @param userId |
| | | */ |
| | |
| | | url: '/system/user/resetPwd', |
| | | method: 'put', |
| | | headers: { |
| | | isEncrypt: true |
| | | isEncrypt: true, |
| | | repeatSubmit: false |
| | | }, |
| | | data: data |
| | | }); |
| | |
| | | url: '/system/user/profile/updatePwd', |
| | | method: 'put', |
| | | headers: { |
| | | isEncrypt: true |
| | | isEncrypt: true, |
| | | repeatSubmit: false |
| | | }, |
| | | data: data |
| | | }); |
| | |
| | | export default { |
| | | listUser, |
| | | getUser, |
| | | optionSelect, |
| | | addUser, |
| | | updateUser, |
| | | delUser, |
| | |
| | | import { DeptVO } from './../dept/types'; |
| | | import { RoleVO } from '@/api/system/role/types'; |
| | | import { PostVO } from '@/api/system/post/types'; |
| | | |
| | |
| | | loginIp: string; |
| | | loginDate: string; |
| | | remark: string; |
| | | dept: DeptVO; |
| | | deptName: string; |
| | | roles: RoleVO[]; |
| | | roleIds: any; |
| | | postIds: any; |
| | |
| | | }; |
| | | |
| | | // ä¿®æ¹ä»£ç çæä¿¡æ¯ |
| | | export const updateGenTable = (data: DbTableForm) => { |
| | | export const updateGenTable = (data: DbTableForm): AxiosPromise<GenTableVO> => { |
| | | return request({ |
| | | url: '/tool/gen', |
| | | method: 'put', |
| | |
| | | }; |
| | | |
| | | // 导å
¥è¡¨ |
| | | export const importTable = (data: { tables: string; dataName: string }) => { |
| | | export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<GenTableVO> => { |
| | | return request({ |
| | | url: '/tool/gen/importTable', |
| | | method: 'post', |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/workflow/category/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨åç±»å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => { |
| | | return request({ |
| | | url: '/workflow/category/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨åç±»è¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => { |
| | | return request({ |
| | | url: '/workflow/category/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢æµç¨åç±» |
| | | * @param data |
| | | */ |
| | | export const addCategory = (data: CategoryForm) => { |
| | | return request({ |
| | | url: '/workflow/category', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹æµç¨åç±» |
| | | * @param data |
| | | */ |
| | | export const updateCategory = (data: CategoryForm) => { |
| | | return request({ |
| | | url: '/workflow/category', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å 餿µç¨åç±» |
| | | * @param id |
| | | */ |
| | | export const delCategory = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/workflow/category/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface CategoryVO { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id: string; |
| | | |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode: string; |
| | | |
| | | /** |
| | | * ç¶çº§id |
| | | */ |
| | | parentId: string | number; |
| | | |
| | | /** |
| | | * æåº |
| | | */ |
| | | sortNum: number; |
| | | |
| | | children?: CategoryVO[]; |
| | | } |
| | | |
| | | export interface CategoryForm extends BaseEntity { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id?: string | number; |
| | | |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName?: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode?: string; |
| | | |
| | | /** |
| | | * ç¶çº§id |
| | | */ |
| | | parentId?: string | number; |
| | | |
| | | /** |
| | | * æåº |
| | | */ |
| | | sortNum?: number; |
| | | } |
| | | |
| | | export interface CategoryQuery extends PageQuery { |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName?: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode?: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { DefinitionConfigVO, DefinitionConfigForm } from '@/api/workflow/definitionConfig/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¡¨åé
ç½®è¯¦ç» |
| | | * @param definitionId |
| | | */ |
| | | export const getByDefId = (definitionId: string | number): AxiosPromise<DefinitionConfigVO> => { |
| | | return request({ |
| | | url: '/workflow/definitionConfig/getByDefId/' + definitionId, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢è¡¨åé
ç½® |
| | | * @param data |
| | | */ |
| | | export const saveOrUpdate = (data: DefinitionConfigForm) => { |
| | | return request({ |
| | | url: '/workflow/definitionConfig/saveOrUpdate', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å é¤è¡¨åé
ç½® |
| | | * @param id |
| | | */ |
| | | export const deldefinitionConfig = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/workflow/definitionConfig/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨å®ä¹é
ç½®æé¤å½åæ¥è¯¢çæµç¨å®ä¹ |
| | | * @param tableName |
| | | * @param definitionId |
| | | */ |
| | | export const getByTableNameNotDefId = (tableName: string, definitionId: string | number) => { |
| | | return request({ |
| | | url: `/workflow/definitionConfig/getByTableNameNotDefId/${tableName}/${definitionId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { FormManageVO } from '@/api/workflow/formManage/types'; |
| | | |
| | | export interface DefinitionConfigVO { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id: string | number; |
| | | |
| | | /** |
| | | * 表å |
| | | */ |
| | | tableName?: string; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹ID |
| | | */ |
| | | definitionId: string | number; |
| | | |
| | | /** |
| | | * æµç¨KEY |
| | | */ |
| | | processKey: string; |
| | | |
| | | /** |
| | | * æµç¨çæ¬ |
| | | */ |
| | | version?: string | number; |
| | | |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | remark: string; |
| | | |
| | | /** |
| | | * 表å管ç |
| | | */ |
| | | wfFormManageVo: FormManageVO; |
| | | } |
| | | |
| | | export interface DefinitionConfigForm extends BaseEntity { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id?: string | number; |
| | | |
| | | /** |
| | | * 表å |
| | | */ |
| | | tableName?: string; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹ID |
| | | */ |
| | | definitionId?: string | number; |
| | | |
| | | /** |
| | | * æµç¨KEY |
| | | */ |
| | | processKey?: string; |
| | | |
| | | /** |
| | | * æµç¨çæ¬ |
| | | */ |
| | | version?: string | number; |
| | | |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | remark?: string; |
| | | |
| | | /** |
| | | * 表å管ç |
| | | */ |
| | | wfFormManageVo?: FormManageVO; |
| | | } |
| | | |
| | | export interface DefinitionConfigQuery extends PageQuery { |
| | | /** |
| | | * 表å |
| | | */ |
| | | tableName?: string; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹ID |
| | | */ |
| | | definitionId?: string | number; |
| | | |
| | | /** |
| | | * æµç¨KEY |
| | | */ |
| | | processKey?: string; |
| | | |
| | | /** |
| | | * æµç¨çæ¬ |
| | | */ |
| | | version?: string | number; |
| | | |
| | | /** |
| | | * 表å管ç |
| | | */ |
| | | wfFormManageVo: FormManageVO; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { FormManageVO, FormManageForm, FormManageQuery } from '@/api/workflow/formManage/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¡¨å管çå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listFormManage = (query?: FormManageQuery): AxiosPromise<FormManageVO[]> => { |
| | | return request({ |
| | | url: '/workflow/formManage/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¡¨å管çå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const selectListFormManage = (): AxiosPromise<FormManageVO[]> => { |
| | | return request({ |
| | | url: '/workflow/formManage/list/selectList', |
| | | method: 'get', |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¡¨å管çè¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getFormManage = (id: string | number): AxiosPromise<FormManageVO> => { |
| | | return request({ |
| | | url: '/workflow/formManage/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢è¡¨å管ç |
| | | * @param data |
| | | */ |
| | | export const addFormManage = (data: FormManageForm) => { |
| | | return request({ |
| | | url: '/workflow/formManage', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹è¡¨å管ç |
| | | * @param data |
| | | */ |
| | | export const updateFormManage = (data: FormManageForm) => { |
| | | return request({ |
| | | url: '/workflow/formManage', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å é¤è¡¨å管ç |
| | | * @param id |
| | | */ |
| | | export const delFormManage = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/workflow/formManage/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface FormManageVO { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id: string | number; |
| | | |
| | | /** |
| | | * 表ååç§° |
| | | */ |
| | | formName: string; |
| | | |
| | | /** |
| | | * 表åç±»å |
| | | */ |
| | | formType: string; |
| | | /** |
| | | * 表åç±»ååç§° |
| | | */ |
| | | formTypeName: string; |
| | | |
| | | /** |
| | | * è·¯ç±å°å/表åID |
| | | */ |
| | | router: string; |
| | | |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | remork: string; |
| | | } |
| | | |
| | | export interface FormManageForm extends BaseEntity { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id?: string | number; |
| | | |
| | | /** |
| | | * 表ååç§° |
| | | */ |
| | | formName?: string; |
| | | |
| | | /** |
| | | * 表åç±»å |
| | | */ |
| | | formType?: string; |
| | | |
| | | /** |
| | | * è·¯ç±å°å/表åID |
| | | */ |
| | | router?: string; |
| | | |
| | | /** |
| | | * 夿³¨ |
| | | */ |
| | | remork?: string; |
| | | } |
| | | |
| | | export interface FormManageQuery extends PageQuery { |
| | | /** |
| | | * 表ååç§° |
| | | */ |
| | | formName?: string; |
| | | |
| | | /** |
| | | * 表åç±»å |
| | | */ |
| | | formType?: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { LeaveVO, LeaveQuery, LeaveForm } from '@/api/workflow/leave/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¯·åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listLeave = (query?: LeaveQuery): AxiosPromise<LeaveVO[]> => { |
| | | return request({ |
| | | url: '/demo/leave/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¯·åè¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢è¯·å |
| | | * @param data |
| | | */ |
| | | export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹è¯·å |
| | | * @param data |
| | | */ |
| | | export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å é¤è¯·å |
| | | * @param id |
| | | */ |
| | | export const delLeave = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/demo/leave/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface LeaveVO { |
| | | id: string | number; |
| | | leaveType: string; |
| | | startDate: string; |
| | | endDate: string; |
| | | leaveDays: number; |
| | | remark: string; |
| | | processInstanceVo: any; |
| | | } |
| | | |
| | | export interface LeaveForm extends BaseEntity { |
| | | id?: string | number; |
| | | leaveType?: string; |
| | | startDate?: string; |
| | | endDate?: string; |
| | | leaveDays?: number; |
| | | remark?: string; |
| | | processInstanceVo?: any; |
| | | } |
| | | |
| | | export interface LeaveQuery extends PageQuery { |
| | | startLeaveDays?: number; |
| | | endLeaveDays?: number; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { ModelForm, ModelQuery, ModelVO } from '@/api/workflow/model/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¨¡åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const listModel = (query: ModelQuery): AxiosPromise<ModelVO[]> => { |
| | | return request({ |
| | | url: '/workflow/model/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¨¡åä¿¡æ¯ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getInfo = (id: string): AxiosPromise<ModelForm> => { |
| | | return request({ |
| | | url: '/workflow/model/getInfo/'+id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢æ¨¡å |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const addModel = (data: ModelForm): AxiosPromise<void> => { |
| | | return request({ |
| | | url: '/workflow/model/save', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¨¡åä¿¡æ¯ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export function update(data: ModelForm): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/update', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¨¡åä¿¡æ¯ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export function editModelXml(data: ModelForm): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/editModelXml', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * æidå 餿¨¡å |
| | | * @returns {*} |
| | | * @param id 模åid |
| | | */ |
| | | export function delModel(id: string | string[]): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/' + id, |
| | | method: 'delete' |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 模åé¨ç½² |
| | | * @returns {*} |
| | | * @param id 模åid |
| | | */ |
| | | export const modelDeploy = (id: string): AxiosPromise<void> => { |
| | | return request({ |
| | | url: `/workflow/model/modelDeploy/${id}`, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å¤å¶æ¨¡å |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const copyModel = (data: ModelForm): AxiosPromise<void> => { |
| | | return request({ |
| | | url: '/workflow/model/copyModel', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface ModelForm { |
| | | id: string, |
| | | name: string; |
| | | key: string; |
| | | categoryCode: string; |
| | | xml:string, |
| | | svg:string, |
| | | description: string; |
| | | } |
| | | |
| | | export interface ModelQuery extends PageQuery { |
| | | name?: string; |
| | | key?: string; |
| | | categoryCode?: string; |
| | | } |
| | | |
| | | export interface OriginalPersistentState { |
| | | metaInfo: string; |
| | | editorSourceValueId: string; |
| | | createTime: string; |
| | | deploymentId?: string; |
| | | name: string; |
| | | tenantId: string; |
| | | category?: string; |
| | | version: number; |
| | | editorSourceExtraValueId?: string; |
| | | key: string; |
| | | lastUpdateTime: string; |
| | | } |
| | | |
| | | export interface PersistentState { |
| | | metaInfo: string; |
| | | editorSourceValueId: string; |
| | | createTime: string; |
| | | deploymentId?: string; |
| | | name: string; |
| | | tenantId: string; |
| | | category?: string; |
| | | version: number; |
| | | editorSourceExtraValueId?: string; |
| | | key: string; |
| | | lastUpdateTime: string; |
| | | } |
| | | |
| | | export interface ModelVO { |
| | | id: string; |
| | | revision: number; |
| | | originalPersistentState: OriginalPersistentState; |
| | | name: string; |
| | | key: string; |
| | | category?: string; |
| | | createTime: string; |
| | | lastUpdateTime: string; |
| | | version: number; |
| | | metaInfo: string; |
| | | deploymentId?: string; |
| | | editorSourceValueId: string; |
| | | editorSourceExtraValueId?: string; |
| | | tenantId: string; |
| | | persistentState: PersistentState; |
| | | revisionNext: number; |
| | | idPrefix: string; |
| | | inserted: boolean; |
| | | updated: boolean; |
| | | deleted: boolean; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { NodeConfigVO, NodeConfigForm, NodeConfigQuery } from '@/api/workflow/nodeConfig/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢èç¹é
ç½®å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listNodeConfig = (query?: NodeConfigQuery): AxiosPromise<NodeConfigVO[]> => { |
| | | return request({ |
| | | url: '/workflow/nodeConfig/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢èç¹é
ç½®è¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getNodeConfig = (id: string | number): AxiosPromise<NodeConfigVO> => { |
| | | return request({ |
| | | url: '/workflow/nodeConfig/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢èç¹é
ç½® |
| | | * @param data |
| | | */ |
| | | export const addNodeConfig = (data: NodeConfigForm) => { |
| | | return request({ |
| | | url: '/workflow/nodeConfig', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹èç¹é
ç½® |
| | | * @param data |
| | | */ |
| | | export const updateNodeConfig = (data: NodeConfigForm) => { |
| | | return request({ |
| | | url: '/workflow/nodeConfig', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å é¤èç¹é
ç½® |
| | | * @param id |
| | | */ |
| | | export const delNodeConfig = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/workflow/nodeConfig/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { FormManageVO } from '@/api/workflow/formManage/types'; |
| | | |
| | | export interface NodeConfigVO { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id: string | number; |
| | | |
| | | /** |
| | | * 表åid |
| | | */ |
| | | formId: string | number; |
| | | |
| | | /** |
| | | * 表åç±»å |
| | | */ |
| | | formType: string; |
| | | |
| | | /** |
| | | * èç¹åç§° |
| | | */ |
| | | nodeName: string; |
| | | |
| | | /** |
| | | * èç¹id |
| | | */ |
| | | nodeId: string | number; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹id |
| | | */ |
| | | definitionId: string | number; |
| | | |
| | | /** |
| | | * 表å管ç |
| | | */ |
| | | wfFormManageVo: FormManageVO; |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { ProcessDefinitionQuery, ProcessDefinitionVO, definitionXmlVO } from '@/api/workflow/processDefinition/types'; |
| | | import { AxiosPromise } from 'axios'; |
| | | |
| | | /** |
| | | * è·åæµç¨å®ä¹å表 |
| | | * @param query æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const listProcessDefinition = (query: ProcessDefinitionQuery): AxiosPromise<ProcessDefinitionVO[]> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/list`, |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | /** |
| | | * æç
§æµç¨å®ä¹keyè·åæµç¨å®ä¹ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const getListByKey = (key: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/getListByKey/${key}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¹idè·åæµç¨å¾ |
| | | */ |
| | | export const definitionImage = (processDefinitionId: string): AxiosPromise<any> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/definitionImage/${processDefinitionId}` + '?t' + Math.random(), |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¹idè·åxml |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const definitionXml = (processDefinitionId: string): AxiosPromise<definitionXmlVO> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/definitionXml/${processDefinitionId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å 餿µç¨å®ä¹ |
| | | * @param deploymentId é¨ç½²id |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const deleteProcessDefinition = (deploymentId: string | string[], processDefinitionId: string | string[]) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/${deploymentId}/${processDefinitionId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æèµ·/æ¿æ´» |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const updateDefinitionState = (processDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/updateDefinitionState/${processDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹è½¬æ¢ä¸ºæ¨¡å |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const convertToModel = (processDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/convertToModel/${processDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿zipæxmlé¨ç½²æµç¨å®ä¹ |
| | | * @returns |
| | | */ |
| | | export function deployProcessFile(data: any) { |
| | | return request({ |
| | | url: '/workflow/processDefinition/deployByFile', |
| | | method: 'post', |
| | | data: data, |
| | | headers: { |
| | | repeatSubmit: false |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * è¿ç§»æµç¨ |
| | | * @param currentProcessDefinitionId |
| | | * @param fromProcessDefinitionId |
| | | * @returns |
| | | */ |
| | | export const migrationDefinition = (currentProcessDefinitionId: string, fromProcessDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/migrationDefinition/${currentProcessDefinitionId}/${fromProcessDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
| | | export interface ProcessDefinitionQuery extends PageQuery { |
| | | key?: string; |
| | | name?: string; |
| | | categoryCode?: string; |
| | | } |
| | | |
| | | export interface ProcessDefinitionVO extends BaseEntity { |
| | | id: string; |
| | | name: string; |
| | | key: string; |
| | | version: number; |
| | | suspensionState: number; |
| | | resourceName: string; |
| | | diagramResourceName: string; |
| | | deploymentId: string; |
| | | deploymentTime: string; |
| | | wfDefinitionConfigVo: DefinitionConfigVO; |
| | | } |
| | | |
| | | export interface definitionXmlVO { |
| | | xml: string[]; |
| | | xmlStr: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
| | | import { AxiosPromise } from 'axios'; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¿è¡ä¸å®ä¾å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByRunning = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getPageByRunning', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²å®æå®ä¾å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByFinish = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getPageByFinish', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¾idè·åå岿µç¨å¾ |
| | | */ |
| | | export const getHistoryImage = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/getHistoryImage/${processInstanceId}` + '?t' + Math.random(), |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¾idè·åå岿µç¨å¾è¿è¡ä¸ï¼åå²çèç¹ |
| | | */ |
| | | export const getHistoryList = (instanceId: string): AxiosPromise<Record<string, any>> => { |
| | | return request({ |
| | | url: `/workflow/processInstance/getHistoryList/${instanceId}` + '?t' + Math.random(), |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·å审æ¹è®°å½ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const getHistoryRecord = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/getHistoryRecord/${processInstanceId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä½åº |
| | | * @param data åæ° |
| | | * @returns |
| | | */ |
| | | export const deleteRunInstance = (data: object) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteRunInstance`, |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è¿è¡ä¸çå®ä¾ å é¤ç¨å®ä¾ï¼å é¤åå²è®°å½ï¼å é¤ä¸å¡ä¸æµç¨å
³èä¿¡æ¯ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const deleteRunAndHisInstance = (processInstanceId: string | string[]) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteRunAndHisInstance/${processInstanceId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 已宿çå®ä¾ å é¤ç¨å®ä¾ï¼å é¤åå²è®°å½ï¼å é¤ä¸å¡ä¸æµç¨å
³èä¿¡æ¯ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const deleteFinishAndHisInstance = (processInstanceId: string | string[]) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteFinishAndHisInstance/${processInstanceId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢å½åç»å½äººåæ® |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByCurrent = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getPageByCurrent', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¤éæµç¨ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const cancelProcessApply = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/cancelProcessApply/${processInstanceId}`, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | export default { |
| | | getPageByRunning, |
| | | getPageByFinish, |
| | | getHistoryImage, |
| | | getHistoryList, |
| | | getHistoryRecord, |
| | | deleteRunInstance, |
| | | deleteRunAndHisInstance, |
| | | deleteFinishAndHisInstance, |
| | | getPageByCurrent, |
| | | cancelProcessApply |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { TaskVO } from '@/api/workflow/task/types'; |
| | | |
| | | export interface ProcessInstanceQuery extends PageQuery { |
| | | categoryCode?: string; |
| | | name?: string; |
| | | key?: string; |
| | | startUserId?: string; |
| | | businessKey?: string; |
| | | } |
| | | |
| | | export interface ProcessInstanceVO extends BaseEntity { |
| | | id: string; |
| | | processDefinitionId: string; |
| | | processDefinitionName: string; |
| | | processDefinitionKey: string; |
| | | processDefinitionVersion: string; |
| | | deploymentId: string; |
| | | businessKey: string; |
| | | isSuspended?: any; |
| | | tenantId: string; |
| | | startTime: string; |
| | | endTime?: string; |
| | | startUserId: string; |
| | | businessStatus: string; |
| | | businessStatusName: string; |
| | | taskVoList: TaskVO[]; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢å¾
åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getPageByTaskWait', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getPageByTaskFinish', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å½åç¨æ·çæéå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByTaskCopy = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getPageByTaskCopy', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½åç§æ·ææå¾
åä»»å¡ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByAllTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getPageByAllTaskWait', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½åç§æ·ææå·²åä»»å¡ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getPageByAllTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getPageByAllTaskFinish', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å¯å¨æµç¨ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const startWorkFlow = (data: object): any => { |
| | | return request({ |
| | | url: '/workflow/task/startWorkFlow', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åçæµç¨ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const completeTask = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/completeTask', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 认é¢ä»»å¡ |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const claim = (taskId: string): any => { |
| | | return request({ |
| | | url: '/workflow/task/claim/' + taskId, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½è¿ä»»å¡ |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const returnTask = (taskId: string): any => { |
| | | return request({ |
| | | url: '/workflow/task/returnTask/' + taskId, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä»»å¡é©³å |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const backProcess = (data: any): any => { |
| | | return request({ |
| | | url: '/workflow/task/backProcess', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·åå½åä»»å¡ |
| | | * @param taskId |
| | | * @returns |
| | | */ |
| | | export const getTaskById = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/getTaskById/' + taskId, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å ç¾ |
| | | * @param data |
| | | * @returns |
| | | */ |
| | | export const addMultiInstanceExecution = (data: any) => { |
| | | return request({ |
| | | url: '/workflow/task/addMultiInstanceExecution', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åç¾ |
| | | * @param data |
| | | * @returns |
| | | */ |
| | | export const deleteMultiInstanceExecution = (data: any) => { |
| | | return request({ |
| | | url: '/workflow/task/deleteMultiInstanceExecution', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹ä»»å¡åç人 |
| | | * @param taskIds |
| | | * @param userId |
| | | * @returns |
| | | */ |
| | | export const updateAssignee = (taskIds: Array<string>, userId: string) => { |
| | | return request({ |
| | | url: `/workflow/task/updateAssignee/${taskIds}/${userId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 转åä»»å¡ |
| | | * @returns |
| | | */ |
| | | export const transferTask = (data: any) => { |
| | | return request({ |
| | | url: `/workflow/task/transferTask`, |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ç»æ¢ä»»å¡ |
| | | * @returns |
| | | */ |
| | | export const terminationTask = (data: any) => { |
| | | return request({ |
| | | url: `/workflow/task/terminationTask`, |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨åé |
| | | * @returns |
| | | */ |
| | | export const getInstanceVariable = (taskId: string) => { |
| | | return request({ |
| | | url: `/workflow/task/getInstanceVariable/${taskId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·åå¯é©³åå¾ä»»å¡èç¹ |
| | | * @returns |
| | | */ |
| | | export const getTaskNodeList = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/task/getTaskNodeList/${processInstanceId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å§æä»»å¡ |
| | | * @returns |
| | | */ |
| | | export const delegateTask = (data: any) => { |
| | | return request({ |
| | | url: `/workflow/task/delegateTask`, |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·¥ä½æµä»»å¡ç¨æ·éæ©å ç¾äººå |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const getTaskUserIdsByAddMultiInstance = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/getTaskUserIdsByAddMultiInstance/' + taskId, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·¥ä½æµéæ©åç¾äººå |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const getListByDeleteMultiInstance = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/getListByDeleteMultiInstance/' + taskId, |
| | | method: 'get' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { NodeConfigVO } from '@/api/workflow/nodeConfig/types'; |
| | | import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
| | | export interface TaskQuery extends PageQuery { |
| | | name?: string; |
| | | processDefinitionKey?: string; |
| | | processDefinitionName?: string; |
| | | } |
| | | |
| | | export interface ParticipantVo { |
| | | groupIds?: string[] | number[]; |
| | | candidate: string[] | number[]; |
| | | candidateName: string[]; |
| | | claim: boolean; |
| | | } |
| | | |
| | | export interface TaskVO extends BaseEntity { |
| | | id: string; |
| | | name: string; |
| | | description?: string; |
| | | priority: number; |
| | | owner?: string; |
| | | assignee?: string | number; |
| | | assigneeName?: string; |
| | | processInstanceId: string; |
| | | executionId: string; |
| | | taskDefinitionId?: any; |
| | | processDefinitionId: string; |
| | | endTime?: string; |
| | | taskDefinitionKey: string; |
| | | dueDate?: string; |
| | | category?: any; |
| | | parentTaskId?: any; |
| | | tenantId: string; |
| | | claimTime?: string; |
| | | businessStatus?: string; |
| | | businessStatusName?: string; |
| | | processDefinitionName?: string; |
| | | processDefinitionKey?: string; |
| | | participantVo?: ParticipantVo; |
| | | multiInstance?: boolean; |
| | | businessKey?: string; |
| | | wfNodeConfigVo?: NodeConfigVO; |
| | | wfDefinitionConfigVo?: DefinitionConfigVO; |
| | | } |
| | | |
| | | export interface VariableVo { |
| | | key: string; |
| | | value: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
| | | |
| | | export default { |
| | | routerJump(routerJumpVo: RouterJumpVo,proxy){ |
| | | if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'static' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) { |
| | | proxy.$tab.closePage(proxy.$route); |
| | | proxy.$router.push({ |
| | | path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`, |
| | | query: { |
| | | id: routerJumpVo.businessKey, |
| | | type: routerJumpVo.type, |
| | | taskId: routerJumpVo.taskId |
| | | } |
| | | }); |
| | | } else if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'dynamic' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) { |
| | | proxy.$tab.closePage(proxy.$route); |
| | | proxy.$router.push({ |
| | | path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`, |
| | | query: { |
| | | id: routerJumpVo.businessKey, |
| | | type: routerJumpVo.type, |
| | | taskId: routerJumpVo.taskId |
| | | } |
| | | }); |
| | | }else { |
| | | proxy?.$modal.msgError('è¯·å°æ¨¡åé
ç½®èåï¼'); |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { NodeConfigVO } from '@/api/workflow/nodeConfig/types'; |
| | | import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
| | | |
| | | export interface RouterJumpVo { |
| | | wfNodeConfigVo: NodeConfigVO; |
| | | wfDefinitionConfigVo: DefinitionConfigVO; |
| | | businessKey: string; |
| | | taskId: string; |
| | | type: string; |
| | | } |
| | | |
| | | export interface StartProcessBo { |
| | | businessKey: string | number; |
| | | tableName: string; |
| | | variables: any; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M321.94 98L158.82 237.78a24 24 0 000 36.44L321.94 414c15.57 13.34 39.62 2.28 39.62-18.22v-279.6c0-20.5-24.05-31.56-39.62-18.18z"/></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M190.06 414l163.12-139.78a24 24 0 000-36.44L190.06 98c-15.57-13.34-39.62-2.28-39.62 18.22v279.6c0 20.5 24.05 31.56 39.62 18.18z"/></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1715954426124" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3305" width="200" height="200"><path d="M664.081597 1023.943114a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.27448 78.27448 0 0 1 78.985549-76.93767h280.843828A78.189152 78.189152 0 0 1 1023.939417 662.151187v284.996471a78.246037 78.246037 0 0 1-79.013992 76.795456z m-585.067605 0a78.246037 78.246037 0 0 1-78.985549-76.795456v-284.996471a78.160709 78.160709 0 0 1 78.985549-76.93767h280.786942a78.302923 78.302923 0 0 1 79.042434 76.93767v284.996471h-0.170656a78.246037 78.246037 0 0 1-78.985549 76.795456z m0-585.096048a78.217594 78.217594 0 0 1-78.985549-76.93767V76.912925a78.189152 78.189152 0 0 1 78.957106-76.795456h280.786942a78.27448 78.27448 0 0 1 79.042435 76.93767v284.996471a78.27448 78.27448 0 0 1-79.013992 76.795456z m589.675333-5.688552a77.193655 77.193655 0 0 1-77.990052-75.885288V75.888985a77.25054 77.25054 0 0 1 77.990052-75.942173h277.26004a77.25054 77.25054 0 0 1 77.961609 75.942173v281.384241a77.421197 77.421197 0 0 1-78.132266 75.885288z" p-id="3306" fill="currentColor"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1716006237008" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12400" width="200" height="200"><path d="M738.826039 1005.166431c-150.226824 0-272.00251-121.916235-272.00251-272.303686 0-150.407529 121.775686-272.323765 272.00251-272.323765 150.206745 0 271.982431 121.916235 271.982432 272.323765 0 150.387451-121.775686 272.303686-271.982432 272.303686z m-0.040157-508.225255c-128.582275 0-232.789333 104.347608-232.789333 233.09051s104.207059 233.110588 232.789333 233.110589c128.562196 0 232.769255-104.367686 232.769255-233.110589 0-128.742902-104.207059-233.09051-232.769255-233.09051z m10.561255 318.243138s-3.694431 3.674353-7.408941 3.674353a18.010353 18.010353 0 0 1-25.941333 0l-74.10949-80.916079a17.66902 17.66902 0 0 1 0-25.740549c7.408941-7.368784 22.246902-7.368784 25.941333 0l63.006118 69.872941 129.686588-117.699764a18.010353 18.010353 0 0 1 25.941333 0 17.709176 17.709176 0 0 1 0 25.760627L749.347137 815.184314zM391.529412 682.666667H190.745098a20.078431 20.078431 0 0 1 0-40.156863h200.784314a20.078431 20.078431 0 1 1 0 40.156863zM170.666667 261.019608a20.078431 20.078431 0 0 1 20.078431-20.078432h481.882353a20.078431 20.078431 0 0 1 0 40.156863H190.745098a20.078431 20.078431 0 0 1-20.078431-20.078431z m341.333333 200.784314H190.745098a20.078431 20.078431 0 0 1 0-40.156863h321.254902a20.078431 20.078431 0 0 1 0 40.156863zM813.176471 120.470588a80.313725 80.313725 0 0 0-80.313726-80.313725H130.509804a80.313725 80.313725 0 0 0-80.313726 80.313725v762.980392a80.313725 80.313725 0 0 0 80.313726 80.313726h366.832941a346.112 346.112 0 0 0 40.417882 40.779294H130.509804a120.470588 120.470588 0 0 1-120.470588-120.470588V120.470588a120.470588 120.470588 0 0 1 120.470588-120.470588h602.352941a120.470588 120.470588 0 0 1 120.470588 120.470588v293.667137a340.188863 340.188863 0 0 0-40.156862-8.533333V120.470588z" fill="currentColor" p-id="12401"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1715953291934" class="icon" viewBox="0 0 1061 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1715" id="mx_n_1715953291935" width="200" height="200"><path d="M447.122465 467.332105L49.240301 268.161564A33.501036 33.501036 0 0 0 0.136043 300.744763v441.020484a33.042117 33.042117 0 0 0 16.06214 27.994016L413.162511 1018.034062a33.959954 33.959954 0 0 0 17.438895 5.50702 33.042117 33.042117 0 0 0 33.042117-33.042118V497.161795a33.042117 33.042117 0 0 0-17.438895-29.82969zM398.018207 931.298504l-331.339011-208.348907v-367.134638l331.339011 162.915996zM1046.010843 263.572381a33.042117 33.042117 0 0 0-31.665363 0L550.838 467.332105a33.042117 33.042117 0 0 0-19.733487 30.288608v493.33717a33.042117 33.042117 0 0 0 49.563176 28.452934l463.048562-265.254776a33.042117 33.042117 0 0 0 16.521059-28.452934V291.566398a33.042117 33.042117 0 0 0-14.685386-27.994017z m-50.939931 441.020484L596.72983 931.298504v-413.026468l397.882163-176.224626zM991.399565 178.672496a33.042117 33.042117 0 0 0-22.486996-29.829689L550.838 1.530034a32.583199 32.583199 0 0 0-19.733487 0L83.659173 158.021173a33.042117 33.042117 0 0 0-4.130264 61.036134l397.882163 199.170541a33.042117 33.042117 0 0 0 14.685386 3.212428 33.959954 33.959954 0 0 0 13.30863 0l463.966399-205.595398a33.042117 33.042117 0 0 0 22.028078-37.172382zM494.391049 349.849021L180.490934 195.193555l358.874108-125.743613 328.126583 112.434982z m0 0" fill="currentColor" p-id="1716"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1716006583362" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="38505" width="200" height="200"><path d="M733.696 666.624l56.32-65.536-15.36-12.8c-41.472-34.816-87.552-61.44-136.192-79.36 75.264-49.152 124.928-134.144 124.928-230.912 0-152.576-123.904-276.48-276.48-276.48-74.24 0-143.872 28.672-195.584 80.384-52.224 51.712-80.896 121.344-80.896 195.584 0 92.16 45.568 174.08 115.2 224.256-81.408 26.624-156.672 74.752-215.552 144.896C34.304 736.768-4.096 850.944 0.512 968.192l1.024 20.48 86.528-4.608-1.024-19.968c-4.096-96.256 27.136-188.928 88.576-261.12 136.704-162.816 380.416-184.32 543.232-48.64l14.848 12.288zM296.96 278.016c0-106.496 83.456-189.952 189.952-189.952 104.96 0 189.952 84.992 189.952 189.952 0 106.496-83.456 189.952-189.952 189.952S296.96 384.512 296.96 278.016z m690.688 522.24H802.304c13.824-16.896 32.256-38.4 55.808-67.072 7.68-8.192 11.776-19.456 10.752-31.744-1.024-11.776-6.144-22.528-15.36-29.696-8.192-7.68-19.456-11.264-31.232-10.752-12.288 1.024-23.04 6.656-30.208 15.872-38.4 45.568-96.256 114.176-101.376 119.808-7.68 7.68-10.752 15.36-13.312 22.528-4.096 8.704-4.096 16.384-4.096 24.064 0 5.632 0 12.8 3.584 23.04 2.56 7.68 6.144 15.872 13.824 23.552l104.96 124.416 4.096 2.048c9.216 4.096 18.432 6.144 26.624 6.144 8.704 0 21.504-4.096 28.672-11.776 8.704-8.704 13.824-19.968 14.336-31.744 0-10.752-3.584-20.48-11.264-28.16l-54.272-63.488h183.296c19.456 0 35.84-18.944 36.352-43.008v-0.512c0.512-25.088-14.848-43.52-35.84-43.52z" fill="currentColor" p-id="38506"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1715953932254" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11266" width="200" height="200"><path d="M955.59576334 565.84816928C921.71190561 470.40769794 828.48968821 401.08719229 717.79871055 401.08719229c-111.30100029 0-204.91141024 70.09689085-238.29616047 166.36920831h-253.43576475c-26.23088067 0-47.5261393 24.84446618-47.5261329 55.45640711s21.2952586 55.4564006 47.5261329 55.45640054h242.73267482c6.54385326 41.3150179 23.95716606 79.02537397 49.30074631 110.91280755h-292.03342113c-26.23088067 0-47.5261393 24.84446618-47.5261329 55.45640061s21.2952586 55.4564006 47.5261329 55.45640059h214.0617167a376.93717152 376.93717152 0 0 0-33.44021086 110.91280754h-292.47706801a46.36155474 46.36155474 0 0 1-45.91790151-46.8052016V169.1685161c0-25.06629616 21.23980441-45.36333956 47.35977009-45.3633331h63.38666838v55.45640059c0 50.07713168 67.6013528 55.4564006 110.91280122 55.45640061 43.31144833 0 88.50841878 5.76746809 88.5084187-55.45640061v-55.45640059h44.53149358v55.45640059c0 61.22386864 38.15400297 55.4564006 88.84115713 55.45640061 50.74260854 0 88.56387296 5.76746809 88.56387308-55.45640061v-55.45640059h44.19875511v55.45640059c0 61.22386864 38.43128719 55.4564006 89.11844137 55.45640061s110.91280771-2.82827659 110.91280118-55.45640061v-55.45640059h63.44212904a47.69250853 47.69250853 0 0 1 47.74796275 47.63704778l-0.22182994 394.4059385zM407.96379074 345.63079175h-181.95245955c-26.23088067 0-47.5261393 24.84446618-47.52613946 55.45640054s21.2952586 55.4564006 47.52613946 55.45640711h181.95245955c26.23088067 0 47.5261393-24.84446618 47.52613268-55.45640711s-21.2952586-55.4564006-47.52613268-55.45640054z m325.75090957-166.36920816c-30.61193437 0-55.4564006-18.63335139-55.45640712-41.59230208v-83.18460405c0-22.95895071 24.84446618-41.59230206 55.45640712-41.592302s55.4564006 18.63335139 55.4564006 41.592302v83.18460405c0 22.95895071-24.84446618 41.59230206-55.4564006 41.59230208z m-222.71291552 0c-30.61193437 0-55.4009463-18.63335139-55.4009464-41.59230208v-83.18460405c0-22.95895071 24.84446618-41.59230206 55.4009464-41.592302 30.61193437 0 55.4564006 18.63335139 55.45640054 41.592302v83.18460405c-0.0554542 22.95895071-24.84446618 41.59230206-55.45640054 41.59230208z m-220.6610244 0c-30.61193437 0-55.4009463-18.63335139-55.40094634-41.59230208v-83.18460405c0-22.95895071 24.84446618-41.59230206 55.40094634-41.592302 30.61193437 0 55.4564006 18.63335139 55.45640063 41.592302v83.18460405c0 22.95895071-24.84446618 41.59230206-55.45640063 41.59230208z m443.31847922 665.92048622c-91.28124099 0-165.53736215-74.69977454-165.53736218-166.59103817 0-91.83580289 74.2561211-166.59103164 165.53736218-166.59103164s165.53736215 74.75522879 165.53736218 166.59103164-74.2561211 166.59103164-165.53736218 166.59103817z m-115.73750824-29.33644132c32.1647114 24.45627358 71.98241282 39.59587158 115.68205395 39.59587144 44.14329437 0 84.34918863-15.47233629 116.68026924-40.3722568a235.13514545 235.13514545 0 0 1 105.14533952 195.98292729h-443.6512175c0-80.35632762 41.92504052-153.94697186 106.14355479-195.20654193z" fill="currentColor" p-id="11267"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1716005059256" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3268" width="200" height="200"><path d="M497.798958 952.225272A345.95419 345.95419 0 0 1 359.273733 892.652247a171.541601 171.541601 0 0 0 7.177473-47.37132A179.436821 179.436821 0 0 0 211.417793 665.126359a345.95419 345.95419 0 0 1 185.896546-380.40606 179.436821 179.436821 0 0 0 317.244299 0 351.696169 351.696169 0 0 1 143.549456 128.476763 35.169617 35.169617 0 0 0 30.145386 16.508188 37.322859 37.322859 0 0 0 19.379177-5.024231 36.605111 36.605111 0 0 0 10.766209-46.653574 424.188644 424.188644 0 0 0-183.743304-160.775391v-13.637198a180.872315 180.872315 0 1 0-358.873642 0 129.194511 129.194511 0 0 0 0 15.79044A423.470897 423.470897 0 0 0 132.465591 600.529103a467.253481 467.253481 0 0 0 6.459726 71.774728A180.154568 180.154568 0 0 0 187.014385 1024a178.001326 178.001326 0 0 0 139.96072-68.185992 430.64837 430.64837 0 0 0 158.62215 62.444014h6.459725a35.887364 35.887364 0 0 0 5.741978-71.774729z m57.419783-861.29674a109.097587 109.097587 0 1 1-108.37984 110.533082A109.097587 109.097587 0 0 1 555.218741 90.928532zM187.014385 952.225272a109.097587 109.097587 0 1 1 108.37984-108.37984A109.097587 109.097587 0 0 1 187.014385 952.225272zM933.471559 617.755038l-104.791103-71.774728a35.887364 35.887364 0 0 0-48.089068 8.612967L560.242972 858.918125a37.322859 37.322859 0 0 0-6.459725 24.403408l9.330714 104.073356a35.169617 35.169617 0 0 0 14.354946 25.838902 38.758353 38.758353 0 0 0 21.532418 7.177473h7.177473l98.331378-21.532419a38.758353 38.758353 0 0 0 22.250166-14.354946L945.673263 665.126359a36.605111 36.605111 0 0 0 5.741978-27.274397 37.322859 37.322859 0 0 0-17.943682-20.096924zM675.800285 930.692853l-45.218079 9.330715-4.306484-49.524563 193.791766-262.695505 45.218079 29.427638z m311.50232-399.067489l-103.355608-66.750497a35.887364 35.887364 0 0 0-49.524563 10.048462 35.169617 35.169617 0 0 0 10.766209 49.524562L947.826505 593.35163a34.45187 34.45187 0 0 0 20.096924 5.741979 37.322859 37.322859 0 0 0 30.145386-15.790441 36.605111 36.605111 0 0 0-10.76621-51.677804z" fill="currentColor" p-id="3269"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g clip-path="url(#clip0_446_540)"> |
| | | <path d="M113.069 160.072C103.717 170.743 93.0453 180.216 81.5345 188.609C61.5105 174.46 44.3642 156.595 30.9349 135.971C23.5009 124.46 17.2659 112.11 12.4697 99.0407C9.592 91.3668 7.19392 83.3332 5.27545 75.2996C2.03803 61.3907 0.359375 47.0022 0.359375 32.1341C0.359375 30.6953 0.359375 29.1365 0.359375 27.6977C6.35459 23.9806 12.7095 20.7432 19.0644 17.7456C20.7431 32.1341 24.1004 46.043 28.8966 59.3524C31.6544 66.9063 34.7719 74.3404 38.4889 81.4147C44.604 93.5251 52.0381 104.796 60.4314 115.228C75.1796 133.093 92.9254 148.321 113.069 160.072Z" fill="url(#paint0_linear_446_540)"/> |
| | | <path d="M196.643 67.6256C195.084 76.3786 192.926 84.8918 190.168 93.1652C178.897 91.1269 167.266 90.0477 155.276 90.0477C154.197 90.0477 153.118 90.0477 152.039 90.0477C126.859 90.4074 102.878 95.6832 80.9352 105.036C72.302 94.8439 64.868 83.453 58.9927 71.3427C81.6546 61.8702 106.475 56.7144 132.614 56.7144C141.487 56.7144 150.24 57.3139 158.753 58.5129C171.823 60.1916 184.533 63.3091 196.643 67.6256Z" fill="url(#paint1_linear_446_540)"/> |
| | | <path d="M199.64 34.0528C199.64 39.2087 199.401 44.3646 199.041 49.4005C186.691 44.1247 173.621 40.048 160.072 37.53C148.321 35.2518 136.211 34.0528 123.981 34.0528C97.7218 34.0528 72.6619 39.3286 49.88 48.9209C42.6858 51.9185 35.7313 55.3958 29.0167 59.2327C24.2205 46.0432 20.8632 32.0144 19.1846 17.6259C26.6186 14.1487 34.2925 11.271 42.2062 8.75301C60.3117 3.11751 79.4964 0 99.4005 0C119.904 0 139.568 3.23741 158.153 9.11272C172.782 13.789 186.691 20.2638 199.52 28.1775C199.64 30.2159 199.64 32.1343 199.64 34.0528Z" fill="url(#paint2_linear_446_540)"/> |
| | | <path d="M190.168 93.2855C182.494 116.547 170.384 137.65 154.796 155.875C149.76 161.751 144.364 167.386 138.609 172.542C126.858 183.214 113.789 192.446 99.7601 200C93.4052 196.523 87.41 192.686 81.5347 188.609C93.0455 180.336 103.717 170.744 113.069 160.072C117.866 154.676 122.302 148.921 126.499 143.046C137.65 127.098 146.403 109.233 152.158 90.1679C153.237 90.1679 154.316 90.1679 155.396 90.1679C167.146 90.048 178.777 91.1272 190.168 93.2855Z" fill="url(#paint3_linear_446_540)"/> |
| | | </g> |
| | | <defs> |
| | | <linearGradient id="paint0_linear_446_540" x1="15.8569" y1="27.5782" x2="86.4712" y2="182.06" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#57A4F7"/> |
| | | <stop offset="1" stop-color="#2158F9"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint1_linear_446_540" x1="58.9501" y1="80.8427" x2="196.648" y2="80.8427" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#2158F9"/> |
| | | <stop offset="1" stop-color="#33E1E5"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint2_linear_446_540" x1="19.1564" y1="29.6353" x2="199.647" y2="29.6353" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#255DF9"/> |
| | | <stop offset="1" stop-color="#7C35BA"/> |
| | | </linearGradient> |
| | | <linearGradient id="paint3_linear_446_540" x1="95.3808" y1="192.567" x2="174.674" y2="97.4815" gradientUnits="userSpaceOnUse"> |
| | | <stop stop-color="#54A0F7"/> |
| | | <stop offset="1" stop-color="#2158F9"/> |
| | | </linearGradient> |
| | | <clipPath id="clip0_446_540"> |
| | | <rect width="200" height="200" fill="white"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1716005941920" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6808" width="200" height="200"><path d="M739.555556 512a256 256 0 1 1 0 512 256 256 0 0 1 0-512z m18.887111-512a180.167111 180.167111 0 0 1 179.882666 169.870222l0.284445 10.24v311.068445a28.444444 28.444444 0 0 1-56.433778 5.12l-0.455111-5.12V180.110222a123.278222 123.278222 0 0 0-114.460445-122.936889l-8.817777-0.341333H209.237333a123.278222 123.278222 0 0 0-122.993777 114.460444l-0.284445 8.817778v662.641778c0 65.080889 50.460444 118.385778 114.460445 122.88l8.817777 0.341333h283.875556a28.444444 28.444444 0 0 1 5.12 56.433778l-5.12 0.455111h-283.875556a180.167111 180.167111 0 0 1-179.882666-169.927111l-0.284445-10.24V180.167111A180.167111 180.167111 0 0 1 198.997333 0.227556L209.237333 0h549.205334zM739.555556 568.888889a199.111111 199.111111 0 1 0 0 398.222222 199.111111 199.111111 0 0 0 0-398.222222z m115.712 314.026667a14.222222 14.222222 0 0 1 0 28.444444h-222.890667a14.222222 14.222222 0 0 1 0-28.444444h222.890667z m-45.738667-227.555556a74.126222 74.126222 0 0 1-37.660445 95.459556v24.234666c0 6.257778 5.12 11.377778 11.377778 11.377778h51.313778c19.057778-0.170667 34.645333 16.042667 34.929778 36.295111v25.486222a11.377778 11.377778 0 0 1-11.377778 11.377778h-228.579556a11.377778 11.377778 0 0 1-11.377777-11.377778v-25.486222c0.512-20.48 16.213333-36.693333 35.271111-36.295111h51.143111a11.377778 11.377778 0 0 0 11.377778-11.377778v-24.291555c-16.440889-7.793778-32.426667-21.674667-39.253334-38.570667a73.500444 73.500444 0 0 1 36.295111-95.459556c35.328-16.497778 81.123556 0.967111 96.540445 38.684445zM360.789333 682.666667a28.444444 28.444444 0 0 1 5.12 56.433777l-5.12 0.455112H199.111111a28.444444 28.444444 0 0 1-5.12-56.433778L199.111111 682.666667h161.678222z m113.777778-227.555556a28.444444 28.444444 0 0 1 5.12 56.433778L474.510222 512H199.111111a28.444444 28.444444 0 0 1-5.12-56.433778L199.111111 455.111111h275.456zM768 227.555556a28.444444 28.444444 0 0 1 5.12 56.433777L768 284.444444H199.111111a28.444444 28.444444 0 0 1-5.12-56.433777L199.111111 227.555556h568.888889z" fill="currentColor" p-id="6809"></path></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg t="1716004936483" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2712" width="200" height="200"><path d="M1024.99477 113.778v227.555a57.458 57.458 0 0 1-58.027 56.89H734.86277a57.458 57.458 0 0 1-58.027-56.89v-56.889H560.83877v455.112h115.996v-56.89a57.458 57.458 0 0 1 58.027-56.888h231.936a57.458 57.458 0 0 1 58.197 56.889v227.555a57.458 57.458 0 0 1-58.027 56.89H734.86277a57.458 57.458 0 0 1-58.027-56.89v-56.889H502.86877a57.458 57.458 0 0 1-58.027-56.889V568.89L274.51677 735.972a46.763 46.763 0 0 1-65.252 0l-195.754-192a44.658 44.658 0 0 1 0-64l195.754-192.057a46.763 46.763 0 0 1 65.252 0L445.01277 455.11V227.556a57.458 57.458 0 0 1 58.027-56.89h173.966v-56.888a57.458 57.458 0 0 1 58.026-56.89h231.936a57.458 57.458 0 0 1 58.027 56.89z" fill="currentColor" p-id="2713"></path></svg> |
| | |
| | | // cover some element-ui styles |
| | | |
| | | .el-collapse { |
| | | .collapse__title { |
| | | font-weight: 600; |
| | | padding: 0 8px; |
| | | font-size: 1.2em; |
| | | line-height: 1.1em; |
| | | } |
| | | .el-collapse-item__content { |
| | | padding: 0 8px; |
| | | } |
| | | } |
| | | |
| | | .el-divider--horizontal { |
| | | margin-bottom: 10px; |
| | |
| | | .el-dialog__body { |
| | | padding: 15px !important; |
| | | } |
| | | .el-dialog__header { |
| | | padding: 16px 16px 8px 16px; |
| | | box-sizing: border-box; |
| | | border-bottom: 1px solid var(--brder-color); |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | .el-dropdown .el-dropdown-link { |
| | | color: var(--el-color-primary) !important; |
| | | } |
| | | |
| | | /* å½ el-form ç inline 屿§ä¸º true æ¶ */ |
| | | /* 设置 label ç宽度é»è®¤ä¸º 68px */ |
| | | .el-form--inline .el-form-item__label { |
| | | width: 68px; |
| | | } |
| | | |
| | | /* 设置 el-select ç宽度é»è®¤ä¸º 240px */ |
| | | .el-form--inline .el-select { |
| | | width: 240px; |
| | | } |
| | | |
| | | /* 设置 el-input ç宽度é»è®¤ä¸º 240px */ |
| | | .el-form--inline .el-input { |
| | | width: 240px; |
| | | } |
| | |
| | | -moz-osx-font-smoothing: grayscale; |
| | | -webkit-font-smoothing: antialiased; |
| | | text-rendering: optimizeLegibility; |
| | | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; |
| | | font-family: |
| | | Helvetica Neue, |
| | | Helvetica, |
| | | PingFang SC, |
| | | Hiragino Sans GB, |
| | | Microsoft YaHei, |
| | | Arial, |
| | | sans-serif; |
| | | } |
| | | |
| | | label { |
| | |
| | | |
| | | // reset element-ui css |
| | | .horizontal-collapse-transition { |
| | | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; |
| | | transition: |
| | | 0s width ease-in-out, |
| | | 0s padding-left ease-in-out, |
| | | 0s padding-right ease-in-out; |
| | | } |
| | | |
| | | .scrollbar-wrapper { |
| | |
| | | background-color: rgba(0, 0, 0, 0.1) !important; |
| | | } |
| | | } |
| | | |
| | | |
| | | & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title, |
| | | & .theme-dark .el-sub-menu .el-menu-item { |
| | |
| | | --fixedHeaderBg: #ffffff; |
| | | --tableHeaderBg: #f8f8f9; |
| | | --tableHeaderTextColor: #515a6e; |
| | | |
| | | // 工使µ |
| | | --bpmn-panel-border: #eeeeee; |
| | | --bpmn-panel-box-shadow: #cccccc; |
| | | --bpmn-panel-bar-background-color: #f5f7fa; |
| | | |
| | | // ele |
| | | --brder-color: #e8e8e8 |
| | | } |
| | | html.dark { |
| | | --menuBg: #1d1e1f; |
| | |
| | | .el-tree-node__content { |
| | | --el-color-primary-light-9: #262727; |
| | | } |
| | | // vxe-table ä¸»é¢ |
| | | --vxe-font-color: #98989E; |
| | | --vxe-primary-color: #2C7ECF; |
| | | --vxe-icon-background-color: #98989E; |
| | | --vxe-table-font-color: #98989E; |
| | | --vxe-table-resizable-color: #95969a; |
| | | --vxe-table-header-background-color: #28282A; |
| | | --vxe-table-body-background-color: #151518; |
| | | --vxe-table-background-color: #4a5663; |
| | | --vxe-table-border-width: 1px; |
| | | --vxe-table-border-color: #37373A; |
| | | --vxe-toolbar-background-color: #37373A; |
| | | |
| | | // 工使µ |
| | | --bpmn-panel-border: #37373A; |
| | | --bpmn-panel-box-shadow: #37373A; |
| | | --bpmn-panel-bar-background-color: #37373A; |
| | | |
| | | // ele |
| | | --brder-color: #37373A |
| | | } |
| | | |
| | | // base color |
¶Ô±ÈÐÂÎļþ |
| | |
| | | function generateRandomValue() { |
| | | // çæä¸ä¸ªéæºæ° |
| | | const randomValue = Math.random().toString(36).slice(2, 12); |
| | | return `Process_${randomValue}`; |
| | | } |
| | | |
| | | const cartage: string = 'default'; |
| | | export default `<?xml version="1.0" encoding="UTF-8"?> |
| | | <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/processdef"> |
| | | <process id="process_${generateRandomValue()}" name="name_${generateRandomValue()}"> |
| | | <startEvent id="startNode1" name="å¼å§" /> |
| | | </process> |
| | | <bpmndi:BPMNDiagram id="BPMNDiagram_flow"> |
| | | <bpmndi:BPMNPlane id="BPMNPlane_flow" bpmnElement="T-2d89e7a3-ba79-4abd-9f64-ea59621c258c"> |
| | | <bpmndi:BPMNShape id="BPMNShape_startNode1" bpmnElement="startNode1" bioc:stroke=""> |
| | | <omgdc:Bounds x="240" y="200" width="30" height="30" /> |
| | | <bpmndi:BPMNLabel> |
| | | <omgdc:Bounds x="242" y="237" width="23" height="14" /> |
| | | </bpmndi:BPMNLabel> |
| | | </bpmndi:BPMNShape> |
| | | </bpmndi:BPMNPlane> |
| | | </bpmndi:BPMNDiagram> |
| | | </definitions>`; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export const NodeName = { |
| | | 'bpmn:Process': 'æµç¨', |
| | | 'bpmn:StartEvent': 'å¼å§äºä»¶', |
| | | 'bpmn:IntermediateThrowEvent': 'ä¸é´äºä»¶', |
| | | 'bpmn:Task': 'ä»»å¡', |
| | | 'bpmn:SendTask': 'åéä»»å¡', |
| | | 'bpmn:ReceiveTask': 'æ¥æ¶ä»»å¡', |
| | | 'bpmn:UserTask': 'ç¨æ·ä»»å¡', |
| | | 'bpmn:ManualTask': 'æå·¥ä»»å¡', |
| | | 'bpmn:BusinessRuleTask': 'ä¸å¡è§åä»»å¡', |
| | | 'bpmn:ServiceTask': 'æå¡ä»»å¡', |
| | | 'bpmn:ScriptTask': 'èæ¬ä»»å¡', |
| | | 'bpmn:EndEvent': 'ç»æäºä»¶', |
| | | 'bpmn:SequenceFlow': 'æµç¨çº¿', |
| | | 'bpmn:ExclusiveGateway': 'äºæ¥ç½å
³', |
| | | 'bpmn:ParallelGateway': 'å¹¶è¡ç½å
³', |
| | | 'bpmn:InclusiveGateway': 'ç¸å®¹ç½å
³', |
| | | 'bpmn:ComplexGateway': '夿ç½å
³', |
| | | 'bpmn:EventBasedGateway': 'äºä»¶ç½å
³', |
| | | 'bpmn:Participant': 'æ± /åä¸è
', |
| | | 'bpmn:SubProcess': 'åæµç¨', |
| | | 'bpmn:DataObjectReference': 'æ°æ®å¯¹è±¡å¼ç¨', |
| | | 'bpmn:DataStoreReference': 'æ°æ®åå¨å¼ç¨', |
| | | 'bpmn:Group': 'ç»' |
| | | }; |
| | | |
| | | export default { |
| | | 'Activate hand tool': 'å¯å¨æå¨å·¥å
·', |
| | | 'Activate lasso tool': 'å¯å¨ Lasso å·¥å
·', |
| | | 'Activate create/remove space tool': 'å¯å¨å建/å é¤ç©ºé´å·¥å
·', |
| | | 'Activate global connect tool': 'å¯å¨å
¨å±è¿æ¥å·¥å
·', |
| | | 'Ad-hoc': 'Ad-hoc', |
| | | 'Add lane above': 'å¨ä¸æ¹æ·»å æ³³é', |
| | | 'Add lane below': 'å¨ä¸æ¹æ·»å æ³³é', |
| | | 'Business rule task': 'è§åä»»å¡', |
| | | 'Call activity': 'å¼ç¨æµç¨', |
| | | 'Compensation end event': 'ç»æè¡¥å¿äºä»¶', |
| | | 'Compensation intermediate throw event': 'ä¸é´è¡¥å¿æåºäºä»¶', |
| | | 'Complex gateway': '夿ç½å
³', |
| | | 'Conditional intermediate catch event': 'ä¸é´æ¡ä»¶æè·äºä»¶', |
| | | 'Conditional start event (non-interrupting)': 'æ¡ä»¶å¯å¨äºä»¶ (é䏿)', |
| | | 'Conditional start event': 'æ¡ä»¶å¯å¨äºä»¶', |
| | | 'Connect using association': 'ææ¬å
³è', |
| | | 'Connect using sequence/message flow or association': 'æ¶æ¯å
³è', |
| | | 'Change element': 'æ´æ¹å
ç´ ', |
| | | 'Change type': 'æ´æ¹ç±»å', |
| | | 'Create data object reference': 'åå»ºæ°æ®å¯¹è±¡å¼ç¨', |
| | | 'Create data store reference': 'åå»ºæ°æ®åå¨å¼ç¨', |
| | | 'Create expanded sub-process': 'åå»ºå¯æå åæµç¨', |
| | | 'Create pool/participant': 'åå»ºæ± /åä¸è
', |
| | | 'Collection': 'éå', |
| | | 'Connect using data input association': 'æ°æ®è¾å
¥å
³è', |
| | | 'Data store reference': 'æ°æ®åå¨å¼ç¨', |
| | | 'Data object reference': 'æ°æ®å¯¹è±¡å¼ç¨', |
| | | 'Divide into two lanes': 'åæä¸¤ä¸ªæ³³é', |
| | | 'Divide into three lanes': 'åæä¸ä¸ªæ³³é', |
| | | 'End event': 'ç»æäºä»¶', |
| | | 'Error end event': 'ç»æé误äºä»¶', |
| | | 'Escalation end event': 'ç»æå级äºä»¶', |
| | | 'Escalation intermediate throw event': 'ä¸é´å级æåºäºä»¶', |
| | | 'Event sub-process': 'äºä»¶åæµç¨', |
| | | 'Event-based gateway': 'äºä»¶ç½å
³', |
| | | 'Exclusive gateway': 'äºæ¥ç½å
³', |
| | | 'Empty pool/participant (removes content)': 'æ¸
ç©ºæ± /åä¸è
(å é¤å
容)', |
| | | 'Empty pool/participant': 'æ¸
ç©ºæ± /åä¸è
', |
| | | 'Expanded pool/participant': 'å±å¼æ± /åä¸è
', |
| | | 'Inclusive gateway': 'ç¸å®¹ç½å
³', |
| | | 'Intermediate throw event': 'ä¸é´æåºäºä»¶', |
| | | 'Loop': '循ç¯', |
| | | 'Link intermediate catch event': 'ä¸é´é¾æ¥æè·äºä»¶', |
| | | 'Link intermediate throw event': 'ä¸é´é¾æ¥æåºäºä»¶', |
| | | 'Manual task': 'æå¨ä»»å¡', |
| | | 'Message end event': 'ç»ææ¶æ¯äºä»¶', |
| | | 'Message intermediate catch event': 'ä¸é´æ¶æ¯æè·äºä»¶', |
| | | 'Message intermediate throw event': 'ä¸é´æ¶æ¯æåºäºä»¶', |
| | | 'Message start event': 'æ¶æ¯å¯å¨äºä»¶', |
| | | 'Parallel gateway': 'å¹¶è¡ç½å
³', |
| | | 'Parallel multi-instance': 'å¹¶è¡å¤å®ä¾', |
| | | 'Participant multiplicity': 'åä¸è
å¤éæ§', |
| | | 'Receive task': 'æ¥åä»»å¡', |
| | | 'Remove': 'ç§»é¤', |
| | | 'Script task': 'èæ¬ä»»å¡', |
| | | 'Send task': 'åéä»»å¡', |
| | | 'Sequential multi-instance': '串è¡å¤å®ä¾', |
| | | 'Service task': 'æå¡ä»»å¡', |
| | | 'Signal end event': 'ç»æä¿¡å·äºä»¶', |
| | | 'Signal intermediate catch event': 'ä¸é´ä¿¡å·æè·äºä»¶', |
| | | 'Signal intermediate throw event': 'ä¸é´ä¿¡å·æåºäºä»¶', |
| | | 'Signal start event (non-interrupting)': 'ä¿¡å·å¯å¨äºä»¶ (é䏿)', |
| | | 'Signal start event': 'ä¿¡å·å¯å¨äºä»¶', |
| | | 'Start event': 'å¼å§äºä»¶', |
| | | 'Sub-process (collapsed)': '坿å åæµç¨', |
| | | 'Sub-process (expanded)': 'å¯å±å¼åæµç¨', |
| | | 'Sub rocess': 'åæµç¨', |
| | | 'Task': 'ä»»å¡', |
| | | 'Transaction': 'äºå¡', |
| | | 'Terminate end event': 'ç»æ¢è¾¹çäºä»¶', |
| | | 'Timer intermediate catch event': 'ä¸é´å®æ¶æè·äºä»¶', |
| | | 'Timer start event (non-interrupting)': '宿¶å¯å¨äºä»¶ (é䏿)', |
| | | 'Timer start event': '宿¶å¯å¨äºä»¶', |
| | | 'User task': 'ç¨æ·ä»»å¡', |
| | | 'Create start event': 'å建å¼å§äºä»¶', |
| | | 'Create gateway': 'å建ç½å
³', |
| | | 'Create intermediate/boundary event': 'å建ä¸é´/è¾¹çäºä»¶', |
| | | 'Create end event': 'åå»ºç»æäºä»¶', |
| | | 'Create group': 'å建ç»', |
| | | 'Create startEvent': 'å¼å§èç¹', |
| | | 'Create endEvent': 'ç»æèç¹', |
| | | 'Create exclusiveGateway': 'äºæ¥ç½å
³', |
| | | 'Create parallelGateway': 'å¹¶è¡ç½å
³', |
| | | 'Create task': 'ä»»å¡èç¹', |
| | | 'Create userTask': 'ç¨æ·ä»»å¡èç¹', |
| | | 'Condition type': 'æ¡ä»¶ç±»å', |
| | | 'Append end event': '追å ç»æäºä»¶èç¹', |
| | | 'Append gateway': '追å ç½å
³èç¹', |
| | | 'Append task': '追å ä»»å¡', |
| | | 'Append user task': '追å ç¨æ·ä»»å¡èç¹', |
| | | 'Append text annotation': 'è¿½å ææ¬æ³¨é', |
| | | 'Append intermediate/boundary event': '追å ä¸é´æè¾¹çäºä»¶', |
| | | 'Append receive task': 'è¿½å æ¥æ¶ä»»å¡èç¹', |
| | | 'Append message intermediate catch event': '追å ä¸é´æ¶æ¯æè·äºä»¶', |
| | | 'Append timer intermediate catch event': '追å ä¸é´å®æ¶æè·äºä»¶', |
| | | 'Append conditional intermediate catch event': '追å ä¸é´æ¡ä»¶æè·äºä»¶', |
| | | 'Append signal intermediate catch event': '追å ä¸é´ä¿¡å·æè·äºä»¶', |
| | | 'flow elements must be children of pools/participants': 'æµç¨å
ç´ å¿
é¡»æ¯æ± /åä¸è
çåå
ç´ ' |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export default { |
| | | 'name': 'Flowable', |
| | | 'uri': 'http://flowable.org/bpmn', |
| | | 'prefix': 'flowable', |
| | | 'xml': { |
| | | 'tagAlias': 'lowerCase' |
| | | }, |
| | | 'associations': [], |
| | | 'types': [ |
| | | { |
| | | 'name': 'flowable:extCandidateUsers', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'type': 'String', |
| | | 'isBody': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:extAssignee', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'type': 'String', |
| | | 'isBody': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:property', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:properties', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'flowable:property', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InOutBinding', |
| | | 'superClass': ['Element'], |
| | | 'isAbstract': true, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'sourceExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'businessKey', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'local', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'variables', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'In', |
| | | 'superClass': ['InOutBinding'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:CallActivity'] |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'Out', |
| | | 'superClass': ['InOutBinding'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:CallActivity'] |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'AsyncCapable', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Activity', 'bpmn:Gateway', 'bpmn:Event'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'async', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'asyncBefore', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'asyncAfter', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'exclusive', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:in', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:out', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'BoundaryEvent', |
| | | 'superClass': ['CatchEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'cancelActivity', |
| | | 'default': true, |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'attachedToRef', |
| | | 'type': 'Activity', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'JobPriorized', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process', 'flowable:AsyncCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'jobPriority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'SignalEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:SignalEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'async', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ErrorEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ErrorEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'errorCodeVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'errorMessageVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Error', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Error'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'flowable:errorMessage', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'PotentialStarter', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resourceAssignmentExpression', |
| | | 'type': 'bpmn:ResourceAssignmentExpression' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'UserTask', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'timerEventDefinition', |
| | | 'type': 'Expression' |
| | | }, |
| | | { |
| | | 'name': 'multiInstanceLoopCharacteristics', |
| | | 'type': 'MultiInstanceLoopCharacteristics' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'StartEvent', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'timerEventDefinition', |
| | | 'type': 'Expression' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormSupported', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent', 'bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'formHandlerClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'formKey', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TemplateSupported', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process', 'bpmn:FlowElement'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'modelerTemplate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Initiator', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'initiator', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ScriptTask', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ScriptTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resultVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Process', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'candidateStarterGroups', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'candidateStarterUsers', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'versionTag', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'historyTimeToLive', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'isStartableInTasklist', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'EscalationEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:EscalationEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'escalationCodeVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormalExpression', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:FormalExpression'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Assignable', |
| | | 'extends': ['bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'candidateGroups', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'dueDate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'followUpDate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'priority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'CallActivity', |
| | | 'extends': ['bpmn:CallActivity'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'calledElementBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'calledElementVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'calledElementVersionTag', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'calledElementTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseRef', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'caseVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableMappingClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableMappingDelegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ServiceTaskLike', |
| | | 'extends': ['bpmn:ServiceTask', 'bpmn:BusinessRuleTask', 'bpmn:SendTask', 'bpmn:MessageEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resultVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExclusiveGateway', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ExclusiveGateway'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'serviceClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'DmnCapable', |
| | | 'extends': ['bpmn:BusinessRuleTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'decisionRef', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'mapDecisionResult', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'resultList' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExternalCapable', |
| | | 'extends': ['flowable:ServiceTaskLike'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'type', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'topic', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TaskPriorized', |
| | | 'extends': ['bpmn:Process', 'flowable:ExternalCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'taskPriority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Properties', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Property', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Property', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Connector', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:ServiceTaskLike'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'inputOutput', |
| | | 'type': 'InputOutput' |
| | | }, |
| | | { |
| | | 'name': 'connectorId', |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutput', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:FlowNode', 'flowable:Connector'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'inputOutput', |
| | | 'type': 'InputOutput' |
| | | }, |
| | | { |
| | | 'name': 'connectorId', |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'inputParameters', |
| | | 'isMany': true, |
| | | 'type': 'InputParameter' |
| | | }, |
| | | { |
| | | 'name': 'outputParameters', |
| | | 'isMany': true, |
| | | 'type': 'OutputParameter' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutputParameter', |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'definition', |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutputParameterDefinition', |
| | | 'isAbstract': true |
| | | }, |
| | | { |
| | | 'name': 'List', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'items', |
| | | 'isMany': true, |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Map', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'entries', |
| | | 'isMany': true, |
| | | 'type': 'Entry' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Entry', |
| | | 'properties': [ |
| | | { |
| | | 'name': 'key', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'definition', |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Value', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Script', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'scriptFormat', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Field', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:ServiceTaskLike', 'flowable:ExecutionListener', 'flowable:TaskListener'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'expression' |
| | | }, |
| | | { |
| | | 'name': 'string', |
| | | 'type': 'string' |
| | | }, |
| | | { |
| | | 'name': 'stringValue', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'string', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:Field'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:Field'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputParameter', |
| | | 'superClass': ['InputOutputParameter'] |
| | | }, |
| | | { |
| | | 'name': 'OutputParameter', |
| | | 'superClass': ['InputOutputParameter'] |
| | | }, |
| | | { |
| | | 'name': 'Collectable', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:MultiInstanceLoopCharacteristics'], |
| | | 'superClass': ['flowable:AsyncCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'collection', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'elementVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'SequenceFlow', |
| | | 'superClass': ['FlowElement'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'isImmediate', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'conditionExpression', |
| | | 'type': 'Expression' |
| | | }, |
| | | { |
| | | 'name': 'sourceRef', |
| | | 'type': 'FlowNode', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'targetRef', |
| | | 'type': 'FlowNode', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'MultiInstanceLoopCharacteristics', |
| | | 'superClass': ['LoopCharacteristics'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'isSequential', |
| | | 'default': false, |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'behavior', |
| | | 'type': 'MultiInstanceBehavior', |
| | | 'default': 'All', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'loopCardinality', |
| | | 'type': 'Expression', |
| | | 'xml': { |
| | | 'serialize': 'xsi:type' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'loopDataInputRef', |
| | | 'type': 'ItemAwareElement', |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'loopDataOutputRef', |
| | | 'type': 'ItemAwareElement', |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'inputDataItem', |
| | | 'type': 'DataInput', |
| | | 'xml': { |
| | | 'serialize': 'property' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'outputDataItem', |
| | | 'type': 'DataOutput', |
| | | 'xml': { |
| | | 'serialize': 'property' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'complexBehaviorDefinition', |
| | | 'type': 'ComplexBehaviorDefinition', |
| | | 'isMany': true |
| | | }, |
| | | { |
| | | 'name': 'completionCondition', |
| | | 'type': 'Expression', |
| | | 'xml': { |
| | | 'serialize': 'xsi:type' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'oneBehaviorEventRef', |
| | | 'type': 'EventDefinition', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'noneBehaviorEventRef', |
| | | 'type': 'EventDefinition', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FailedJobRetryTimeCycle', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:AsyncCapable', 'bpmn:MultiInstanceLoopCharacteristics'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExecutionListener', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': [ |
| | | 'bpmn:Task', |
| | | 'bpmn:ServiceTask', |
| | | 'bpmn:UserTask', |
| | | 'bpmn:BusinessRuleTask', |
| | | 'bpmn:ScriptTask', |
| | | 'bpmn:ReceiveTask', |
| | | 'bpmn:ManualTask', |
| | | 'bpmn:ExclusiveGateway', |
| | | 'bpmn:SequenceFlow', |
| | | 'bpmn:ParallelGateway', |
| | | 'bpmn:InclusiveGateway', |
| | | 'bpmn:EventBasedGateway', |
| | | 'bpmn:StartEvent', |
| | | 'bpmn:IntermediateCatchEvent', |
| | | 'bpmn:IntermediateThrowEvent', |
| | | 'bpmn:EndEvent', |
| | | 'bpmn:BoundaryEvent', |
| | | 'bpmn:CallActivity', |
| | | 'bpmn:SubProcess', |
| | | 'bpmn:Process' |
| | | ] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'event', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'script', |
| | | 'type': 'Script' |
| | | }, |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'Field', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TaskListener', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'event', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'script', |
| | | 'type': 'Script' |
| | | }, |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'Field', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormProperty', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:StartEvent', 'bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'type', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'required', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'readable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'writable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'variable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'datePattern', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'default', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Value', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormData', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:StartEvent', 'bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'FormField', |
| | | 'isMany': true |
| | | }, |
| | | { |
| | | 'name': 'businessKey', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormField', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'label', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'type', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'datePattern', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'defaultValue', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'properties', |
| | | 'type': 'Properties' |
| | | }, |
| | | { |
| | | 'name': 'validation', |
| | | 'type': 'Validation' |
| | | }, |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Value', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Validation', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'constraints', |
| | | 'type': 'Constraint', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Constraint', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'config', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ConditionalEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ConditionalEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'variableName', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableEvent', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | } |
| | | ], |
| | | 'emumerations': [] |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import ContextPadProvider from 'bpmn-js/lib/features/context-pad/ContextPadProvider'; |
| | | import { Injector } from 'didi'; |
| | | import EventBus from 'diagram-js/lib/core/EventBus'; |
| | | import ContextPad from 'diagram-js/lib/features/context-pad/ContextPad'; |
| | | import Modeling from 'bpmn-js/lib/features/modeling/Modeling.js'; |
| | | import ElementFactory from 'bpmn-js/lib/features/modeling/ElementFactory'; |
| | | import Connect from 'diagram-js/lib/features/connect/Connect'; |
| | | import Create from 'diagram-js/lib/features/create/Create'; |
| | | import PopupMenu from 'diagram-js/lib/features/popup-menu/PopupMenu'; |
| | | import Canvas from 'diagram-js/lib/core/Canvas'; |
| | | import Rules from 'diagram-js/lib/features/rules/Rules'; |
| | | import { Element, Shape } from 'diagram-js/lib/model/Types'; |
| | | import BpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | import modeler from '@/store/modules/modeler'; |
| | | |
| | | // @Description: å¢å¼ºå
ç´ è¿çº¿äºä»¶ |
| | | |
| | | class CustomContextPadProvider extends ContextPadProvider { |
| | | private _contextPad: ContextPad; |
| | | private _modeling: Modeling; |
| | | private _elementFactory: ElementFactory; |
| | | private _autoPlace: any; |
| | | private _connect: Connect; |
| | | private _create: Create; |
| | | private _popupMenu: PopupMenu; |
| | | private _canvas: Canvas; |
| | | private _rules: Rules; |
| | | |
| | | constructor( |
| | | config: any, |
| | | injector: Injector, |
| | | eventBus: EventBus, |
| | | contextPad: ContextPad, |
| | | modeling: Modeling, |
| | | elementFactory: ElementFactory, |
| | | connect: Connect, |
| | | create: Create, |
| | | popupMenu: PopupMenu, |
| | | canvas: Canvas, |
| | | rules: Rules, |
| | | translate |
| | | ) { |
| | | // @ts-ignore |
| | | super(config, injector, eventBus, contextPad, modeling, elementFactory, connect, create, popupMenu, canvas, rules, translate); |
| | | |
| | | this._contextPad = contextPad; |
| | | this._modeling = modeling; |
| | | this._elementFactory = elementFactory; |
| | | this._connect = connect; |
| | | this._create = create; |
| | | this._popupMenu = popupMenu; |
| | | this._canvas = canvas; |
| | | this._rules = rules; |
| | | |
| | | this._autoPlace = injector.get('autoPlace', false); |
| | | } |
| | | |
| | | getContextPadEntries(element: Element) { |
| | | const actions: Record<string, any> = {}; |
| | | |
| | | const appendUserTask = (event: Event, element: Shape) => { |
| | | const shape = this._elementFactory.createShape({ type: 'bpmn:UserTask' }); |
| | | this._create.start(event, shape, { |
| | | source: element |
| | | }); |
| | | }; |
| | | |
| | | const appendMultiInstanceUserTask = (event: Event, element: Shape) => { |
| | | const store = modeler(); |
| | | const bpmnFactory = store.getModeler().get('bpmnFactory') as BpmnFactory; |
| | | const businessObject = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡', |
| | | isForCompensation: false |
| | | }); |
| | | businessObject.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | // å建 Shape |
| | | const shape = this._elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: businessObject |
| | | }); |
| | | this._create.start(event, shape, { source: element }); |
| | | }; |
| | | |
| | | const appendTask = this._autoPlace |
| | | ? (event, element) => { |
| | | const bpmnFactory: BpmnFactory | undefined = modeler().getModeler().get('bpmnFactory'); |
| | | const businessObject = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡',// å³é®å建æ¾ç¤º |
| | | isForCompensation: false |
| | | }); |
| | | |
| | | // å建å¤å®ä¾å±æ§å¹¶åé
ç»ç¨æ·ä»»å¡ç loopCharacteristics |
| | | businessObject.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | |
| | | // å建 Shape |
| | | const shape = this._elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: businessObject |
| | | }); |
| | | |
| | | this._autoPlace.append(element, shape); |
| | | } |
| | | : appendMultiInstanceUserTask; |
| | | |
| | | const append = this._autoPlace |
| | | ? (event: Event, element: Shape) => { |
| | | const shape = this._elementFactory.createShape({ type: 'bpmn:UserTask' }); |
| | | this._autoPlace.append(element, shape); |
| | | } |
| | | : appendUserTask; |
| | | |
| | | // // æ·»å åå»ºç¨æ·ä»»å¡æé® |
| | | actions['append.append-user-task'] = { |
| | | group: 'model', |
| | | className: 'bpmn-icon-user-task', |
| | | title: 'ç¨æ·ä»»å¡', |
| | | action: { |
| | | dragstart: appendUserTask, |
| | | click: append |
| | | } |
| | | }; |
| | | |
| | | // æ·»å å建å¤å®ä¾ç¨æ·ä»»å¡æé® |
| | | actions['append.append-multi-instance-user-task'] = { |
| | | group: 'model', |
| | | className: 'bpmn-icon-user', // ä½ å¯ä»¥ä½¿ç¨å¤å®ä¾ç¨æ·ä»»å¡ç徿 bpmn-icon-user bpmn-icon-user-task |
| | | title: 'å¤å®ä¾ç¨æ·ä»»å¡', |
| | | action: { |
| | | dragstart: appendMultiInstanceUserTask, |
| | | click: appendTask |
| | | } |
| | | }; |
| | | |
| | | return actions; |
| | | } |
| | | } |
| | | |
| | | export default CustomContextPadProvider; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { assign } from 'min-dash'; |
| | | import PaletteProvider from 'bpmn-js/lib/features/palette/PaletteProvider'; |
| | | import ElementFactory from 'bpmn-js/lib/features/modeling/ElementFactory'; |
| | | import Create from 'diagram-js/lib/features/create/Create'; |
| | | import SpaceTool from 'diagram-js/lib/features/space-tool/SpaceTool'; |
| | | import LassoTool from 'diagram-js/lib/features/lasso-tool/LassoTool'; |
| | | import HandTool from 'diagram-js/lib/features/hand-tool/HandTool'; |
| | | import GlobalConnect from 'diagram-js/lib/features/global-connect/GlobalConnect'; |
| | | import Palette from 'diagram-js/lib/features/palette/Palette'; |
| | | import modeler from '@/store/modules/modeler'; |
| | | import BpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | |
| | | // @Description: å¢å¼ºå·¦ä¾§é¢æ¿ |
| | | class CustomPaletteProvider extends PaletteProvider { |
| | | private readonly _palette: Palette; |
| | | private readonly _create: Create; |
| | | private readonly _elementFactory: ElementFactory; |
| | | private readonly _spaceTool: SpaceTool; |
| | | private readonly _lassoTool: LassoTool; |
| | | private readonly _handTool: HandTool; |
| | | private readonly _globalConnect: GlobalConnect; |
| | | private readonly _translate: any; |
| | | |
| | | constructor(palette, create, elementFactory, spaceTool, lassoTool, handTool, globalConnect, translate) { |
| | | super(palette, create, elementFactory, spaceTool, lassoTool, handTool, globalConnect, translate); |
| | | this._palette = palette; |
| | | this._create = create; |
| | | this._elementFactory = elementFactory; |
| | | this._spaceTool = spaceTool; |
| | | this._lassoTool = lassoTool; |
| | | this._handTool = handTool; |
| | | this._globalConnect = globalConnect; |
| | | this._translate = translate; |
| | | } |
| | | |
| | | getPaletteEntries() { |
| | | const actions = {}, |
| | | create = this._create, |
| | | elementFactory = this._elementFactory, |
| | | translate = this._translate; |
| | | |
| | | function createAction(type: string, group: string, className: string, title: string, options?: object) { |
| | | function createListener(event) { |
| | | const shape = elementFactory.createShape(assign({ type: type }, options)); |
| | | if (options) { |
| | | !shape.businessObject.di && (shape.businessObject.di = {}); |
| | | shape.businessObject.di.isExpanded = (options as { [key: string]: any }).isExpanded; |
| | | } |
| | | create.start(event, shape, null); |
| | | } |
| | | const shortType = type.replace(/^bpmn:/, ''); |
| | | return { |
| | | group: group, |
| | | className: className, |
| | | title: title || translate('Create {type}', { type: shortType }), |
| | | action: { |
| | | dragstart: createListener, |
| | | click: createListener |
| | | } |
| | | }; |
| | | } |
| | | |
| | | function createMultiInstanceUserTask(event) { |
| | | const bpmnFactory: BpmnFactory | undefined = modeler().getBpmnFactory(); |
| | | // å建ä¸ä¸ª bpmn:UserTask |
| | | const userTask = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡', // å¨ç»æ¿ä¸æ¾ç¤ºå段 |
| | | isForCompensation: false |
| | | }); |
| | | // å°å¤å®ä¾å±æ§åé
ç» bpmn:UserTask ç loopCharacteristics |
| | | userTask.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | const customUserTask = elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: userTask // åé
å建ç userTask å° businessObject |
| | | }); |
| | | create.start(event, customUserTask, {}); |
| | | } |
| | | |
| | | assign(actions, { |
| | | 'create.parallel-gateway': createAction('bpmn:ParallelGateway', 'gateway', 'bpmn-icon-gateway-parallel', 'å¹¶è¡ç½å
³'), |
| | | 'create.event-base-gateway': createAction('bpmn:EventBasedGateway', 'gateway', 'bpmn-icon-gateway-eventbased', 'äºä»¶ç½å
³'), |
| | | // åç»çº¿ |
| | | 'gateway-separator': { |
| | | group: 'gateway', |
| | | separator: true |
| | | }, |
| | | 'create.user-task': createAction('bpmn:UserTask', 'activity', 'bpmn-icon-user-task', 'åå»ºç¨æ·ä»»å¡'), |
| | | 'create.multi-instance-user-task': { |
| | | group: 'activity', |
| | | type: 'bpmn:UserTask', |
| | | className: 'bpmn-icon-user task-multi-instance', |
| | | title: 'å建å¤å®ä¾ç¨æ·ä»»å¡', |
| | | action: { |
| | | click: createMultiInstanceUserTask, |
| | | dragstart: createMultiInstanceUserTask |
| | | } |
| | | }, |
| | | 'task-separator': { |
| | | group: 'activity', |
| | | separator: true |
| | | } |
| | | }); |
| | | return actions; |
| | | } |
| | | } |
| | | |
| | | CustomPaletteProvider['$inject'] = ['palette', 'create', 'elementFactory', 'spaceTool', 'lassoTool', 'handTool', 'globalConnect', 'translate']; |
| | | |
| | | export default CustomPaletteProvider; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'; |
| | | import { |
| | | append as svgAppend, |
| | | attr as svgAttr, |
| | | create as svgCreate, |
| | | select as svgSelect, |
| | | selectAll as svgSelectAll, |
| | | clone as svgClone, |
| | | clear as svgClear, |
| | | remove as svgRemove |
| | | } from 'tiny-svg'; |
| | | |
| | | const HIGH_PRIORITY = 1500; |
| | | export default class CustomRenderer extends BaseRenderer { |
| | | bpmnRenderer: BaseRenderer; |
| | | modeling: any; |
| | | constructor(eventBus, bpmnRenderer, modeling) { |
| | | super(eventBus, HIGH_PRIORITY); |
| | | this.bpmnRenderer = bpmnRenderer; |
| | | this.modeling = modeling; |
| | | } |
| | | canRender(element) { |
| | | // ignore labels |
| | | return !element.labelTarget; |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹èç¹å¾å½¢ |
| | | * @param {*} parentNode å½åå
ç´ çsvgNode |
| | | * @param {*} element |
| | | * @returns |
| | | */ |
| | | drawShape(parentNode, element) { |
| | | const shape = this.bpmnRenderer.drawShape(parentNode, element); |
| | | const { type, width, height } = element; |
| | | // å¼å§ å¡«å
ç»¿è² |
| | | if (type === 'bpmn:StartEvent') { |
| | | svgAttr(shape, { fill: '#77DF6D' }); |
| | | return shape; |
| | | } |
| | | if (type === 'bpmn:EndEvent') { |
| | | svgAttr(shape, { fill: '#EE7B77' }); |
| | | return shape; |
| | | } |
| | | if (type === 'bpmn:UserTask') { |
| | | svgAttr(shape, { fill: '#A9C4F8' }); |
| | | return shape; |
| | | } |
| | | return shape; |
| | | } |
| | | |
| | | getShapePath(shape) { |
| | | return this.bpmnRenderer.getShapePath(shape); |
| | | } |
| | | } |
| | | CustomRenderer['$inject'] = ['eventBus', 'bpmnRenderer']; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import zh from '../../lang/zh'; |
| | | |
| | | const customTranslate = (template: any, replacements: any) => { |
| | | replacements = replacements || {}; |
| | | template = zh[template] || template; |
| | | return template.replace(/{([^}]+)}/g, function (_: any, key: any) { |
| | | return replacements[key] || '{' + key + '}'; |
| | | }); |
| | | }; |
| | | |
| | | export const translateModule = { |
| | | translate: ['value', customTranslate] |
| | | }; |
| | | |
| | | export default translateModule; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | // ç¿»è¯æ¨¡å |
| | | import TranslationModule from './Translate'; |
| | | import { ModuleDeclaration } from 'didi'; |
| | | import CustomPaletteProvider from './Palette/CustomPaletteProvider'; |
| | | import CustomRenderer from './Renderer/CustomRenderer'; |
| | | import CustomContextPadProvider from './ContextPad/CustomContextPadProvider'; |
| | | |
| | | const Module: ModuleDeclaration[] = [ |
| | | { |
| | | __init__: ['customPaletteProvider', 'customContextPadProvider', 'customRenderer'], |
| | | customPaletteProvider: ['type', CustomPaletteProvider], |
| | | customRenderer: ['type', CustomRenderer], |
| | | customContextPadProvider: ['type', CustomContextPadProvider] |
| | | }, |
| | | TranslationModule |
| | | ]; |
| | | export default Module; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export default { |
| | | 'bpmn:EndEvent': {}, |
| | | 'bpmn:StartEvent': { |
| | | initiator: true, |
| | | formKey: true |
| | | }, |
| | | 'bpmn:UserTask': { |
| | | allocationType: true, |
| | | specifyDesc: true, |
| | | multipleUserAuditType: true, |
| | | async: true, |
| | | priority: true, |
| | | skipExpression: true, |
| | | dueDate: true, |
| | | taskListener: true, |
| | | executionListener: true |
| | | }, |
| | | 'bpmn:ServiceTask': { |
| | | async: true, |
| | | skipExpression: true, |
| | | isForCompensation: true, |
| | | triggerable: true, |
| | | class: true |
| | | }, |
| | | 'bpmn:ScriptTask': { |
| | | async: true, |
| | | isForCompensation: true, |
| | | autoStoreVariables: true |
| | | }, |
| | | 'bpmn:ManualTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:ReceiveTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:SendTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:BusinessRuleTask': { |
| | | async: true, |
| | | isForCompensation: true, |
| | | ruleVariablesInput: true, |
| | | rules: true, |
| | | resultVariable: true, |
| | | exclude: true |
| | | } |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | .djs-palette { |
| | | width: 300px; |
| | | |
| | | .bpmn-icon-hand-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨æå¨å·¥å
·'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-lasso-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨å¥ç´¢å·¥å
·'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-space-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨å建/å é¤ç©ºé´å·¥å
·'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 170px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-connection-multi:hover { |
| | | &:after { |
| | | content: 'å¯å¨å
¨å±è¿æ¥å·¥å
·'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-start-event-none:hover { |
| | | &:after { |
| | | content: 'å建å¼å§äºä»¶'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-intermediate-event-none:hover { |
| | | &:after { |
| | | content: 'å建ä¸é´/è¾¹çäºä»¶'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-end-event-none:hover { |
| | | &:after { |
| | | content: 'åå»ºç»æäºä»¶'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-none:hover { |
| | | &:after { |
| | | content: 'å建ç½å
³'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 90px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-parallel:hover { |
| | | &:after { |
| | | content: 'å建并è¡ç½å
³'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-eventbased:hover { |
| | | &:after { |
| | | content: 'å建äºä»¶ç½å
³'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-task:hover { |
| | | &:after { |
| | | content: 'å建任å¡'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 80px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-subprocess-expanded:hover { |
| | | &:after { |
| | | content: 'åå»ºå¯æå åæµç¨'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-user-task:hover { |
| | | &:after { |
| | | content: 'åå»ºç¨æ·ä»»å¡'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | |
| | | .task-multi-instance:hover { |
| | | &:after { |
| | | content: 'å建å¤å®ä¾ç¨æ·ä»»å¡'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 160px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-participant:hover { |
| | | &:after { |
| | | content: 'åå»ºæ³³æ± /æ³³é'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-data-object { |
| | | display: none; |
| | | &:hover { |
| | | &:after { |
| | | content: 'åå»ºæ°æ®å¯¹è±¡'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
| | | .bpmn-icon-data-store { |
| | | display: none; |
| | | &:hover { |
| | | &:after { |
| | | content: 'åå»ºæ°æ®åå¨'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
| | | .bpmn-icon-group { |
| | | display: none; |
| | | &:hover { |
| | | &:after { |
| | | content: 'å建åç»'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 100px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import showConfig from '../assets/showConfig'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | import { MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
| | | interface Options { |
| | | element: ModdleElement; |
| | | } |
| | | |
| | | export default (ops: Options) => { |
| | | const { element } = ops; |
| | | const { getModeling, getModdle } = useModelerStore(); |
| | | const modeling = getModeling(); |
| | | const moddle = getModdle(); |
| | | |
| | | /** |
| | | * å½åèç¹ç±»å |
| | | */ |
| | | const elementType = computed(() => { |
| | | const bizObj = element.businessObject; |
| | | return bizObj.eventDefinitions ? bizObj.eventDefinitions[0].$type : bizObj.$type; |
| | | }); |
| | | |
| | | /** |
| | | * ç¨äºæ§å¶é¢æ¿å段æ¾ç¤ºä¸éèçé
ç½® |
| | | */ |
| | | const config = computed(() => showConfig[elementType.value] || {}); |
| | | |
| | | /** |
| | | * å建ä¸ä¸ªèç¹ |
| | | * @param elementType èç¹ç±»å |
| | | * @param properties 屿§ |
| | | * @param parent ç¶èç¹ |
| | | */ |
| | | const createModdleElement = (elementType: string, properties: any, parent: ModdleElement) => { |
| | | const element = moddle.create(elementType, properties); |
| | | parent && (element.$parent = parent); |
| | | return element; |
| | | }; |
| | | |
| | | /** |
| | | * è·åæ©å±å±æ§ï¼å¦æä¸åå¨ä¼èªå¨å建 |
| | | */ |
| | | const getExtensionElements = (create = true) => { |
| | | let extensionElements = element.businessObject.get<ModdleElement>('extensionElements'); |
| | | if (!extensionElements && create) { |
| | | extensionElements = createModdleElement('bpmn:ExtensionElements', { values: [] }, element.businessObject); |
| | | modeling.updateModdleProperties(element, element.businessObject, { extensionElements }); |
| | | } |
| | | return extensionElements; |
| | | }; |
| | | |
| | | /** |
| | | * è·åextensionElementsä¸çproperties |
| | | * @param extensionElements å¯éåæ°ï¼é»è®¤è·åå½åElementä¸çextensionElementsä¸çProperties |
| | | */ |
| | | const getPropertiesElements = (extensionElements?: ModdleElement) => { |
| | | if (!extensionElements) { |
| | | extensionElements = getExtensionElements(); |
| | | } |
| | | let propertiesElements = extensionElements.values.find((item) => item.$type === 'flowable:properties'); |
| | | if (!propertiesElements) { |
| | | propertiesElements = createModdleElement('flowable:properties', { values: [] }, extensionElements); |
| | | modeling.updateModdleProperties(element, extensionElements, { |
| | | values: [...extensionElements.get<[]>('values'), propertiesElements] |
| | | }); |
| | | } |
| | | return propertiesElements; |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°èç¹å±æ§ |
| | | * @param properties 屿§å¼ |
| | | */ |
| | | const updateProperties = (properties: any) => { |
| | | modeling.updateProperties(element, properties); |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°èç¹ä¿¡æ¯ |
| | | * @param updateElement éè¦æ´æ°çèç¹ |
| | | * @param properties 屿§ |
| | | */ |
| | | const updateModdleProperties = (updateElement, properties: any) => { |
| | | modeling.updateModdleProperties(element, updateElement, properties); |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°Property屿§ |
| | | * @param name keyå¼ |
| | | * @param value å¼ |
| | | */ |
| | | const updateProperty = (name: string, value: string) => { |
| | | const propertiesElements = getPropertiesElements(); |
| | | |
| | | let propertyElements = propertiesElements.values.find((item) => item.name === name); |
| | | if (!propertyElements) { |
| | | propertyElements = createModdleElement('flowable:property', { name: name, value: value }, propertiesElements); |
| | | modeling.updateModdleProperties(element, propertiesElements, { |
| | | values: [...propertiesElements.get('values'), propertyElements] |
| | | }); |
| | | } else { |
| | | propertyElements.name = name; |
| | | propertyElements.value = value; |
| | | } |
| | | return propertyElements; |
| | | }; |
| | | |
| | | const idChange = (newVal: string) => { |
| | | if (newVal) { |
| | | updateProperties({ id: newVal }); |
| | | } |
| | | }; |
| | | const nameChange = (newVal: string) => { |
| | | if (newVal) { |
| | | updateProperties({ name: newVal }); |
| | | } |
| | | }; |
| | | const formKeyChange = (newVal: string) => { |
| | | updateProperties({ formKey: newVal }); |
| | | }; |
| | | const constant = { |
| | | MultiInstanceType: [ |
| | | { id: '373d4b81-a0d1-4eb8-8685-0d2fb1b468e2', label: 'æ ', value: MultiInstanceTypeEnum.NONE }, |
| | | { id: 'b5acea7c-b7e5-46b0-8778-390db091bdab', label: '串è¡', value: MultiInstanceTypeEnum.SERIAL }, |
| | | { id: 'b4f0c683-1ccc-43c4-8380-e1b998986caf', label: 'å¹¶è¡', value: MultiInstanceTypeEnum.PARALLEL } |
| | | ] |
| | | }; |
| | | |
| | | return { |
| | | elementType, |
| | | constant, |
| | | showConfig: config, |
| | | |
| | | updateProperties, |
| | | updateProperty, |
| | | updateModdleProperties, |
| | | |
| | | createModdleElement, |
| | | idChange, |
| | | nameChange, |
| | | formKeyChange, |
| | | getExtensionElements, |
| | | getPropertiesElements |
| | | }; |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { ModdleElement } from 'bpmn'; |
| | | |
| | | interface Options { |
| | | element: ModdleElement; |
| | | } |
| | | |
| | | interface Data { |
| | | id: string; |
| | | } |
| | | |
| | | export default (ops: Options) => { |
| | | const { element } = ops; |
| | | |
| | | const parseData = <T>(): T => { |
| | | const result = { |
| | | ...element.businessObject, |
| | | ...element.businessObject.$attrs |
| | | }; |
| | | |
| | | // ç§»é¤flowableåç¼ï¼æ ¼å¼åæ°ç» |
| | | for (const key in result) { |
| | | if (key.indexOf('flowable:') === 0) { |
| | | const newKey = key.replace('flowable:', ''); |
| | | result[newKey] = result[key]; |
| | | delete result[key]; |
| | | } |
| | | } |
| | | return { ...result } as T; |
| | | }; |
| | | |
| | | return { |
| | | parseData |
| | | }; |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="containers-bpmn"> |
| | | <!-- dark模å¼ä¸ è¿æ¥çº¿çç®å¤´æ ·å¼ --> |
| | | <svg width="0" height="0" style="position: absolute"> |
| | | <defs> |
| | | <marker id="markerArrow-dark-mode" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto"> |
| | | <path d="M 1 5 L 11 10 L 1 15 Z" class="arrow-dark" /> |
| | | </marker> |
| | | </defs> |
| | | </svg> |
| | | <div v-loading="loading" class="app-containers-bpmn"> |
| | | <el-container class="h-full"> |
| | | <el-container style="align-items: stretch"> |
| | | <el-header> |
| | | <div class="process-toolbar"> |
| | | <el-space wrap :size="10"> |
| | | <el-tooltip effect="dark" content="èªéåºå±å¹" placement="bottom"> |
| | | <el-button size="small" icon="Rank" @click="fitViewport" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="æ¾å¤§" placement="bottom"> |
| | | <el-button size="small" icon="ZoomIn" @click="zoomViewport(true)" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="缩å°" placement="bottom"> |
| | | <el-button size="small" icon="ZoomOut" @click="zoomViewport(false)" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="åé" placement="bottom"> |
| | | <el-button size="small" icon="Back" @click="bpmnModeler.get('commandStack').undo()" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="åè¿" placement="bottom"> |
| | | <el-button size="small" icon="Right" @click="bpmnModeler.get('commandStack').redo()" /> |
| | | </el-tooltip> |
| | | </el-space> |
| | | <el-space wrap :size="10" style="float: right; padding-right: 10px"> |
| | | <el-button size="small" type="primary" @click="saveXml">ä¿ å</el-button> |
| | | <el-dropdown size="small"> |
| | | <el-button size="small" type="primary"> é¢ è§ </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Document" @click="previewXML">XMLé¢è§</el-dropdown-item> |
| | | <el-dropdown-item icon="View" @click="previewSVG"> SVGé¢è§</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | <el-dropdown size="small"> |
| | | <el-button size="small" type="primary"> ä¸ è½½ </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Download" @click="downloadXML">ä¸è½½XML</el-dropdown-item> |
| | | <el-dropdown-item icon="Download" @click="downloadSVG"> ä¸è½½SVG</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </el-space> |
| | | </div> |
| | | </el-header> |
| | | <div ref="canvas" class="canvas" /> |
| | | </el-container> |
| | | <div :class="{ 'process-panel': true, 'hide': panelFlag }"> |
| | | <div class="process-panel-bar" @click="panelBarClick"> |
| | | <div class="open-bar"> |
| | | <el-link type="default" :underline="false"> |
| | | <svg-icon class-name="open-bar" :icon-class="panelFlag ? 'caret-back' : 'caret-forward'"></svg-icon> |
| | | </el-link> |
| | | </div> |
| | | </div> |
| | | <transition enter-active-class="animate__animated animate__fadeIn"> |
| | | <div v-show="showPanel" v-if="bpmnModeler" class="panel-content"> |
| | | <PropertyPanel :modeler="bpmnModeler" /> |
| | | </div> |
| | | </transition> |
| | | </div> |
| | | </el-container> |
| | | </div> |
| | | </div> |
| | | <div> |
| | | <el-dialog v-model="perviewXMLShow" title="XMLé¢è§" width="80%" append-to-body> |
| | | <highlightjs :code="xmlStr" language="XML" /> |
| | | </el-dialog> |
| | | </div> |
| | | <div> |
| | | <el-dialog v-model="perviewSVGShow" title="SVGé¢è§" width="80%" append-to-body> |
| | | <div style="text-align: center" v-html="svgData" /> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="BpmnDesign"> |
| | | import 'bpmn-js/dist/assets/diagram-js.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; |
| | | import './assets/style/index.scss'; |
| | | import { Canvas, Modeler } from 'bpmn'; |
| | | import PropertyPanel from './panel/index.vue'; |
| | | import BpmnModeler from 'bpmn-js/lib/Modeler.js'; |
| | | import defaultXML from './assets/defaultXML'; |
| | | import flowableModdle from './assets/moddle/flowable'; |
| | | import Modules from './assets/module/index'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | const emit = defineEmits(['closeCallBack', 'saveCallBack']); |
| | | |
| | | const { visible, title, openDialog, closeDialog } = useDialog({ |
| | | title: 'ç¼è¾æµç¨' |
| | | }); |
| | | const modelerStore = useModelerStore(); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const panelFlag = ref(false); |
| | | const showPanel = ref(true); |
| | | const canvas = ref<HTMLDivElement>(); |
| | | const panel = ref<HTMLDivElement>(); |
| | | const bpmnModeler = ref<Modeler>(); |
| | | const zoom = ref(1); |
| | | const perviewXMLShow = ref(false); |
| | | const perviewSVGShow = ref(false); |
| | | const xmlStr = ref(''); |
| | | const svgData = ref(''); |
| | | const loading = ref(false); |
| | | |
| | | const panelBarClick = () => { |
| | | // å»¶è¿æ§è¡ï¼å¦åä¼å¯¼è´é¢æ¿æ¶èµ·æ¶ï¼å±æ§é¢æ¿ä¸æ¾ç¤º |
| | | panelFlag.value = !panelFlag.value; |
| | | setTimeout(() => { |
| | | showPanel.value = !panelFlag.value; |
| | | }, 100); |
| | | }; |
| | | |
| | | /** |
| | | * åå§åCanvas |
| | | */ |
| | | const initCanvas = () => { |
| | | bpmnModeler.value = new BpmnModeler({ |
| | | container: canvas.value, |
| | | // é®ç |
| | | keyboard: { |
| | | bindTo: window // æè
windowï¼æ³¨æä¸å¤é¨è¡¨åçé®ççå¬äºä»¶æ¯å¦å²çª |
| | | }, |
| | | propertiesPanel: { |
| | | parent: panel.value |
| | | }, |
| | | additionalModules: Modules, |
| | | moddleExtensions: { |
| | | flowable: flowableModdle |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åå§åModel |
| | | */ |
| | | const initModel = () => { |
| | | if (modelerStore.getModeler()) { |
| | | modelerStore.getModeler().destroy(); |
| | | modelerStore.setModeler(undefined); |
| | | } |
| | | modelerStore.setModeler(bpmnModeler.value); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å»º |
| | | */ |
| | | const newDiagram = async () => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ°å»º'); |
| | | initDiagram(); |
| | | }; |
| | | |
| | | /** |
| | | * åå§å |
| | | */ |
| | | const initDiagram = (xml?: string) => { |
| | | if (!xml) xml = defaultXML; |
| | | bpmnModeler.value.importXML(xml); |
| | | }; |
| | | |
| | | /** |
| | | * èªéåºå±å¹ |
| | | */ |
| | | const fitViewport = () => { |
| | | zoom.value = bpmnModeler.value.get<Canvas>('canvas').zoom('fit-viewport'); |
| | | const bbox = document.querySelector<SVGGElement>('.app-containers-bpmn .viewport').getBBox(); |
| | | const currentViewBox = bpmnModeler.value.get<Canvas>('canvas').viewbox(); |
| | | const elementMid = { |
| | | x: bbox.x + bbox.width / 2 - 65, |
| | | y: bbox.y + bbox.height / 2 |
| | | }; |
| | | bpmnModeler.value.get<Canvas>('canvas').viewbox({ |
| | | x: elementMid.x - currentViewBox.width / 2, |
| | | y: elementMid.y - currentViewBox.height / 2, |
| | | width: currentViewBox.width, |
| | | height: currentViewBox.height |
| | | }); |
| | | zoom.value = (bbox.width / currentViewBox.width) * 1.8; |
| | | }; |
| | | /** |
| | | * æ¾å¤§æè
ç¼©å° |
| | | * @param zoomIn true æ¾å¤§ | false ç¼©å° |
| | | */ |
| | | const zoomViewport = (zoomIn = true) => { |
| | | zoom.value = bpmnModeler.value.get<Canvas>('canvas').zoom(); |
| | | zoom.value += zoomIn ? 0.1 : -0.1; |
| | | bpmnModeler.value.get<Canvas>('canvas').zoom(zoom.value); |
| | | }; |
| | | |
| | | /** |
| | | * ä¸è½½XML |
| | | */ |
| | | const downloadXML = async () => { |
| | | try { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | downloadFile(`${getProcessElement().name}.bpmn20.xml`, xml, 'application/xml'); |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * ä¸è½½SVG |
| | | */ |
| | | const downloadSVG = async () => { |
| | | try { |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | downloadFile(getProcessElement().name, svg, 'image/svg+xml'); |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * XMLé¢è§ |
| | | */ |
| | | const previewXML = async () => { |
| | | try { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | xmlStr.value = xml; |
| | | perviewXMLShow.value = true; |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * SVGé¢è§ |
| | | */ |
| | | const previewSVG = async () => { |
| | | try { |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | svgData.value = svg; |
| | | perviewSVGShow.value = true; |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | const curNodeInfo = reactive({ |
| | | curType: '', // ä»»å¡ç±»å ç¨æ·ä»»å¡ |
| | | curNode: '', |
| | | expValue: '' //å¤ç¨æ·åé¨é¨è§è²å®ç° |
| | | }); |
| | | |
| | | const downloadFile = (fileName: string, data: any, type: string) => { |
| | | const a = document.createElement('a'); |
| | | const url = window.URL.createObjectURL(new Blob([data], { type: type })); |
| | | a.href = url; |
| | | a.download = fileName; |
| | | a.click(); |
| | | window.URL.revokeObjectURL(url); |
| | | }; |
| | | |
| | | const getProcessElement = () => { |
| | | const rootElements = bpmnModeler.value?.getDefinitions().rootElements; |
| | | for (let i = 0; i < rootElements.length; i++) { |
| | | if (rootElements[i].$type === 'bpmn:Process') return rootElements[i]; |
| | | } |
| | | }; |
| | | |
| | | const getProcess = () => { |
| | | const element = getProcessElement(); |
| | | return { |
| | | id: element.id, |
| | | name: element.name |
| | | }; |
| | | }; |
| | | |
| | | const saveXml = async () => { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | const process = getProcess(); |
| | | let data = { |
| | | xml: xml, |
| | | svg: svg, |
| | | key: process.id, |
| | | name: process.name, |
| | | loading: loading |
| | | }; |
| | | emit('saveCallBack', data); |
| | | }; |
| | | |
| | | const open = (xml?: string) => { |
| | | openDialog(); |
| | | nextTick(() => { |
| | | initDiagram(xml); |
| | | }); |
| | | }; |
| | | const close = () => { |
| | | closeDialog(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | initCanvas(); |
| | | initModel(); |
| | | }); |
| | | }); |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | initDiagram, |
| | | saveXml, |
| | | open, |
| | | close |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | /** å¤é´æ¨¡å¼ 线æ¡çé¢è² */ |
| | | $stroke-color-dark: white; |
| | | $bpmn-font-size: 12px; |
| | | /** æ¥é´æ¨¡å¼ åä½é¢è² */ |
| | | $bpmn-font-color-dark: white; |
| | | /** å¤é´æ¨¡å¼ åä½é¢è² */ |
| | | $bpmn-font-color-light: #222; |
| | | |
| | | /* èæ¯ç½æ ¼ */ |
| | | @mixin djs-container { |
| | | background-image: linear-gradient(90deg, hsl(0deg 0% 78.4% / 15%) 10%, transparent 0), linear-gradient(hsl(0deg 0% 78.4% / 15%) 10%, transparent 0) !important; |
| | | background-size: 10px 10px !important; |
| | | } |
| | | |
| | | html[class='light'] { |
| | | /** ä»å·¦ä¾§æå¨æ¶çèæ¯å¾ */ |
| | | svg.new-parent { |
| | | @include djs-container; |
| | | } |
| | | |
| | | /** åå»ç¼è¾å
ç´ æ¶æ ·å¼ä¿æä¸è´ */ |
| | | div.djs-direct-editing-parent { |
| | | border-radius: 10px; |
| | | background-color: transparent !important; |
| | | color: $bpmn-font-color-light; |
| | | } |
| | | |
| | | g.djs-visual { |
| | | .djs-label { |
| | | fill: $bpmn-font-color-light !important; |
| | | font-size: $bpmn-font-size !important; |
| | | } |
| | | } |
| | | } |
| | | |
| | | html[class='dark'] { |
| | | /** dark模å¼ä¸ è¿æ¥çº¿çç®å¤´æ ·å¼ */ |
| | | .arrow-dark { |
| | | stroke-width: 1px; |
| | | stroke-linecap: round; |
| | | stroke: $stroke-color-dark; |
| | | fill: $stroke-color-dark; |
| | | stroke-linejoin: round; |
| | | } |
| | | |
| | | /** ä»å·¦ä¾§æå¨æ¶çèæ¯å¾ */ |
| | | svg.new-parent { |
| | | background-color: black !important; |
| | | @include djs-container; |
| | | } |
| | | |
| | | /** åå»ç¼è¾å
ç´ æ¶æ ·å¼ä¿æä¸è´ */ |
| | | div.djs-direct-editing-parent { |
| | | border-radius: 10px; |
| | | background-color: transparent !important; |
| | | color: $bpmn-font-color-dark; |
| | | } |
| | | |
| | | /** å
ç´ ç¸å
³è®¾ç½® */ |
| | | g.djs-visual { |
| | | /** å
ç´ è¾¹æ¡ éè¦å»é¤æå(.djs-label) */ |
| | | & > *:first-child:not(.djs-label) { |
| | | stroke: $stroke-color-dark !important; |
| | | } |
| | | |
| | | /** åä½é¢è² */ |
| | | .djs-label { |
| | | fill: $bpmn-font-color-dark !important; |
| | | font-size: $bpmn-font-size !important; |
| | | } |
| | | |
| | | /* è¿æ¥çº¿æ ·å¼ */ |
| | | path[data-corner-radius] { |
| | | stroke: $stroke-color-dark !important; |
| | | marker-end: url('#markerArrow-dark-mode') !important; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .containers-bpmn { |
| | | height: 100%; |
| | | .app-containers-bpmn { |
| | | width: 100%; |
| | | height: 100%; |
| | | .canvas { |
| | | width: 100%; |
| | | height: 100%; |
| | | @include djs-container; |
| | | } |
| | | .el-header { |
| | | height: 35px; |
| | | padding: 0; |
| | | } |
| | | |
| | | .process-panel { |
| | | transition: width 0.25s ease-in; |
| | | .process-panel-bar { |
| | | width: 34px; |
| | | height: 40px; |
| | | .open-bar { |
| | | width: 34px; |
| | | line-height: 40px; |
| | | } |
| | | } |
| | | // æ¶èµ·é¢æ¿æ ·å¼ |
| | | &.hide { |
| | | width: 34px; |
| | | overflow: hidden; |
| | | padding: 0; |
| | | .process-panel-bar { |
| | | width: 34px; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | display: block; |
| | | text-align: left; |
| | | line-height: 34px; |
| | | } |
| | | .process-panel-bar:hover { |
| | | background-color: var(--bpmn-panel-bar-background-color); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | pre { |
| | | margin: 0; |
| | | height: 100%; |
| | | max-height: calc(80vh - 32px); |
| | | overflow-x: hidden; |
| | | overflow-y: auto; |
| | | .hljs { |
| | | word-break: break-word; |
| | | white-space: pre-wrap; |
| | | padding: 0.5em; |
| | | } |
| | | } |
| | | |
| | | .open-bar { |
| | | font-size: 20px; |
| | | cursor: pointer; |
| | | text-align: center; |
| | | } |
| | | .process-panel { |
| | | box-sizing: border-box; |
| | | padding: 0 8px 0 8px; |
| | | border-left: 1px solid var(--bpmn-panel-border); |
| | | box-shadow: var(--bpmn-panel-box-shadow) 0 0 8px; |
| | | max-height: 100%; |
| | | width: 25%; |
| | | height: calc(100vh - 100px); |
| | | .el-collapse { |
| | | height: calc(100vh - 182px); |
| | | overflow: auto; |
| | | } |
| | | } |
| | | |
| | | // 任塿 éæåº¦ |
| | | //:deep(.djs-palette) { |
| | | // opacity: 0.3; |
| | | // transition: all 1s; |
| | | //} |
| | | // |
| | | //:deep(.djs-palette:hover) { |
| | | // opacity: 1; |
| | | // transition: all 1s; |
| | | //} |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { GatewayPanel } from 'bpmnDesign'; |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref(parseData<GatewayPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | processCategory: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import { ParticipantPanel } from 'bpmnDesign'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const formData = ref(parseData<ParticipantPanel>()); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> |
| | | <el-form-item label="æµç¨æ è¯" prop="id"> |
| | | <el-input v-model="formData.id" @change="idChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨åç§°" prop="name"> |
| | | <el-input v-model="formData.name" @change="nameChange"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { ProcessPanel } from 'bpmnDesign'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { idChange, nameChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref<ProcessPanel>(parseData<ProcessPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="conditionExpression" label="跳转æ¡ä»¶"> |
| | | <el-input v-model="formData.conditionExpressionValue" @change="conditionExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="skipExpression" label="è·³è¿è¡¨è¾¾å¼"> |
| | | <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { SequenceFlowPanel } from 'bpmnDesign'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const moddle = useModelerStore().getModdle(); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref(parseData<SequenceFlowPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | processCategory: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const conditionExpressionChange = (val: string) => { |
| | | if (val) { |
| | | const newCondition = moddle.create('bpmn:FormalExpression', { body: val }); |
| | | updateProperties({ conditionExpression: newCondition }); |
| | | } else { |
| | | updateProperties({ conditionExpression: null }); |
| | | } |
| | | }; |
| | | |
| | | const skipExpressionChange = (val: string) => { |
| | | updateProperties({ 'flowable:skipExpression': val }); |
| | | }; |
| | | |
| | | onBeforeMount(() => { |
| | | if (formData.value.conditionExpression) { |
| | | formData.value.conditionExpressionValue = formData.value.conditionExpression.body; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { StartEndPanel } from 'bpmnDesign'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const formData = ref(parseData<StartEndPanel>()); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="3"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <HelpFilled /> |
| | | </el-icon> |
| | | å¤å®ä¾ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item label="å¤å®ä¾ç±»å"> |
| | | <el-select v-model="formData.multiInstanceType" @change="multiInstanceTypeChange"> |
| | | <el-option v-for="item in constant.MultiInstanceType" :key="item.id" :value="item.value" :label="item.label"> </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <div v-if="formData.multiInstanceType !== MultiInstanceTypeEnum.NONE"> |
| | | <el-form-item label="éå"> |
| | | <template #label> |
| | | <span> |
| | | éå |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | 屿§ä¼ä½ä¸ºè¡¨è¾¾å¼è¿è¡è§£æãå¦æè¡¨è¾¾å¼è§£æä¸ºå符串è䏿¯ä¸ä¸ªéåï¼<br /> |
| | | ä¸è®ºæ¯å 为æ¬èº«é
ç½®çå°±æ¯éæå符串å¼ï¼è¿æ¯è¡¨è¾¾å¼è®¡ç®ç»æä¸ºå符串ï¼<br /> |
| | | è¿ä¸ªå符串é½ä¼è¢«å½ååéåï¼å¹¶ä»æµç¨åéä¸ç¨äºè·åå®é
çéåã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.collection" @change="collectionChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å
ç´ åé"> |
| | | <template #label> |
| | | <span> |
| | | å
ç´ åé |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | æ¯å建ä¸ä¸ªç¨æ·ä»»å¡åï¼å
以该å
ç´ åé为labelï¼éåä¸çä¸é¡¹ä¸ºvalueï¼<br /> |
| | | å建ï¼å±é¨ï¼æµç¨åéï¼è¯¥å±é¨æµç¨åé被ç¨äºææ´¾ç¨æ·ä»»å¡ã<br /> |
| | | ä¸è¬æ¥è¯´ï¼è¯¥å符串åºä¸æå®äººååéç¸åã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.elementVariable" @change="elementVariableChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="宿æ¡ä»¶"> |
| | | <template #label> |
| | | <span> |
| | | 宿æ¡ä»¶ |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | å¤å®ä¾æ´»å¨å¨ææå®ä¾é½å®ææ¶ç»æï¼ç¶èä¹å¯ä»¥æå®ä¸ä¸ªè¡¨è¾¾å¼ï¼å¨æ¯ä¸ªå®ä¾<br /> |
| | | ç»ææ¶è¿è¡è®¡ç®ãå½è¡¨è¾¾å¼è®¡ç®ä¸ºtrueæ¶ï¼å°éæ¯ææå©ä½çå®ä¾ï¼å¹¶ç»æå¤å®ä¾<br /> |
| | | æ´»å¨ï¼ç»§ç»æ§è¡æµç¨ãä¾å¦ ${nrOfCompletedInstances/nrOfInstances >= 0.6 }ï¼<br /> |
| | | 表示å½ä»»å¡å®æ60%æ¶ï¼è¯¥èç¹å°±ç®å®æ |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.completionCondition" @change="completionConditionChange"> </el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </el-form> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import { SubProcessPanel } from 'bpmnDesign'; |
| | | import { MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange, updateProperties, createModdleElement, constant } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const formData = ref(parseData<SubProcessPanel>()); |
| | | const currentCollapseItem = ref(['1', '2', '3']); |
| | | |
| | | const multiInstanceTypeChange = (newVal) => { |
| | | if (newVal !== MultiInstanceTypeEnum.NONE) { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.isSequential = newVal === MultiInstanceTypeEnum.SERIAL; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | } else { |
| | | updateProperties({ loopCharacteristics: undefined }); |
| | | } |
| | | }; |
| | | const collectionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.collection = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const elementVariableChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.elementVariable = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const completionConditionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get<ModdleElement>('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | if (newVal && newVal.length > 0) { |
| | | if (!loopCharacteristics.completionCondition) { |
| | | loopCharacteristics.completionCondition = createModdleElement('bpmn:Expression', { body: newVal }, loopCharacteristics); |
| | | } else { |
| | | loopCharacteristics.completionCondition.body = newVal; |
| | | } |
| | | } else { |
| | | loopCharacteristics.completionCondition = undefined; |
| | | } |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | |
| | | onBeforeMount(() => { |
| | | if (formData.value.loopCharacteristics) { |
| | | const loopCharacteristics = formData.value.loopCharacteristics; |
| | | formData.value.collection = loopCharacteristics.collection || ''; |
| | | formData.value.elementVariable = loopCharacteristics.elementVariable || ''; |
| | | formData.value.completionCondition = loopCharacteristics.completionCondition?.body || ''; |
| | | formData.value.multiInstanceType = loopCharacteristics.isSequential ? MultiInstanceTypeEnum.SERIAL : MultiInstanceTypeEnum.PARALLEL; |
| | | } |
| | | }); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-form ref="formRef" size="default" :model="formData" :rules="formRules" label-width="100px"> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.skipExpression" prop="skipExpression" label="è·³è¿è¡¨è¾¾å¼"> |
| | | <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-loading="formManageListLoading" prop="formKey" label="表åå°å"> |
| | | <el-select v-model="formData.formKey" clearable filterable placeholder="è¯·éæ©è¡¨å" style="width: 260px" @change="formKeyChange"> |
| | | <el-option |
| | | v-for="item in formManageList" |
| | | :key="item.id" |
| | | :label="item.formTypeName + ':' + item.formName" |
| | | :value="item.formType + ':' + item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <Checked /> |
| | | </el-icon> |
| | | ä»»å¡ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item v-if="showConfig.async" prop="sync" label="æ¯å¦å¼æ¥"> |
| | | <el-switch v-model="formData.async" inline-prompt active-text="æ¯" inactive-text="å¦" @change="syncChange" /> |
| | | </el-form-item> |
| | | |
| | | <el-tabs tab-position="left" class="demo-tabs"> |
| | | <el-tab-pane label="身份åå¨"> |
| | | <el-form-item label="åé
人å"> |
| | | <el-input v-model="formData.assignee" @blur="blurAssignee(formData.assignee)"> |
| | | <template #append> |
| | | <el-button icon="Search" type="primary" @click="openSingleUserSelect" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åé人å"> |
| | | <el-badge :value="selectUserLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openUserSelect">éæ©äººå</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | <el-form-item label="åéç»"> |
| | | <el-badge :value="selectRoleLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openRoleSelect">éæ©ç»</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | </el-tab-pane> |
| | | |
| | | <!-- <el-tab-pane label="åºå®å¼"> |
| | | <el-form-item prop="auditUserType" label="åé
ç±»å"> |
| | | <el-select v-model="formData.allocationType"> |
| | | <el-option v-for="item in AllocationTypeSelect" :key="item.id" :value="item.value" :label="item.label"> </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item v-if="formData.allocationType === AllocationTypeEnum.USER" label="åé
人å"> |
| | | <el-input v-model="formData.assignee"> |
| | | <template #append> |
| | | <el-button icon="Search" type="primary" @click="openSingleUserSelect" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <div v-if="formData.allocationType === AllocationTypeEnum.CANDIDATE"> |
| | | <el-form-item label="åé人å"> |
| | | <el-badge :value="selectUserLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openUserSelect">éæ©äººå</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | <el-form-item label="åéç»"> |
| | | <el-badge :value="selectRoleLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openRoleSelect">éæ©ç»</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | </div> |
| | | <el-form-item v-if="formData.allocationType === AllocationTypeEnum.SPECIFY && showConfig.specifyDesc" style=""> |
| | | <el-radio-group v-model="formData.specifyDesc" class="ml-4"> |
| | | <el-radio v-for="item in SpecifyDesc" :key="item.id" :value="item.value" size="large">{{ item.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-tab-pane> --> |
| | | </el-tabs> |
| | | |
| | | <el-form-item v-if="showConfig.dueDate" prop="dueDate" label="å°ææ¶é´"> |
| | | <el-input v-model="formData.dueDate" clearable @change="dueDateChange" @click="openDueDate"> |
| | | <template #append> |
| | | <el-button icon="Search" type="primary" @click="openDueDate" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.priority" prop="priority" label="ä¼å
级"> |
| | | <el-input-number v-model="formData.priority" :min="0" @change="priorityChange"> </el-input-number> |
| | | </el-form-item> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="3"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <HelpFilled /> |
| | | </el-icon> |
| | | å¤å®ä¾ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item label="å¤å®ä¾ç±»å"> |
| | | <el-select v-model="formData.multiInstanceType" @change="multiInstanceTypeChange"> |
| | | <el-option v-for="item in constant.MultiInstanceType" :key="item.id" :value="item.value" :label="item.label"> </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <div v-if="formData.multiInstanceType !== MultiInstanceTypeEnum.NONE"> |
| | | <el-form-item label="éå"> |
| | | <template #label> |
| | | <span> |
| | | éå |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | 屿§ä¼ä½ä¸ºè¡¨è¾¾å¼è¿è¡è§£æãå¦æè¡¨è¾¾å¼è§£æä¸ºå符串è䏿¯ä¸ä¸ªéåï¼<br /> |
| | | ä¸è®ºæ¯å 为æ¬èº«é
ç½®çå°±æ¯éæå符串å¼ï¼è¿æ¯è¡¨è¾¾å¼è®¡ç®ç»æä¸ºå符串ï¼<br /> |
| | | è¿ä¸ªå符串é½ä¼è¢«å½ååéåï¼å¹¶ä»æµç¨åéä¸ç¨äºè·åå®é
çéåã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.collection" @change="collectionChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å
ç´ åé"> |
| | | <template #label> |
| | | <span> |
| | | å
ç´ åé |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | æ¯å建ä¸ä¸ªç¨æ·ä»»å¡åï¼å
以该å
ç´ åé为labelï¼éåä¸çä¸é¡¹ä¸ºvalueï¼<br /> |
| | | å建ï¼å±é¨ï¼æµç¨åéï¼è¯¥å±é¨æµç¨åé被ç¨äºææ´¾ç¨æ·ä»»å¡ã<br /> |
| | | ä¸è¬æ¥è¯´ï¼è¯¥å符串åºä¸æå®äººååéç¸åã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.elementVariable" @change="elementVariableChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="宿æ¡ä»¶"> |
| | | <template #label> |
| | | <span> |
| | | 宿æ¡ä»¶ |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | å¤å®ä¾æ´»å¨å¨ææå®ä¾é½å®ææ¶ç»æï¼ç¶èä¹å¯ä»¥æå®ä¸ä¸ªè¡¨è¾¾å¼ï¼å¨æ¯ä¸ªå®ä¾<br /> |
| | | ç»ææ¶è¿è¡è®¡ç®ãå½è¡¨è¾¾å¼è®¡ç®ä¸ºtrueæ¶ï¼å°éæ¯ææå©ä½çå®ä¾ï¼å¹¶ç»æå¤å®ä¾<br /> |
| | | æ´»å¨ï¼ç»§ç»æ§è¡æµç¨ãä¾å¦ ${nrOfCompletedInstances/nrOfInstances >= 0.6 }ï¼<br /> |
| | | 表示å½ä»»å¡å®æ60%æ¶ï¼è¯¥èç¹å°±ç®å®æ |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.completionCondition" @change="completionConditionChange"> </el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item v-if="showConfig.taskListener" name="4"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | ä»»å¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <TaskListener v-if="showConfig.taskListener" :element="element"></TaskListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item v-if="showConfig.executionListener" name="5"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener v-if="showConfig.executionListener" :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-form-item v-if="showConfig.isForCompensation" prop="isForCompensation" label="æ¯å¦ä¸ºè¡¥å¿"> |
| | | <el-switch v-model="formData.isForCompensation" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.triggerServiceTask" prop="triggerServiceTask" label="æå¡ä»»å¡å¯è§¦å"> |
| | | <el-switch v-model="formData.triggerServiceTask" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.autoStoreVariables" prop="autoStoreVariables" label="èªå¨åå¨åé"> |
| | | <el-switch v-model="formData.autoStoreVariables" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.ruleVariablesInput" prop="skipExpression" label="è¾å
¥åé"> |
| | | <el-input v-model="formData.ruleVariablesInput"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.exclude" prop="exclude" label="æé¤"> |
| | | <el-switch v-model="formData.exclude" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.class" prop="class" label="ç±»"> |
| | | <el-input v-model="formData.class"> </el-input> |
| | | </el-form-item> |
| | | </el-collapse> |
| | | </el-form> |
| | | <UserSelect ref="userSelectRef" :data="formData.candidateUsers" @confirm-call-back="userSelectCallBack"></UserSelect> |
| | | <UserSelect ref="singleUserSelectRef" :data="formData.assignee" :multiple="false" @confirm-call-back="singleUserSelectCallBack"></UserSelect> |
| | | <RoleSelect ref="roleSelectRef" :data="formData.candidateGroups" @confirm-call-back="roleSelectCallBack"></RoleSelect> |
| | | <DueDate ref="dueDateRef" v-model="formData.dueDate" :data="formData.dueDate" @confirm-call-back="dueDateCallBack"></DueDate> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '../hooks/useParseElement'; |
| | | import usePanel from '../hooks/usePanel'; |
| | | import UserSelect from '@/components/UserSelect'; |
| | | import RoleSelect from '@/components/RoleSelect'; |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import TaskListener from './property/TaskListener.vue'; |
| | | import DueDate from './property/DueDate.vue'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import { TaskPanel } from 'bpmnDesign'; |
| | | import { AllocationTypeEnum, MultiInstanceTypeEnum, SpecifyDescEnum } from '@/enums/bpmn/IndexEnums'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { RoleVO } from '@/api/system/role/types'; |
| | | import { selectListFormManage } from '@/api/workflow/formManage'; |
| | | import { FormManageVO } from '@/api/workflow/formManage/types'; |
| | | const formManageList = ref<FormManageVO[]>([]); |
| | | const formManageListLoading = ref(false); |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { showConfig, nameChange, formKeyChange, idChange, updateProperties, getExtensionElements, createModdleElement, constant } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const initFormData = { |
| | | id: '', |
| | | name: '', |
| | | dueDate: '', |
| | | multiInstanceType: MultiInstanceTypeEnum.NONE, |
| | | allocationType: AllocationTypeEnum.USER, |
| | | specifyDesc: SpecifyDescEnum.SPECIFY_SINGLE |
| | | }; |
| | | const formData = ref({ ...initFormData, ...parseData<TaskPanel>() }); |
| | | const assignee = ref<Partial<UserVO>>({ |
| | | userName: '' |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const userSelectRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const singleUserSelectRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const roleSelectRef = ref<InstanceType<typeof RoleSelect>>(); |
| | | const dueDateRef = ref<InstanceType<typeof DueDate>>(); |
| | | |
| | | const isMultiple = ref(true); |
| | | const openUserSelect = () => { |
| | | userSelectRef.value.open(); |
| | | }; |
| | | const openSingleUserSelect = () => { |
| | | if (formData.value.assignee.includes('$')) { |
| | | formData.value.assignee = ''; |
| | | } |
| | | singleUserSelectRef.value.open(); |
| | | }; |
| | | const openRoleSelect = () => { |
| | | roleSelectRef.value.open(); |
| | | }; |
| | | const openDueDate = (e) => { |
| | | dueDateRef.value.openDialog(); |
| | | }; |
| | | const blurAssignee = (assignee) => { |
| | | updateProperties({ 'flowable:assignee': assignee ? assignee : undefined }); |
| | | }; |
| | | const singleUserSelectCallBack = (data: UserVO[]) => { |
| | | const user: UserVO = data.length !== 0 ? data[0] : undefined; |
| | | updateProperties({ 'flowable:assignee': user?.userId }); |
| | | assignee.value = user ? user : { userName: '' }; |
| | | formData.value.assignee = String(user?.userId); |
| | | let extensionElements = getExtensionElements(); |
| | | extensionElements.values = extensionElements.get('values').filter((item) => item.$type !== 'flowable:extAssignee'); |
| | | if (user) { |
| | | const extAssigneeElement = createModdleElement('flowable:extAssignee', { body: '' }, extensionElements); |
| | | extensionElements.get('values').push(extAssigneeElement); |
| | | extAssigneeElement.body = JSON.stringify({ userName: user.userName, userId: user.userId }); |
| | | } |
| | | if (extensionElements.values.length === 0) { |
| | | extensionElements = undefined; |
| | | } |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | }; |
| | | const userSelectCallBack = (data: UserVO[]) => { |
| | | let extensionElements = getExtensionElements(); |
| | | extensionElements.values = extensionElements.values.filter((item) => item.$type !== 'flowable:extCandidateUsers'); |
| | | if (data.length === 0) { |
| | | formData.value.candidateUsers = undefined; |
| | | updateProperties({ 'flowable:candidateUsers': undefined }); |
| | | } else { |
| | | const userIds = data.map((item) => item.userId).join(','); |
| | | formData.value.candidateUsers = userIds; |
| | | updateProperties({ 'flowable:candidateUsers': userIds }); |
| | | const extCandidateUsersElement = createModdleElement('flowable:extCandidateUsers', { body: '' }, extensionElements); |
| | | extensionElements.values.push(extCandidateUsersElement); |
| | | const users = data.map((item) => { |
| | | return { |
| | | userId: item.userId, |
| | | userName: item.userName |
| | | }; |
| | | }); |
| | | extCandidateUsersElement.body = JSON.stringify(users); |
| | | } |
| | | if (extensionElements.values.length === 0) { |
| | | extensionElements = undefined; |
| | | } |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | }; |
| | | const roleSelectCallBack = (data: RoleVO[]) => { |
| | | if (data.length === 0) { |
| | | formData.value.candidateGroups = ''; |
| | | updateProperties({ 'flowable:candidateGroups': undefined }); |
| | | } else { |
| | | const roleIds = data.map((item) => item.roleId).join(','); |
| | | formData.value.candidateGroups = roleIds; |
| | | updateProperties({ 'flowable:candidateGroups': roleIds }); |
| | | } |
| | | }; |
| | | const dueDateCallBack = (data: string) => { |
| | | updateProperties({ 'flowable:dueDate': data }); |
| | | }; |
| | | |
| | | const taskTabClick = (e) => { |
| | | formData.value.candidateGroups = ''; |
| | | formData.value.candidateUsers = ''; |
| | | formData.value.assignee = ''; |
| | | // formData.value.fixedAssignee = ''; |
| | | assignee.value = {}; |
| | | }; |
| | | |
| | | const syncChange = (newVal) => { |
| | | updateProperties({ 'flowable:async': newVal }); |
| | | }; |
| | | const skipExpressionChange = (newVal) => { |
| | | updateProperties({ 'flowable:skipExpression': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const priorityChange = (newVal) => { |
| | | updateProperties({ 'flowable:priority': newVal }); |
| | | }; |
| | | const fixedAssigneeChange = (newVal) => { |
| | | updateProperties({ 'flowable:assignee': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const multiInstanceTypeChange = (newVal) => { |
| | | if (newVal !== MultiInstanceTypeEnum.NONE) { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.isSequential = newVal === MultiInstanceTypeEnum.SERIAL; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | } else { |
| | | updateProperties({ loopCharacteristics: undefined }); |
| | | } |
| | | }; |
| | | const collectionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.collection = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const elementVariableChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.elementVariable = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const completionConditionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get<ModdleElement>('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | if (newVal && newVal.length > 0) { |
| | | if (!loopCharacteristics.completionCondition) { |
| | | loopCharacteristics.completionCondition = createModdleElement('bpmn:Expression', { body: newVal }, loopCharacteristics); |
| | | } else { |
| | | loopCharacteristics.completionCondition.body = newVal; |
| | | } |
| | | } else { |
| | | loopCharacteristics.completionCondition = undefined; |
| | | } |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const dueDateChange = (newVal) => { |
| | | updateProperties({ 'flowable:dueDate': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const selectUserLength = computed(() => { |
| | | if (formData.value.candidateUsers) { |
| | | return formData.value.candidateUsers.split(',').length; |
| | | } else { |
| | | return 0; |
| | | } |
| | | }); |
| | | const selectRoleLength = computed(() => { |
| | | if (formData.value.candidateGroups) { |
| | | return formData.value.candidateGroups.split(',').length; |
| | | } else { |
| | | return 0; |
| | | } |
| | | }); |
| | | |
| | | onBeforeMount(() => { |
| | | const extensionElements = getExtensionElements(false); |
| | | if (extensionElements && extensionElements.get('values')) { |
| | | let extAssigneeElement = extensionElements.get('values').find((item) => item.$type === 'flowable:extAssignee'); |
| | | if (extAssigneeElement) { |
| | | assignee.value = JSON.parse(extAssigneeElement.body); |
| | | } |
| | | } |
| | | |
| | | if (formData.value.loopCharacteristics) { |
| | | const loopCharacteristics = formData.value.loopCharacteristics; |
| | | formData.value.collection = loopCharacteristics.collection || ''; |
| | | formData.value.elementVariable = loopCharacteristics.elementVariable || ''; |
| | | formData.value.completionCondition = loopCharacteristics.completionCondition?.body || ''; |
| | | formData.value.multiInstanceType = loopCharacteristics.isSequential ? MultiInstanceTypeEnum.SERIAL : MultiInstanceTypeEnum.PARALLEL; |
| | | } |
| | | |
| | | if (formData.value.assignee) { |
| | | formData.value.fixedAssignee = formData.value.assignee; |
| | | } |
| | | }); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const AllocationTypeSelect = [ |
| | | { id: 'b9cdf970-dd91-47c0-819f-42a7010ca2a6', label: 'æå®äººå', value: AllocationTypeEnum.USER }, |
| | | { id: '3f7ccbcd-c464-4602-bb9d-e96649d10585', label: 'åé人å', value: AllocationTypeEnum.CANDIDATE }, |
| | | { id: 'c49065e0-7f2d-4c09-aedb-ab2d47d9a454', label: 'å起人èªå·±', value: AllocationTypeEnum.YOURSELF }, |
| | | { id: '6ef40a03-7e9a-4898-89b2-c88fe9064542', label: 'å起人æå®', value: AllocationTypeEnum.SPECIFY } |
| | | ]; |
| | | const SpecifyDesc = [ |
| | | { id: 'fa253b34-4335-458c-b1bc-b039e2a2b7a6', label: 'æå®ä¸ä¸ªäºº', value: 'specifySingle' }, |
| | | { id: '7365ff54-2e05-4312-9bfb-0b8edd779c5b', label: 'æå®å¤ä¸ªäºº', value: 'specifyMultiple' } |
| | | ]; |
| | | |
| | | const listFormManage = async () => { |
| | | formManageListLoading.value = true; |
| | | const res = await selectListFormManage(); |
| | | formManageList.value = res.data; |
| | | formManageListLoading.value = false; |
| | | }; |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | listFormManage(); |
| | | }); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div ref="propertyPanel"> |
| | | <div v-if="nodeName" class="node-name">{{ nodeName }}</div> |
| | | <component :is="component" v-if="element" :element="element" /> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts" name="PropertyPanel"> |
| | | import { NodeName } from '../assets/lang/zh'; |
| | | import TaskPanel from './TaskPanel.vue'; |
| | | import ProcessPanel from './ProcessPanel.vue'; |
| | | import StartEndPanel from './StartEndPanel.vue'; |
| | | import GatewayPanel from './GatewayPanel.vue'; |
| | | import SequenceFlowPanel from './SequenceFlowPanel.vue'; |
| | | import ParticipantPanel from './ParticipantPanel.vue'; |
| | | import SubProcessPanel from './SubProcessPanel.vue'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | interface propsType { |
| | | modeler: Modeler; |
| | | } |
| | | const props = withDefaults(defineProps<propsType>(), {}); |
| | | |
| | | const element = ref<ModdleElement>(); |
| | | const processElement = ref<ModdleElement>(); |
| | | |
| | | const startEndType = ['bpmn:IntermediateThrowEvent', 'bpmn:StartEvent', 'bpmn:EndEvent']; |
| | | const taskType = [ |
| | | 'bpmn:UserTask', |
| | | 'bpmn:Task', |
| | | 'bpmn:SendTask', |
| | | 'bpmn:ReceiveTask', |
| | | 'bpmn:ManualTask', |
| | | 'bpmn:BusinessRuleTask', |
| | | 'bpmn:ServiceTask', |
| | | 'bpmn:ScriptTask' |
| | | ]; |
| | | const sequenceType = ['bpmn:SequenceFlow']; |
| | | const gatewayType = ['bpmn:InclusiveGateway', 'bpmn:ExclusiveGateway', 'bpmn:ParallelGateway', 'bpmn:EventBasedGateway', 'bpmn:ComplexGateway']; |
| | | const processType = ['bpmn:Process']; |
| | | |
| | | // ç»ä»¶è®¡ç® |
| | | const component = computed(() => { |
| | | if (!element.value) return null; |
| | | const type = element.value.type; |
| | | if (startEndType.includes(type)) return StartEndPanel; |
| | | if (taskType.includes(type)) return TaskPanel; |
| | | if (sequenceType.includes(type)) return SequenceFlowPanel; |
| | | if (gatewayType.includes(type)) return GatewayPanel; |
| | | if (processType.includes(type)) return ProcessPanel; |
| | | if (type === 'bpmn:Participant') return ParticipantPanel; |
| | | if (type === 'bpmn:SubProcess') return SubProcessPanel; |
| | | //return proxy?.$modal.msgWarning('颿¿å¼åä¸....'); |
| | | return undefined; |
| | | }); |
| | | |
| | | const nodeName = computed(() => { |
| | | if (element.value) { |
| | | const bizObj = element.value.businessObject; |
| | | const type = bizObj?.eventDefinitions && bizObj?.eventDefinitions.length > 0 ? bizObj.eventDefinitions[0].$type : bizObj.$type; |
| | | return NodeName[type] || type; |
| | | } |
| | | return ''; |
| | | }); |
| | | |
| | | const handleModeler = () => { |
| | | props.modeler.on('root.added', (e: any) => { |
| | | element.value = null; |
| | | if (e.element.type === 'bpmn:Process') { |
| | | nextTick(() => { |
| | | element.value = e.element; |
| | | processElement.value = e.element; |
| | | }); |
| | | } |
| | | }); |
| | | props.modeler.on('element.click', (e: any) => { |
| | | if (e.element.type === 'bpmn:Process') { |
| | | nextTick(() => { |
| | | element.value = e.element; |
| | | processElement.value = e.element; |
| | | }); |
| | | } |
| | | }); |
| | | props.modeler.on('selection.changed', (e: any) => { |
| | | // å
ç»null为äºè®©vueå·æ° |
| | | element.value = null; |
| | | const newElement = e.newSelection[0]; |
| | | if (newElement) { |
| | | nextTick(() => { |
| | | element.value = newElement; |
| | | }); |
| | | } else { |
| | | nextTick(() => { |
| | | element.value = processElement.value; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | handleModeler(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .node-name { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | padding: 10px; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog v-model="visible" :title="title" width="600px" append-to-body> |
| | | <el-form label-width="100px"> |
| | | <el-form-item label="å°æ¶"> |
| | | <el-radio-group v-model="hourValue" @change="hourChange"> |
| | | <el-radio-button label="4" value="4" /> |
| | | <el-radio-button label="8" value="8" /> |
| | | <el-radio-button label="12" value="12" /> |
| | | <el-radio-button label="24" value="24" /> |
| | | <el-radio-button label="èªå®ä¹" value="èªå®ä¹" /> |
| | | <el-input-number v-show="hourValue === 'èªå®ä¹'" v-model="customHourValue" :min="1" @change="customHourValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="天"> |
| | | <el-radio-group v-model="dayValue" @change="dayChange"> |
| | | <el-radio-button label="1" value="1" /> |
| | | <el-radio-button label="2" value="2" /> |
| | | <el-radio-button label="3" value="3" /> |
| | | <el-radio-button label="4" value="4" /> |
| | | <el-radio-button label="èªå®ä¹" value="èªå®ä¹" /> |
| | | <el-input-number v-show="dayValue === 'èªå®ä¹'" v-model="customDayValue" :min="1" @change="customDayValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="å¨"> |
| | | <el-radio-group v-model="weekValue" @change="weekChange"> |
| | | <el-radio-button label="1" value="1" /> |
| | | <el-radio-button label="2" value="2" /> |
| | | <el-radio-button label="3" value="3" /> |
| | | <el-radio-button label="4" value="4" /> |
| | | <el-radio-button label="èªå®ä¹" value="èªå®ä¹" /> |
| | | <el-input-number v-show="weekValue === 'èªå®ä¹'" v-model="customWeekValue" :min="1" @change="customWeekValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="æ"> |
| | | <el-radio-group v-model="monthValue" @change="monthChange"> |
| | | <el-radio-button label="1" value="1" /> |
| | | <el-radio-button label="2" value="2" /> |
| | | <el-radio-button label="3" value="3" /> |
| | | <el-radio-button label="4" value="4" /> |
| | | <el-radio-button label="èªå®ä¹" value="èªå®ä¹" /> |
| | | <el-input-number v-show="monthValue === 'èªå®ä¹'" v-model="customMonthValue" :min="1" @change="customMonthValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <div> |
| | | <el-button @click="closeDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirm">ç¡®å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | interface PropType { |
| | | modelValue?: string; |
| | | data?: string; |
| | | } |
| | | const prop = withDefaults(defineProps<PropType>(), { |
| | | modelValue: '', |
| | | data: '' |
| | | }); |
| | | const emit = defineEmits(['update:modelValue', 'confirmCallBack']); |
| | | |
| | | const { title, visible, openDialog, closeDialog } = useDialog({ |
| | | title: '设置任å¡å°ææ¶é´' |
| | | }); |
| | | const formValue = ref(); |
| | | const valueType = ref(); |
| | | |
| | | const hourValue = ref(''); |
| | | const dayValue = ref(''); |
| | | const weekValue = ref(''); |
| | | const monthValue = ref(''); |
| | | |
| | | const customHourValue = ref(1); |
| | | const customDayValue = ref(1); |
| | | const customWeekValue = ref(1); |
| | | const customMonthValue = ref(1); |
| | | |
| | | const hourValueConst = ['4', '8', '12', '24']; |
| | | const dayAndWeekAndMonthValueConst = ['1', '2', '3', '4']; |
| | | |
| | | const initValue = () => { |
| | | formValue.value = prop.data; |
| | | if (prop.data) { |
| | | const lastStr = prop.data.substring(prop.data.length - 1); |
| | | if (lastStr === 'H') { |
| | | const hourValueValue = prop.data.substring(2, prop.data.length - 1); |
| | | if (hourValueConst.includes(hourValueValue)) { |
| | | hourValue.value = hourValueValue; |
| | | } else { |
| | | hourValue.value = 'èªå®ä¹'; |
| | | customHourValue.value = Number(hourValueValue); |
| | | } |
| | | } |
| | | const dayAndWeekAndMonthValue = prop.data.substring(1, prop.data.length - 1); |
| | | if (lastStr === 'D') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | dayValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | dayValue.value = 'èªå®ä¹'; |
| | | customDayValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | if (lastStr === 'W') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | weekValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | weekValue.value = 'èªå®ä¹'; |
| | | customWeekValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | if (lastStr === 'M') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | monthValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | monthValue.value = 'èªå®ä¹'; |
| | | customMonthValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const confirm = () => { |
| | | emit('update:modelValue', formValue.value); |
| | | emit('confirmCallBack', formValue.value); |
| | | closeDialog(); |
| | | }; |
| | | |
| | | const customHourValueChange = (customHourValue) => { |
| | | formValue.value = `PT${customHourValue}H`; |
| | | |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const customDayValueChange = (customDayValue) => { |
| | | formValue.value = `P${customDayValue}D`; |
| | | hourValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | |
| | | const customWeekValueChange = (customWeekValue) => { |
| | | formValue.value = `P${customWeekValue}W`; |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | |
| | | const customMonthValueChange = (customMonthValue) => { |
| | | formValue.value = `P${customMonthValue}M`; |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | }; |
| | | |
| | | const hourChange = (hourValue) => { |
| | | if (hourValue === 'èªå®ä¹') { |
| | | formValue.value = `PT${customHourValue.value}H`; |
| | | } else { |
| | | formValue.value = `PT${hourValue}H`; |
| | | } |
| | | |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const dayChange = (dayValue) => { |
| | | if (dayValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customDayValue.value}D`; |
| | | } else { |
| | | formValue.value = `P${dayValue}D`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const weekChange = (weekValue) => { |
| | | if (weekValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customWeekValue.value}W`; |
| | | } else { |
| | | formValue.value = `P${weekValue}W`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const monthChange = (monthValue) => { |
| | | if (monthValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customMonthValue.value}M`; |
| | | } else { |
| | | formValue.value = `P${monthValue}M`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | }; |
| | | |
| | | watch( |
| | | () => visible.value, |
| | | () => { |
| | | if (visible.value) { |
| | | initValue(); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | closeDialog |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button type="primary" link size="small" @click="insertEvent">æ°å¢</el-button> |
| | | <el-button type="primary" link size="small" @click="removeSelectRowEvent">å é¤</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | size="mini" |
| | | height="100px" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :menu-config="menuConfig" |
| | | @cell-dblclick="cellDBLClickEvent" |
| | | @menu-click="contextMenuClickEvent" |
| | | > |
| | | <vxe-column type="checkbox" width="40"></vxe-column> |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="event" title="äºä»¶" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ eventSelect.find((e) => e.value === slotParams.row.event)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="type" title="ç±»å" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="className" title="Java ç±»å" min-width="100px"> </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <el-dialog |
| | | v-model="formDialog.visible.value" |
| | | :title="formDialog.title.value" |
| | | width="600px" |
| | | :close-on-click-modal="false" |
| | | :close-on-press-escape="false" |
| | | :show-close="false" |
| | | append-to-body |
| | | > |
| | | <el-form ref="formRef" :model="formData" :rules="tableRules" label-width="100px"> |
| | | <el-form-item label="äºä»¶" prop="event"> |
| | | <el-select v-model="formData.event"> |
| | | <el-option v-for="item in eventSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="type"> |
| | | <template #label> |
| | | <span> |
| | | ç±»å |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | ç±»ï¼ç¤ºä¾ com.company.MyCustomListenerï¼èªå®ä¹ç±»å¿
é¡»å®ç° org.flowable.engine.delegate.TaskListener æ¥å£<br /> |
| | | 表达å¼ï¼ç¤ºä¾ ${myObject.callMethod(task, task.eventName)}<br /> |
| | | å§æè¡¨è¾¾å¼ï¼ç¤ºä¾ ${myListenerSpringBean} ï¼è¯¥ springBean éè¦å®ç° org.flowable.engine.delegate.TaskListener æ¥å£ |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-select v-model="formData.type"> |
| | | <el-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item |
| | | :label="typeSelect.filter((e) => e.value === formData.type)[0] ? typeSelect.filter((e) => e.value === formData.type)[0]?.label : '表达å¼'" |
| | | prop="className" |
| | | > |
| | | <el-input v-model="formData.className" type="text"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="åæ°"> |
| | | <ListenerParam ref="listenerParamRef" :table-data="formData.params" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="formDialog.closeDialog">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitEvent">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ListenerParam from './ListenerParam.vue'; |
| | | import { VxeTableEvents, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { ExecutionListenerVO } from 'bpmnDesign'; |
| | | import { Moddle, Modeler, ModdleElement } from 'bpmn'; |
| | | |
| | | import usePanel from '../../hooks/usePanel'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | |
| | | const emit = defineEmits(['close']); |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const selectRow = ref<ExecutionListenerVO | null>(); |
| | | const formDialog = useDialog({ |
| | | title: selectRow.value ? 'ç¼è¾&ä¿å' : 'æ°å¢&ä¿å' |
| | | }); |
| | | |
| | | const { showConfig, elementType, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { getModdle } = useModelerStore(); |
| | | const moddle = getModdle(); |
| | | |
| | | const listenerParamRef = ref<InstanceType<typeof ListenerParam>>(); |
| | | const tableRef = ref<VxeTableInstance<ExecutionListenerVO>>(); |
| | | const formRef = ref<ElFormInstance>(); |
| | | |
| | | const initData: ExecutionListenerVO = { |
| | | event: '', |
| | | type: '', |
| | | className: '', |
| | | params: [] |
| | | }; |
| | | const formData = ref<ExecutionListenerVO>({ ...initData }); |
| | | const tableData = ref<ExecutionListenerVO[]>([]); |
| | | const tableRules = ref<ElFormRules>({ |
| | | event: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | className: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const submitEvent = async () => { |
| | | const error = await listenerParamRef.value.validate(); |
| | | await formRef.value.validate((validate) => { |
| | | if (validate && !error) { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | formData.value.params = listenerParamRef.value.getTableData(); |
| | | if (selectRow.value) { |
| | | Object.assign(selectRow.value, formData.value); |
| | | } else { |
| | | $table.insertAt({ ...formData.value }, -1); |
| | | } |
| | | updateElement(); |
| | | formDialog.closeDialog(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const removeSelectRowEvent = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const selectCount = $table.getCheckboxRecords().length; |
| | | if (selectCount === 0) { |
| | | proxy?.$modal.msgWarning('è¯·éæ©è¡'); |
| | | } else { |
| | | await $table.removeCheckboxRow(); |
| | | updateElement(); |
| | | } |
| | | } |
| | | }; |
| | | const insertEvent = async () => { |
| | | Object.assign(formData.value, initData); |
| | | selectRow.value = null; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const editEvent = (row: ExecutionListenerVO) => { |
| | | Object.assign(formData.value, row); |
| | | selectRow.value = row; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const removeEvent = async (row: ExecutionListenerVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | updateElement(); |
| | | } |
| | | }; |
| | | const updateElement = () => { |
| | | const $table = tableRef.value; |
| | | const data = $table.getTableData().fullData; |
| | | if (data.length) { |
| | | let extensionElements = props.element.businessObject.get('extensionElements'); |
| | | if (!extensionElements) { |
| | | extensionElements = moddle.create('bpmn:ExtensionElements'); |
| | | } |
| | | // æ¸
餿§å¼ |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; |
| | | data.forEach((item) => { |
| | | const executionListener = moddle.create('flowable:ExecutionListener'); |
| | | executionListener['event'] = item.event; |
| | | executionListener[item.type] = item.className; |
| | | if (item.params && item.params.length) { |
| | | item.params.forEach((field) => { |
| | | const fieldElement = moddle.create('flowable:Field'); |
| | | fieldElement['name'] = field.name; |
| | | fieldElement[field.type] = field.value; |
| | | executionListener.get('fields').push(fieldElement); |
| | | }); |
| | | } |
| | | extensionElements.get('values').push(executionListener); |
| | | }); |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | } else { |
| | | const extensionElements = props.element.businessObject[`extensionElements`]; |
| | | if (extensionElements) { |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const cellDBLClickEvent: VxeTableEvents.CellDblclick<ExecutionListenerVO> = ({ row }) => { |
| | | editEvent(row); |
| | | }; |
| | | |
| | | const menuConfig = reactive<VxeTablePropTypes.MenuConfig<ExecutionListenerVO>>({ |
| | | body: { |
| | | options: [ |
| | | [ |
| | | { code: 'edit', name: 'ç¼è¾', prefixIcon: 'vxe-icon-edit', disabled: false }, |
| | | { code: 'remove', name: 'å é¤', prefixIcon: 'vxe-icon-delete', disabled: false } |
| | | ] |
| | | ] |
| | | }, |
| | | visibleMethod({ options, column }) { |
| | | const isDisabled = !column; |
| | | options.forEach((list) => { |
| | | list.forEach((item) => { |
| | | item.disabled = isDisabled; |
| | | }); |
| | | }); |
| | | return true; |
| | | } |
| | | }); |
| | | const contextMenuClickEvent: VxeTableEvents.MenuClick<ExecutionListenerVO> = ({ menu, row, column }) => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | switch (menu.code) { |
| | | case 'edit': |
| | | editEvent(row); |
| | | break; |
| | | case 'remove': |
| | | removeEvent(row); |
| | | break; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const initTableData = () => { |
| | | tableData.value = |
| | | props.element.businessObject.extensionElements?.values |
| | | .filter((item) => item.$type === 'flowable:ExecutionListener') |
| | | .map((item) => { |
| | | let type; |
| | | if ('class' in item) type = 'class'; |
| | | if ('expression' in item) type = 'expression'; |
| | | if ('delegateExpression' in item) type = 'delegateExpression'; |
| | | return { |
| | | event: item.event, |
| | | type: type, |
| | | className: item[type], |
| | | params: |
| | | item.fields?.map((field) => { |
| | | let fieldType; |
| | | if ('stringValue' in field) fieldType = 'stringValue'; |
| | | if ('expression' in field) fieldType = 'expression'; |
| | | return { |
| | | name: field.name, |
| | | type: fieldType, |
| | | value: field[fieldType] |
| | | }; |
| | | }) ?? [] |
| | | }; |
| | | }) ?? []; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initTableData(); |
| | | }); |
| | | |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'ç±»', value: 'class' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' }, |
| | | { id: '4b8135ab-6bc3-4a0f-80be-22f58bc6c5fd', label: 'å§æè¡¨è¾¾å¼', value: 'delegateExpression' } |
| | | ]; |
| | | const eventSelect = [ |
| | | { id: 'e6e0a51a-2d5d-4dc4-b847-b5c14f43a6ab', label: 'å¼å§', value: 'start' }, |
| | | { id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: 'ç»æ', value: 'end' }, |
| | | { id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: 'å¯ç¨', value: 'take' } |
| | | ]; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .el-badge { |
| | | :deep(.el-badge__content) { |
| | | top: 10px; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button icon="Plus" @click="insertRow">æ°å¢</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | :height="height" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :edit-rules="tableRules" |
| | | :edit-config="{ trigger: 'click', mode: 'row', showStatus: true }" |
| | | > |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="type" title="ç±»å" :edit-render="{}"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | <template #edit="slotParams"> |
| | | <vxe-select v-model="slotParams.row.type"> |
| | | <vxe-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></vxe-option> |
| | | </vxe-select> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="name" title="åç§°" :edit-render="{}"> |
| | | <template #edit="slotParams"> |
| | | <vxe-input v-model="slotParams.row.name" type="text"></vxe-input> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="value" title="å¼" :edit-render="{}"> |
| | | <template #edit="slotParams"> |
| | | <vxe-input v-model="slotParams.row.value" type="text"></vxe-input> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column title="æä½" width="100" show-overflow align="center"> |
| | | <template #default="slotParams"> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="danger" icon="Delete" @click="removeRow(slotParams.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </vxe-column> |
| | | </vxe-table> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { VXETable, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { ParamVO } from 'bpmnDesign'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | interface PropType { |
| | | height?: string; |
| | | tableData?: ParamVO[]; |
| | | } |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = withDefaults(defineProps<PropType>(), { |
| | | height: '200px', |
| | | tableData: () => [] |
| | | }); |
| | | |
| | | const tableRules = ref<VxeTablePropTypes.EditRules>({ |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | value: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const { title, visible, openDialog, closeDialog } = useDialog({ |
| | | title: 'çå¬å¨åæ°' |
| | | }); |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'å符串', value: 'stringValue' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' } |
| | | ]; |
| | | |
| | | const tableRef = ref<VxeTableInstance<ParamVO>>(); |
| | | |
| | | const getTableData = () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | return $table.getTableData().fullData; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const insertRow = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const { row: newRow } = await $table.insertAt({}, -1); |
| | | // æå
¥ä¸æ¡æ°æ®å¹¶è§¦åæ ¡éª |
| | | await $table.validate(newRow); |
| | | } |
| | | }; |
| | | |
| | | const removeRow = async (row: ParamVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | } |
| | | }; |
| | | |
| | | const validate = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | return await $table.validate(true); |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | closeDialog, |
| | | openDialog, |
| | | validate, |
| | | getTableData |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button type="primary" link size="small" @click="insertEvent">æ°å¢</el-button> |
| | | <el-button type="primary" link size="small" @click="removeSelectRowEvent">å é¤</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | size="mini" |
| | | height="100px" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :menu-config="menuConfig" |
| | | @cell-dblclick="cellDBLClickEvent" |
| | | @menu-click="contextMenuClickEvent" |
| | | > |
| | | <vxe-column type="checkbox" width="40"></vxe-column> |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="event" title="äºä»¶" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ eventSelect.find((e) => e.value === slotParams.row.event)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="type" title="ç±»å" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="className" title="Java ç±»å" min-width="100px"> </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <el-dialog |
| | | v-model="formDialog.visible.value" |
| | | :title="formDialog.title.value" |
| | | width="600px" |
| | | :close-on-click-modal="false" |
| | | :close-on-press-escape="false" |
| | | :show-close="false" |
| | | append-to-body |
| | | > |
| | | <el-form ref="formRef" :model="formData" :rules="tableRules" label-width="100px"> |
| | | <el-form-item label="äºä»¶" prop="event"> |
| | | <template #label> |
| | | <span> |
| | | äºä»¶ |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | createï¼å建ï¼ï¼å½ä»»å¡å·²ç»å建ï¼å¹¶ä¸ææä»»å¡åæ°é½å·²ç»è®¾ç½®æ¶è§¦åã<br /> |
| | | assignmentï¼ææ´¾ï¼ï¼å½ä»»å¡å·²ç»ææ´¾ç»æäººæ¶è§¦åã请注æï¼å½æµç¨æ§è¡å°è¾¾ç¨æ·ä»»å¡æ¶ï¼å¨è§¦åcreateäºä»¶ä¹åï¼ä¼é¦å
触åassignmentäºä»¶ã<br /> |
| | | completeï¼å®æï¼ï¼å½ä»»å¡å·²ç»å®æï¼ä»è¿è¡æ¶æ°æ®ä¸å é¤å触åã<br /> |
| | | deleteï¼å é¤ï¼ï¼å¨ä»»å¡å³å°è¢«å é¤å触åã请注æä»»å¡ç±completeTaskæ£å¸¸å®ææ¶ä¹ä¼è§¦åã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-select v-model="formData.event"> |
| | | <el-option v-for="item in eventSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="type"> |
| | | <el-select v-model="formData.type"> |
| | | <el-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item |
| | | :label="typeSelect.filter((e) => e.value === formData.type)[0] ? typeSelect.filter((e) => e.value === formData.type)[0]?.label : '表达å¼'" |
| | | prop="className" |
| | | > |
| | | <el-input v-model="formData.className" type="text"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="åæ°"> |
| | | <ListenerParam ref="listenerParamRef" :table-data="formData.params" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="formDialog.closeDialog">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitEvent">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ListenerParam from './ListenerParam.vue'; |
| | | import { VxeTableEvents, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { TaskListenerVO } from 'bpmnDesign'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | |
| | | import usePanel from '../../hooks/usePanel'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const selectRow = ref<TaskListenerVO | null>(); |
| | | const formDialog = useDialog({ |
| | | title: selectRow.value ? 'ç¼è¾&ä¿å' : 'æ°å¢&ä¿å' |
| | | }); |
| | | const { showConfig, elementType, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { getModdle } = useModelerStore(); |
| | | const moddle = getModdle(); |
| | | |
| | | const listenerParamRef = ref<InstanceType<typeof ListenerParam>>(); |
| | | const tableRef = ref<VxeTableInstance<TaskListenerVO>>(); |
| | | const formRef = ref<ElFormInstance>(); |
| | | |
| | | const initData: TaskListenerVO = { |
| | | event: '', |
| | | type: '', |
| | | className: '', |
| | | name: '', |
| | | params: [] |
| | | }; |
| | | const formData = ref<TaskListenerVO>({ ...initData }); |
| | | const currentIndex = ref(0); |
| | | const tableData = ref<TaskListenerVO[]>([]); |
| | | const tableRules = ref<VxeTablePropTypes.EditRules>({ |
| | | event: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | className: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const submitEvent = async () => { |
| | | const error = await listenerParamRef.value.validate(); |
| | | await formRef.value.validate((validate) => { |
| | | if (validate && !error) { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | formData.value.params = listenerParamRef.value.getTableData(); |
| | | if (selectRow.value) { |
| | | Object.assign(selectRow.value, formData.value); |
| | | } else { |
| | | $table.insertAt({ ...formData.value }, -1); |
| | | } |
| | | updateElement(); |
| | | formDialog.closeDialog(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const insertEvent = async () => { |
| | | Object.assign(formData.value, initData); |
| | | selectRow.value = null; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const editEvent = (row: TaskListenerVO) => { |
| | | Object.assign(formData.value, row); |
| | | selectRow.value = row; |
| | | formDialog.openDialog(); |
| | | }; |
| | | const removeEvent = async (row: TaskListenerVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | updateElement(); |
| | | } |
| | | }; |
| | | |
| | | const removeSelectRowEvent = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const selectCount = $table.getCheckboxRecords().length; |
| | | if (selectCount === 0) { |
| | | proxy?.$modal.msgWarning('è¯·éæ©è¡'); |
| | | } else { |
| | | await $table.removeCheckboxRow(); |
| | | updateElement(); |
| | | } |
| | | } |
| | | }; |
| | | const updateElement = () => { |
| | | const $table = tableRef.value; |
| | | const data = $table.getTableData().fullData; |
| | | if (data.length) { |
| | | let extensionElements = props.element.businessObject.get('extensionElements'); |
| | | if (!extensionElements) { |
| | | extensionElements = moddle.create('bpmn:ExtensionElements'); |
| | | } |
| | | // æ¸
餿§å¼ |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:TaskListener') ?? []; |
| | | data.forEach((item) => { |
| | | const taskListener = moddle.create('flowable:TaskListener'); |
| | | taskListener['event'] = item.event; |
| | | taskListener[item.type] = item.className; |
| | | if (item.params && item.params.length) { |
| | | item.params.forEach((field) => { |
| | | const fieldElement = moddle.create('flowable:Field'); |
| | | fieldElement['name'] = field.name; |
| | | fieldElement[field.type] = field.value; |
| | | taskListener.get('fields').push(fieldElement); |
| | | }); |
| | | } |
| | | extensionElements.get('values').push(taskListener); |
| | | }); |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | } else { |
| | | const extensionElements = props.element.businessObject[`extensionElements`]; |
| | | if (extensionElements) { |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:TaskListener') ?? []; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const cellDBLClickEvent: VxeTableEvents.CellDblclick<TaskListenerVO> = ({ row }) => { |
| | | editEvent(row); |
| | | }; |
| | | |
| | | const menuConfig = reactive<VxeTablePropTypes.MenuConfig<TaskListenerVO>>({ |
| | | body: { |
| | | options: [ |
| | | [ |
| | | { code: 'edit', name: 'ç¼è¾', prefixIcon: 'vxe-icon-edit', disabled: false }, |
| | | { code: 'remove', name: 'å é¤', prefixIcon: 'vxe-icon-delete', disabled: false } |
| | | ] |
| | | ] |
| | | }, |
| | | visibleMethod({ options, column }) { |
| | | const isDisabled = !column; |
| | | options.forEach((list) => { |
| | | list.forEach((item) => { |
| | | item.disabled = isDisabled; |
| | | }); |
| | | }); |
| | | return true; |
| | | } |
| | | }); |
| | | const contextMenuClickEvent: VxeTableEvents.MenuClick<TaskListenerVO> = ({ menu, row, column }) => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | switch (menu.code) { |
| | | case 'edit': |
| | | editEvent(row); |
| | | break; |
| | | case 'remove': |
| | | removeEvent(row); |
| | | break; |
| | | } |
| | | } |
| | | }; |
| | | const initTableData = () => { |
| | | tableData.value = |
| | | props.element.businessObject.extensionElements?.values |
| | | .filter((item) => item.$type === 'flowable:TaskListener') |
| | | .map((item) => { |
| | | let type; |
| | | if ('class' in item) type = 'class'; |
| | | if ('expression' in item) type = 'expression'; |
| | | if ('delegateExpression' in item) type = 'delegateExpression'; |
| | | return { |
| | | event: item.event, |
| | | type: type, |
| | | className: item[type], |
| | | params: |
| | | item.fields?.map((field) => { |
| | | let fieldType; |
| | | if ('stringValue' in field) fieldType = 'stringValue'; |
| | | if ('expression' in field) fieldType = 'expression'; |
| | | return { |
| | | name: field.name, |
| | | type: fieldType, |
| | | value: field[fieldType] |
| | | }; |
| | | }) ?? [] |
| | | }; |
| | | }) ?? []; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initTableData(); |
| | | }); |
| | | |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'ç±»', value: 'class' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' }, |
| | | { id: '4b8135ab-6bc3-4a0f-80be-22f58bc6c5fd', label: 'å§æè¡¨è¾¾å¼', value: 'delegateExpression' } |
| | | ]; |
| | | const eventSelect = [ |
| | | { id: 'e6e0a51a-2d5d-4dc4-b847-b5c14f43a6ab', label: 'å建', value: 'create' }, |
| | | { id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: 'ææ´¾', value: 'assignment' }, |
| | | { id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: '宿', value: 'complete' }, |
| | | { id: '68801972-85f1-482f-bd86-1fad015c26ed', label: 'å é¤', value: 'delete' } |
| | | ]; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .el-badge { |
| | | :deep(.el-badge__content) { |
| | | top: 10px; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="design"> |
| | | <el-dialog v-model="visible" width="100%" fullscreen :title="title"> |
| | | <div class="modeler"> |
| | | <bpmn-design ref="bpmnDesignRef" @save-call-back="saveCallBack"></bpmn-design> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="Design"> |
| | | import { getInfo, editModelXml } from '@/api/workflow/model'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | import { ModelForm } from '@/api/workflow/model/types'; |
| | | import BpmnDesign from '@/bpmn/index.vue'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | const bpmnDesignRef = ref<InstanceType<typeof BpmnDesign>>(); |
| | | const modelForm = ref<ModelForm>(); |
| | | const emit = defineEmits(['closeCallBack']); |
| | | const { visible, title } = useDialog({ |
| | | title: 'ç¼è¾æµç¨' |
| | | }); |
| | | const modelId = ref(''); |
| | | const open = async (id) => { |
| | | visible.value = true; |
| | | modelId.value = id; |
| | | const { data } = await getInfo(id); |
| | | modelForm.value = data; |
| | | bpmnDesignRef.value.initDiagram(modelForm.value.xml); |
| | | }; |
| | | //ä¿å模å |
| | | const saveCallBack = async (data) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤ä¿åï¼'); |
| | | data.loading.value = true; |
| | | modelForm.value.id = modelId.value; |
| | | modelForm.value.xml = data.xml; |
| | | modelForm.value.svg = data.svg; |
| | | modelForm.value.key = data.key; |
| | | modelForm.value.name = data.name; |
| | | editModelXml(modelForm.value).then((res) => { |
| | | if (res.code === 200) { |
| | | visible.value = false; |
| | | proxy?.$modal.msgSuccess('ä¿åæå'); |
| | | emit('closeCallBack', data); |
| | | } |
| | | }); |
| | | data.loading.value = false; |
| | | }; |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | open |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .design { |
| | | :deep(.el-dialog .el-dialog__body) { |
| | | max-height: 100% !important; |
| | | min-height: calc(100vh - 80px); |
| | | padding: 10px 0 10px 0 !important; |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | padding: 0 0 5px 0 !important; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div v-loading="loading" class="bpmnDialogContainers"> |
| | | <el-header style="border-bottom: 1px solid rgb(218 218 218); height: auto"> |
| | | <div class="header-div"> |
| | | <div> |
| | | <el-tooltip effect="dark" content="èªéåºå±å¹" placement="bottom"> |
| | | <el-button size="small" icon="Rank" @click="fitViewport" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="æ¾å¤§" placement="bottom"> |
| | | <el-button size="small" icon="ZoomIn" @click="zoomViewport(true)" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="缩å°" placement="bottom"> |
| | | <el-button size="small" icon="ZoomOut" @click="zoomViewport(false)" /> |
| | | </el-tooltip> |
| | | </div> |
| | | <div> |
| | | <div class="tips-label"> |
| | | <div class="un-complete">æªå®æ</div> |
| | | <div class="in-progress">è¿è¡ä¸</div> |
| | | <div class="complete">已宿</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-header> |
| | | <div class="flow-containers"> |
| | | <el-container class="bpmn-el-container" style="align-items: stretch"> |
| | | <el-main style="padding: 0"> |
| | | <div ref="canvas" class="canvas" /> |
| | | </el-main> |
| | | </el-container> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import BpmnViewer from 'bpmn-js/lib/Viewer'; |
| | | import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; |
| | | import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; |
| | | import { ModuleDeclaration } from 'didi'; |
| | | import { Canvas, ModdleElement } from 'bpmn'; |
| | | import EventBus from 'diagram-js/lib/core/EventBus'; |
| | | import Overlays from 'diagram-js/lib/features/overlays/Overlays'; |
| | | import processApi from '@/api/workflow/processInstance/index'; |
| | | |
| | | const canvas = ref<HTMLElement>(); |
| | | const modeler = ref<BpmnViewer>(); |
| | | const taskList = ref([]); |
| | | const zoom = ref(1); |
| | | const xml = ref(''); |
| | | const loading = ref(false); |
| | | const bpmnVisible = ref(true); |
| | | const historyList = ref([]); |
| | | |
| | | const init = (instanceId) => { |
| | | loading.value = true; |
| | | bpmnVisible.value = true; |
| | | nextTick(async () => { |
| | | if (modeler.value) modeler.value.destroy(); |
| | | modeler.value = new BpmnViewer({ |
| | | container: canvas.value, |
| | | additionalModules: [ |
| | | { |
| | | //ç¦æ¢æ»è½®æ»å¨ |
| | | zoomScroll: ['value', ''] |
| | | }, |
| | | ZoomScrollModule, |
| | | MoveCanvasModule |
| | | ] as ModuleDeclaration[] |
| | | }); |
| | | const resp = await processApi.getHistoryList(instanceId); |
| | | xml.value = resp.data.xml; |
| | | taskList.value = resp.data.taskList; |
| | | historyList.value = resp.data.historyList; |
| | | await createDiagram(xml.value); |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const initXml = (xmlStr: string) => { |
| | | loading.value = true; |
| | | bpmnVisible.value = true; |
| | | nextTick(async () => { |
| | | if (modeler.value) modeler.value.destroy(); |
| | | modeler.value = new BpmnViewer({ |
| | | container: canvas.value, |
| | | additionalModules: [ |
| | | { |
| | | //ç¦æ¢æ»è½®æ»å¨ |
| | | zoomScroll: ['value', ''] |
| | | }, |
| | | ZoomScrollModule, |
| | | MoveCanvasModule |
| | | ] as ModuleDeclaration[] |
| | | }); |
| | | xml.value = xmlStr; |
| | | await createDiagram(xml.value); |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const createDiagram = async (data) => { |
| | | try { |
| | | await modeler.value.importXML(data); |
| | | fitViewport(); |
| | | fillColor(); |
| | | loading.value = false; |
| | | addEventBusListener(); |
| | | } catch (err) { |
| | | console.log(err); |
| | | } |
| | | }; |
| | | const addEventBusListener = () => { |
| | | const eventBus = modeler.value.get<EventBus>('eventBus'); |
| | | const overlays = modeler.value.get<Overlays>('overlays'); |
| | | eventBus.on<ModdleElement>('element.hover', (e) => { |
| | | let data = historyList.value.find((t) => t.taskDefinitionKey === e.element.id); |
| | | if (e.element.type === 'bpmn:UserTask' && data) { |
| | | setTimeout(() => { |
| | | genNodeDetailBox(e, overlays, data); |
| | | }, 10); |
| | | } |
| | | }); |
| | | eventBus.on('element.out', (e) => { |
| | | overlays.clear(); |
| | | }); |
| | | }; |
| | | const genNodeDetailBox = (e, overlays, data) => { |
| | | overlays.add(e.element.id, { |
| | | position: { top: e.element.height, left: 0 }, |
| | | html: `<div class="verlays"> |
| | | <p>审æ¹äººå: ${data.nickName || ''}<p/> |
| | | <p>èç¹ç¶æï¼${data.status || ''}</p> |
| | | <p>å¼å§æ¶é´ï¼${data.startTime || ''}</p> |
| | | <p>ç»ææ¶é´ï¼${data.endTime || ''}</p> |
| | | <p>审æ¹èæ¶ï¼${data.runDuration || ''}</p> |
| | | </div>` |
| | | }); |
| | | }; |
| | | // 让å¾è½èªéåºå±å¹ |
| | | const fitViewport = () => { |
| | | zoom.value = modeler.value.get<Canvas>('canvas').zoom('fit-viewport'); |
| | | const bbox = document.querySelector<SVGGElement>('.flow-containers .viewport').getBBox(); |
| | | const currentViewBox = modeler.value.get('canvas').viewbox(); |
| | | const elementMid = { |
| | | x: bbox.x + bbox.width / 2 - 65, |
| | | y: bbox.y + bbox.height / 2 |
| | | }; |
| | | modeler.value.get<Canvas>('canvas').viewbox({ |
| | | x: elementMid.x - currentViewBox.width / 2, |
| | | y: elementMid.y - currentViewBox.height / 2, |
| | | width: currentViewBox.width, |
| | | height: currentViewBox.height |
| | | }); |
| | | zoom.value = (bbox.width / currentViewBox.width) * 1.8; |
| | | }; |
| | | // æ¾å¤§ç¼©å° |
| | | const zoomViewport = (zoomIn = true) => { |
| | | zoom.value = modeler.value.get<Canvas>('canvas').zoom(); |
| | | zoom.value += zoomIn ? 0.1 : -0.1; |
| | | modeler.value.get<Canvas>('canvas').zoom(zoom.value); |
| | | }; |
| | | //ä¸è² |
| | | const fillColor = () => { |
| | | const canvas = modeler.value.get<Canvas>('canvas'); |
| | | bpmnNodeList(modeler.value._definitions.rootElements[0].flowElements, canvas); |
| | | }; |
| | | //éå½ä¸è² |
| | | const bpmnNodeList = (flowElements, canvas) => { |
| | | flowElements.forEach((n) => { |
| | | if (n.$type === 'bpmn:UserTask') { |
| | | const completeTask = taskList.value.find((m) => m.key === n.id); |
| | | if (completeTask) { |
| | | canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | n.outgoing?.forEach((nn) => { |
| | | const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
| | | if (targetTask) { |
| | | canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
| | | } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') { |
| | | canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | nn.targetRef.outgoing.forEach((e) => { |
| | | gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
| | | }); |
| | | } else if (nn.targetRef.$type === 'bpmn:ParallelGateway') { |
| | | canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | nn.targetRef.outgoing.forEach((e) => { |
| | | gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
| | | }); |
| | | } else if (nn.targetRef.$type === 'bpmn:InclusiveGateway') { |
| | | canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | nn.targetRef.outgoing.forEach((e) => { |
| | | gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | } else if (n.$type === 'bpmn:ExclusiveGateway') { |
| | | n.outgoing.forEach((nn) => { |
| | | const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
| | | if (targetTask) { |
| | | canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | }); |
| | | } else if (n.$type === 'bpmn:ParallelGateway') { |
| | | n.outgoing.forEach((nn) => { |
| | | const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
| | | if (targetTask) { |
| | | canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | }); |
| | | } else if (n.$type === 'bpmn:InclusiveGateway') { |
| | | n.outgoing.forEach((nn) => { |
| | | const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
| | | if (targetTask) { |
| | | canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | }); |
| | | } else if (n.$type === 'bpmn:SubProcess') { |
| | | const completeTask = taskList.value.find((m) => m.key === n.id); |
| | | if (completeTask) { |
| | | canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | bpmnNodeList(n.flowElements, canvas); |
| | | } else if (n.$type === 'bpmn:StartEvent') { |
| | | canvas.addMarker(n.id, 'startEvent'); |
| | | if (n.outgoing) { |
| | | n.outgoing.forEach((nn) => { |
| | | const completeTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
| | | if (completeTask) { |
| | | canvas.addMarker(nn.id, 'highlight'); |
| | | canvas.addMarker(n.id, 'highlight'); |
| | | } |
| | | }); |
| | | } |
| | | } else if (n.$type === 'bpmn:EndEvent') { |
| | | canvas.addMarker(n.id, 'endEvent'); |
| | | const completeTask = taskList.value.find((m) => m.key === n.id); |
| | | if (completeTask) { |
| | | canvas.addMarker(completeTask.key, 'highlight'); |
| | | canvas.addMarker(n.id, 'highlight'); |
| | | return; |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | const gateway = (id, targetRefType, targetRefId, canvas, completed) => { |
| | | if (targetRefType === 'bpmn:ExclusiveGateway') { |
| | | canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | if (targetRefType === 'bpmn:ParallelGateway') { |
| | | canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | if (targetRefType === 'bpmn:InclusiveGateway') { |
| | | canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
| | | canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
| | | } |
| | | }; |
| | | defineExpose({ |
| | | init, |
| | | initXml |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .canvas { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .header-div { |
| | | display: flex; |
| | | padding: 10px 0; |
| | | justify-content: space-between; |
| | | |
| | | .tips-label { |
| | | display: flex; |
| | | div { |
| | | margin-right: 10px; |
| | | padding: 5px; |
| | | font-size: 12px; |
| | | } |
| | | .un-complete { |
| | | border: 1px solid #000; |
| | | } |
| | | .in-progress { |
| | | background-color: rgb(255, 237, 204); |
| | | border: 1px dashed orange; |
| | | } |
| | | .complete { |
| | | background-color: rgb(204, 230, 204); |
| | | border: 1px solid green; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .view-mode { |
| | | .el-header, |
| | | .el-aside, |
| | | .djs-palette, |
| | | .bjs-powered-by { |
| | | display: none; |
| | | } |
| | | .el-loading-mask { |
| | | background-color: initial; |
| | | } |
| | | .el-loading-spinner { |
| | | display: none; |
| | | } |
| | | } |
| | | .bpmn-el-container { |
| | | height: calc(100vh - 350px); |
| | | } |
| | | .flow-containers { |
| | | width: 100%; |
| | | height: 100%; |
| | | overflow-y: auto; |
| | | .canvas { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | .load { |
| | | margin-right: 10px; |
| | | } |
| | | :deep(.el-form-item__label) { |
| | | font-size: 13px; |
| | | } |
| | | |
| | | :deep(.djs-palette) { |
| | | left: 0 !important; |
| | | top: 0; |
| | | border-top: none; |
| | | } |
| | | |
| | | :deep(.djs-container svg) { |
| | | min-height: 650px; |
| | | } |
| | | |
| | | :deep(.startEvent.djs-shape .djs-visual > :nth-child(1)) { |
| | | fill: #77df6d !important; |
| | | } |
| | | :deep(.endEvent.djs-shape .djs-visual > :nth-child(1)) { |
| | | fill: #ee7b77 !important; |
| | | } |
| | | :deep(.highlight.djs-shape .djs-visual > :nth-child(1)) { |
| | | fill: green !important; |
| | | stroke: green !important; |
| | | fill-opacity: 0.2 !important; |
| | | } |
| | | :deep(.highlight.djs-shape .djs-visual > :nth-child(2)) { |
| | | fill: green !important; |
| | | } |
| | | :deep(.highlight.djs-shape .djs-visual > path) { |
| | | fill: green !important; |
| | | fill-opacity: 0.2 !important; |
| | | stroke: green !important; |
| | | } |
| | | :deep(.highlight.djs-connection > .djs-visual > path) { |
| | | stroke: green !important; |
| | | } |
| | | |
| | | // è¾¹æ¡æ»å¨å¨ç» |
| | | @keyframes path-animation { |
| | | from { |
| | | stroke-dashoffset: 100%; |
| | | } |
| | | |
| | | to { |
| | | stroke-dashoffset: 0%; |
| | | } |
| | | } |
| | | |
| | | :deep(.highlight-todo.djs-connection > .djs-visual > path) { |
| | | animation: path-animation 60s; |
| | | animation-timing-function: linear; |
| | | animation-iteration-count: infinite; |
| | | stroke-dasharray: 4px !important; |
| | | stroke: orange !important; |
| | | fill-opacity: 0.2 !important; |
| | | marker-end: url('#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr'); |
| | | } |
| | | |
| | | :deep(.highlight-todo.djs-shape .djs-visual > :nth-child(1)) { |
| | | animation: path-animation 60s; |
| | | animation-timing-function: linear; |
| | | animation-iteration-count: infinite; |
| | | stroke-dasharray: 4px !important; |
| | | stroke: orange !important; |
| | | fill: orange !important; |
| | | fill-opacity: 0.2 !important; |
| | | } |
| | | } |
| | | :deep(.verlays) { |
| | | width: 250px; |
| | | background: rgb(102, 102, 102); |
| | | border-radius: 4px; |
| | | border: 1px solid #ebeef5; |
| | | color: #fff; |
| | | padding: 15px 10px; |
| | | p { |
| | | line-height: 28px; |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | cursor: pointer; |
| | | } |
| | | </style> |
| | |
| | | <el-breadcrumb class="app-breadcrumb" separator="/"> |
| | | <transition-group name="breadcrumb"> |
| | | <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path"> |
| | | <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ |
| | | item.meta?.title }}</span> |
| | | <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta?.title }}</span> |
| | | <a v-else @click.prevent="handleLink(item)">{{ item.meta?.title }}</a> |
| | | </el-breadcrumb-item> |
| | | </transition-group> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { RouteLocationMatched } from 'vue-router' |
| | | import { RouteLocationMatched } from 'vue-router'; |
| | | |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | const levelList = ref<RouteLocationMatched[]>([]) |
| | | const levelList = ref<RouteLocationMatched[]>([]); |
| | | |
| | | const getBreadcrumb = () => { |
| | | // only show routes with meta.title |
| | | let matched = route.matched.filter(item => item.meta && item.meta.title); |
| | | const first = matched[0] |
| | | let matched = route.matched.filter((item) => item.meta && item.meta.title); |
| | | const first = matched[0]; |
| | | // 夿æ¯å¦ä¸ºé¦é¡µ |
| | | if (!isDashboard(first)) { |
| | | matched = ([{ path: '/index', meta: { title: 'é¦é¡µ' } }] as any).concat(matched) |
| | | matched = ([{ path: '/index', meta: { title: 'é¦é¡µ' } }] as any).concat(matched); |
| | | } |
| | | levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) |
| | | } |
| | | levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false); |
| | | }; |
| | | const isDashboard = (route: RouteLocationMatched) => { |
| | | const name = route && route.name as string |
| | | const name = route && (route.name as string); |
| | | if (!name) { |
| | | return false |
| | | return false; |
| | | } |
| | | return name.trim() === 'Index' |
| | | } |
| | | const handleLink = (item: RouteLocationMatched) => { |
| | | const { redirect, path } = item |
| | | redirect ? router.push(redirect as string) : router.push(path) |
| | | } |
| | | return name.trim() === 'Index'; |
| | | }; |
| | | const handleLink = (item) => { |
| | | const { redirect, path } = item; |
| | | redirect ? router.push(redirect) : router.push(path); |
| | | }; |
| | | |
| | | watchEffect(() => { |
| | | // if you go to the redirect page, do not update the breadcrumbs |
| | | if (route.path.startsWith('/redirect/')) return |
| | | getBreadcrumb() |
| | | }) |
| | | if (route.path.startsWith('/redirect/')) return; |
| | | getBreadcrumb(); |
| | | }); |
| | | onMounted(() => { |
| | | getBreadcrumb(); |
| | | }) |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | <!-- ä»£ç æå»º --> |
| | | <script setup lang="ts"> |
| | | |
| | | const props = defineProps({ |
| | | showBtn: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | formJson: { |
| | | type: Object, |
| | | default: undefined |
| | | } |
| | | }) |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const buildRef = ref(); |
| | | const emits = defineEmits(['reJson', 'saveDesign']); |
| | | |
| | | |
| | | |
| | | //è·å表åjson |
| | | const getJson = () => { |
| | | const formJson = JSON.stringify(buildRef.value.getFormJson()) |
| | | const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets()) |
| | | let data = { |
| | | formJson, fieldJson |
| | | } |
| | | emits("saveDesign", data) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | if (props.formJson) { |
| | | buildRef.value.setFormJson(props.formJson) |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <template> |
| | | <!-- ä»£ç æå»º --> |
| | | <div> |
| | | <v-form-designer |
| | | class="build" |
| | | ref="buildRef" |
| | | class="build" |
| | | :designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }" |
| | | > |
| | | <template #customToolButtons v-if="showBtn"> |
| | | <template v-if="showBtn" #customToolButtons> |
| | | <el-button link type="primary" icon="Select" @click="getJson">ä¿å</el-button> |
| | | </template> |
| | | </v-form-designer> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | interface Props { |
| | | showBtn: boolean; |
| | | formJson: any; |
| | | } |
| | | |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | showBtn: true, |
| | | formJson: '' |
| | | }); |
| | | |
| | | const buildRef = ref(); |
| | | const emits = defineEmits(['reJson', 'saveDesign']); |
| | | |
| | | //è·å表åjson |
| | | const getJson = () => { |
| | | const formJson = JSON.stringify(buildRef.value.getFormJson()); |
| | | const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets()); |
| | | let data = { |
| | | formJson, |
| | | fieldJson |
| | | }; |
| | | emits('saveDesign', data); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | if (props.formJson) { |
| | | buildRef.value.setFormJson(props.formJson); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .build { |
| | | margin: 0 !important; |
| | |
| | | <template> |
| | | <div class=""> |
| | | <v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- å¨æè¡¨åæ¸²æ --> |
| | | <script setup name="Render"> |
| | | <script setup name="Render" lang="ts"> |
| | | interface Props { |
| | | formJson: string | object; |
| | | formData: string | object; |
| | | isView: boolean; |
| | | } |
| | | |
| | | const props = defineProps({ |
| | | formJson: { |
| | | type: [String, Object], |
| | | default: "" |
| | | }, |
| | | formData: { |
| | | type: [String, Object], |
| | | default: "" |
| | | }, |
| | | isView: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | }) |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | formJson: '', |
| | | formData: '', |
| | | isView: false |
| | | }); |
| | | |
| | | const vFormRef = ref(null) |
| | | const vFormRef = ref(); |
| | | // è·åè¡¨åæ°æ®-弿¥ |
| | | const getFormData = () => { |
| | | return vFormRef.value.getFormData() |
| | | } |
| | | return vFormRef.value.getFormData(); |
| | | }; |
| | | |
| | | /** |
| | | * 设置表åå
容 |
| | | * @param {表åé
ç½®} formConf |
| | | * formConfigï¼{ formTemplateï¼è¡¨å模æ¿ï¼formDataï¼è¡¨åæ°æ®ï¼hiddenFieldï¼éè¦éèçåæ®µå符串éåï¼disabledFieldï¼éè¦ç¦ç¨çèªè¯»å符串éå} |
| | | */ |
| | | const initForm = (formConf) => { |
| | | const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf) |
| | | const initForm = (formConf: any) => { |
| | | const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf); |
| | | if (formTemplate) { |
| | | vFormRef.value.setFormJson(formTemplate) |
| | | vFormRef.value.setFormJson(formTemplate); |
| | | if (formData) { |
| | | vFormRef.value.setFormData(formData) |
| | | vFormRef.value.setFormData(formData); |
| | | } |
| | | if (disabledField && disabledField.length > 0) { |
| | | setTimeout(() => { |
| | | vFormRef.value.disableWidgets(disabledField) |
| | | }, 200) |
| | | vFormRef.value.disableWidgets(disabledField); |
| | | }, 200); |
| | | } |
| | | if (hiddenField && hiddenField.length > 0) { |
| | | setTimeout(() => { |
| | | vFormRef.value.hideWidgets(hiddenField) |
| | | }, 200) |
| | | vFormRef.value.hideWidgets(hiddenField); |
| | | }, 200); |
| | | } |
| | | if (props.isView) { |
| | | console.log(props.isView) |
| | | setTimeout(() => { |
| | | vFormRef.value.disableForm() |
| | | }, 100) |
| | | vFormRef.value.disableForm(); |
| | | }, 100); |
| | | } |
| | | } |
| | | } |
| | | defineExpose({ getFormData, initForm }) |
| | | }; |
| | | defineExpose({ getFormData, initForm }); |
| | | </script> |
| | | |
| | | <template> |
| | | <div class=""> |
| | | <v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" /> |
| | | </div> |
| | | </template> |
| | |
| | | <div> |
| | | <template v-for="(item, index) in options"> |
| | | <template v-if="values.includes(item.value)"> |
| | | <span v-if="(item.elTagType === 'default' || item.elTagType === '') && (item.elTagClass === '' || item.elTagClass == null)" |
| | | :key="item.value" :index="index" :class="item.elTagClass"> |
| | | {{ item.label + " " }} |
| | | <span |
| | | v-if="(item.elTagType === 'default' || item.elTagType === '') && (item.elTagClass === '' || item.elTagClass == null)" |
| | | :key="item.value" |
| | | :index="index" |
| | | :class="item.elTagClass" |
| | | > |
| | | {{ item.label + ' ' }} |
| | | </span> |
| | | <el-tag |
| | | v-else |
| | | :disable-transitions="true" |
| | | :key="item.value + ''" |
| | | :disable-transitions="true" |
| | | :index="index" |
| | | :type="(item.elTagType === 'primary' || item.elTagType === 'default')? '' : item.elTagType" |
| | | :type=" |
| | | item.elTagType === 'primary' || |
| | | item.elTagType === 'success' || |
| | | item.elTagType === 'info' || |
| | | item.elTagType === 'warning' || |
| | | item.elTagType === 'danger' |
| | | ? item.elTagType |
| | | : 'primary' |
| | | " |
| | | :class="item.elTagClass" |
| | | > |
| | | {{ item.label + " " }} |
| | | {{ item.label + ' ' }} |
| | | </el-tag> |
| | | </template> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | |
| | | const props = defineProps({ |
| | | // æ°æ® |
| | | options: { |
| | | type: Array as PropType<DictDataOption[]>, |
| | | default: null, |
| | | }, |
| | | // å½åçå¼ |
| | | value: [Number, String, Array] as PropType<number | string | Array<number | string>>, |
| | | // 彿ªæ¾å°å¹é
çæ°æ®æ¶ï¼æ¾ç¤ºvalue |
| | | showValue: propTypes.bool.def(true), |
| | | separator: propTypes.string.def(","), |
| | | interface Props { |
| | | options: Array<DictDataOption>; |
| | | value: number | string | Array<number | string>; |
| | | showValue?: boolean; |
| | | separator?: string; |
| | | } |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | showValue: true, |
| | | separator: ',' |
| | | }); |
| | | |
| | | const values = computed(() => { |
| | | if (props.value === '' || props.value === null || typeof props.value === "undefined") return [] |
| | | return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator); |
| | | if (props.value === '' || props.value === null || typeof props.value === 'undefined') return []; |
| | | return Array.isArray(props.value) ? props.value.map((item) => '' + item) : String(props.value).split(props.separator); |
| | | }); |
| | | |
| | | const unmatch = computed(() => { |
| | | if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === "undefined") return false |
| | | if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === 'undefined') return false; |
| | | // ä¼ å
¥å¼ä¸ºéæ°ç» |
| | | values.value.forEach(item => { |
| | | if (!props.options.some(v => v.value === item)) { |
| | | return true // å¦æææªå¹é
项ï¼å°æ å¿è®¾ç½®ä¸ºtrue |
| | | let unmatch = false; // æ·»å ä¸ä¸ªæ å¿æ¥å¤ææ¯å¦ææªå¹é
项 |
| | | values.value.forEach((item) => { |
| | | if (!props.options.some((v) => v.value === item)) { |
| | | unmatch = true; // å¦æææªå¹é
项ï¼å°æ å¿è®¾ç½®ä¸ºtrue |
| | | } |
| | | }) |
| | | return false // è¿åæ å¿çå¼ |
| | | }); |
| | | return unmatch; // è¿åæ å¿çå¼ |
| | | }); |
| | | |
| | | const unmatchArray = computed(() => { |
| | | // è®°å½æªå¹é
ç项 |
| | | // è®°å½æªå¹é
ç项 |
| | | const itemUnmatchArray: Array<string | number> = []; |
| | | if (props.value !== '' && props.value !== null && typeof props.value !== "undefined") { |
| | | values.value.forEach(item => { |
| | | if (!props.options.some(v => v.value === item)) { |
| | | if (props.value !== '' && props.value !== null && typeof props.value !== 'undefined') { |
| | | values.value.forEach((item) => { |
| | | if (!props.options.some((v) => v.value === item)) { |
| | | itemUnmatchArray.push(item); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | // 没ævalue䏿¾ç¤º |
| | | return handleArray(itemUnmatchArray); |
| | | }); |
| | | |
| | | const handleArray = (array: Array<string | number>) => { |
| | | if (array.length === 0) return ""; |
| | | if (array.length === 0) return ''; |
| | | return array.reduce((pre, cur) => { |
| | | return pre + " " + cur; |
| | | return pre + ' ' + cur; |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | |
| | | <template> |
| | | <div> |
| | | <el-upload |
| | | v-if="type === 'url'" |
| | | :action="upload.url" |
| | | :before-upload="handleBeforeUpload" |
| | | :on-success="handleUploadSuccess" |
| | |
| | | name="file" |
| | | :show-file-list="false" |
| | | :headers="upload.headers" |
| | | ref="uploadRef" |
| | | v-if="type === 'url'" |
| | | > |
| | | <i ref="uploadRef"></i> |
| | | </el-upload> |
| | | <div class="editor"> |
| | | <quill-editor |
| | | ref="quillEditorRef" |
| | | v-model:content="content" |
| | | contentType="html" |
| | | @textChange="(e: any) => $emit('update:modelValue', content)" |
| | | :options="options" |
| | | :style="styles" |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="editor"> |
| | | <quill-editor |
| | | ref="quillEditorRef" |
| | | v-model:content="content" |
| | | content-type="html" |
| | | :options="options" |
| | | :style="styles" |
| | | @text-change="(e: any) => $emit('update:modelValue', content)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { QuillEditor, Quill } from '@vueup/vue-quill'; |
| | | import '@vueup/vue-quill/dist/vue-quill.snow.css'; |
| | | |
| | | import { QuillEditor, Quill } from '@vueup/vue-quill'; |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | import { globalHeaders } from "@/utils/request"; |
| | | import { globalHeaders } from '@/utils/request'; |
| | | |
| | | defineEmits(['update:modelValue']); |
| | | |
| | | const props = defineProps({ |
| | | /* ç¼è¾å¨çå
容 */ |
| | |
| | | const upload = reactive<UploadOption>({ |
| | | headers: globalHeaders(), |
| | | url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload' |
| | | }) |
| | | }); |
| | | const quillEditorRef = ref(); |
| | | const uploadRef = ref<HTMLDivElement>(); |
| | | |
| | | const options = ref({ |
| | | theme: "snow", |
| | | const options = ref<any>({ |
| | | theme: 'snow', |
| | | bounds: document.body, |
| | | debug: "warn", |
| | | debug: 'warn', |
| | | modules: { |
| | | // å·¥å
·æ é
ç½® |
| | | toolbar: { |
| | | container: [ |
| | | ["bold", "italic", "underline", "strike"], // å ç² æä½ ä¸å线 å é¤çº¿ |
| | | ["blockquote", "code-block"], // å¼ç¨ 代ç å |
| | | [{ list: "ordered" }, { list: "bullet" }], // æåºãæ åºå表 |
| | | [{ indent: "-1" }, { indent: "+1" }], // ç¼©è¿ |
| | | [{ size: ["small", false, "large", "huge"] }], // åä½å¤§å° |
| | | [{ header: [1, 2, 3, 4, 5, 6, false] }], // æ é¢ |
| | | [{ color: [] }, { background: [] }], // åä½é¢è²ãåä½èæ¯é¢è² |
| | | [{ align: [] }], // 坹齿¹å¼ |
| | | ["clean"], // æ¸
é¤ææ¬æ ¼å¼ |
| | | ["link", "image", "video"] // 龿¥ãå¾çãè§é¢ |
| | | ['bold', 'italic', 'underline', 'strike'], // å ç² æä½ ä¸å线 å é¤çº¿ |
| | | ['blockquote', 'code-block'], // å¼ç¨ 代ç å |
| | | [{ list: 'ordered' }, { list: 'bullet' }], // æåºãæ åºå表 |
| | | [{ indent: '-1' }, { indent: '+1' }], // ç¼©è¿ |
| | | [{ size: ['small', false, 'large', 'huge'] }], // åä½å¤§å° |
| | | [{ header: [1, 2, 3, 4, 5, 6, false] }], // æ é¢ |
| | | [{ color: [] }, { background: [] }], // åä½é¢è²ãåä½èæ¯é¢è² |
| | | [{ align: [] }], // 坹齿¹å¼ |
| | | ['clean'], // æ¸
é¤ææ¬æ ¼å¼ |
| | | ['link', 'image', 'video'] // 龿¥ãå¾çãè§é¢ |
| | | ], |
| | | handlers: { |
| | | image: function (value: any) { |
| | | image: (value: boolean) => { |
| | | if (value) { |
| | | // è°ç¨elementå¾çä¸ä¼ |
| | | (document.querySelector(".editor-img-uploader>.el-upload") as HTMLDivElement)?.click(); |
| | | uploadRef.value.click(); |
| | | } else { |
| | | Quill.format("image", true); |
| | | Quill.format('image', true); |
| | | } |
| | | }, |
| | | }, |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | placeholder: "请è¾å
¥å
容", |
| | | readOnly: props.readOnly, |
| | | placeholder: '请è¾å
¥å
容', |
| | | readOnly: props.readOnly |
| | | }); |
| | | |
| | | const styles = computed(() => { |
| | |
| | | style.height = `${props.height}px`; |
| | | } |
| | | return style; |
| | | }) |
| | | }); |
| | | |
| | | const content = ref(""); |
| | | watch(() => props.modelValue, (v) => { |
| | | if (v !== content.value) { |
| | | content.value = v === undefined ? "<p></p>" : v; |
| | | } |
| | | }, { immediate: true }); |
| | | const content = ref(''); |
| | | watch( |
| | | () => props.modelValue, |
| | | (v: string) => { |
| | | if (v !== content.value) { |
| | | content.value = v === undefined ? '<p></p>' : v; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | // å¾çä¸ä¼ æåè¿åå¾çå°å |
| | | const handleUploadSuccess = (res: any) => { |
| | |
| | | // è·åå
æ ä½ç½® |
| | | let length = quill.selection.savedRange.index; |
| | | // æå
¥å¾çï¼res为æå¡å¨è¿åçå¾ç龿¥å°å |
| | | quill.insertEmbed(length, "image", res.data.url); |
| | | quill.insertEmbed(length, 'image', res.data.url); |
| | | // è°æ´å
æ å°æå |
| | | quill.setSelection(length + 1); |
| | | proxy?.$modal.closeLoading(); |
| | | } else { |
| | | proxy?.$modal.loading(res.msg); |
| | | proxy?.$modal.msgError('å¾çæå
¥å¤±è´¥'); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // å¾çä¸ä¼ åæ¦æª |
| | | const handleBeforeUpload = (file: any) => { |
| | | const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]; |
| | | const type = ['image/jpeg', 'image/jpg', 'image/png', 'image/svg']; |
| | | const isJPG = type.includes(file.type); |
| | | //æ£éªæä»¶æ ¼å¼ |
| | | if (!isJPG) { |
| | |
| | | } |
| | | proxy?.$modal.loading('æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å...'); |
| | | return true; |
| | | } |
| | | }; |
| | | |
| | | // å¾çå¤±è´¥æ¦æª |
| | | const handleUploadError = (err: any) => { |
| | | console.error(err); |
| | | proxy?.$modal.msgError('ä¸ä¼ æä»¶å¤±è´¥'); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | |
| | | .quill-img { |
| | | display: none; |
| | | } |
| | | .ql-snow .ql-tooltip[data-mode="link"]::before { |
| | | content: "请è¾å
¥é¾æ¥å°å:"; |
| | | .ql-snow .ql-tooltip[data-mode='link']::before { |
| | | content: '请è¾å
¥é¾æ¥å°å:'; |
| | | } |
| | | .ql-snow .ql-tooltip.ql-editing a.ql-action::after { |
| | | border-right: 0; |
| | | content: "ä¿å"; |
| | | content: 'ä¿å'; |
| | | padding-right: 0; |
| | | } |
| | | .ql-snow .ql-tooltip[data-mode="video"]::before { |
| | | content: "请è¾å
¥è§é¢å°å:"; |
| | | .ql-snow .ql-tooltip[data-mode='video']::before { |
| | | content: '请è¾å
¥è§é¢å°å:'; |
| | | } |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item::before { |
| | | content: "14px"; |
| | | content: '14px'; |
| | | } |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before { |
| | | content: "10px"; |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before { |
| | | content: '10px'; |
| | | } |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before { |
| | | content: "18px"; |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before { |
| | | content: '18px'; |
| | | } |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { |
| | | content: "32px"; |
| | | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before, |
| | | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before { |
| | | content: '32px'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item::before { |
| | | content: "ææ¬"; |
| | | content: 'ææ¬'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { |
| | | content: "æ é¢1"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before { |
| | | content: 'æ é¢1'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { |
| | | content: "æ é¢2"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before { |
| | | content: 'æ é¢2'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { |
| | | content: "æ é¢3"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before { |
| | | content: 'æ é¢3'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { |
| | | content: "æ é¢4"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before { |
| | | content: 'æ é¢4'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { |
| | | content: "æ é¢5"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before { |
| | | content: 'æ é¢5'; |
| | | } |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { |
| | | content: "æ é¢6"; |
| | | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before, |
| | | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before { |
| | | content: 'æ é¢6'; |
| | | } |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label::before, |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item::before { |
| | | content: "æ ååä½"; |
| | | content: 'æ ååä½'; |
| | | } |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before, |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before { |
| | | content: "衬线åä½"; |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before, |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before { |
| | | content: '衬线åä½'; |
| | | } |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before, |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before { |
| | | content: "ç宽åä½"; |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before, |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before { |
| | | content: 'ç宽åä½'; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="upload-file"> |
| | | <el-upload |
| | | ref="fileUploadRef" |
| | | multiple |
| | | :action="uploadFileUrl" |
| | | :before-upload="handleBeforeUpload" |
| | |
| | | :show-file-list="false" |
| | | :headers="headers" |
| | | class="upload-file-uploader" |
| | | ref="fileUploadRef" |
| | | > |
| | | <!-- ä¸ä¼ æé® --> |
| | | <el-button type="primary">éåæä»¶</el-button> |
| | | </el-upload> |
| | | <!-- ä¸ä¼ æç¤º --> |
| | | <div class="el-upload__tip" v-if="showTip"> |
| | | <div v-if="showTip" class="el-upload__tip"> |
| | | 请ä¸ä¼ |
| | | <template v-if="fileSize"> |
| | | 大å°ä¸è¶
è¿ <b style="color: #f56c6c">{{ fileSize }}MB</b> |
| | | </template> |
| | | <template v-if="fileType"> |
| | | æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b> |
| | | æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join('/') }}</b> |
| | | </template> |
| | | çæä»¶ |
| | | </div> |
| | | <!-- æä»¶å表 --> |
| | | <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul"> |
| | | <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"> |
| | | <li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content"> |
| | | <el-link :href="`${file.url}`" :underline="false" target="_blank"> |
| | | <span class="el-icon-document"> {{ getFileName(file.name) }} </span> |
| | | </el-link> |
| | | <div class="ele-upload-list__item-content-action"> |
| | | <el-link :underline="false" @click="handleDelete(index)" type="danger">å é¤</el-link> |
| | | <el-button type="danger" link @click="handleDelete(index)">å é¤</el-button> |
| | | </div> |
| | | </li> |
| | | </transition-group> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { listByIds, delOss } from "@/api/system/oss"; |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | import { globalHeaders } from "@/utils/request"; |
| | | import { delOss, listByIds } from '@/api/system/oss'; |
| | | import { globalHeaders } from '@/utils/request'; |
| | | |
| | | const props = defineProps({ |
| | | modelValue: [String, Object, Array], |
| | | // æ°ééå¶ |
| | | limit: propTypes.number.def(5), |
| | | // 大å°éå¶(MB) |
| | | fileSize: propTypes.number.def(5), |
| | | // æä»¶ç±»å, ä¾å¦['png', 'jpg', 'jpeg'] |
| | | fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]), |
| | | // æ¯å¦æ¾ç¤ºæç¤º |
| | | isShowTip: propTypes.bool.def(true), |
| | | modelValue: { |
| | | type: [String, Object, Array], |
| | | default: () => [] |
| | | }, |
| | | // æ°ééå¶ |
| | | limit: propTypes.number.def(5), |
| | | // 大å°éå¶(MB) |
| | | fileSize: propTypes.number.def(5), |
| | | // æä»¶ç±»å, ä¾å¦['png', 'jpg', 'jpeg'] |
| | | fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), |
| | | // æ¯å¦æ¾ç¤ºæç¤º |
| | | isShowTip: propTypes.bool.def(true) |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | |
| | | const uploadList = ref<any[]>([]); |
| | | |
| | | const baseUrl = import.meta.env.VITE_APP_BASE_API; |
| | | const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // ä¸ä¼ æä»¶æå¡å¨å°å |
| | | const uploadFileUrl = ref(baseUrl + '/resource/oss/upload'); // ä¸ä¼ æä»¶æå¡å¨å°å |
| | | const headers = ref(globalHeaders()); |
| | | |
| | | const fileList = ref<any[]>([]); |
| | | const showTip = computed( |
| | | () => props.isShowTip && (props.fileType || props.fileSize) |
| | | ); |
| | | const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize)); |
| | | |
| | | const fileUploadRef = ref<ElUploadInstance>(); |
| | | |
| | | watch(() => props.modelValue, async val => { |
| | | watch( |
| | | () => props.modelValue, |
| | | async (val) => { |
| | | if (val) { |
| | | let temp = 1; |
| | | // é¦å
å°å¼è½¬ä¸ºæ°ç» |
| | | let list = []; |
| | | if (Array.isArray(val)) { |
| | | list = val; |
| | | } else { |
| | | const res = await listByIds(val as string) |
| | | list = res.data.map((oss) => { |
| | | const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId }; |
| | | return data; |
| | | }); |
| | | } |
| | | // ç¶åå°æ°ç»è½¬ä¸ºå¯¹è±¡æ°ç» |
| | | fileList.value = list.map(item => { |
| | | item = { name: item.name, url: item.url, ossId: item.ossId }; |
| | | item.uid = item.uid || new Date().getTime() + temp++; |
| | | return item; |
| | | let temp = 1; |
| | | // é¦å
å°å¼è½¬ä¸ºæ°ç» |
| | | let list: any[] = []; |
| | | if (Array.isArray(val)) { |
| | | list = val; |
| | | } else { |
| | | const res = await listByIds(val); |
| | | list = res.data.map((oss) => { |
| | | return { |
| | | name: oss.originalName, |
| | | url: oss.url, |
| | | ossId: oss.ossId |
| | | }; |
| | | }); |
| | | } |
| | | // ç¶åå°æ°ç»è½¬ä¸ºå¯¹è±¡æ°ç» |
| | | fileList.value = list.map((item) => { |
| | | item = { name: item.name, url: item.url, ossId: item.ossId }; |
| | | item.uid = item.uid || new Date().getTime() + temp++; |
| | | return item; |
| | | }); |
| | | } else { |
| | | fileList.value = []; |
| | | return []; |
| | | fileList.value = []; |
| | | return []; |
| | | } |
| | | }, { deep: true, immediate: true }); |
| | | }, |
| | | { deep: true, immediate: true } |
| | | ); |
| | | |
| | | // ä¸ä¼ åæ ¡æ£æ ¼å¼åå¤§å° |
| | | const handleBeforeUpload = (file: any) => { |
| | | // æ ¡æ£æä»¶ç±»å |
| | | if (props.fileType.length) { |
| | | const fileName = file.name.split('.'); |
| | | const fileExt = fileName[fileName.length - 1]; |
| | | const isTypeOk = props.fileType.indexOf(fileExt) >= 0; |
| | | if (!isTypeOk) { |
| | | proxy?.$modal.msgError(`æä»¶æ ¼å¼ä¸æ£ç¡®, 请ä¸ä¼ ${props.fileType.join("/")}æ ¼å¼æä»¶!`); |
| | | return false; |
| | | } |
| | | // æ ¡æ£æä»¶ç±»å |
| | | if (props.fileType.length) { |
| | | const fileName = file.name.split('.'); |
| | | const fileExt = fileName[fileName.length - 1]; |
| | | const isTypeOk = props.fileType.indexOf(fileExt) >= 0; |
| | | if (!isTypeOk) { |
| | | proxy?.$modal.msgError(`æä»¶æ ¼å¼ä¸æ£ç¡®, 请ä¸ä¼ ${props.fileType.join('/')}æ ¼å¼æä»¶!`); |
| | | return false; |
| | | } |
| | | // æ ¡æ£æä»¶å¤§å° |
| | | if (props.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < props.fileSize; |
| | | if (!isLt) { |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿ ${props.fileSize} MB!`); |
| | | return false; |
| | | } |
| | | } |
| | | // æ ¡æ£æä»¶å¤§å° |
| | | if (props.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < props.fileSize; |
| | | if (!isLt) { |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿ ${props.fileSize} MB!`); |
| | | return false; |
| | | } |
| | | proxy?.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); |
| | | number.value++; |
| | | return true; |
| | | } |
| | | } |
| | | proxy?.$modal.loading('æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å...'); |
| | | number.value++; |
| | | return true; |
| | | }; |
| | | |
| | | // æä»¶ä¸ªæ°è¶
åº |
| | | const handleExceed = () => { |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶æ°éä¸è½è¶
è¿ ${props.limit} 个!`); |
| | | } |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶æ°éä¸è½è¶
è¿ ${props.limit} 个!`); |
| | | }; |
| | | |
| | | // ä¸ä¼ 失败 |
| | | const handleUploadError = () => { |
| | | proxy?.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); |
| | | } |
| | | proxy?.$modal.msgError('ä¸ä¼ æä»¶å¤±è´¥'); |
| | | }; |
| | | |
| | | // ä¸ä¼ æååè° |
| | | const handleUploadSuccess = (res: any, file: UploadFile) => { |
| | | if (res.code === 200) { |
| | | uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId }); |
| | | uploadedSuccessfully(); |
| | | } else { |
| | | number.value--; |
| | | proxy?.$modal.closeLoading(); |
| | | proxy?.$modal.msgError(res.msg); |
| | | fileUploadRef.value?.handleRemove(file); |
| | | uploadedSuccessfully(); |
| | | } |
| | | } |
| | | if (res.code === 200) { |
| | | uploadList.value.push({ |
| | | name: res.data.fileName, |
| | | url: res.data.url, |
| | | ossId: res.data.ossId |
| | | }); |
| | | uploadedSuccessfully(); |
| | | } else { |
| | | number.value--; |
| | | proxy?.$modal.closeLoading(); |
| | | proxy?.$modal.msgError(res.msg); |
| | | fileUploadRef.value?.handleRemove(file); |
| | | uploadedSuccessfully(); |
| | | } |
| | | }; |
| | | |
| | | // å 餿件 |
| | | const handleDelete = (index: number) => { |
| | | let ossId = fileList.value[index].ossId; |
| | | delOss(ossId); |
| | | fileList.value.splice(index, 1); |
| | | emit("update:modelValue", listToString(fileList.value)); |
| | | } |
| | | let ossId = fileList.value[index].ossId; |
| | | delOss(ossId); |
| | | fileList.value.splice(index, 1); |
| | | emit('update:modelValue', listToString(fileList.value)); |
| | | }; |
| | | |
| | | // ä¸ä¼ ç»æå¤ç |
| | | const uploadedSuccessfully = () => { |
| | | if (number.value > 0 && uploadList.value.length === number.value) { |
| | | fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value); |
| | | uploadList.value = []; |
| | | number.value = 0; |
| | | emit("update:modelValue", listToString(fileList.value)); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | } |
| | | if (number.value > 0 && uploadList.value.length === number.value) { |
| | | fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value); |
| | | uploadList.value = []; |
| | | number.value = 0; |
| | | emit('update:modelValue', listToString(fileList.value)); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | }; |
| | | |
| | | // è·åæä»¶åç§° |
| | | const getFileName = (name: string) => { |
| | | // 妿æ¯urlé£ä¹åæåçåå 妿䏿¯ç´æ¥è¿å |
| | | if (name.lastIndexOf("/") > -1) { |
| | | return name.slice(name.lastIndexOf("/") + 1); |
| | | } else { |
| | | return name; |
| | | } |
| | | } |
| | | // 妿æ¯urlé£ä¹åæåçåå 妿䏿¯ç´æ¥è¿å |
| | | if (name.lastIndexOf('/') > -1) { |
| | | return name.slice(name.lastIndexOf('/') + 1); |
| | | } else { |
| | | return name; |
| | | } |
| | | }; |
| | | |
| | | // 对象转ææå®å符串åé |
| | | const listToString = (list: any[], separator?: string) => { |
| | | let strs = ""; |
| | | separator = separator || ","; |
| | | list.forEach(item => { |
| | | if (item.ossId) { |
| | | strs += item.ossId + separator; |
| | | } |
| | | }) |
| | | return strs != "" ? strs.substring(0, strs.length - 1) : ""; |
| | | } |
| | | let strs = ''; |
| | | separator = separator || ','; |
| | | list.forEach((item) => { |
| | | if (item.ossId) { |
| | | strs += item.ossId + separator; |
| | | } |
| | | }); |
| | | return strs != '' ? strs.substring(0, strs.length - 1) : ''; |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .upload-file-uploader { |
| | | margin-bottom: 5px; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .upload-file-list .el-upload-list__item { |
| | | border: 1px solid #e4e7ed; |
| | | line-height: 2; |
| | | margin-bottom: 10px; |
| | | position: relative; |
| | | border: 1px solid #e4e7ed; |
| | | line-height: 2; |
| | | margin-bottom: 10px; |
| | | position: relative; |
| | | } |
| | | |
| | | .upload-file-list .ele-upload-list__item-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | color: inherit; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | color: inherit; |
| | | } |
| | | |
| | | .ele-upload-list__item-content-action .el-link { |
| | | margin-right: 10px; |
| | | margin-right: 10px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div style="padding: 0 15px;" @click="toggleClick"> |
| | | <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" |
| | |
| | | |
| | | defineProps({ |
| | | isActive: propTypes.bool.def(false) |
| | | }) |
| | | }); |
| | | |
| | | const emit = defineEmits(['toggleClick']) |
| | | const emit = defineEmits(['toggleClick']); |
| | | const toggleClick = () => { |
| | | emit('toggleClick'); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | |
| | | <template> |
| | | <div :class="{ 'show': show }" class="header-search"> |
| | | <svg-icon class-name="search-icon" icon-class="search" @click.stop="click"/> |
| | | <div :class="{ show: show }" class="header-search"> |
| | | <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" /> |
| | | <el-select |
| | | ref="headerSearchSelectRef" |
| | | v-model="search" |
| | |
| | | class="header-search-select" |
| | | @change="change" |
| | | > |
| | | <el-option v-for="option in options" :key="option.item.path" :value="option.item" |
| | | :label="option.item.title.join(' > ')"/> |
| | | <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" /> |
| | | </el-select> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts" name="HeaderSearch"> |
| | | import Fuse from 'fuse.js'; |
| | | import {getNormalPath} from '@/utils/ruoyi'; |
| | | import {isHttp} from '@/utils/validate'; |
| | | import { getNormalPath } from '@/utils/ruoyi'; |
| | | import { isHttp } from '@/utils/validate'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import {RouteOption} from 'vue-router'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | type Router = Array<{ |
| | | path: string; |
| | | title: string[]; |
| | | }> |
| | | }>; |
| | | |
| | | const search = ref(''); |
| | | const options = ref<any>([]); |
| | |
| | | const fuse = ref(); |
| | | const headerSearchSelectRef = ref<ElSelectInstance>(); |
| | | const router = useRouter(); |
| | | const routes = computed(() => usePermissionStore().routes); |
| | | const routes = computed(() => usePermissionStore().getRoutes()); |
| | | |
| | | const click = () => { |
| | | show.value = !show.value |
| | | show.value = !show.value; |
| | | if (show.value) { |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.focus() |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.focus(); |
| | | } |
| | | }; |
| | | const close = () => { |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.blur() |
| | | options.value = [] |
| | | show.value = false |
| | | } |
| | | headerSearchSelectRef.value && headerSearchSelectRef.value.blur(); |
| | | options.value = []; |
| | | show.value = false; |
| | | }; |
| | | const change = (val: any) => { |
| | | const path = val.path; |
| | | const query = val.query; |
| | | if (isHttp(path)) { |
| | | // http(s):// è·¯å¾æ°çªå£æå¼ |
| | | const pindex = path.indexOf("http"); |
| | | window.open(path.substr(pindex, path.length), "_blank"); |
| | | const pindex = path.indexOf('http'); |
| | | window.open(path.substr(pindex, path.length), '_blank'); |
| | | } else { |
| | | if (query) { |
| | | router.push({ path: path, query: JSON.parse(query) }); |
| | | } else { |
| | | router.push(path) |
| | | router.push(path); |
| | | } |
| | | } |
| | | search.value = '' |
| | | options.value = [] |
| | | search.value = ''; |
| | | options.value = []; |
| | | nextTick(() => { |
| | | show.value = false |
| | | }) |
| | | } |
| | | show.value = false; |
| | | }); |
| | | }; |
| | | const initFuse = (list: Router) => { |
| | | fuse.value = new Fuse(list, { |
| | | shouldSort: true, |
| | |
| | | location: 0, |
| | | distance: 100, |
| | | minMatchCharLength: 1, |
| | | keys: [{ |
| | | name: 'title', |
| | | weight: 0.7 |
| | | }, { |
| | | name: 'path', |
| | | weight: 0.3 |
| | | }] |
| | | }) |
| | | } |
| | | keys: [ |
| | | { |
| | | name: 'title', |
| | | weight: 0.7 |
| | | }, |
| | | { |
| | | name: 'path', |
| | | weight: 0.3 |
| | | } |
| | | ] |
| | | }); |
| | | }; |
| | | // Filter out the routes that can be displayed in the sidebar |
| | | // And generate the internationalized title |
| | | const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => { |
| | | let res: Router = [] |
| | | routes.forEach(r => { |
| | | const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => { |
| | | let res: Router = []; |
| | | routes.forEach((r) => { |
| | | // skip hidden router |
| | | if (!r.hidden) { |
| | | const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path; |
| | |
| | | path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path, |
| | | title: [...prefixTitle], |
| | | query: '' |
| | | } |
| | | }; |
| | | if (r.meta && r.meta.title) { |
| | | data.title = [...data.title, r.meta.title]; |
| | | if (r.redirect !== 'noRedirect') { |
| | |
| | | } |
| | | |
| | | if (r.query) { |
| | | data.query = r.query |
| | | data.query = r.query; |
| | | } |
| | | |
| | | // recursive child routes |
| | |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | }); |
| | | return res; |
| | | } |
| | | }; |
| | | const querySearch = (query: string) => { |
| | | if (query !== '') { |
| | | options.value = fuse.value.search(query) |
| | | options.value = fuse.value.search(query); |
| | | } else { |
| | | options.value = [] |
| | | options.value = []; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | searchPool.value = generateRoutes(routes.value); |
| | | }) |
| | | }); |
| | | |
| | | // watchEffect(() => { |
| | | // searchPool.value = generateRoutes(routes.value) |
| | |
| | | |
| | | watch(show, (value) => { |
| | | if (value) { |
| | | document.body.addEventListener('click', close) |
| | | document.body.addEventListener('click', close); |
| | | } else { |
| | | document.body.removeEventListener('click', close) |
| | | document.body.removeEventListener('click', close); |
| | | } |
| | | }) |
| | | }); |
| | | |
| | | watch(searchPool, (list) => { |
| | | initFuse(list) |
| | | }) |
| | | watch(searchPool, (list: Router) => { |
| | | initFuse(list); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | <template> |
| | | <div class="relative" :style="{ width: width }"> |
| | | <el-input v-model="modelValue" readonly @click="visible = !visible" placeholder="ç¹å»éæ©å¾æ "> |
| | | <div class="relative" :style="{ 'width': width }"> |
| | | <el-input v-model="modelValue" readonly placeholder="ç¹å»éæ©å¾æ " @click="visible = !visible"> |
| | | <template #prepend> |
| | | <svg-icon :icon-class="modelValue" /> |
| | | </template> |
| | |
| | | |
| | | <el-popover shadow="none" :visible="visible" placement="bottom-end" trigger="click" :width="450"> |
| | | <template #reference> |
| | | <div @click="visible = !visible" class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]"> |
| | | <div class="cursor-pointer text-[#999] absolute right-[10px] top-0 height-[32px] leading-[32px]" @click="visible = !visible"> |
| | | <i-ep-caret-top v-show="visible"></i-ep-caret-top> |
| | | <i-ep-caret-bottom v-show="!visible"></i-ep-caret-bottom> |
| | | </div> |
| | | </template> |
| | | |
| | | <el-input class="p-2" v-model="filterValue" placeholder="æç´¢å¾æ " clearable @input="filterIcons" /> |
| | | <el-input v-model="filterValue" class="p-2" placeholder="æç´¢å¾æ " clearable @input="filterIcons" /> |
| | | |
| | | <el-scrollbar height="w-[200px]"> |
| | | <ul class="icon-list"> |
| | | <el-tooltip v-for="(iconName, index) in iconNames" :key="index" :content="iconName" placement="bottom" effect="light"> |
| | | <li :class="['icon-item', {active: modelValue == iconName}]" @click="selectedIcon(iconName)"> |
| | | <li :class="['icon-item', { active: modelValue == iconName }]" @click="selectedIcon(iconName)"> |
| | | <svg-icon color="var(--el-text-color-regular)" :icon-class="iconName" /> |
| | | </li> |
| | | </el-tooltip> |
| | |
| | | */ |
| | | const filterIcons = () => { |
| | | if (filterValue.value) { |
| | | iconNames.value = icons.filter(iconName => |
| | | iconName.includes(filterValue.value) |
| | | ); |
| | | iconNames.value = icons.filter((iconName) => iconName.includes(filterValue.value)); |
| | | } else { |
| | | iconNames.value = icons; |
| | | } |
| | | } |
| | | }; |
| | | /** |
| | | * 鿩徿 |
| | | * @param iconName éæ©ç徿 åç§° |
| | |
| | | const selectedIcon = (iconName: string) => { |
| | | emit('update:modelValue', iconName); |
| | | visible.value = false; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .el-scrollbar { |
| | | max-height: calc(50vh - 100px)!important; |
| | | max-height: calc(50vh - 100px) !important; |
| | | overflow-y: auto; |
| | | } |
| | | .el-divider--horizontal { |
| | |
| | | } |
| | | } |
| | | .active { |
| | | border-color: var(--el-color-primary); |
| | | color: var(--el-color-primary); |
| | | } |
| | | border-color: var(--el-color-primary); |
| | | color: var(--el-color-primary); |
| | | } |
| | | } |
| | | </style> |
| | |
| | | src: propTypes.string.def(''), |
| | | width: { |
| | | type: [Number, String], |
| | | default: "" |
| | | default: '' |
| | | }, |
| | | height: { |
| | | type: [Number, String], |
| | | default: "" |
| | | default: '' |
| | | } |
| | | }); |
| | | |
| | |
| | | if (!props.src) { |
| | | return; |
| | | } |
| | | let real_src = props.src.split(",")[0]; |
| | | let real_src = props.src.split(',')[0]; |
| | | return real_src; |
| | | }); |
| | | |
| | | const realSrcList = computed(() => { |
| | | if (!props.src) { |
| | | return; |
| | | return []; |
| | | } |
| | | let real_src_list = props.src.split(","); |
| | | let real_src_list = props.src.split(','); |
| | | let srcList: string[] = []; |
| | | real_src_list.forEach(item => { |
| | | real_src_list.forEach((item: string) => { |
| | | if(item.trim() === '') { |
| | | return; |
| | | } |
| | | return srcList.push(item); |
| | | }); |
| | | return srcList; |
| | | }); |
| | | |
| | | const realWidth = computed(() => |
| | | typeof props.width == "string" ? props.width : `${props.width}px` |
| | | ); |
| | | const realWidth = computed(() => (typeof props.width == 'string' ? props.width : `${props.width}px`)); |
| | | |
| | | const realHeight = computed(() => |
| | | typeof props.height == "string" ? props.height : `${props.height}px` |
| | | ); |
| | | const realHeight = computed(() => (typeof props.height == 'string' ? props.height : `${props.height}px`)); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | <template> |
| | | <div class="component-upload-image"> |
| | | <el-upload |
| | | ref="imageUpload" |
| | | multiple |
| | | :action="uploadImgUrl" |
| | | list-type="picture-card" |
| | |
| | | :limit="limit" |
| | | :on-error="handleUploadError" |
| | | :on-exceed="handleExceed" |
| | | ref="imageUpload" |
| | | :before-remove="handleDelete" |
| | | :show-file-list="true" |
| | | :headers="headers" |
| | |
| | | </el-icon> |
| | | </el-upload> |
| | | <!-- ä¸ä¼ æç¤º --> |
| | | <div class="el-upload__tip" v-if="showTip"> |
| | | <div v-if="showTip" class="el-upload__tip"> |
| | | 请ä¸ä¼ |
| | | <template v-if="fileSize"> |
| | | 大å°ä¸è¶
è¿ <b style="color: #f56c6c">{{ fileSize }}MB</b> |
| | | </template> |
| | | <template v-if="fileType"> |
| | | æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join("/") }}</b> |
| | | æ ¼å¼ä¸º <b style="color: #f56c6c">{{ fileType.join('/') }}</b> |
| | | </template> |
| | | çæä»¶ |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { listByIds, delOss } from "@/api/system/oss"; |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import { OssVO } from "@/api/system/oss/types"; |
| | | import { listByIds, delOss } from '@/api/system/oss'; |
| | | import { OssVO } from '@/api/system/oss/types'; |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | import {globalHeaders} from "@/utils/request"; |
| | | import { globalHeaders } from '@/utils/request'; |
| | | import { compressAccurately } from 'image-conversion'; |
| | | |
| | | const props = defineProps({ |
| | | modelValue: [String, Object, Array], |
| | | // å¾çæ°ééå¶ |
| | | limit: propTypes.number.def(5), |
| | | // 大å°éå¶(MB) |
| | | fileSize: propTypes.number.def(5), |
| | | // æä»¶ç±»å, ä¾å¦['png', 'jpg', 'jpeg'] |
| | | fileType: propTypes.array.def(["png", "jpg", "jpeg"]), |
| | | // æ¯å¦æ¾ç¤ºæç¤º |
| | | isShowTip: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | modelValue: { |
| | | type: [String, Object, Array], |
| | | default: () => [] |
| | | }, |
| | | // å¾çæ°ééå¶ |
| | | limit: propTypes.number.def(5), |
| | | // 大å°éå¶(MB) |
| | | fileSize: propTypes.number.def(5), |
| | | // æä»¶ç±»å, ä¾å¦['png', 'jpg', 'jpeg'] |
| | | fileType: propTypes.array.def(['png', 'jpg', 'jpeg']), |
| | | // æ¯å¦æ¾ç¤ºæç¤º |
| | | isShowTip: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | // æ¯å¦æ¯æå缩ï¼é»è®¤å¦ |
| | | compressSupport: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // åç¼©ç®æ 大å°ï¼åä½KBãé»è®¤300KB以䏿件æå缩ï¼å¹¶å缩è³300KB以å
|
| | | compressTargetSize: propTypes.number.def(300) |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const emit = defineEmits(['update:modelValue']); |
| | | const number = ref(0); |
| | | const uploadList = ref<any[]>([]); |
| | | const dialogImageUrl = ref(""); |
| | | const dialogImageUrl = ref(''); |
| | | const dialogVisible = ref(false); |
| | | |
| | | const baseUrl = import.meta.env.VITE_APP_BASE_API; |
| | | const uploadImgUrl = ref(baseUrl + "/resource/oss/upload"); // ä¸ä¼ çå¾çæå¡å¨å°å |
| | | const uploadImgUrl = ref(baseUrl + '/resource/oss/upload'); // ä¸ä¼ çå¾çæå¡å¨å°å |
| | | const headers = ref(globalHeaders()); |
| | | |
| | | const fileList = ref<any[]>([]); |
| | | const showTip = computed( |
| | | () => props.isShowTip && (props.fileType || props.fileSize) |
| | | ); |
| | | const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize)); |
| | | |
| | | const imageUploadRef = ref<ElUploadInstance>(); |
| | | |
| | | watch(() => props.modelValue, async val => { |
| | | watch( |
| | | () => props.modelValue, |
| | | async (val: string) => { |
| | | if (val) { |
| | | // é¦å
å°å¼è½¬ä¸ºæ°ç» |
| | | let list: OssVO[] = []; |
| | | if (Array.isArray(val)) { |
| | | list = val as OssVO[]; |
| | | // é¦å
å°å¼è½¬ä¸ºæ°ç» |
| | | let list: OssVO[] = []; |
| | | if (Array.isArray(val)) { |
| | | list = val as OssVO[]; |
| | | } else { |
| | | const res = await listByIds(val); |
| | | list = res.data; |
| | | } |
| | | // ç¶åå°æ°ç»è½¬ä¸ºå¯¹è±¡æ°ç» |
| | | fileList.value = list.map((item) => { |
| | | // åç¬¦ä¸²åæ¾å¤ç 妿æ¤å¤åçæ¯urlå¯ç´æ¥åæ¾ å¦æåçæ¯idéè¦è°ç¨æ¥å£æ¥åºæ¥ |
| | | let itemData; |
| | | if (typeof item === 'string') { |
| | | itemData = { name: item, url: item }; |
| | | } else { |
| | | const res = await listByIds(val as string) |
| | | list = res.data |
| | | // æ¤å¤name使ç¨ossId 鲿¢å é¤åºç°éå |
| | | itemData = { name: item.ossId, url: item.url, ossId: item.ossId }; |
| | | } |
| | | // ç¶åå°æ°ç»è½¬ä¸ºå¯¹è±¡æ°ç» |
| | | fileList.value = list.map(item => { |
| | | // åç¬¦ä¸²åæ¾å¤ç 妿æ¤å¤åçæ¯urlå¯ç´æ¥åæ¾ å¦æåçæ¯idéè¦è°ç¨æ¥å£æ¥åºæ¥ |
| | | let itemData; |
| | | if (typeof item === "string") { |
| | | itemData = { name: item, url: item }; |
| | | } else { |
| | | // æ¤å¤name使ç¨ossId 鲿¢å é¤åºç°éå |
| | | itemData = { name: item.ossId, url: item.url, ossId: item.ossId }; |
| | | } |
| | | return itemData; |
| | | }); |
| | | return itemData; |
| | | }); |
| | | } else { |
| | | fileList.value = []; |
| | | return []; |
| | | fileList.value = []; |
| | | return []; |
| | | } |
| | | }, { deep: true, immediate: true }); |
| | | }, |
| | | { deep: true, immediate: true } |
| | | ); |
| | | |
| | | /** ä¸ä¼ åloadingå è½½ */ |
| | | const handleBeforeUpload = (file: any) => { |
| | | let isImg = false; |
| | | if (props.fileType.length) { |
| | | let fileExtension = ""; |
| | | if (file.name.lastIndexOf(".") > -1) { |
| | | fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1); |
| | | } |
| | | isImg = props.fileType.some((type: any) => { |
| | | if (file.type.indexOf(type) > -1) return true; |
| | | if (fileExtension && fileExtension.indexOf(type) > -1) return true; |
| | | return false; |
| | | }); |
| | | } else { |
| | | isImg = file.type.indexOf("image") > -1; |
| | | let isImg = false; |
| | | if (props.fileType.length) { |
| | | let fileExtension = ''; |
| | | if (file.name.lastIndexOf('.') > -1) { |
| | | fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1); |
| | | } |
| | | if (!isImg) { |
| | | proxy?.$modal.msgError( |
| | | `æä»¶æ ¼å¼ä¸æ£ç¡®, 请ä¸ä¼ ${props.fileType.join("/")}å¾çæ ¼å¼æä»¶!` |
| | | ); |
| | | return false; |
| | | isImg = props.fileType.some((type: any) => { |
| | | if (file.type.indexOf(type) > -1) return true; |
| | | if (fileExtension && fileExtension.indexOf(type) > -1) return true; |
| | | return false; |
| | | }); |
| | | } else { |
| | | isImg = file.type.indexOf('image') > -1; |
| | | } |
| | | if (!isImg) { |
| | | proxy?.$modal.msgError(`æä»¶æ ¼å¼ä¸æ£ç¡®, 请ä¸ä¼ ${props.fileType.join('/')}å¾çæ ¼å¼æä»¶!`); |
| | | return false; |
| | | } |
| | | if (props.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < props.fileSize; |
| | | if (!isLt) { |
| | | proxy?.$modal.msgError(`ä¸ä¼ 头åå¾ç大å°ä¸è½è¶
è¿ ${props.fileSize} MB!`); |
| | | return false; |
| | | } |
| | | if (props.fileSize) { |
| | | const isLt = file.size / 1024 / 1024 < props.fileSize; |
| | | if (!isLt) { |
| | | proxy?.$modal.msgError(`ä¸ä¼ 头åå¾ç大å°ä¸è½è¶
è¿ ${props.fileSize} MB!`); |
| | | return false; |
| | | } |
| | | } |
| | | proxy?.$modal.loading("æ£å¨ä¸ä¼ å¾çï¼è¯·ç¨å..."); |
| | | } |
| | | |
| | | //å缩å¾çï¼å¼å¯å缩并ä¸å¤§äºæå®çåç¼©å¤§å°æ¶æå缩 |
| | | if (props.compressSupport && file.size / 1024 > props.compressTargetSize) { |
| | | proxy?.$modal.loading('æ£å¨ä¸ä¼ å¾çï¼è¯·ç¨å...'); |
| | | number.value++; |
| | | } |
| | | return compressAccurately(file, props.compressTargetSize); |
| | | } else { |
| | | proxy?.$modal.loading('æ£å¨ä¸ä¼ å¾çï¼è¯·ç¨å...'); |
| | | number.value++; |
| | | } |
| | | }; |
| | | |
| | | // æä»¶ä¸ªæ°è¶
åº |
| | | const handleExceed = () => { |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶æ°éä¸è½è¶
è¿ ${props.limit} 个!`); |
| | | } |
| | | proxy?.$modal.msgError(`ä¸ä¼ æä»¶æ°éä¸è½è¶
è¿ ${props.limit} 个!`); |
| | | }; |
| | | |
| | | // ä¸ä¼ æååè° |
| | | const handleUploadSuccess = (res: any, file: UploadFile) => { |
| | | if (res.code === 200) { |
| | | uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId }); |
| | | uploadedSuccessfully(); |
| | | } else { |
| | | number.value--; |
| | | proxy?.$modal.closeLoading(); |
| | | proxy?.$modal.msgError(res.msg); |
| | | imageUploadRef.value?.handleRemove(file); |
| | | uploadedSuccessfully(); |
| | | } |
| | | } |
| | | if (res.code === 200) { |
| | | uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId }); |
| | | uploadedSuccessfully(); |
| | | } else { |
| | | number.value--; |
| | | proxy?.$modal.closeLoading(); |
| | | proxy?.$modal.msgError(res.msg); |
| | | imageUploadRef.value?.handleRemove(file); |
| | | uploadedSuccessfully(); |
| | | } |
| | | }; |
| | | |
| | | // å é¤å¾ç |
| | | const handleDelete = (file: UploadFile): boolean => { |
| | | const findex = fileList.value.map(f => f.name).indexOf(file.name); |
| | | if (findex > -1 && uploadList.value.length === number.value) { |
| | | let ossId = fileList.value[findex].ossId; |
| | | delOss(ossId); |
| | | fileList.value.splice(findex, 1); |
| | | emit("update:modelValue", listToString(fileList.value)); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | const findex = fileList.value.map((f) => f.name).indexOf(file.name); |
| | | if (findex > -1 && uploadList.value.length === number.value) { |
| | | let ossId = fileList.value[findex].ossId; |
| | | delOss(ossId); |
| | | fileList.value.splice(findex, 1); |
| | | emit('update:modelValue', listToString(fileList.value)); |
| | | return false; |
| | | } |
| | | return true; |
| | | }; |
| | | |
| | | // ä¸ä¼ ç»æå¤ç |
| | | const uploadedSuccessfully = () => { |
| | | if (number.value > 0 && uploadList.value.length === number.value) { |
| | | fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value); |
| | | uploadList.value = []; |
| | | number.value = 0; |
| | | emit("update:modelValue", listToString(fileList.value)); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | } |
| | | if (number.value > 0 && uploadList.value.length === number.value) { |
| | | fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value); |
| | | uploadList.value = []; |
| | | number.value = 0; |
| | | emit('update:modelValue', listToString(fileList.value)); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ 失败 |
| | | const handleUploadError = () => { |
| | | proxy?.$modal.msgError("ä¸ä¼ å¾ç失败"); |
| | | proxy?.$modal.closeLoading(); |
| | | } |
| | | proxy?.$modal.msgError('ä¸ä¼ å¾ç失败'); |
| | | proxy?.$modal.closeLoading(); |
| | | }; |
| | | |
| | | // é¢è§ |
| | | const handlePictureCardPreview = (file: any) => { |
| | | dialogImageUrl.value = file.url; |
| | | dialogVisible.value = true; |
| | | } |
| | | dialogImageUrl.value = file.url; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | // 对象转ææå®å符串åé |
| | | const listToString = (list: any[], separator?: string) => { |
| | | let strs = ""; |
| | | separator = separator || ","; |
| | | for (let i in list) { |
| | | if (undefined !== list[i].ossId && list[i].url.indexOf("blob:") !== 0) { |
| | | strs += list[i].ossId + separator; |
| | | } |
| | | let strs = ''; |
| | | separator = separator || ','; |
| | | for (let i in list) { |
| | | if (undefined !== list[i].ossId && list[i].url.indexOf('blob:') !== 0) { |
| | | strs += list[i].ossId + separator; |
| | | } |
| | | return strs != "" ? strs.substring(0, strs.length - 1) : ""; |
| | | } |
| | | } |
| | | return strs != '' ? strs.substring(0, strs.length - 1) : ''; |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | // .el-upload--picture-card æ§å¶å å·é¨å |
| | | :deep(.hide .el-upload--picture-card) { |
| | | display: none; |
| | | display: none; |
| | | } |
| | | </style> |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | import { useI18n } from 'vue-i18n'; |
| | | import SvgIcon from '@/components/SvgIcon/index.vue'; |
| | | import { useAppStore } from '@/store/modules/app'; |
| | | import SvgIcon from '@/components/SvgIcon/index.vue'; |
| | | |
| | | const appStore = useAppStore(); |
| | | const { locale } = useI18n(); |
| | | |
| | | |
| | | const message: any = { |
| | | zh_CN: '忢è¯è¨æåï¼', |
| | | en_US: 'Switch Language Successful!', |
| | | } |
| | | const handleLanguageChange = (lang: string) => { |
| | | en_US: 'Switch Language Successful!' |
| | | }; |
| | | const handleLanguageChange = (lang: any) => { |
| | | locale.value = lang; |
| | | appStore.changeLanguage(lang); |
| | | ElMessage.success(message[lang] || '忢è¯è¨æåï¼'); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | <template> |
| | | <div :class="{ 'hidden': hidden }" class="pagination-container"> |
| | | <div :class="{ hidden: hidden }" class="pagination-container"> |
| | | <el-pagination |
| | | :background="background" |
| | | v-model:current-page="currentPage" |
| | | v-model:page-size="pageSize" |
| | | :background="background" |
| | | :layout="layout" |
| | | :page-sizes="pageSizes" |
| | | :pager-count="pagerCount" |
| | |
| | | |
| | | <script lang="ts"> |
| | | export default { |
| | | name: 'Pagination' |
| | | } |
| | | name: 'Pagination' |
| | | }; |
| | | </script> |
| | | |
| | | <script setup lang="ts"> |
| | | import { scrollTo } from '@/utils/scroll-to' |
| | | import { propTypes } from "@/utils/propTypes"; |
| | | import { scrollTo } from '@/utils/scroll-to'; |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | const props = defineProps({ |
| | | total: propTypes.number, |
| | | page: propTypes.number.def(1), |
| | | limit: propTypes.number.def(20), |
| | | pageSizes: { |
| | | type: Array as PropType<number[]>, |
| | | default: () => [10, 20, 30, 50] |
| | | }, |
| | | // ç§»å¨ç«¯é¡µç æé®çæ°é端é»è®¤å¼5 |
| | | pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7), |
| | | layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'), |
| | | background: propTypes.bool.def(true), |
| | | autoScroll: propTypes.bool.def(true), |
| | | hidden: propTypes.bool.def(false), |
| | | float: propTypes.string.def('right') |
| | | }) |
| | | total: propTypes.number, |
| | | page: propTypes.number.def(1), |
| | | limit: propTypes.number.def(20), |
| | | pageSizes: { |
| | | type: Array, |
| | | default: () => [10, 20, 30, 50] |
| | | }, |
| | | // ç§»å¨ç«¯é¡µç æé®çæ°é端é»è®¤å¼5 |
| | | pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7), |
| | | layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'), |
| | | background: propTypes.bool.def(true), |
| | | autoScroll: propTypes.bool.def(true), |
| | | hidden: propTypes.bool.def(false), |
| | | float: propTypes.string.def('right') |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:page', 'update:limit', 'pagination']); |
| | | const currentPage = computed({ |
| | | get() { |
| | | return props.page |
| | | }, |
| | | set(val) { |
| | | emit('update:page', val) |
| | | } |
| | | }) |
| | | get() { |
| | | return props.page; |
| | | }, |
| | | set(val) { |
| | | emit('update:page', val); |
| | | } |
| | | }); |
| | | const pageSize = computed({ |
| | | get() { |
| | | return props.limit |
| | | }, |
| | | set(val){ |
| | | emit('update:limit', val) |
| | | } |
| | | }) |
| | | get() { |
| | | return props.limit; |
| | | }, |
| | | set(val) { |
| | | emit('update:limit', val); |
| | | } |
| | | }); |
| | | function handleSizeChange(val: number) { |
| | | if (currentPage.value * val > props.total) { |
| | | currentPage.value = 1 |
| | | } |
| | | emit('pagination', { page: currentPage.value, limit: val }) |
| | | if (props.autoScroll) { |
| | | scrollTo(0, 800) |
| | | } |
| | | if (currentPage.value * val > props.total) { |
| | | currentPage.value = 1; |
| | | } |
| | | emit('pagination', { page: currentPage.value, limit: val }); |
| | | if (props.autoScroll) { |
| | | scrollTo(0, 800); |
| | | } |
| | | } |
| | | function handleCurrentChange(val: number) { |
| | | emit('pagination', { page: val, limit: pageSize.value }) |
| | | if (props.autoScroll) { |
| | | scrollTo(0, 800) |
| | | } |
| | | emit('pagination', { page: val, limit: pageSize.value }); |
| | | if (props.autoScroll) { |
| | | scrollTo(0, 800); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .pagination-container { |
| | | padding: 32px 16px; |
| | | .el-pagination{ |
| | | .el-pagination { |
| | | float: v-bind(float); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="container"> |
| | | <el-dialog v-model="visible" draggable title="审æ¹è®°å½" :width="props.width" :height="props.height" :close-on-click-modal="false"> |
| | | <el-tabs v-model="tabActiveName" class="demo-tabs"> |
| | | <el-tab-pane label="æµç¨å¾" name="bpmn"> |
| | | <BpmnView ref="bpmnViewRef"></BpmnView> |
| | | </el-tab-pane> |
| | | <el-tab-pane v-loading="loading" label="审æ¹ä¿¡æ¯" name="info"> |
| | | <div> |
| | | <el-table :data="historyList" style="width: 100%" border fit> |
| | | <el-table-column type="index" label="åºå·" align="center" width="60"></el-table-column> |
| | | <el-table-column prop="name" label="ä»»å¡åç§°" sortable align="center"></el-table-column> |
| | | <el-table-column prop="nickName" :show-overflow-tooltip="true" label="åç人" sortable align="center"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.nickName || 'æ ' }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" sortable align="center"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.statusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="comment" label="å®¡æ¹æè§" sortable align="center"></el-table-column> |
| | | <el-table-column prop="startTime" label="å¼å§æ¶é´" sortable align="center"></el-table-column> |
| | | <el-table-column prop="endTime" label="ç»ææ¶é´" sortable align="center"></el-table-column> |
| | | <el-table-column prop="runDuration" label="è¿è¡æ¶é¿" sortable align="center"></el-table-column> |
| | | <el-table-column prop="attachmentList" label="éä»¶" sortable align="center"> |
| | | <template #default="scope"> |
| | | <el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click"> |
| | | <template #reference> |
| | | <el-button style="margin-right: 16px">éä»¶</el-button> |
| | | </template> |
| | | <el-table border :data="scope.row.attachmentList"> |
| | | <el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="éä»¶åç§°"></el-table-column> |
| | | <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="æä½"> |
| | | <template #default="tool"> |
| | | <el-button type="text" @click="handleDownload(tool.row.contentId)">ä¸è½½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-popover> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import BpmnView from '@/components/BpmnView/index.vue'; |
| | | import processApi from '@/api/workflow/processInstance'; |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = defineProps({ |
| | | width: propTypes.string.def('70%'), |
| | | height: propTypes.string.def('100%') |
| | | }); |
| | | const loading = ref(false); |
| | | const visible = ref(false); |
| | | const historyList = ref<Array<any>>([]); |
| | | const tabActiveName = ref('bpmn'); |
| | | |
| | | const bpmnViewRef = ref<BpmnView>(); |
| | | |
| | | //åå§åæ¥è¯¢å®¡æ¹è®°å½ |
| | | const init = async (instanceId: string) => { |
| | | visible.value = true; |
| | | loading.value = true; |
| | | tabActiveName.value = 'bpmn'; |
| | | historyList.value = []; |
| | | processApi.getHistoryRecord(instanceId).then((resp) => { |
| | | historyList.value = resp.data; |
| | | loading.value = false; |
| | | }); |
| | | await nextTick(() => { |
| | | bpmnViewRef.value.init(instanceId); |
| | | }); |
| | | }; |
| | | |
| | | /** ä¸è½½æé®æä½ */ |
| | | const handleDownload = (ossId: string) => { |
| | | proxy?.$download.oss(ossId); |
| | | }; |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | init |
| | | }); |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .triangle { |
| | | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .triangle::after { |
| | | content: ' '; |
| | | position: absolute; |
| | | top: 8em; |
| | | right: 215px; |
| | | border: 15px solid; |
| | | border-color: transparent #fff transparent transparent; |
| | | } |
| | | |
| | | .container { |
| | | :deep(.el-dialog .el-dialog__body) { |
| | | max-height: calc(100vh - 170px) !important; |
| | | min-height: calc(100vh - 170px) !important; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" draggable :title="title" :width="width" :height="height" append-to-body |
| | | :close-on-click-modal="false"> |
| | | <div class="p-2" v-if="multiInstance === 'add'"> |
| | | <el-row :gutter="20"> |
| | | <!-- é¨é¨æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="deptName" placeholder="请è¾å
¥é¨é¨åç§°" prefix-icon="Search" clearable /> |
| | | <el-tree class="mt-2" ref="deptTreeRef" node-key="id" :data="deptOptions" |
| | | :props="{ label: 'label', children: 'children' }" :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" highlight-current default-expand-all |
| | | @node-click="handleNodeClick"></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" |
| | | :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="search" v-show="showSearch"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææºå·ç " prop="phonenumber"> |
| | | <el-input v-model="queryParams.phonenumber" placeholder="请è¾å
¥ææºå·ç " clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery" icon="Search">æç´¢</el-button> |
| | | <el-button @click="resetQuery" icon="Refresh">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10"> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="handleQuery" :search="true"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="userList" ref="multipleTableRef" row-key="userId" |
| | | @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | | <el-table-column label="ç¨æ·ç¼å·" align="center" key="userId" prop="userId" /> |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="ç¨æ·æµç§°" align="center" key="nickName" prop="nickName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="ææºå·ç " align="center" key="phonenumber" prop="phonenumber" width="120" /> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="160"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.createTime }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" @pagination="handleQuery" /> |
| | | </el-card> |
| | | <el-card shadow="hover"> |
| | | <el-tag v-for="(user, index) in chooseUserList" :key="user.userId" style="margin:2px" closable |
| | | @close="handleCloseTag(user, index)">{{ user.userName }} |
| | | </el-tag> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="p-2" v-if="multiInstance === 'delete'"> |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleTaskSelection"> |
| | | <el-table-column type="selection" width="55" /> |
| | | <el-table-column prop="name" label="ä»»å¡åç§°" /> |
| | | <el-table-column prop="assigneeName" label="åç人" /> |
| | | </el-table> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="visible = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup name="User" lang="ts"> |
| | | import { deptTreeSelect, listUser, optionSelect } from '@/api/system/user'; |
| | | import { |
| | | addMultiInstanceExecution, |
| | | deleteMultiInstanceExecution, |
| | | getTaskUserIdsByAddMultiInstance, |
| | | getListByDeleteMultiInstance |
| | | } from '@/api/workflow/task'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { DeptVO } from '@/api/system/dept/types'; |
| | | import { ComponentInternalInstance } from 'vue'; |
| | | import { ElTree, ElTable } from 'element-plus'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = defineProps({ |
| | | // 宽 |
| | | width: { |
| | | type: String, |
| | | default: '70%' |
| | | }, |
| | | // é« |
| | | height: { |
| | | type: String, |
| | | default: '100%' |
| | | }, |
| | | // æ é¢ |
| | | title: { |
| | | type: String, |
| | | default: 'å ç¾äººå' |
| | | }, |
| | | //æ¯å¦å¤é |
| | | multiple: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | //åæ¾ç¨æ·id |
| | | userIdList: { |
| | | type: Array, |
| | | default: [] |
| | | } |
| | | }); |
| | | const deptTreeRef = ref(ElTree); |
| | | const multipleTableRef = ref(ElTable); |
| | | |
| | | const userList = ref<UserVO[]>(); |
| | | const taskList = ref<Array<any>[]>(); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const selectionTask = ref<Array<any>[]>(); |
| | | const visible = ref(false); |
| | | const total = ref(0); |
| | | const deptName = ref(''); |
| | | const deptOptions = ref<DeptVO[]>([]); |
| | | const chooseUserList = ref(ref<UserVO[]>()); |
| | | const userIds = ref<Array<number | string>>([]); |
| | | //å ç¾æè
åç¾ |
| | | const multiInstance = ref(''); |
| | | const queryParams = ref<Record<string, any>>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | userName: '', |
| | | nickName: '', |
| | | taskId: '' |
| | | }); |
| | | /** æ¥è¯¢ç¨æ·å表 */ |
| | | const getAddMultiInstanceList = async (taskId: string, userIdList: Array<number | string>) => { |
| | | deptOptions.value = []; |
| | | getTreeSelect(); |
| | | multiInstance.value = 'add'; |
| | | userIds.value = userIdList; |
| | | visible.value = true; |
| | | queryParams.value.taskId = taskId; |
| | | loading.value = true; |
| | | const res1 = await getTaskUserIdsByAddMultiInstance(taskId); |
| | | queryParams.value.excludeUserIds = res1.data; |
| | | const res = await listUser(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await optionSelect(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res1 = await getTaskUserIdsByAddMultiInstance(queryParams.value.taskId); |
| | | queryParams.value.excludeUserIds = res1.data; |
| | | const res = await listUser(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await optionSelect(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const getDeleteMultiInstanceList = async (taskId: string) => { |
| | | deptOptions.value = []; |
| | | loading.value = true; |
| | | queryParams.value.taskId = taskId; |
| | | multiInstance.value = 'delete'; |
| | | visible.value = true; |
| | | const res = await getListByDeleteMultiInstance(taskId); |
| | | taskList.value = res.data; |
| | | loading.value = false; |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getAddMultiInstanceList(queryParams.value.taskId, userIds.value); |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.deptId = undefined; |
| | | queryParams.value.userName = undefined; |
| | | queryParams.value.nickName = undefined; |
| | | deptTreeRef.value.setCurrentKey(null); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** éæ©æ¡æ° */ |
| | | const handleSelectionChange = (selection: UserVO[]) => { |
| | | if (props.multiple) { |
| | | chooseUserList.value = selection.filter((element, index, self) => { |
| | | return self.findIndex((x) => x.userId === element.userId) === index; |
| | | }); |
| | | selection.forEach((u) => { |
| | | if (chooseUserList.value && !chooseUserList.value.includes(u)) { |
| | | multipleTableRef.value!.toggleRowSelection(u, undefined); |
| | | } |
| | | }); |
| | | userIds.value = chooseUserList.value.map((item) => { |
| | | return item.userId; |
| | | }); |
| | | } else { |
| | | chooseUserList.value = selection; |
| | | if (selection.length > 1) { |
| | | let delRow = selection.shift(); |
| | | multipleTableRef.value!.toggleRowSelection(delRow, undefined); |
| | | } |
| | | if (selection.length === 0) { |
| | | chooseUserList.value = []; |
| | | } |
| | | } |
| | | }; |
| | | /** éæ©æ¡æ° */ |
| | | const handleTaskSelection = (selection: any) => { |
| | | selectionTask.value = selection; |
| | | }; |
| | | |
| | | /** æ¥è¯¢é¨é¨ä¸ææ ç»æ */ |
| | | const getTreeSelect = async () => { |
| | | const res = await deptTreeSelect(); |
| | | deptOptions.value = res.data; |
| | | }; |
| | | |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | if (visible.value && deptOptions.value && deptOptions.value.length > 0) { |
| | | deptTreeRef.value.filter(deptName.value); |
| | | } |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: DeptVO) => { |
| | | queryParams.value.deptId = data.id; |
| | | getList(); |
| | | }; |
| | | //å é¤tag |
| | | const handleCloseTag = (user: UserVO, index: any) => { |
| | | if (multipleTableRef.value.selection && multipleTableRef.value.selection.length > 0) { |
| | | multipleTableRef.value.selection.forEach((u: UserVO, i: Number) => { |
| | | if (user.userId === u.userId) { |
| | | multipleTableRef.value.selection.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | if (chooseUserList.value && chooseUserList.value.length > 0) { |
| | | chooseUserList.value.splice(index, 1); |
| | | } |
| | | multipleTableRef.value.toggleRowSelection(user, undefined); |
| | | |
| | | if (userIds.value && userIds.value.length > 0) { |
| | | userIds.value.forEach((userId, i) => { |
| | | if (userId === user.userId) { |
| | | userIds.value.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | const submitFileForm = async () => { |
| | | if (multiInstance.value === 'add') { |
| | | if (chooseUserList.value && chooseUserList.value.length > 0) { |
| | | loading.value = true; |
| | | let userIds = chooseUserList.value.map((item) => { |
| | | return item.userId; |
| | | }); |
| | | let nickNames = chooseUserList.value.map((item) => { |
| | | return item.nickName; |
| | | }); |
| | | let params = { |
| | | taskId: queryParams.value.taskId, |
| | | assignees: userIds, |
| | | assigneeNames: nickNames |
| | | }; |
| | | await addMultiInstanceExecution(params); |
| | | emits('submitCallback'); |
| | | loading.value = false; |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | visible.value = false; |
| | | } |
| | | } else { |
| | | if (selectionTask.value && selectionTask.value.length > 0) { |
| | | loading.value = true; |
| | | let taskIds = selectionTask.value.map((item: any) => { |
| | | return item.id; |
| | | }); |
| | | let executionIds = selectionTask.value.map((item: any) => { |
| | | return item.executionId; |
| | | }); |
| | | let assigneeIds = selectionTask.value.map((item: any) => { |
| | | return item.assignee; |
| | | }); |
| | | let assigneeNames = selectionTask.value.map((item: any) => { |
| | | return item.assigneeName; |
| | | }); |
| | | let params = { |
| | | taskId: queryParams.value.taskId, |
| | | taskIds: taskIds, |
| | | executionIds: executionIds, |
| | | assigneeIds: assigneeIds, |
| | | assigneeNames: assigneeNames |
| | | }; |
| | | await deleteMultiInstanceExecution(params); |
| | | emits('submitCallback'); |
| | | loading.value = false; |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | visible.value = false; |
| | | } |
| | | } |
| | | }; |
| | | //äºä»¶ |
| | | const emits = defineEmits(['submitCallback']); |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | getAddMultiInstanceList, |
| | | getDeleteMultiInstanceList |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="50%" draggable :before-close="cancel" center :close-on-click-modal="false"> |
| | | <el-form v-loading="loading" :model="form" label-width="120px"> |
| | | <el-form-item label="æ¶æ¯æé"> |
| | | <el-checkbox-group v-model="form.messageType"> |
| | | <el-checkbox label="1" name="type" disabled>ç«å
ä¿¡</el-checkbox> |
| | | <el-checkbox label="2" name="type">é®ä»¶</el-checkbox> |
| | | <el-checkbox label="3" name="type">çä¿¡</el-checkbox> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | <el-form-item label="éä»¶" v-if="task.businessStatus === 'waiting'"> |
| | | <fileUpload v-model="form.fileId" :fileType="['doc', 'xls', 'ppt', 'txt', 'pdf', 'xlsx', 'docx', 'zip']" :fileSize="'20'"/> |
| | | </el-form-item> |
| | | <el-form-item label="æé"> |
| | | <el-button type="primary" @click="openUserSelectCopy" icon="Plus" circle /> |
| | | <el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)"> |
| | | {{ user.userName }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="å®¡æ¹æè§" v-if="task.businessStatus === 'waiting'"> |
| | | <el-input v-model="form.message" type="textarea" resize="none" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button v-loading="buttonLoading" type="primary" @click="handleCompleteTask"> æäº¤ </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting'" v-loading="buttonLoading" type="primary" @click="openDelegateTask"> å§æ </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting'" v-loading="buttonLoading" type="primary" @click="openTransferTask"> 转å </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting' && task.multiInstance" v-loading="buttonLoading" type="primary" @click="addMultiInstanceUser"> å ç¾ </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting' && task.multiInstance" v-loading="buttonLoading" type="primary" @click="deleteMultiInstanceUser"> åç¾ </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting'" v-loading="buttonLoading" type="danger" @click="handleTerminationTask"> ç»æ¢ </el-button> |
| | | <el-button v-if="task.businessStatus === 'waiting'" v-loading="buttonLoading" type="danger" @click="handleBackProcessOpen"> éå </el-button> |
| | | <el-button v-loading="buttonLoading" @click="cancel">åæ¶</el-button> |
| | | </span> |
| | | </template> |
| | | <!-- æé --> |
| | | <UserSelect ref="userSelectCopyRef" :multiple="true" :data="selectCopyUserIds" @confirm-call-back="userSelectCopyCallBack"></UserSelect> |
| | | <!-- 转å --> |
| | | <UserSelect ref="transferTaskRef" :multiple="false" @confirm-call-back="handleTransferTask"></UserSelect> |
| | | <!-- å§æ --> |
| | | <UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect> |
| | | <!-- å ç¾ç»ä»¶ --> |
| | | <multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback='closeDialog' /> |
| | | |
| | | <!-- 驳åå¼å§ --> |
| | | <el-dialog v-model="backVisible" draggable title="驳å" width="40%" :close-on-click-modal="false"> |
| | | <el-form v-loading="backLoading" :model="backForm" label-width="120px" v-if="task.businessStatus === 'waiting'"> |
| | | <el-form-item label="驳åèç¹"> |
| | | <el-select clearable placeholder="è¯·éæ©" v-model="backForm.targetActivityId" style="width: 300px"> |
| | | <el-option |
| | | v-for="item in taskNodeList" |
| | | :key="item.nodeId" |
| | | :label="item.nodeName" |
| | | :value="item.nodeId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¶æ¯æé"> |
| | | <el-checkbox-group v-model="backForm.messageType"> |
| | | <el-checkbox label="1" name="type" disabled>ç«å
ä¿¡</el-checkbox> |
| | | <el-checkbox label="2" name="type">é®ä»¶</el-checkbox> |
| | | <el-checkbox label="3" name="type">çä¿¡</el-checkbox> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | <el-form-item label="å®¡æ¹æè§"> |
| | | <el-input v-model="backForm.message" type="textarea" resize="none" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer" style="float: right;padding-bottom: 20px;"> |
| | | <el-button type="primary" v-loading="backLoading" @click="handleBackProcess">确认</el-button> |
| | | <el-button v-loading="backLoading" @click="backVisible = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 驳åç»æ --> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref } from 'vue'; |
| | | import { ComponentInternalInstance } from 'vue'; |
| | | import { ElForm } from 'element-plus'; |
| | | import { completeTask, backProcess, getTaskById,transferTask,terminationTask,getTaskNodeList,delegateTask } from '@/api/workflow/task'; |
| | | import UserSelect from '@/components/UserSelect'; |
| | | import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { TaskVO } from '@/api/workflow/task/types'; |
| | | const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const transferTaskRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const delegateTaskRef = ref<InstanceType<typeof UserSelect>>(); |
| | | |
| | | //å ç¾ç»ä»¶ |
| | | const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>(); |
| | | |
| | | const props = defineProps({ |
| | | taskVariables: { |
| | | type: Object as () => Record<string, any>, |
| | | default: {} |
| | | } |
| | | }); |
| | | //é®ç½©å± |
| | | const loading = ref(true); |
| | | //æé® |
| | | const buttonLoading = ref(true); |
| | | //ä»»å¡id |
| | | const taskId = ref<string>(''); |
| | | //æé人 |
| | | const selectCopyUserList = ref<UserVO[]>([]); |
| | | //æé人id |
| | | const selectCopyUserIds = ref<string>(undefined); |
| | | // 驳忝妿¾ç¤º |
| | | const backVisible = ref(false); |
| | | const backLoading = ref(true); |
| | | // å¯é©³åå¾ä»»å¡èç¹ |
| | | const taskNodeList = ref([]); |
| | | //ä»»å¡ |
| | | const task = ref<TaskVO>({ |
| | | id: undefined, |
| | | name: undefined, |
| | | description: undefined, |
| | | priority: undefined, |
| | | owner: undefined, |
| | | assignee: undefined, |
| | | assigneeName: undefined, |
| | | processInstanceId: undefined, |
| | | executionId: undefined, |
| | | taskDefinitionId: undefined, |
| | | processDefinitionId: undefined, |
| | | endTime: undefined, |
| | | taskDefinitionKey: undefined, |
| | | dueDate: undefined, |
| | | category: undefined, |
| | | parentTaskId: undefined, |
| | | tenantId: undefined, |
| | | claimTime: undefined, |
| | | businessStatus: undefined, |
| | | businessStatusName: undefined, |
| | | processDefinitionName: undefined, |
| | | processDefinitionKey: undefined, |
| | | participantVo: undefined, |
| | | multiInstance: undefined, |
| | | businessKey: undefined, |
| | | wfNodeConfigVo: undefined |
| | | }); |
| | | //å ç¾ åç¾æ é¢ |
| | | const title = ref(''); |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: 'æç¤º' |
| | | }); |
| | | |
| | | const form = ref<Record<string, any>>({ |
| | | taskId: undefined, |
| | | message: undefined, |
| | | variables: {}, |
| | | messageType: ['1'], |
| | | wfCopyList: [] |
| | | }); |
| | | const backForm = ref<Record<string, any>>({ |
| | | taskId: undefined, |
| | | targetActivityId: undefined, |
| | | message: undefined, |
| | | variables: {}, |
| | | messageType: ['1'] |
| | | }); |
| | | const closeDialog = () => { |
| | | dialog.visible = false |
| | | } |
| | | //æå¼å¼¹çª |
| | | const openDialog = (id?: string) => { |
| | | selectCopyUserIds.value = undefined |
| | | selectCopyUserList.value = [] |
| | | form.value.fileId = undefined |
| | | taskId.value = id; |
| | | form.value.message = undefined; |
| | | dialog.visible = true; |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | nextTick(() => { |
| | | getTaskById(taskId.value).then((response) => { |
| | | task.value = response.data; |
| | | loading.value = false; |
| | | buttonLoading.value = false; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => {}); |
| | | const emits = defineEmits(['submitCallback', 'cancelCallback']); |
| | | |
| | | /** åçæµç¨ */ |
| | | const handleCompleteTask = async () => { |
| | | form.value.taskId = taskId.value; |
| | | form.value.taskVariables = props.taskVariables; |
| | | if(selectCopyUserList && selectCopyUserList.value.length > 0){ |
| | | let wfCopyList = [] |
| | | selectCopyUserList.value.forEach( e=> { |
| | | let copyUser = { |
| | | userId: e.userId, |
| | | userName: e.nickName |
| | | } |
| | | wfCopyList.push(copyUser) |
| | | }) |
| | | form.value.wfCopyList = wfCopyList |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æäº¤ï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | try { |
| | | await completeTask(form.value); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | } finally { |
| | | loading.value = false |
| | | buttonLoading.value = false |
| | | } |
| | | }; |
| | | |
| | | /** 驳åå¼¹çªæå¼ */ |
| | | const handleBackProcessOpen = async () => { |
| | | backForm.value = {} |
| | | backForm.value.messageType = ['1'] |
| | | backVisible.value = true |
| | | backLoading.value = true |
| | | let data = await getTaskNodeList(task.value.processInstanceId) |
| | | taskNodeList.value = data.data |
| | | backLoading.value = false |
| | | backForm.value.targetActivityId = taskNodeList.value[0].nodeId |
| | | } |
| | | /** é©³åæµç¨ */ |
| | | const handleBackProcess = async () => { |
| | | backForm.value.taskId = taskId.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤é©³åå°ç³è¯·äººï¼'); |
| | | loading.value = true; |
| | | backLoading.value = true; |
| | | await backProcess(backForm.value).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | backLoading.value = false |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | //åæ¶ |
| | | const cancel = async () => { |
| | | dialog.visible = false; |
| | | buttonLoading.value = false; |
| | | emits('cancelCallback'); |
| | | }; |
| | | //æå¼æé人å |
| | | const openUserSelectCopy = () => { |
| | | userSelectCopyRef.value.open(); |
| | | }; |
| | | //确认æé人å |
| | | const userSelectCopyCallBack = (data: UserVO[]) => { |
| | | if(data && data.length > 0){ |
| | | selectCopyUserList.value = data |
| | | selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(','); |
| | | } |
| | | } |
| | | //å 餿é人å |
| | | const handleCopyCloseTag = (user: UserVO) => { |
| | | const userId = user.userId; |
| | | // 使ç¨splitå é¤ç¨æ· |
| | | const index = selectCopyUserList.value.findIndex((item) => item.userId === userId); |
| | | selectCopyUserList.value.splice(index, 1); |
| | | selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(','); |
| | | }; |
| | | //å ç¾ |
| | | const addMultiInstanceUser = () => { |
| | | if (multiInstanceUserRef.value) { |
| | | title.value = 'å ç¾äººå'; |
| | | multiInstanceUserRef.value.getAddMultiInstanceList(taskId.value, []); |
| | | } |
| | | }; |
| | | //åç¾ |
| | | const deleteMultiInstanceUser = () => { |
| | | if (multiInstanceUserRef.value) { |
| | | title.value = 'åç¾äººå'; |
| | | multiInstanceUserRef.value.getDeleteMultiInstanceList(taskId.value); |
| | | } |
| | | }; |
| | | //æå¼è½¬å |
| | | const openTransferTask = () => { |
| | | transferTaskRef.value.open(); |
| | | }; |
| | | //转å |
| | | const handleTransferTask = async (data) => { |
| | | if(data && data.length > 0){ |
| | | let params = { |
| | | taskId: taskId.value, |
| | | userId: data[0].userId, |
| | | comment: form.value.message |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æäº¤ï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | await transferTask(params).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }else{ |
| | | proxy?.$modal.msgWarning('è¯·éæ©ç¨æ·ï¼'); |
| | | } |
| | | } |
| | | |
| | | //æå¼å§æ |
| | | const openDelegateTask = () => { |
| | | delegateTaskRef.value.open(); |
| | | }; |
| | | //å§æ |
| | | const handleDelegateTask = async (data) => { |
| | | if(data && data.length > 0){ |
| | | let params = { |
| | | taskId: taskId.value, |
| | | userId: data[0].userId, |
| | | nickName: data[0].nickName |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æäº¤ï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | await delegateTask(params).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }else{ |
| | | proxy?.$modal.msgWarning('è¯·éæ©ç¨æ·ï¼'); |
| | | } |
| | | } |
| | | //ç»æ¢ä»»å¡ |
| | | const handleTerminationTask = async (data) => { |
| | | let params = { |
| | | taskId: taskId.value, |
| | | comment: form.value.message |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤ç»æ¢ï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | await terminationTask(params).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | openDialog |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="top-right-btn" :style="style"> |
| | | <el-row> |
| | | <el-tooltip class="item" effect="dark" :content="showSearch ? 'éèæç´¢' : 'æ¾ç¤ºæç´¢'" placement="top" v-if="search"> |
| | | <el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? 'éèæç´¢' : 'æ¾ç¤ºæç´¢'" placement="top"> |
| | | <el-button circle icon="Search" @click="toggleSearch()" /> |
| | | </el-tooltip> |
| | | <el-tooltip class="item" effect="dark" content="å·æ°" placement="top"> |
| | | <el-button circle icon="Refresh" @click="refresh()" /> |
| | | </el-tooltip> |
| | | <el-tooltip class="item" effect="dark" content="æ¾ç¤º/éèå" placement="top" v-if="columns"> |
| | | <el-tooltip v-if="columns" class="item" effect="dark" content="æ¾ç¤º/éèå" placement="top"> |
| | | <div class="show-btn"> |
| | | <el-popover placement="bottom" trigger="click"> |
| | | <div class="tree-header">æ¾ç¤º/éèå</div> |
| | |
| | | ref="columnRef" |
| | | :data="columns" |
| | | show-checkbox |
| | | @check="columnChange" |
| | | node-key="key" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | @check="columnChange" |
| | | ></el-tree> |
| | | <template #reference> |
| | | <el-button circle icon="Menu" /> |
| | |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | const props = defineProps({ |
| | | showSearch: propTypes.bool.def(true), |
| | | columns: { |
| | | type: Array as PropType<FieldOption[]>, |
| | | }, |
| | | search: propTypes.bool.def(true), |
| | | gutter: propTypes.number.def(10), |
| | | }) |
| | | showSearch: propTypes.bool.def(true), |
| | | columns: propTypes.fieldOption, |
| | | search: propTypes.bool.def(true), |
| | | gutter: propTypes.number.def(10) |
| | | }); |
| | | |
| | | const columnRef = ref<ElTreeInstance>(); |
| | | const emits = defineEmits(['update:showSearch', 'queryTable']); |
| | | |
| | | const style = computed(() => { |
| | | const ret: any = {}; |
| | | if (props.gutter) { |
| | | ret.marginRight = `${props.gutter / 2}px`; |
| | | } |
| | | return ret; |
| | | const ret: any = {}; |
| | | if (props.gutter) { |
| | | ret.marginRight = `${props.gutter / 2}px`; |
| | | } |
| | | return ret; |
| | | }); |
| | | |
| | | // æç´¢ |
| | | function toggleSearch() { |
| | | emits("update:showSearch", !props.showSearch); |
| | | emits('update:showSearch', !props.showSearch); |
| | | } |
| | | |
| | | // å·æ° |
| | | function refresh() { |
| | | emits("queryTable"); |
| | | emits('queryTable'); |
| | | } |
| | | |
| | | // æ´æ¹æ°æ®åçæ¾ç¤ºåéè |
| | | function columnChange(...args: any[]) { |
| | | props.columns?.forEach((item) => { |
| | | item.visible = args[1].checkedKeys.includes(item.key); |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | // æ¾éååå§é»è®¤éèå |
| | | onMounted(() => { |
| | | props.columns?.forEach((item) => { |
| | | if (item.visible) { |
| | | columnRef.value?.setChecked(item.key, true, false); |
| | | // value.value.push(item.key); |
| | | } |
| | | }) |
| | | }) |
| | | props.columns?.forEach((item) => { |
| | | if (item.visible) { |
| | | columnRef.value?.setChecked(item.key, true, false); |
| | | // value.value.push(item.key); |
| | | } |
| | | }); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | .my-el-transfer { |
| | | text-align: center; |
| | | } |
| | | .tree-header{ |
| | | .tree-header { |
| | | width: 100%; |
| | | line-height: 24px; |
| | | text-align: center; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog v-model="roleDialog.visible.value" :title="roleDialog.title.value" width="80%" append-to-body> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="è§è²åç§°" prop="roleName"> |
| | | <el-input v-model="queryParams.roleName" placeholder="请è¾å
¥è§è²åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æéå符" prop="roleKey"> |
| | | <el-input v-model="queryParams.roleKey" placeholder="请è¾å
¥æéå符" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-tag v-for="role in selectRoleList" :key="role.roleId" closable style="margin: 2px" @close="handleCloseTag(role)"> |
| | | {{ role.roleName }} |
| | | </el-tag> |
| | | </template> |
| | | |
| | | <vxe-table |
| | | ref="tableRef" |
| | | height="400px" |
| | | border |
| | | show-overflow |
| | | :data="roleList" |
| | | :loading="loading" |
| | | :row-config="{ keyField: 'roleId' }" |
| | | :checkbox-config="{ reserve: true, checkRowKeys: defaultSelectRoleIds }" |
| | | highlight-current-row |
| | | @checkbox-all="handleCheckboxAll" |
| | | @checkbox-change="handleCheckboxChange" |
| | | > |
| | | <vxe-column type="checkbox" width="50" align="center" /> |
| | | <vxe-column v-if="false" key="roleId" label="è§è²ç¼å·" /> |
| | | <vxe-column field="roleName" title="è§è²åç§°" /> |
| | | <vxe-column field="roleKey" title="æéå符" /> |
| | | <vxe-column field="roleSort" title="æ¾ç¤ºé¡ºåº" width="100" /> |
| | | <vxe-column title="ç¶æ" align="center" width="100"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_normal_disable" :value="scope.row.status"></dict-tag> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="createTime" title="å建æ¶é´" align="center"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <pagination |
| | | v-if="total > 0" |
| | | v-model:total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="pageList" |
| | | /> |
| | | </el-card> |
| | | <template #footer> |
| | | <el-button @click="close">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirm">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { RoleVO, RoleQuery } from '@/api/system/role/types'; |
| | | import { VxeTableInstance } from 'vxe-table'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | import api from '@/api/system/role'; |
| | | interface PropType { |
| | | modelValue?: RoleVO[] | RoleVO | undefined; |
| | | multiple?: boolean; |
| | | data?: string | number | (string | number)[]; |
| | | } |
| | | const prop = withDefaults(defineProps<PropType>(), { |
| | | multiple: true, |
| | | modelValue: undefined, |
| | | data: undefined |
| | | }); |
| | | const emit = defineEmits(['update:modelValue', 'confirmCallBack']); |
| | | |
| | | const router = useRouter(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); |
| | | |
| | | const roleList = ref<RoleVO[]>(); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const total = ref(0); |
| | | const dateRange = ref<[DateModelType, DateModelType]>(['', '']); |
| | | const selectRoleList = ref<RoleVO[]>([]); |
| | | |
| | | const roleDialog = useDialog({ |
| | | title: 'è§è²éæ©' |
| | | }); |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const tableRef = ref<VxeTableInstance<RoleVO>>(); |
| | | |
| | | const queryParams = ref<RoleQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | roleName: '', |
| | | roleKey: '', |
| | | status: '' |
| | | }); |
| | | |
| | | const defaultSelectRoleIds = computed(() => computedIds(prop.data)); |
| | | |
| | | const confirm = () => { |
| | | emit('update:modelValue', selectRoleList.value); |
| | | emit('confirmCallBack', selectRoleList.value); |
| | | roleDialog.closeDialog(); |
| | | }; |
| | | |
| | | const computedIds = (data) => { |
| | | if (data instanceof Array) { |
| | | return [...data]; |
| | | } else if (typeof data === 'string') { |
| | | return data.split(','); |
| | | } else if (typeof data === 'number') { |
| | | return [data]; |
| | | } else { |
| | | console.warn('<RoleSelect> The data type of data should be array or string or number, but I received other'); |
| | | return []; |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è§è²å表 |
| | | */ |
| | | const getList = () => { |
| | | loading.value = true; |
| | | api.listRole(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => { |
| | | roleList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | const pageList = async () => { |
| | | await getList(); |
| | | const roles = roleList.value.filter((item) => { |
| | | return selectRoleList.value.some((role) => role.roleId === item.roleId); |
| | | }); |
| | | await tableRef.value.setCheckboxRow(roles, true); |
| | | }; |
| | | /** |
| | | * æç´¢æé®æä½ |
| | | */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | /** éç½® */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const handleCheckboxChange = (checked) => { |
| | | if (!prop.multiple && checked.checked) { |
| | | tableRef.value.setCheckboxRow(selectRoleList.value, false); |
| | | selectRoleList.value = []; |
| | | } |
| | | const row = checked.row; |
| | | if (checked.checked) { |
| | | selectRoleList.value.push(row); |
| | | } else { |
| | | selectRoleList.value = selectRoleList.value.filter((item) => { |
| | | return item.roleId !== row.roleId; |
| | | }); |
| | | } |
| | | }; |
| | | const handleCheckboxAll = (checked) => { |
| | | const rows = roleList.value; |
| | | if (checked.checked) { |
| | | rows.forEach((row) => { |
| | | if (!selectRoleList.value.some((item) => item.roleId === row.roleId)) { |
| | | selectRoleList.value.push(row); |
| | | } |
| | | }); |
| | | } else { |
| | | selectRoleList.value = selectRoleList.value.filter((item) => { |
| | | return !rows.some((row) => row.roleId === item.roleId); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const handleCloseTag = (user: RoleVO) => { |
| | | const roleId = user.roleId; |
| | | // 使ç¨splitå é¤ç¨æ· |
| | | const index = selectRoleList.value.findIndex((item) => item.roleId === roleId); |
| | | const rows = selectRoleList.value[index]; |
| | | tableRef.value?.setCheckboxRow(rows, false); |
| | | selectRoleList.value.splice(index, 1); |
| | | }; |
| | | /** |
| | | * åå§åé䏿°æ® |
| | | */ |
| | | const initSelectRole = async () => { |
| | | if (defaultSelectRoleIds.value.length > 0) { |
| | | const { data } = await api.optionSelect(defaultSelectRoleIds.value); |
| | | selectRoleList.value = data; |
| | | const users = roleList.value.filter((item) => { |
| | | return defaultSelectRoleIds.value.includes(String(item.roleId)); |
| | | }); |
| | | await nextTick(() => { |
| | | tableRef.value.setCheckboxRow(users, true); |
| | | }); |
| | | } |
| | | }; |
| | | const close = () => { |
| | | roleDialog.closeDialog(); |
| | | }; |
| | | watch( |
| | | () => roleDialog.visible.value, |
| | | (newValue: boolean) => { |
| | | if (newValue) { |
| | | initSelectRole(); |
| | | } else { |
| | | tableRef.value.clearCheckboxReserve(); |
| | | tableRef.value.clearCheckboxRow(); |
| | | resetQuery(); |
| | | selectRoleList.value = []; |
| | | } |
| | | } |
| | | ); |
| | | onMounted(() => { |
| | | getList(); // åå§ååè¡¨æ°æ® |
| | | }); |
| | | |
| | | defineExpose({ |
| | | open: roleDialog.openDialog, |
| | | close: roleDialog.closeDialog |
| | | }); |
| | | </script> |
| | |
| | | const url = ref('https://plus-doc.dromara.org/'); |
| | | |
| | | function goto() { |
| | | window.open(url.value) |
| | | window.open(url.value); |
| | | } |
| | | </script> |
| | |
| | | const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus'); |
| | | |
| | | function goto() { |
| | | window.open(url.value) |
| | | window.open(url.value); |
| | | } |
| | | </script> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import useAppStore from "@/store/modules/app"; |
| | | import useAppStore from '@/store/modules/app'; |
| | | |
| | | const appStore = useAppStore(); |
| | | const size = computed(() => appStore.size); |
| | | |
| | | const sizeOptions = ref([ |
| | | { label: "è¾å¤§", value: "large" }, |
| | | { label: "é»è®¤", value: "default" }, |
| | | { label: "ç¨å°", value: "small" }, |
| | | { label: 'è¾å¤§', value: 'large' }, |
| | | { label: 'é»è®¤', value: 'default' }, |
| | | { label: 'ç¨å°', value: 'small' } |
| | | ]); |
| | | |
| | | const handleSetSize = (size: string) => { |
| | | appStore.setSize(size); |
| | | } |
| | | const handleSetSize = (size: 'large' | 'default' | 'small') => { |
| | | appStore.setSize(size); |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | const props = defineProps({ |
| | | iconClass: propTypes.string.isRequired, |
| | | className: propTypes.string.def(''), |
| | | color: propTypes.string.def(''), |
| | | }) |
| | | const iconName = computed(() => `#icon-${props.iconClass}`); |
| | | iconClass: propTypes.string.isRequired, |
| | | className: propTypes.string.def(''), |
| | | color: propTypes.string.def('') |
| | | }); |
| | | const iconName = computed(() => `#icon-${props.iconClass}`); |
| | | const svgClass = computed(() => { |
| | | if (props.className) { |
| | | return `svg-icon ${props.className}` |
| | | } |
| | | return 'svg-icon' |
| | | }) |
| | | if (props.className) { |
| | | return `svg-icon ${props.className}`; |
| | | } |
| | | return 'svg-icon'; |
| | | }); |
| | | </script> |
| | | |
| | | <style scope lang="scss"> |
| | |
| | | <template> |
| | | <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false"> |
| | | <el-menu :default-active="activeMenu" mode="horizontal" :ellipsis="false" @select="handleSelect"> |
| | | <template v-for="(item, index) in topMenus"> |
| | | <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber" |
| | | ><svg-icon |
| | | v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" |
| | | :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item |
| | | <el-menu-item v-if="index < visibleNumber" :key="index" :style="{ '--theme': theme }" :index="item.path" |
| | | ><svg-icon v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" :icon-class="item.meta ? item.meta.icon : ''" /> |
| | | {{ item.meta?.title }}</el-menu-item |
| | | > |
| | | </template> |
| | | |
| | | <!-- é¡¶é¨èåè¶
åºæ°éæå --> |
| | | <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber"> |
| | | <el-sub-menu v-if="topMenus.length > visibleNumber" :style="{ '--theme': theme }" index="more"> |
| | | <template #title>æ´å¤èå</template> |
| | | <template v-for="(item, index) in topMenus"> |
| | | <el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber" |
| | | ><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item |
| | | <el-menu-item v-if="index >= visibleNumber" :key="index" :index="item.path" |
| | | ><svg-icon :icon-class="item.meta ? item.meta.icon : ''" /> {{ item.meta?.title }}</el-menu-item |
| | | > |
| | | </template> |
| | | </el-sub-menu> |
| | |
| | | import useAppStore from '@/store/modules/app'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import { RouteOption } from 'vue-router'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | // 顶鍿 åå§æ° |
| | | const visibleNumber = ref<number>(-1); |
| | |
| | | // éèä¾§è¾¹æ è·¯ç± |
| | | const hideList = ['/index', '/user/profile']; |
| | | |
| | | const appStore = useAppStore() |
| | | const settingsStore = useSettingsStore() |
| | | const permissionStore = usePermissionStore() |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | |
| | | // 主é¢é¢è² |
| | | const theme = computed(() => settingsStore.theme); |
| | | // ææçè·¯ç±ä¿¡æ¯ |
| | | const routers = computed(() => permissionStore.topbarRouters); |
| | | const routers = computed(() => permissionStore.getTopbarRoutes()); |
| | | |
| | | // 顶鍿¾ç¤ºèå |
| | | const topMenus = computed(() => { |
| | | let topMenus:RouteOption[] = []; |
| | | let topMenus: RouteRecordRaw[] = []; |
| | | routers.value.map((menu) => { |
| | | if (menu.hidden !== true) { |
| | | // å
¼å®¹é¡¶é¨æ ä¸çº§èåå
é¨è·³è½¬ |
| | | if (menu.path === "/") { |
| | | topMenus.push(menu.children? menu.children[0] : menu); |
| | | if (menu.path === '/') { |
| | | topMenus.push(menu.children ? menu.children[0] : menu); |
| | | } else { |
| | | topMenus.push(menu); |
| | | topMenus.push(menu); |
| | | } |
| | | } |
| | | }) |
| | | }); |
| | | return topMenus; |
| | | }) |
| | | }); |
| | | |
| | | // 设置åè·¯ç± |
| | | const childrenMenus = computed(() => { |
| | | let childrenMenus:RouteOption[] = []; |
| | | let childrenMenus: RouteRecordRaw[] = []; |
| | | routers.value.map((router) => { |
| | | router.children?.forEach((item) => { |
| | | if (item.parentPath === undefined) { |
| | | if(router.path === "/") { |
| | | item.path = "/" + item.path; |
| | | if (router.path === '/') { |
| | | item.path = '/' + item.path; |
| | | } else { |
| | | if(!isHttp(item.path)) { |
| | | item.path = router.path + "/" + item.path; |
| | | if (!isHttp(item.path)) { |
| | | item.path = router.path + '/' + item.path; |
| | | } |
| | | } |
| | | item.parentPath = router.path; |
| | | } |
| | | childrenMenus.push(item); |
| | | }) |
| | | }) |
| | | }); |
| | | }); |
| | | return constantRoutes.concat(childrenMenus); |
| | | }) |
| | | }); |
| | | |
| | | // é»è®¤æ¿æ´»çèå |
| | | const activeMenu = computed(() => { |
| | | const path = route.path; |
| | | let path = route.path; |
| | | if (path === '/index') { |
| | | path = '/system/user'; |
| | | } |
| | | let activePath = path; |
| | | if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) { |
| | | if (path !== undefined && path.lastIndexOf('/') > 0 && hideList.indexOf(path) === -1) { |
| | | const tmpPath = path.substring(1, path.length); |
| | | activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/")); |
| | | activePath = '/' + tmpPath.substring(0, tmpPath.indexOf('/')); |
| | | if (!route.meta.link) { |
| | | appStore.toggleSideBarHide(false); |
| | | appStore.toggleSideBarHide(false); |
| | | } |
| | | } else if(!route.children) { |
| | | } else if (!route.children) { |
| | | activePath = path; |
| | | appStore.toggleSideBarHide(true); |
| | | } |
| | | activeRoutes(activePath); |
| | | return activePath; |
| | | }) |
| | | }); |
| | | |
| | | const setVisibleNumber = () => { |
| | | const width = document.body.getBoundingClientRect().width / 3; |
| | | visibleNumber.value = parseInt(String(width / 85)); |
| | | } |
| | | }; |
| | | |
| | | const handleSelect = (key: string) => { |
| | | currentIndex.value = key; |
| | | const route = routers.value.find(item => item.path === key); |
| | | const route = routers.value.find((item) => item.path === key); |
| | | if (isHttp(key)) { |
| | | // http(s):// è·¯å¾æ°çªå£æå¼ |
| | | window.open(key, "_blank"); |
| | | window.open(key, '_blank'); |
| | | } else if (!route || !route.children) { |
| | | // 没æåè·¯ç±è·¯å¾å
é¨æå¼ |
| | | const routeMenu = childrenMenus.value.find(item => item.path === key); |
| | | const routeMenu = childrenMenus.value.find((item) => item.path === key); |
| | | if (routeMenu && routeMenu.query) { |
| | | let query = JSON.parse(routeMenu.query); |
| | | router.push({ path: key, query: query }); |
| | |
| | | activeRoutes(key); |
| | | appStore.toggleSideBarHide(false); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const activeRoutes = (key: string) => { |
| | | let routes:RouteOption[] = []; |
| | | let routes: RouteRecordRaw[] = []; |
| | | if (childrenMenus.value && childrenMenus.value.length > 0) { |
| | | childrenMenus.value.map((item) => { |
| | | if (key == item.parentPath || (key == "index" && "" == item.path)) { |
| | | if (key == item.parentPath || (key == 'index' && '' == item.path)) { |
| | | routes.push(item); |
| | | } |
| | | }); |
| | | } |
| | | if(routes.length > 0) { |
| | | if (routes.length > 0) { |
| | | permissionStore.setSidebarRouters(routes); |
| | | } else { |
| | | appStore.toggleSideBarHide(true); |
| | | } |
| | | return routes; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | window.addEventListener('resize', setVisibleNumber) |
| | | }) |
| | | window.addEventListener('resize', setVisibleNumber); |
| | | }); |
| | | onBeforeUnmount(() => { |
| | | window.removeEventListener('resize', setVisibleNumber) |
| | | }) |
| | | window.removeEventListener('resize', setVisibleNumber); |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | setVisibleNumber() |
| | | }) |
| | | setVisibleNumber(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | |
| | | margin: 0 10px !important; |
| | | } |
| | | |
| | | .topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title { |
| | | .topmenu-container.el-menu--horizontal > .el-menu-item.is-active, |
| | | .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title { |
| | | border-bottom: 2px solid #{'var(--theme)'} !important; |
| | | color: #303133; |
| | | } |
| | |
| | | } |
| | | |
| | | /* èæ¯è²éè */ |
| | | .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover { |
| | | .topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):focus, |
| | | .topmenu-container.el-menu--horizontal > .el-menu-item:not(.is-disabled):hover, |
| | | .topmenu-container.el-menu--horizontal > .el-submenu .el-submenu__title:hover { |
| | | background-color: #ffffff !important; |
| | | } |
| | | |
| | |
| | | <template> |
| | | <div class="el-tree-select"> |
| | | <el-select |
| | | style="width: 100%" |
| | | v-model="valueId" |
| | | ref="treeSelect" |
| | | v-model="valueId" |
| | | style="width: 100%" |
| | | :filterable="true" |
| | | :clearable="true" |
| | | @clear="clearHandle" |
| | | :filter-method="selectFilterData" |
| | | :placeholder="placeholder" |
| | | @clear="clearHandle" |
| | | > |
| | | <el-option :value="valueId" :label="valueTitle"> |
| | | <el-tree |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | interface ObjMap { |
| | | value: string; |
| | | label: string; |
| | | children: string; |
| | | } |
| | | interface Props { |
| | | objMap: ObjMap; |
| | | accordion: boolean; |
| | | value: string | number; |
| | | options: any[]; |
| | | placeholder: string; |
| | | } |
| | | |
| | | const props = defineProps({ |
| | | /* é
置项 */ |
| | | objMap: { |
| | | type: Object, |
| | | default: () => { |
| | | return { |
| | | value: 'id', // IDåæ®µå |
| | | label: 'label', // æ¾ç¤ºåç§° |
| | | children: 'children' // åçº§åæ®µå |
| | | } |
| | | } |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | objMap: () => { |
| | | return { |
| | | value: 'id', |
| | | label: 'label', |
| | | children: 'children' |
| | | }; |
| | | }, |
| | | /* èªå¨æ¶èµ· */ |
| | | accordion: { |
| | | type: Boolean, |
| | | default: () => { |
| | | return false |
| | | } |
| | | }, |
| | | /**å½åååæ°æ®ç»å®çå¼ */ |
| | | value: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | /**å½åçæ°æ® */ |
| | | options: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | /**è¾å
¥æ¡å
é¨çæå */ |
| | | placeholder: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }) |
| | | |
| | | accordion: false, |
| | | value: '', |
| | | options: () => [], |
| | | placeholder: '' |
| | | }); |
| | | |
| | | const selectTree = ref<ElTreeSelectInstance>(); |
| | | |
| | |
| | | const valueId = computed({ |
| | | get: () => props.value, |
| | | set: (val) => { |
| | | emit('update:value', val) |
| | | emit('update:value', val); |
| | | } |
| | | }); |
| | | const valueTitle = ref(''); |
| | |
| | | const initHandle = () => { |
| | | nextTick(() => { |
| | | const selectedValue = valueId.value; |
| | | if (selectedValue !== null && typeof (selectedValue) !== 'undefined') { |
| | | const node = selectTree.value?.getNode(selectedValue) |
| | | if (selectedValue !== null && typeof selectedValue !== 'undefined') { |
| | | const node = selectTree.value?.getNode(selectedValue); |
| | | if (node) { |
| | | valueTitle.value = node.data[props.objMap.label] |
| | | selectTree.value?.setCurrentKey(selectedValue) // 设置é»è®¤éä¸ |
| | | defaultExpandedKey.value = [selectedValue] // 设置é»è®¤å±å¼ |
| | | valueTitle.value = node.data[props.objMap.label]; |
| | | selectTree.value?.setCurrentKey(selectedValue); // 设置é»è®¤éä¸ |
| | | defaultExpandedKey.value = [selectedValue]; // 设置é»è®¤å±å¼ |
| | | } |
| | | } else { |
| | | clearHandle() |
| | | clearHandle(); |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | const handleNodeClick = (node: any) => { |
| | | valueTitle.value = node[props.objMap.label] |
| | | valueTitle.value = node[props.objMap.label]; |
| | | valueId.value = node[props.objMap.value]; |
| | | defaultExpandedKey.value = []; |
| | | selectTree.value?.blur() |
| | | selectFilterData('') |
| | | } |
| | | selectTree.value?.blur(); |
| | | selectFilterData(''); |
| | | }; |
| | | const selectFilterData = (val: any) => { |
| | | selectTree.value?.filter(val) |
| | | } |
| | | selectTree.value?.filter(val); |
| | | }; |
| | | const filterNode = (value: any, data: any) => { |
| | | if (!value) return true |
| | | return data[props.objMap['label']].indexOf(value) !== -1 |
| | | } |
| | | if (!value) return true; |
| | | return data[props.objMap['label']].indexOf(value) !== -1; |
| | | }; |
| | | const clearHandle = () => { |
| | | valueTitle.value = '' |
| | | valueId.value = '' |
| | | valueTitle.value = ''; |
| | | valueId.value = ''; |
| | | defaultExpandedKey.value = []; |
| | | clearSelected() |
| | | } |
| | | clearSelected(); |
| | | }; |
| | | const clearSelected = () => { |
| | | const allNode = document.querySelectorAll('#tree-option .el-tree-node') |
| | | allNode.forEach((element) => element.classList.remove('is-current')) |
| | | } |
| | | const allNode = document.querySelectorAll('#tree-option .el-tree-node'); |
| | | allNode.forEach((element) => element.classList.remove('is-current')); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initHandle() |
| | | }) |
| | | initHandle(); |
| | | }); |
| | | |
| | | watch(valueId, () => { |
| | | initHandle(); |
| | | }) |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | @import "@/assets/styles/variables.module.scss"; |
| | | @import '@/assets/styles/variables.module.scss'; |
| | | |
| | | .el-scrollbar .el-scrollbar__view .el-select-dropdown__item { |
| | | padding: 0; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog v-model="userDialog.visible.value" :title="userDialog.title.value" width="80%" append-to-body> |
| | | <el-row :gutter="20"> |
| | | <!-- é¨é¨æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="deptName" placeholder="请è¾å
¥é¨é¨åç§°" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="deptTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="deptOptions" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææºå·ç " prop="phonenumber"> |
| | | <el-input |
| | | v-model="queryParams.phonenumber" |
| | | placeholder="请è¾å
¥ææºå·ç " |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="hover"> |
| | | <template v-if="prop.multiple" #header> |
| | | <el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)"> |
| | | {{ user.userName }} |
| | | </el-tag> |
| | | </template> |
| | | |
| | | <vxe-table |
| | | ref="tableRef" |
| | | height="400px" |
| | | border |
| | | show-overflow |
| | | :data="userList" |
| | | :loading="loading" |
| | | :row-config="{ keyField: 'userId', isHover: true }" |
| | | :checkbox-config="{ reserve: true, trigger: 'row', highlight: true, showHeader: prop.multiple }" |
| | | @checkbox-all="handleCheckboxAll" |
| | | @checkbox-change="handleCheckboxChange" |
| | | > |
| | | <vxe-column type="checkbox" width="50" align="center" /> |
| | | <vxe-column key="userId" title="ç¨æ·ç¼å·" align="center" field="userId" /> |
| | | <vxe-column key="userName" title="ç¨æ·åç§°" align="center" field="userName" /> |
| | | <vxe-column key="nickName" title="ç¨æ·æµç§°" align="center" field="nickName" /> |
| | | <vxe-column key="deptName" title="é¨é¨" align="center" field="deptName" /> |
| | | <vxe-column key="phonenumber" title="ææºå·ç " align="center" field="phonenumber" width="120" /> |
| | | <vxe-column key="status" title="ç¶æ" align="center"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_normal_disable" :value="scope.row.status"></dict-tag> |
| | | </template> |
| | | </vxe-column> |
| | | |
| | | <vxe-column title="å建æ¶é´" align="center" width="160"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.createTime }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="pageList" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <template #footer> |
| | | <el-button @click="close">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirm">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import api from '@/api/system/user'; |
| | | import { UserQuery, UserVO } from '@/api/system/user/types'; |
| | | import { DeptVO } from '@/api/system/dept/types'; |
| | | import { VxeTableInstance } from 'vxe-table'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | interface PropType { |
| | | modelValue?: UserVO[] | UserVO | undefined; |
| | | multiple?: boolean; |
| | | data?: string | number | (string | number)[]; |
| | | } |
| | | const prop = withDefaults(defineProps<PropType>(), { |
| | | multiple: true, |
| | | modelValue: undefined, |
| | | data: undefined |
| | | }); |
| | | const emit = defineEmits(['update:modelValue', 'confirmCallBack']); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); |
| | | |
| | | const userList = ref<UserVO[]>(); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const total = ref(0); |
| | | const dateRange = ref<[DateModelType, DateModelType]>(['', '']); |
| | | const deptName = ref(''); |
| | | const deptOptions = ref<DeptVO[]>([]); |
| | | const selectUserList = ref<UserVO[]>([]); |
| | | |
| | | const deptTreeRef = ref<ElTreeInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const tableRef = ref<VxeTableInstance<UserVO>>(); |
| | | |
| | | const userDialog = useDialog({ |
| | | title: 'ç¨æ·éæ©' |
| | | }); |
| | | |
| | | const queryParams = ref<UserQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | userName: '', |
| | | phonenumber: '', |
| | | status: '', |
| | | deptId: '', |
| | | roleId: '' |
| | | }); |
| | | |
| | | const defaultSelectUserIds = computed(() => computedIds(prop.data)); |
| | | |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | deptTreeRef.value?.filter(deptName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | const confirm = () => { |
| | | emit('update:modelValue', selectUserList.value); |
| | | emit('confirmCallBack', selectUserList.value); |
| | | userDialog.closeDialog(); |
| | | }; |
| | | |
| | | const computedIds = (data) => { |
| | | if (data instanceof Array) { |
| | | return [...data]; |
| | | } else if (typeof data === 'string') { |
| | | return data.split(','); |
| | | } else if (typeof data === 'number') { |
| | | return [data]; |
| | | } else { |
| | | console.warn('<UserSelect> The data type of data should be array or string or number, but I received other'); |
| | | return []; |
| | | } |
| | | }; |
| | | |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }; |
| | | |
| | | /** æ¥è¯¢é¨é¨ä¸ææ ç»æ */ |
| | | const getTreeSelect = async () => { |
| | | const res = await api.deptTreeSelect(); |
| | | deptOptions.value = res.data; |
| | | }; |
| | | |
| | | /** æ¥è¯¢ç¨æ·å表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | }; |
| | | |
| | | const pageList = async () => { |
| | | await getList(); |
| | | const users = userList.value.filter((item) => { |
| | | return selectUserList.value.some((user) => user.userId === item.userId); |
| | | }); |
| | | await tableRef.value.setCheckboxRow(users, true); |
| | | }; |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: DeptVO) => { |
| | | queryParams.value.deptId = data.id; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.deptId = undefined; |
| | | deptTreeRef.value?.setCurrentKey(undefined); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const handleCheckboxChange = (checked) => { |
| | | if (!prop.multiple && checked.checked) { |
| | | tableRef.value.setCheckboxRow(selectUserList.value, false); |
| | | selectUserList.value = []; |
| | | } |
| | | const row = checked.row; |
| | | if (checked.checked) { |
| | | selectUserList.value.push(row); |
| | | } else { |
| | | selectUserList.value = selectUserList.value.filter((item) => { |
| | | return item.userId !== row.userId; |
| | | }); |
| | | } |
| | | }; |
| | | const handleCheckboxAll = (checked) => { |
| | | const rows = userList.value; |
| | | if (checked.checked) { |
| | | rows.forEach((row) => { |
| | | if (!selectUserList.value.some((item) => item.userId === row.userId)) { |
| | | selectUserList.value.push(row); |
| | | } |
| | | }); |
| | | } else { |
| | | selectUserList.value = selectUserList.value.filter((item) => { |
| | | return !rows.some((row) => row.userId === item.userId); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const handleCloseTag = (user: UserVO) => { |
| | | const userId = user.userId; |
| | | // 使ç¨splitå é¤ç¨æ· |
| | | const index = selectUserList.value.findIndex((item) => item.userId === userId); |
| | | const rows = selectUserList.value[index]; |
| | | tableRef.value?.setCheckboxRow(rows, false); |
| | | selectUserList.value.splice(index, 1); |
| | | }; |
| | | |
| | | const initSelectUser = async () => { |
| | | if (defaultSelectUserIds.value.length > 0) { |
| | | const { data } = await api.optionSelect(defaultSelectUserIds.value); |
| | | selectUserList.value = data; |
| | | const users = userList.value.filter((item) => { |
| | | return defaultSelectUserIds.value.includes(String(item.userId)); |
| | | }); |
| | | await nextTick(() => { |
| | | tableRef.value.setCheckboxRow(users, true); |
| | | }); |
| | | } |
| | | }; |
| | | const close = () => { |
| | | userDialog.closeDialog(); |
| | | }; |
| | | |
| | | watch( |
| | | () => userDialog.visible.value, |
| | | (newValue: boolean) => { |
| | | if (newValue) { |
| | | initSelectUser(); |
| | | } else { |
| | | tableRef.value.clearCheckboxReserve(); |
| | | tableRef.value.clearCheckboxRow(); |
| | | resetQuery(); |
| | | selectUserList.value = []; |
| | | } |
| | | } |
| | | ); |
| | | |
| | | onMounted(() => { |
| | | getTreeSelect(); // åå§åé¨é¨æ°æ® |
| | | getList(); // åå§ååè¡¨æ°æ® |
| | | }); |
| | | |
| | | defineExpose({ |
| | | open: userDialog.openDialog, |
| | | close: userDialog.closeDialog |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | |
| | | |
| | | const props = defineProps({ |
| | | src: propTypes.string.isRequired |
| | | }) |
| | | }); |
| | | |
| | | const height = ref(document.documentElement.clientHeight - 94.5 + "px;") |
| | | const loading = ref(true) |
| | | const url = computed(() => props.src) |
| | | const height = ref(document.documentElement.clientHeight - 94.5 + 'px;'); |
| | | const loading = ref(true); |
| | | const url = computed(() => props.src); |
| | | |
| | | onMounted(() => { |
| | | setTimeout(() => { |
| | | loading.value = false; |
| | | }, 300); |
| | | window.onresize = function temp() { |
| | | height.value = document.documentElement.clientHeight - 94.5 + "px;"; |
| | | height.value = document.documentElement.clientHeight - 94.5 + 'px;'; |
| | | }; |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | * v-copyText å¤å¶ææ¬å
容 |
| | | * Copyright (c) 2022 ruoyi |
| | | */ |
| | | import { DirectiveBinding } from 'vue'; |
| | | |
| | | export default { |
| | | beforeMount(el: any, { value, arg }: any) { |
| | | beforeMount(el: any, { value, arg }: DirectiveBinding) { |
| | | if (arg === 'callback') { |
| | | el.$copyCallback = value; |
| | | } else { |
| | |
| | | // ãå
¶ä»è§è²ãæé®æéæ ¡éª |
| | | const { value } = binding; |
| | | if (value && value instanceof Array && value.length > 0) { |
| | | const hasPermission = permissions.some((permi) => { |
| | | const hasPermission = permissions.some((permi: string) => { |
| | | return permi === '*:*:*' || value.includes(permi); |
| | | }); |
| | | if (!hasPermission) { |
| | |
| | | const { value } = binding; |
| | | const { roles } = useUserStore(); |
| | | if (value && value instanceof Array && value.length > 0) { |
| | | const hasRole = roles.some((role) => { |
| | | const hasRole = roles.some((role: string) => { |
| | | return role === 'admin' || value.includes(role); |
| | | }); |
| | | if (!hasRole) { |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export enum LanguageEnum { |
| | | zh_CN = 'zh_CN', |
| | | |
| | | en_US = 'en_US' |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export enum AllocationTypeEnum { |
| | | USER = 'user', |
| | | CANDIDATE = 'candidate', |
| | | YOURSELF = 'yourself', |
| | | SPECIFY = 'specify' |
| | | } |
| | | |
| | | export enum SpecifyDescEnum { |
| | | SPECIFY_MULTIPLE = 'specifyMultiple', |
| | | SPECIFY_SINGLE = 'specifySingle' |
| | | } |
| | | |
| | | export enum MultiInstanceTypeEnum { |
| | | SERIAL = 'serial', |
| | | PARALLEL = 'parallel', |
| | | NONE = 'none' |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { Ref } from 'vue'; |
| | | |
| | | interface Options { |
| | | title?: string; |
| | | } |
| | | interface Return { |
| | | title: Ref<string>; |
| | | visible: Ref<boolean>; |
| | | openDialog: () => void; |
| | | closeDialog: () => void; |
| | | } |
| | | export default (ops?: Options): Return => { |
| | | const visible = ref(false); |
| | | const title = ref(ops.title || ''); |
| | | |
| | | const openDialog = () => { |
| | | visible.value = true; |
| | | }; |
| | | |
| | | const closeDialog = () => { |
| | | visible.value = false; |
| | | }; |
| | | |
| | | return { |
| | | title, |
| | | visible, |
| | | |
| | | openDialog, |
| | | closeDialog |
| | | }; |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "route": { |
| | | "dashboard": "Dashboard", |
| | | "document": "Document" |
| | | }, |
| | | "login": { |
| | | "username": "Username", |
| | | "password": "Password", |
| | | "login": "Login", |
| | | "code": "Verification Code", |
| | | "copyright": "" |
| | | }, |
| | | "navbar": { |
| | | "full": "Full Screen", |
| | | "language": "Language", |
| | | "dashboard": "Dashboard", |
| | | "document": "Document", |
| | | "message": "Message", |
| | | "layoutSize": "Layout Size", |
| | | "selectTenant": "Select Tenant", |
| | | "layoutSetting": "Layout Setting", |
| | | "personalCenter": "Personal Center", |
| | | "logout": "Logout" |
| | | } |
| | | } |
| | |
| | | // èªå®ä¹å½é
åé
ç½® |
| | | import { createI18n } from 'vue-i18n'; |
| | | |
| | | // æ¬å°è¯è¨å
|
| | | import enUSLocale from './en_US'; |
| | | import zhCNLocale from './zh_CN'; |
| | | |
| | | const messages = { |
| | | zh_CN: { |
| | | ...zhCNLocale |
| | | }, |
| | | en_US: { |
| | | ...enUSLocale |
| | | } |
| | | }; |
| | | import { LanguageEnum } from '@/enums/LanguageEnum'; |
| | | import messages from '@intlify/unplugin-vue-i18n/messages'; |
| | | |
| | | /** |
| | | * è·åå½åè¯è¨ |
| | | * @returns zh-cn|en ... |
| | | */ |
| | | export const getLanguage = () => { |
| | | const language = useStorage('language', 'zh_CN'); |
| | | export const getLanguage = (): LanguageEnum => { |
| | | const language = useStorage<LanguageEnum>('language', LanguageEnum.zh_CN); |
| | | if (language.value) { |
| | | return language.value; |
| | | } |
| | | return 'zh_CN'; |
| | | return LanguageEnum.zh_CN; |
| | | }; |
| | | |
| | | const i18n = createI18n({ |
| | | globalInjection: true, |
| | | allowComposition: true, |
| | | legacy: false, |
| | | locale: getLanguage(), |
| | | messages |
¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "route": { |
| | | "dashboard": "é¦é¡µ", |
| | | "document": "é¡¹ç®ææ¡£" |
| | | }, |
| | | "login": { |
| | | "username": "ç¨æ·å", |
| | | "password": "å¯ç ", |
| | | "login": "ç» å½", |
| | | "code": "请è¾å
¥éªè¯ç ", |
| | | "copyright": "" |
| | | }, |
| | | "navbar": { |
| | | "full": "å
¨å±", |
| | | "language": "è¯è¨", |
| | | "dashboard": "é¦é¡µ", |
| | | "document": "é¡¹ç®ææ¡£", |
| | | "message": "æ¶æ¯", |
| | | "layoutSize": "å¸å±å¤§å°", |
| | | "selectTenant": "éæ©ç§æ·", |
| | | "layoutSetting": "å¸å±è®¾ç½®", |
| | | "personalCenter": "个人ä¸å¿", |
| | | "logout": "éåºç»å½" |
| | | } |
| | | } |
| | |
| | | <section class="app-main"> |
| | | <router-view v-slot="{ Component, route }"> |
| | | <transition :enter-active-class="animante" mode="out-in"> |
| | | <keep-alive :include="tagsViewStore.cachedViews"> |
| | | <component v-if="!route.meta.link" :is="Component" :key="route.path" /> |
| | | </keep-alive> |
| | | <div> |
| | | <keep-alive :include="tagsViewStore.cachedViews" v-if="!route.meta.noCache"> |
| | | <component v-if="!route.meta.link" :is="Component" :key="route.path" /> |
| | | </keep-alive> |
| | | <component v-if="!route.meta.link && route.meta.noCache" :is="Component" :key="route.path" /> |
| | | </div> |
| | | </transition> |
| | | </router-view> |
| | | <iframe-toggle /> |
| | |
| | | </template> |
| | | |
| | | <script setup name="AppMain" lang="ts"> |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import IframeToggle from './IframeToggle/index.vue' |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | |
| | | import IframeToggle from './IframeToggle/index.vue'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const tagsViewStore = useTagsViewStore(); |
| | | |
| | | // éæºå¨ç»éå |
| | | const animante = ref<string>(''); |
| | | const animationEnable = ref(useSettingsStore().animationEnable); |
| | | watch(()=> useSettingsStore().animationEnable, (val) => { |
| | | watch( |
| | | () => useSettingsStore().animationEnable, |
| | | (val: boolean) => { |
| | | animationEnable.value = val; |
| | | if (val) { |
| | | animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string; |
| | | animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string; |
| | | } else { |
| | | animante.value = proxy?.animate.defaultAnimate as string; |
| | | animante.value = proxy?.animate.defaultAnimate as string; |
| | | } |
| | | }, { immediate: true }); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .fixed-header+.app-main { |
| | | .fixed-header + .app-main { |
| | | padding-top: 50px; |
| | | } |
| | | |
| | |
| | | min-height: calc(100vh - 84px); |
| | | } |
| | | |
| | | .fixed-header+.app-main { |
| | | .fixed-header + .app-main { |
| | | padding-top: 84px; |
| | | } |
| | | } |
| | |
| | | <template> |
| | | <transition-group name="fade-transform" mode="out-in"> |
| | | <inner-link |
| | | v-for="(item, index) in tagsViewStore.iframeViews" |
| | | :key="item.path" |
| | | :iframeId="'iframe' + index" |
| | | v-show="route.path === item.path" |
| | | :src="iframeUrl(item.meta ? item.meta.link : '', item.query)" |
| | | ></inner-link> |
| | | </transition-group> |
| | | <inner-link |
| | | v-for="(item, index) in tagsViewStore.iframeViews" |
| | | v-show="route.path === item.path" |
| | | :key="item.path" |
| | | :iframe-id="'iframe' + index" |
| | | :src="iframeUrl(item.meta ? item.meta.link : '', item.query)" |
| | | ></inner-link> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import InnerLink from "../InnerLink/index.vue"; |
| | | import InnerLink from '../InnerLink/index.vue'; |
| | | |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | |
| | | const route = useRoute(); |
| | | const tagsViewStore = useTagsViewStore(); |
| | | |
| | | function iframeUrl(url: string, query: any) { |
| | | function iframeUrl(url: string | undefined, query: any) { |
| | | if (Object.keys(query).length > 0) { |
| | | let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&"); |
| | | return url + "?" + params; |
| | | let params = Object.keys(query) |
| | | .map((key) => key + '=' + query[key]) |
| | | .join('&'); |
| | | return url + '?' + params; |
| | | } |
| | | return url; |
| | | } |
| | |
| | | <template> |
| | | <div :style="'height:' + height"> |
| | | <iframe :id="iframeId" style="width: 100%; height: 100%" :src="src" frameborder="no"></iframe> |
| | | <iframe :id="iframeId" style="width: 100%; height: 100%; border: 0" :src="src"></iframe> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { propTypes } from '@/utils/propTypes'; |
| | | |
| | | const props = defineProps({ |
| | | src: { |
| | | type: String, |
| | | default: "/" |
| | | }, |
| | | iframeId: { |
| | | type: String |
| | | } |
| | | src: propTypes.string.def('/'), |
| | | iframeId: propTypes.string.isRequired |
| | | }); |
| | | const height = ref(document.documentElement.clientHeight - 94.5 + "px"); |
| | | const height = ref(document.documentElement.clientHeight - 94.5 + 'px'); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="navbar"> |
| | | <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
| | | <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" /> |
| | | <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" /> |
| | | <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" /> |
| | | <breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" /> |
| | | <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" /> |
| | | |
| | | <div class="right-menu flex align-center"> |
| | | <template v-if="appStore.device !== 'mobile'"> |
| | | <el-select |
| | | v-if="userId === 1 && tenantEnabled" |
| | | v-model="companyName" |
| | | class="min-w-244px" |
| | | clearable |
| | | filterable |
| | | reserve-keyword |
| | | :placeholder="$t('navbar.selectTenant')" |
| | | v-if="userId === 1 && tenantEnabled" |
| | | @change="dynamicTenantEvent" |
| | | @clear="dynamicClearEvent" |
| | | > |
| | |
| | | </el-tooltip> |
| | | </template> |
| | | <div class="avatar-container"> |
| | | <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click"> |
| | | <el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand"> |
| | | <div class="avatar-wrapper"> |
| | | <img :src="userStore.avatar" class="user-avatar" /> |
| | | <el-icon><caret-bottom /></el-icon> |
| | | </div> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <router-link to="/user/profile" v-if="!dynamic"> |
| | | <router-link v-if="!dynamic" to="/user/profile"> |
| | | <el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item> |
| | | </router-link> |
| | | <el-dropdown-item command="setLayout" v-if="settingsStore.showSettings"> |
| | | <el-dropdown-item v-if="settingsStore.showSettings" command="setLayout"> |
| | | <span>{{ $t('navbar.layoutSetting') }}</span> |
| | | </el-dropdown-item> |
| | | <el-dropdown-item divided command="logout"> |
| | |
| | | import useAppStore from '@/store/modules/app'; |
| | | import useUserStore from '@/store/modules/user'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import { getTenantList } from "@/api/login"; |
| | | import { dynamicClear, dynamicTenant } from "@/api/system/tenant"; |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import { TenantVO } from "@/api/types"; |
| | | import notice from './notice/index.vue'; |
| | | import useNoticeStore from '@/store/modules/notice'; |
| | | import { getTenantList } from '@/api/login'; |
| | | import { dynamicClear, dynamicTenant } from '@/api/system/tenant'; |
| | | import { TenantVO } from '@/api/types'; |
| | | import notice from './notice/index.vue'; |
| | | |
| | | const appStore = useAppStore(); |
| | | const userStore = useUserStore(); |
| | |
| | | |
| | | const openSearchMenu = () => { |
| | | searchMenuRef.value?.openSearch(); |
| | | } |
| | | }; |
| | | |
| | | // 卿忢 |
| | | const dynamicTenantEvent = async (tenantId: string) => { |
| | |
| | | proxy?.$tab.closeAllPage(); |
| | | proxy?.$router.push('/'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const dynamicClearEvent = async () => { |
| | | await dynamicClear(); |
| | | dynamic.value = false; |
| | | proxy?.$tab.closeAllPage(); |
| | | proxy?.$router.push('/'); |
| | | } |
| | | }; |
| | | |
| | | /** ç§æ·å表 */ |
| | | const initTenantList = async () => { |
| | |
| | | if (tenantEnabled.value) { |
| | | tenantList.value = data.voList; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | initTenantList, |
| | | }) |
| | | initTenantList |
| | | }); |
| | | |
| | | const toggleSideBar = () => { |
| | | appStore.toggleSideBar(false); |
| | | } |
| | | }; |
| | | |
| | | const logout = async () => { |
| | | await ElMessageBox.confirm('ç¡®å®æ³¨éå¹¶éåºç³»ç»åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }) |
| | | await userStore.logout() |
| | | location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index'; |
| | | } |
| | | await ElMessageBox.confirm('ç¡®å®æ³¨éå¹¶éåºç³»ç»åï¼', 'æç¤º', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }); |
| | | await userStore.logout(); |
| | | location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index'; |
| | | }; |
| | | |
| | | const emits = defineEmits(['setLayout']) |
| | | const emits = defineEmits(['setLayout']); |
| | | const setLayout = () => { |
| | | emits('setLayout'); |
| | | } |
| | | emits('setLayout'); |
| | | }; |
| | | // å®ä¹Commandæ¹æ³å¯¹è±¡ éè¿keyç´æ¥è°ç¨æ¹æ³ |
| | | const commandMap: {[key: string]: any} = { |
| | | setLayout, |
| | | logout |
| | | const commandMap: { [key: string]: any } = { |
| | | setLayout, |
| | | logout |
| | | }; |
| | | const handleCommand = (command: string) => { |
| | | // 夿æ¯å¦åå¨è¯¥æ¹æ³ |
| | | if (commandMap[command]) { |
| | | commandMap[command](); |
| | | } |
| | | } |
| | | |
| | | // 夿æ¯å¦åå¨è¯¥æ¹æ³ |
| | | if (commandMap[command]) { |
| | | commandMap[command](); |
| | | } |
| | | }; |
| | | //ç¨æ·±åº¦çå¬ æ¶æ¯ |
| | | watch(() => noticeStore.state.value.notices, (newVal, oldVal) => { |
| | | newNotice.value = newVal.filter((item: any) => !item.read).length; |
| | | }, { deep: true }); |
| | | watch( |
| | | () => noticeStore.state.value.notices, |
| | | (newVal) => { |
| | | newNotice.value = newVal.filter((item: any) => !item.read).length; |
| | | }, |
| | | { deep: true } |
| | | ); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | |
| | | :deep(.el-select .el-input__wrapper) { |
| | | height:30px; |
| | | height: 30px; |
| | | } |
| | | |
| | | :deep(.el-badge__content.is-fixed){ |
| | | top: 12px; |
| | | :deep(.el-badge__content.is-fixed) { |
| | | top: 12px; |
| | | } |
| | | |
| | | .flex { |
| | |
| | | <template> |
| | | <el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal> |
| | | <el-drawer v-model="showSettings" :with-header="false" direction="rtl" size="300px" close-on-click-modal> |
| | | <h3 class="drawer-title">主é¢é£æ ¼è®¾ç½®</h3> |
| | | |
| | | <div class="setting-drawer-block-checbox"> |
| | | <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.DARK)"> |
| | | <img src="@/assets/images/dark.svg" alt="dark" /> |
| | | <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> |
| | | <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block"> |
| | | <i aria-label="徿 : check" class="anticon anticon-check"> |
| | | <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class> |
| | | <path |
| | |
| | | </div> |
| | | <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.LIGHT)"> |
| | | <img src="@/assets/images/light.svg" alt="light" /> |
| | | <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> |
| | | <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block"> |
| | | <i aria-label="徿 : check" class="anticon anticon-check"> |
| | | <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class> |
| | | <path |
| | |
| | | <div class="drawer-item"> |
| | | <span>æ·±è²æ¨¡å¼</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" /> |
| | | <el-switch v-model="isDark" class="drawer-switch" @change="toggleDark" /> |
| | | </span> |
| | | </div> |
| | | |
| | |
| | | <div class="drawer-item"> |
| | | <span>å¼å¯ TopNav</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="topNav" class="drawer-switch" /> |
| | | <el-switch v-model="settingsStore.topNav" class="drawer-switch" @change="topNavChange" /> |
| | | </span> |
| | | </div> |
| | | |
| | | <div class="drawer-item"> |
| | | <span>å¼å¯ Tags-Views</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="tagsView" class="drawer-switch" /> |
| | | <el-switch v-model="settingsStore.tagsView" class="drawer-switch" /> |
| | | </span> |
| | | </div> |
| | | |
| | | <div class="drawer-item"> |
| | | <span>åºå® Header</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="fixedHeader" class="drawer-switch" /> |
| | | <el-switch v-model="settingsStore.fixedHeader" class="drawer-switch" /> |
| | | </span> |
| | | </div> |
| | | |
| | | <div class="drawer-item"> |
| | | <span>æ¾ç¤º Logo</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="sidebarLogo" class="drawer-switch" /> |
| | | <el-switch v-model="settingsStore.sidebarLogo" class="drawer-switch" /> |
| | | </span> |
| | | </div> |
| | | |
| | | <div class="drawer-item"> |
| | | <span>卿æ é¢</span> |
| | | <span class="comp-style"> |
| | | <el-switch v-model="dynamicTitle" class="drawer-switch" /> |
| | | <el-switch v-model="settingsStore.dynamicTitle" class="drawer-switch" @change="dynamicTitleChange" /> |
| | | </span> |
| | | </div> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { useDynamicTitle } from '@/utils/dynamicTitle' |
| | | import useAppStore from '@/store/modules/app' |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import usePermissionStore from '@/store/modules/permission' |
| | | import { handleThemeStyle } from '@/utils/theme' |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import { SettingTypeEnum } from "@/enums/SettingTypeEnum"; |
| | | import { SideThemeEnum } from "@/enums/SideThemeEnum"; |
| | | import { useDynamicTitle } from '@/utils/dynamicTitle'; |
| | | import useAppStore from '@/store/modules/app'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import { handleThemeStyle } from '@/utils/theme'; |
| | | import { SideThemeEnum } from '@/enums/SideThemeEnum'; |
| | | import defaultSettings from '@/settings'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const appStore = useAppStore() |
| | | const settingsStore = useSettingsStore() |
| | | const permissionStore = usePermissionStore() |
| | | |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | |
| | | const showSettings = ref(false); |
| | | const theme = ref(settingsStore.theme); |
| | | const sideTheme = ref(settingsStore.sideTheme); |
| | | const storeSettings = computed(() => settingsStore); |
| | | const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]); |
| | | const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']); |
| | | |
| | | // æ¯å¦æé»æ¨¡å¼ |
| | | const isDark = useDark({ |
| | | storageKey: 'useDarkKey', |
| | | valueDark: 'dark', |
| | | valueLight: 'light', |
| | | valueLight: 'light' |
| | | }); |
| | | watch(isDark, ()=> { |
| | | // å¹é
èåé¢è² |
| | | watch(isDark, () => { |
| | | if (isDark.value) { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK }) |
| | | settingsStore.sideTheme = SideThemeEnum.DARK; |
| | | } else { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value }) |
| | | settingsStore.sideTheme = sideTheme.value; |
| | | } |
| | | }) |
| | | }); |
| | | const toggleDark = () => useToggle(isDark); |
| | | |
| | | /** æ¯å¦éè¦topNav */ |
| | | const topNav = computed({ |
| | | get: () => storeSettings.value.topNav, |
| | | set: (val) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.TOP_NAV, value: val }) |
| | | if (!val) { |
| | | appStore.toggleSideBarHide(false); |
| | | permissionStore.setSidebarRouters(permissionStore.defaultRoutes); |
| | | } |
| | | } |
| | | }) |
| | | /** æ¯å¦éè¦tagview */ |
| | | const tagsView = computed({ |
| | | get: () => storeSettings.value.tagsView, |
| | | set: (val) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.TAGS_VIEW, value: val }) |
| | | } |
| | | }) |
| | | /**æ¯å¦éè¦åºå®å¤´é¨ */ |
| | | const fixedHeader = computed({ |
| | | get: () => storeSettings.value.fixedHeader, |
| | | set: (val) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.FIXED_HEADER, value: val }) |
| | | } |
| | | }) |
| | | /**æ¯å¦éè¦ä¾§è¾¹æ çlogo */ |
| | | const sidebarLogo = computed({ |
| | | get: () => storeSettings.value.sidebarLogo, |
| | | set: (val) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.SIDEBAR_LOGO, value: val }) |
| | | } |
| | | }) |
| | | /**æ¯å¦éè¦ä¾§è¾¹æ ç卿ç½é¡µçtitle */ |
| | | const dynamicTitle = computed({ |
| | | get: () => storeSettings.value.dynamicTitle, |
| | | set: (val) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.DYNAMIC_TITLE, value: val }) |
| | | // å¨æè®¾ç½®ç½é¡µæ é¢ |
| | | useDynamicTitle() |
| | | } |
| | | }) |
| | | const topNavChange = (val: any) => { |
| | | if (!val) { |
| | | appStore.toggleSideBarHide(false); |
| | | permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any); |
| | | } |
| | | }; |
| | | |
| | | const themeChange = (val: string | null) => { |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.THEME, value: val }) |
| | | theme.value = val; |
| | | if (val) { |
| | | handleThemeStyle(val); |
| | | } |
| | | } |
| | | const dynamicTitleChange = () => { |
| | | // å¨æè®¾ç½®ç½é¡µæ é¢ |
| | | useDynamicTitle(); |
| | | }; |
| | | |
| | | const themeChange = (val: string) => { |
| | | settingsStore.theme = val; |
| | | handleThemeStyle(val); |
| | | }; |
| | | const handleTheme = (val: string) => { |
| | | sideTheme.value = val; |
| | | if (isDark.value && val === SideThemeEnum.LIGHT) { |
| | | // æé»æ¨¡å¼é¢è²ä¸å |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK }) |
| | | return |
| | | } |
| | | settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val }) |
| | | } |
| | | sideTheme.value = val; |
| | | if (isDark.value && val === SideThemeEnum.LIGHT) { |
| | | // æé»æ¨¡å¼é¢è²ä¸å |
| | | settingsStore.sideTheme = SideThemeEnum.DARK; |
| | | return; |
| | | } |
| | | settingsStore.sideTheme = val; |
| | | }; |
| | | const saveSetting = () => { |
| | | proxy?.$modal.loading("æ£å¨ä¿åå°æ¬å°ï¼è¯·ç¨å..."); |
| | | let layoutSetting = { |
| | | "topNav": storeSettings.value.topNav, |
| | | "tagsView": storeSettings.value.tagsView, |
| | | "fixedHeader": storeSettings.value.fixedHeader, |
| | | "sidebarLogo": storeSettings.value.sidebarLogo, |
| | | "dynamicTitle": storeSettings.value.dynamicTitle, |
| | | "sideTheme": storeSettings.value.sideTheme, |
| | | "theme": storeSettings.value.theme |
| | | }; |
| | | localStorage.setItem("layout-setting", JSON.stringify(layoutSetting)); |
| | | setTimeout(() => {proxy?.$modal.closeLoading()}, 1000) |
| | | } |
| | | proxy?.$modal.loading('æ£å¨ä¿åå°æ¬å°ï¼è¯·ç¨å...'); |
| | | const settings = useStorage<LayoutSetting>('layout-setting', defaultSettings); |
| | | settings.value.topNav = storeSettings.value.topNav; |
| | | settings.value.tagsView = storeSettings.value.tagsView; |
| | | settings.value.fixedHeader = storeSettings.value.fixedHeader; |
| | | settings.value.sidebarLogo = storeSettings.value.sidebarLogo; |
| | | settings.value.dynamicTitle = storeSettings.value.dynamicTitle; |
| | | settings.value.sideTheme = storeSettings.value.sideTheme; |
| | | settings.value.theme = storeSettings.value.theme; |
| | | setTimeout(() => { |
| | | proxy?.$modal.closeLoading(); |
| | | }, 1000); |
| | | }; |
| | | const resetSetting = () => { |
| | | proxy?.$modal.loading("æ£å¨æ¸
é¤è®¾ç½®ç¼åå¹¶å·æ°ï¼è¯·ç¨å..."); |
| | | localStorage.removeItem("layout-setting") |
| | | setTimeout("window.location.reload()", 1000) |
| | | } |
| | | proxy?.$modal.loading('æ£å¨æ¸
é¤è®¾ç½®ç¼åå¹¶å·æ°ï¼è¯·ç¨å...'); |
| | | useStorage<any>('layout-setting', null).value = null; |
| | | setTimeout('window.location.reload()', 1000); |
| | | }; |
| | | const openSetting = () => { |
| | | showSettings.value = true; |
| | | } |
| | | showSettings.value = true; |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openSetting, |
| | | }) |
| | | openSetting |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { isExternal } from '@/utils/validate' |
| | | import { isExternal } from '@/utils/validate'; |
| | | |
| | | const props = defineProps({ |
| | | to: { |
| | | type: [String, Object], |
| | | required: true |
| | | } |
| | | }) |
| | | to: { |
| | | type: [String, Object], |
| | | required: true |
| | | } |
| | | }); |
| | | |
| | | const isExt = computed(() => { |
| | | return isExternal(props.to as string) |
| | | }) |
| | | return isExternal(props.to as string); |
| | | }); |
| | | |
| | | const type = computed(() => { |
| | | if (isExt.value) { |
| | | return 'a' |
| | | } |
| | | return 'router-link' |
| | | }) |
| | | if (isExt.value) { |
| | | return 'a'; |
| | | } |
| | | return 'router-link'; |
| | | }); |
| | | |
| | | function linkProps() { |
| | | if (isExt.value) { |
| | | return { |
| | | href: props.to, |
| | | target: '_blank', |
| | | rel: 'noopener' |
| | | } |
| | | } |
| | | if (isExt.value) { |
| | | return { |
| | | to: props.to |
| | | } |
| | | href: props.to, |
| | | target: '_blank', |
| | | rel: 'noopener' |
| | | }; |
| | | } |
| | | return { |
| | | to: props.to |
| | | }; |
| | | } |
| | | </script> |
| | |
| | | <template> |
| | | <div |
| | | class="sidebar-logo-container" |
| | | :class="{ 'collapse': collapse }" |
| | | :class="{ collapse: collapse }" |
| | | :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }" |
| | | > |
| | | <transition :enter-active-class="proxy?.animate.logoAnimate.enter" mode="out-in"> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import variables from '@/assets/styles/variables.module.scss' |
| | | import logo from '@/assets/logo/logo.png' |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import variables from '@/assets/styles/variables.module.scss'; |
| | | import logo from '@/assets/logo/logo.png'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | defineProps({ |
| | | collapse: { |
| | | type: Boolean, |
| | | required: true |
| | | } |
| | | }) |
| | | collapse: { |
| | | type: Boolean, |
| | | required: true |
| | | } |
| | | }); |
| | | |
| | | const title = ref('RuoYi-Vue-Plus'); |
| | | const settingsStore = useSettingsStore(); |
| | |
| | | font-weight: 600; |
| | | line-height: 50px; |
| | | font-size: 14px; |
| | | font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; |
| | | font-family: |
| | | Avenir, |
| | | Helvetica Neue, |
| | | Arial, |
| | | Helvetica, |
| | | sans-serif; |
| | | vertical-align: middle; |
| | | } |
| | | } |
| | |
| | | |
| | | <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported> |
| | | <template v-if="item.meta" #title> |
| | | <svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> |
| | | <svg-icon :icon-class="item.meta ? item.meta.icon : ''" /> |
| | | <span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span> |
| | | </template> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { isExternal } from '@/utils/validate' |
| | | import AppLink from './Link.vue' |
| | | import { getNormalPath } from '@/utils/ruoyi' |
| | | import { RouteOption } from "vue-router"; |
| | | import { isExternal } from '@/utils/validate'; |
| | | import AppLink from './Link.vue'; |
| | | import { getNormalPath } from '@/utils/ruoyi'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | const props = defineProps({ |
| | | // route object |
| | | item: { |
| | | type: Object as PropType<RouteOption>, |
| | | required: true |
| | | }, |
| | | isNest: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | basePath: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }) |
| | | item: { |
| | | type: Object as PropType<RouteRecordRaw>, |
| | | required: true |
| | | }, |
| | | isNest: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | basePath: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }); |
| | | |
| | | const onlyOneChild = ref<any>({}); |
| | | |
| | | const hasOneShowingChild = (parent: RouteOption, children?:RouteOption[]) => { |
| | | if (!children) { |
| | | children = []; |
| | | const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => { |
| | | if (!children) { |
| | | children = []; |
| | | } |
| | | const showingChildren = children.filter((item) => { |
| | | if (item.hidden) { |
| | | return false; |
| | | } else { |
| | | // Temp set(will be used if only has one showing child) |
| | | onlyOneChild.value = item; |
| | | return true; |
| | | } |
| | | const showingChildren = children.filter(item => { |
| | | if (item.hidden) { |
| | | return false |
| | | } else { |
| | | // Temp set(will be used if only has one showing child) |
| | | onlyOneChild.value = item |
| | | return true |
| | | } |
| | | }) |
| | | }); |
| | | |
| | | // When there is only one child router, the child router is displayed by default |
| | | if (showingChildren.length === 1) { |
| | | return true |
| | | } |
| | | // When there is only one child router, the child router is displayed by default |
| | | if (showingChildren.length === 1) { |
| | | return true; |
| | | } |
| | | |
| | | // Show parent if there are no child router to display |
| | | if (showingChildren.length === 0) { |
| | | onlyOneChild.value = { ...parent, path: '', noShowingChildren: true } |
| | | if (parent.name === '2222') { |
| | | console.log(onlyOneChild.value) |
| | | } |
| | | return true |
| | | } |
| | | // Show parent if there are no child router to display |
| | | if (showingChildren.length === 0) { |
| | | onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }; |
| | | return true; |
| | | } |
| | | |
| | | |
| | | return false |
| | | return false; |
| | | }; |
| | | |
| | | const resolvePath = (routePath:string, routeQuery?:string): any => { |
| | | if (isExternal(routePath)) { |
| | | return routePath |
| | | } |
| | | if (isExternal(props.basePath)) { |
| | | return props.basePath |
| | | } |
| | | if (routeQuery) { |
| | | let query = JSON.parse(routeQuery); |
| | | return { path: getNormalPath(props.basePath + '/' + routePath), query: query } |
| | | } |
| | | return getNormalPath(props.basePath + '/' + routePath) |
| | | } |
| | | const resolvePath = (routePath: string, routeQuery?: string): any => { |
| | | if (isExternal(routePath)) { |
| | | return routePath; |
| | | } |
| | | if (isExternal(props.basePath as string)) { |
| | | return props.basePath; |
| | | } |
| | | if (routeQuery) { |
| | | let query = JSON.parse(routeQuery); |
| | | return { path: getNormalPath(props.basePath + '/' + routePath), query: query }; |
| | | } |
| | | return getNormalPath(props.basePath + '/' + routePath); |
| | | }; |
| | | |
| | | const hasTitle = (title: string | undefined): string => { |
| | | if(!title || title.length <= 5) { |
| | | return ""; |
| | | } |
| | | return title; |
| | | } |
| | | if (!title || title.length <= 5) { |
| | | return ''; |
| | | } |
| | | return title; |
| | | }; |
| | | </script> |
| | |
| | | :collapse-transition="false" |
| | | mode="vertical" |
| | | > |
| | | <sidebar-item v-for="(route, index) in sidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" /> |
| | | <sidebar-item v-for="(r, index) in sidebarRouters" :key="r.path + index" :item="r" :base-path="r.path" /> |
| | | </el-menu> |
| | | </transition> |
| | | </el-scrollbar> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import Logo from './Logo.vue' |
| | | import SidebarItem from './SidebarItem.vue' |
| | | import variables from '@/assets/styles/variables.module.scss' |
| | | import useAppStore from '@/store/modules/app' |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import usePermissionStore from '@/store/modules/permission' |
| | | import { RouteOption } from "vue-router"; |
| | | import Logo from './Logo.vue'; |
| | | import SidebarItem from './SidebarItem.vue'; |
| | | import variables from '@/assets/styles/variables.module.scss'; |
| | | import useAppStore from '@/store/modules/app'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const route = useRoute(); |
| | | const appStore = useAppStore() |
| | | const settingsStore = useSettingsStore() |
| | | const permissionStore = usePermissionStore() |
| | | |
| | | const sidebarRouters = computed<RouteOption[]>(() => permissionStore.sidebarRouters); |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | const sidebarRouters = computed<RouteRecordRaw[]>(() => permissionStore.getSidebarRoutes()); |
| | | const showLogo = computed(() => settingsStore.sidebarLogo); |
| | | const sideTheme = computed(() => settingsStore.sideTheme); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const isCollapse = computed(() => !appStore.sidebar.opened); |
| | | |
| | | const activeMenu = computed(() => { |
| | | const { meta, path } = route; |
| | | // if set path, the sidebar will highlight the path you set |
| | | if (meta.activeMenu) { |
| | | return meta.activeMenu; |
| | | } |
| | | return path; |
| | | }) |
| | | const { meta, path } = route; |
| | | // if set path, the sidebar will highlight the path you set |
| | | if (meta.activeMenu) { |
| | | return meta.activeMenu; |
| | | } |
| | | return path; |
| | | }); |
| | | |
| | | const bgColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground); |
| | | const textColor = computed(() => sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor); |
| | | const bgColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground)); |
| | | const textColor = computed(() => (sideTheme.value === 'theme-dark' ? variables.menuColor : variables.menuLightColor)); |
| | | </script> |
| | |
| | | const route = useRoute(); |
| | | const loading = ref(true); |
| | | |
| | | |
| | | /** |
| | | * æ¥æ¶Routeä¼ éçåæ° |
| | | * @param {Object} route.query. |
| | |
| | | const code = route.query.code as string; |
| | | const state = route.query.state as string; |
| | | const source = route.query.source as string; |
| | | const tenantId = localStorage.getItem("tenantId") ? localStorage.getItem("tenantId") as string : '000000'; |
| | | |
| | | const tenantId = localStorage.getItem('tenantId') ? (localStorage.getItem('tenantId') as string) : '000000'; |
| | | |
| | | const processResponse = async (res: any) => { |
| | | if (res.code !== 200) { |
| | |
| | | }; |
| | | |
| | | const loginByCode = async (data: LoginData) => { |
| | | console.log(2) |
| | | try { |
| | | const res = await login(data); |
| | | await processResponse(res); |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import useTagsViewStore from '@/store/modules/tagsView' |
| | | import { TagView } from 'vue-router' |
| | | import { RouteLocationNormalized } from 'vue-router'; |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | |
| | | const tagAndTagSpacing = ref(4); |
| | | |
| | | const scrollContainerRef = ref<ElScrollbarInstance>() |
| | | const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any); |
| | | const scrollContainerRef = ref<ElScrollbarInstance>(); |
| | | const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef); |
| | | |
| | | onMounted(() => { |
| | | scrollWrapper.value?.addEventListener('scroll', emitScroll, true) |
| | | }) |
| | | scrollWrapper.value?.addEventListener('scroll', emitScroll, true); |
| | | }); |
| | | onBeforeUnmount(() => { |
| | | scrollWrapper.value?.removeEventListener('scroll', emitScroll) |
| | | }) |
| | | scrollWrapper.value?.removeEventListener('scroll', emitScroll); |
| | | }); |
| | | |
| | | const handleScroll = (e: WheelEvent) => { |
| | | const eventDelta = (e as any).wheelDelta || - e.deltaY * 40 |
| | | const $scrollWrapper = scrollWrapper.value; |
| | | $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 |
| | | } |
| | | const emits = defineEmits(['scroll']) |
| | | const eventDelta = (e as any).wheelDelta || -e.deltaY * 40; |
| | | const $scrollWrapper = scrollWrapper.value; |
| | | $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4; |
| | | }; |
| | | const emits = defineEmits(['scroll']); |
| | | const emitScroll = () => { |
| | | emits('scroll') |
| | | } |
| | | emits('scroll'); |
| | | }; |
| | | |
| | | const tagsViewStore = useTagsViewStore() |
| | | const tagsViewStore = useTagsViewStore(); |
| | | const visitedViews = computed(() => tagsViewStore.visitedViews); |
| | | |
| | | const moveToTarget = (currentTag: TagView) => { |
| | | const $container = scrollContainerRef.value?.$el |
| | | const $containerWidth = $container.offsetWidth |
| | | const $scrollWrapper = scrollWrapper.value; |
| | | const moveToTarget = (currentTag: RouteLocationNormalized) => { |
| | | const $container = scrollContainerRef.value?.$el; |
| | | const $containerWidth = $container.offsetWidth; |
| | | const $scrollWrapper = scrollWrapper.value; |
| | | |
| | | let firstTag = null |
| | | let lastTag = null |
| | | let firstTag = null; |
| | | let lastTag = null; |
| | | |
| | | // find first tag and last tag |
| | | if (visitedViews.value.length > 0) { |
| | | firstTag = visitedViews.value[0] |
| | | lastTag = visitedViews.value[visitedViews.value.length - 1] |
| | | // find first tag and last tag |
| | | if (visitedViews.value.length > 0) { |
| | | firstTag = visitedViews.value[0]; |
| | | lastTag = visitedViews.value[visitedViews.value.length - 1]; |
| | | } |
| | | |
| | | if (firstTag === currentTag) { |
| | | $scrollWrapper.scrollLeft = 0; |
| | | } else if (lastTag === currentTag) { |
| | | $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth; |
| | | } else { |
| | | const tagListDom: any = document.getElementsByClassName('tags-view-item'); |
| | | const currentIndex = visitedViews.value.findIndex((item) => item === currentTag); |
| | | let prevTag = null; |
| | | let nextTag = null; |
| | | |
| | | for (const k in tagListDom) { |
| | | if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) { |
| | | if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) { |
| | | prevTag = tagListDom[k]; |
| | | } |
| | | if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) { |
| | | nextTag = tagListDom[k]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (firstTag === currentTag) { |
| | | $scrollWrapper.scrollLeft = 0 |
| | | } else if (lastTag === currentTag) { |
| | | $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth |
| | | } else { |
| | | const tagListDom: any = document.getElementsByClassName('tags-view-item'); |
| | | const currentIndex = visitedViews.value.findIndex(item => item === currentTag) |
| | | let prevTag = null |
| | | let nextTag = null |
| | | // the tag's offsetLeft after of nextTag |
| | | const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value; |
| | | |
| | | for (const k in tagListDom) { |
| | | if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) { |
| | | if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) { |
| | | prevTag = tagListDom[k]; |
| | | } |
| | | if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) { |
| | | nextTag = tagListDom[k]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // the tag's offsetLeft after of nextTag |
| | | const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing.value |
| | | |
| | | // the tag's offsetLeft before of prevTag |
| | | const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value |
| | | if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) { |
| | | $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth |
| | | } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) { |
| | | $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft |
| | | } |
| | | // the tag's offsetLeft before of prevTag |
| | | const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing.value; |
| | | if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) { |
| | | $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth; |
| | | } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) { |
| | | $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | moveToTarget, |
| | | }) |
| | | moveToTarget |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | > |
| | | {{ tag.title }} |
| | | <span v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)"> |
| | | <close class="el-icon-close" style="width: 1em; height: 1em;vertical-align: middle;" /> |
| | | <close class="el-icon-close" style="width: 1em; height: 1em; vertical-align: middle" /> |
| | | </span> |
| | | </router-link> |
| | | </scroll-pane> |
| | | <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu"> |
| | | <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em;" /> å·æ°é¡µé¢</li> |
| | | <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em;" /> å
³éå½å</li> |
| | | <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em;" /> å
³éå
¶ä»</li> |
| | | <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em;" /> å
³é左侧</li> |
| | | <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em;" /> å
³éå³ä¾§</li> |
| | | <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em;" /> å
¨é¨å
³é</li> |
| | | <li @click="refreshSelectedTag(selectedTag)"><refresh-right style="width: 1em; height: 1em" /> å·æ°é¡µé¢</li> |
| | | <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><close style="width: 1em; height: 1em" /> å
³éå½å</li> |
| | | <li @click="closeOthersTags"><circle-close style="width: 1em; height: 1em" /> å
³éå
¶ä»</li> |
| | | <li v-if="!isFirstView()" @click="closeLeftTags"><back style="width: 1em; height: 1em" /> å
³é左侧</li> |
| | | <li v-if="!isLastView()" @click="closeRightTags"><right style="width: 1em; height: 1em" /> å
³éå³ä¾§</li> |
| | | <li @click="closeAllTags(selectedTag)"><circle-close style="width: 1em; height: 1em" /> å
¨é¨å
³é</li> |
| | | </ul> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import ScrollPane from './ScrollPane.vue' |
| | | import { getNormalPath } from '@/utils/ruoyi' |
| | | import useTagsViewStore from "@/store/modules/tagsView"; |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import usePermissionStore from '@/store/modules/permission' |
| | | import { ComponentInternalInstance } from "vue"; |
| | | import { RouteOption, TagView, RouteLocationRaw } from "vue-router"; |
| | | import ScrollPane from './ScrollPane.vue'; |
| | | import { getNormalPath } from '@/utils/ruoyi'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | import { RouteRecordRaw, RouteLocationNormalized } from 'vue-router'; |
| | | |
| | | const visible = ref(false); |
| | | const top = ref(0); |
| | | const left = ref(0); |
| | | const selectedTag = ref<TagView>({}); |
| | | const affixTags = ref<TagView[]>([]); |
| | | const scrollPaneRef = ref(ScrollPane); |
| | | const selectedTag = ref<RouteLocationNormalized>(); |
| | | const affixTags = ref<RouteLocationNormalized[]>([]); |
| | | const scrollPaneRef = ref<InstanceType<typeof ScrollPane>>(); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | |
| | | const visitedViews = computed(() => useTagsViewStore().visitedViews); |
| | | const routes = computed(() => usePermissionStore().routes); |
| | | const visitedViews = computed(() => useTagsViewStore().getVisitedViews()); |
| | | const routes = computed(() => usePermissionStore().getRoutes()); |
| | | const theme = computed(() => useSettingsStore().theme); |
| | | |
| | | watch(route, () => { |
| | | addTags(); |
| | | moveToCurrentTag(); |
| | | }) |
| | | addTags(); |
| | | moveToCurrentTag(); |
| | | }); |
| | | watch(visible, (value) => { |
| | | if (value) { |
| | | document.body.addEventListener('click', closeMenu); |
| | | } else { |
| | | document.body.removeEventListener('click', closeMenu); |
| | | } |
| | | }) |
| | | if (value) { |
| | | document.body.addEventListener('click', closeMenu); |
| | | } else { |
| | | document.body.removeEventListener('click', closeMenu); |
| | | } |
| | | }); |
| | | |
| | | const isActive = (r: TagView): boolean => { |
| | | return r.path === route.path; |
| | | } |
| | | const activeStyle = (tag: TagView) => { |
| | | if (!isActive(tag)) return {}; |
| | | return { |
| | | "background-color": theme.value, |
| | | "border-color": theme.value |
| | | }; |
| | | } |
| | | const isAffix = (tag: TagView) => { |
| | | return tag.meta && tag.meta.affix; |
| | | } |
| | | const isActive = (r: RouteLocationNormalized): boolean => { |
| | | return r.path === route.path; |
| | | }; |
| | | const activeStyle = (tag: RouteLocationNormalized) => { |
| | | if (!isActive(tag)) return {}; |
| | | return { |
| | | 'background-color': theme.value, |
| | | 'border-color': theme.value |
| | | }; |
| | | }; |
| | | const isAffix = (tag: RouteLocationNormalized) => { |
| | | return tag?.meta && tag?.meta?.affix; |
| | | }; |
| | | const isFirstView = () => { |
| | | try { |
| | | return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath; |
| | | } catch (err) { |
| | | return false; |
| | | } |
| | | } |
| | | try { |
| | | return selectedTag.value.fullPath === '/index' || selectedTag.value.fullPath === visitedViews.value[1].fullPath; |
| | | } catch (err) { |
| | | return false; |
| | | } |
| | | }; |
| | | const isLastView = () => { |
| | | try { |
| | | return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath; |
| | | } catch (err) { |
| | | return false; |
| | | try { |
| | | return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1].fullPath; |
| | | } catch (err) { |
| | | return false; |
| | | } |
| | | }; |
| | | const filterAffixTags = (routes: RouteRecordRaw[], basePath = '') => { |
| | | let tags: RouteLocationNormalized[] = []; |
| | | |
| | | routes.forEach((route) => { |
| | | if (route.meta && route.meta.affix) { |
| | | const tagPath = getNormalPath(basePath + '/' + route.path); |
| | | tags.push({ |
| | | hash: '', |
| | | matched: [], |
| | | params: undefined, |
| | | query: undefined, |
| | | redirectedFrom: undefined, |
| | | fullPath: tagPath, |
| | | path: tagPath, |
| | | name: route.name as string, |
| | | meta: { ...route.meta } |
| | | }); |
| | | } |
| | | } |
| | | const filterAffixTags = (routes:RouteOption [], basePath = '') => { |
| | | let tags:TagView[] = [] |
| | | routes.forEach(route => { |
| | | if (route.meta && route.meta.affix) { |
| | | const tagPath = getNormalPath(basePath + '/' + route.path); |
| | | tags.push({ |
| | | fullPath: tagPath, |
| | | path: tagPath, |
| | | name: route.name, |
| | | meta: { ...route.meta } |
| | | }) |
| | | } |
| | | if (route.children) { |
| | | const tempTags = filterAffixTags(route.children, route.path); |
| | | if (tempTags.length >= 1) { |
| | | tags = [...tags, ...tempTags]; |
| | | } |
| | | } |
| | | }) |
| | | return tags |
| | | } |
| | | if (route.children) { |
| | | const tempTags = filterAffixTags(route.children, route.path); |
| | | if (tempTags.length >= 1) { |
| | | tags = [...tags, ...tempTags]; |
| | | } |
| | | } |
| | | }); |
| | | return tags; |
| | | }; |
| | | const initTags = () => { |
| | | const res = filterAffixTags(routes.value); |
| | | affixTags.value = res; |
| | | for (const tag of res) { |
| | | // Must have tag name |
| | | if (tag.name) { |
| | | useTagsViewStore().addVisitedView(tag); |
| | | } |
| | | const res = filterAffixTags(routes.value); |
| | | affixTags.value = res; |
| | | for (const tag of res) { |
| | | // Must have tag name |
| | | if (tag.name) { |
| | | useTagsViewStore().addVisitedView(tag); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | const addTags = () => { |
| | | const { name } = route; |
| | | if(route.query.title) { |
| | | route.meta.title = route.query.title; |
| | | } |
| | | if (name) { |
| | | useTagsViewStore().addView(route); |
| | | if (route.meta.link) { |
| | | useTagsViewStore().addIframeView(route); |
| | | } |
| | | } |
| | | return false |
| | | } |
| | | const moveToCurrentTag = () => { |
| | | nextTick(() => { |
| | | for (const r of visitedViews.value) { |
| | | if (r.path === route.path) { |
| | | scrollPaneRef.value.moveToTarget(r); |
| | | // when query is different then update |
| | | if (r.fullPath !== route.fullPath) { |
| | | useTagsViewStore().updateVisitedView(route); |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | const refreshSelectedTag = (view: TagView) => { |
| | | proxy?.$tab.refreshPage(view); |
| | | const { name } = route; |
| | | if (route.query.title) { |
| | | route.meta.title = route.query.title as string; |
| | | } |
| | | if (name) { |
| | | useTagsViewStore().addView(route as any); |
| | | if (route.meta.link) { |
| | | useTagsViewStore().delIframeView(route); |
| | | useTagsViewStore().addIframeView(route as any); |
| | | } |
| | | } |
| | | const closeSelectedTag = (view: TagView) => { |
| | | proxy?.$tab.closePage(view).then(({ visitedViews }: any) => { |
| | | if (isActive(view)) { |
| | | toLastView(visitedViews, view); |
| | | } |
| | | return false; |
| | | }; |
| | | const moveToCurrentTag = () => { |
| | | nextTick(() => { |
| | | for (const r of visitedViews.value) { |
| | | if (r.path === route.path) { |
| | | scrollPaneRef.value?.moveToTarget(r); |
| | | // when query is different then update |
| | | if (r.fullPath !== route.fullPath) { |
| | | useTagsViewStore().updateVisitedView(route); |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | const refreshSelectedTag = (view: RouteLocationNormalized) => { |
| | | proxy?.$tab.refreshPage(view); |
| | | if (route.meta.link) { |
| | | useTagsViewStore().delIframeView(route); |
| | | } |
| | | }; |
| | | const closeSelectedTag = (view: RouteLocationNormalized) => { |
| | | proxy?.$tab.closePage(view).then(({ visitedViews }: any) => { |
| | | if (isActive(view)) { |
| | | toLastView(visitedViews, view); |
| | | } |
| | | }); |
| | | }; |
| | | const closeRightTags = () => { |
| | | proxy?.$tab.closeRightPage(selectedTag.value).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === route.fullPath)) { |
| | | toLastView(visitedViews); |
| | | } |
| | | }) |
| | | } |
| | | proxy?.$tab.closeRightPage(selectedTag.value).then((visitedViews: RouteLocationNormalized[]) => { |
| | | if (!visitedViews.find((i: RouteLocationNormalized) => i.fullPath === route.fullPath)) { |
| | | toLastView(visitedViews); |
| | | } |
| | | }); |
| | | }; |
| | | const closeLeftTags = () => { |
| | | proxy?.$tab.closeLeftPage(selectedTag.value).then(visitedViews => { |
| | | if (!visitedViews.find(i => i.fullPath === route.fullPath)) { |
| | | toLastView(visitedViews); |
| | | } |
| | | }) |
| | | } |
| | | proxy?.$tab.closeLeftPage(selectedTag.value).then((visitedViews: RouteLocationNormalized[]) => { |
| | | if (!visitedViews.find((i: RouteLocationNormalized) => i.fullPath === route.fullPath)) { |
| | | toLastView(visitedViews); |
| | | } |
| | | }); |
| | | }; |
| | | const closeOthersTags = () => { |
| | | router.push(selectedTag.value as RouteLocationRaw).catch(() => { }); |
| | | proxy?.$tab.closeOtherPage(selectedTag.value).then(() => { |
| | | moveToCurrentTag(); |
| | | }) |
| | | } |
| | | const closeAllTags = (view: TagView) => { |
| | | proxy?.$tab.closeAllPage().then(({ visitedViews }) => { |
| | | if (affixTags.value.some(tag => tag.path === route.path)) { |
| | | return; |
| | | } |
| | | toLastView(visitedViews, view); |
| | | }) |
| | | } |
| | | const toLastView = (visitedViews:TagView[], view?: TagView) => { |
| | | const latestView = visitedViews.slice(-1)[0]; |
| | | if (latestView) { |
| | | router.push(latestView.fullPath as string); |
| | | } else { |
| | | // now the default is to redirect to the home page if there is no tags-view, |
| | | // you can adjust it according to your needs. |
| | | if (view?.name === 'Dashboard') { |
| | | // to reload home page |
| | | router.replace({ path: '/redirect' + view?.fullPath }); |
| | | } else { |
| | | router.push('/'); |
| | | } |
| | | router.push(selectedTag.value).catch(() => {}); |
| | | proxy?.$tab.closeOtherPage(selectedTag.value).then(() => { |
| | | moveToCurrentTag(); |
| | | }); |
| | | }; |
| | | const closeAllTags = (view: RouteLocationNormalized) => { |
| | | proxy?.$tab.closeAllPage().then(({ visitedViews }) => { |
| | | if (affixTags.value.some((tag) => tag.path === route.path)) { |
| | | return; |
| | | } |
| | | } |
| | | const openMenu = (tag: TagView, e: MouseEvent) => { |
| | | const menuMinWidth = 105; |
| | | const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left |
| | | const offsetWidth = proxy?.$el.offsetWidth; // container width |
| | | const maxLeft = offsetWidth - menuMinWidth; // left boundary |
| | | const l = e.clientX - offsetLeft + 15; // 15: margin right |
| | | |
| | | if (l > maxLeft) { |
| | | left.value = maxLeft; |
| | | toLastView(visitedViews, view); |
| | | }); |
| | | }; |
| | | const toLastView = (visitedViews: RouteLocationNormalized[], view?: RouteLocationNormalized) => { |
| | | const latestView = visitedViews.slice(-1)[0]; |
| | | if (latestView) { |
| | | router.push(latestView.fullPath as string); |
| | | } else { |
| | | // now the default is to redirect to the home page if there is no tags-view, |
| | | // you can adjust it according to your needs. |
| | | if (view?.name === 'Dashboard') { |
| | | // to reload home page |
| | | router.replace({ path: '/redirect' + view?.fullPath }); |
| | | } else { |
| | | left.value = l; |
| | | router.push('/'); |
| | | } |
| | | } |
| | | }; |
| | | const openMenu = (tag: RouteLocationNormalized, e: MouseEvent) => { |
| | | const menuMinWidth = 105; |
| | | const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left |
| | | const offsetWidth = proxy?.$el.offsetWidth; // container width |
| | | const maxLeft = offsetWidth - menuMinWidth; // left boundary |
| | | const l = e.clientX - offsetLeft + 15; // 15: margin right |
| | | |
| | | top.value = e.clientY |
| | | visible.value = true; |
| | | selectedTag.value = tag; |
| | | } |
| | | if (l > maxLeft) { |
| | | left.value = maxLeft; |
| | | } else { |
| | | left.value = l; |
| | | } |
| | | |
| | | top.value = e.clientY; |
| | | visible.value = true; |
| | | selectedTag.value = tag; |
| | | }; |
| | | const closeMenu = () => { |
| | | visible.value = false; |
| | | } |
| | | visible.value = false; |
| | | }; |
| | | const handleScroll = () => { |
| | | closeMenu(); |
| | | } |
| | | |
| | | closeMenu(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initTags(); |
| | | addTags(); |
| | | }) |
| | | initTags(); |
| | | addTags(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | width: 100%; |
| | | background-color: var(--el-bg-color); |
| | | border: 1px solid var(--el-border-color-light); |
| | | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04); |
| | | box-shadow: |
| | | 0 1px 3px 0 rgba(0, 0, 0, 0.12), |
| | | 0 0 3px 0 rgba(0, 0, 0, 0.04); |
| | | .tags-view-wrapper { |
| | | .tags-view-item { |
| | | display: inline-block; |
| | |
| | | color: #fff; |
| | | border-color: #42b983; |
| | | &::before { |
| | | content: ""; |
| | | content: ''; |
| | | background: #fff; |
| | | display: inline-block; |
| | | width: 8px; |
| | |
| | | <el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false"> |
| | | <template #footer> |
| | | <el-autocomplete |
| | | ref="layoutMenuAutocompleteRef" |
| | | v-model="state.menuQuery" |
| | | :fetch-suggestions="menuSearch" |
| | | placeholder="æç´¢" |
| | | ref="layoutMenuAutocompleteRef" |
| | | @select="onHandleSelect" |
| | | :fit-input-width="true" |
| | | @select="onHandleSelect" |
| | | > |
| | | <template #prefix> |
| | | <svg-icon class-name="search-icon" icon-class="search" /> |
| | |
| | | import { getNormalPath } from '@/utils/ruoyi'; |
| | | import { isHttp } from '@/utils/validate'; |
| | | import usePermissionStore from '@/store/modules/permission'; |
| | | import { RouteOption } from 'vue-router'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | type Router = Array<{ |
| | | path: string; |
| | | icon: string; |
| | | title: string[]; |
| | | }> |
| | | path: string; |
| | | icon: string; |
| | | title: string[]; |
| | | }>; |
| | | type SearchState<T = any> = { |
| | | isShowSearch: boolean; |
| | | menuQuery: string; |
| | | menuList: T[]; |
| | | isShowSearch: boolean; |
| | | menuQuery: string; |
| | | menuList: T[]; |
| | | }; |
| | | // å®ä¹åéå
容 |
| | | const layoutMenuAutocompleteRef = ref(); |
| | | const router = useRouter(); |
| | | const routes = computed(() => usePermissionStore().routes); |
| | | const state = reactive<SearchState>({ |
| | | isShowSearch: false, |
| | | menuQuery: '', |
| | | menuList: [], |
| | | isShowSearch: false, |
| | | menuQuery: '', |
| | | menuList: [] |
| | | }); |
| | | |
| | | // æç´¢å¼¹çªæå¼ |
| | | const openSearch = () => { |
| | | state.menuQuery = ''; |
| | | state.isShowSearch = true; |
| | | state.menuList = generateRoutes(routes.value); |
| | | nextTick(() => { |
| | | setTimeout(() => { |
| | | layoutMenuAutocompleteRef.value.focus(); |
| | | }); |
| | | }); |
| | | state.menuQuery = ''; |
| | | state.isShowSearch = true; |
| | | state.menuList = generateRoutes(routes.value as any); |
| | | nextTick(() => { |
| | | setTimeout(() => { |
| | | layoutMenuAutocompleteRef.value.focus(); |
| | | }); |
| | | }); |
| | | }; |
| | | // æç´¢å¼¹çªå
³é |
| | | const closeSearch = () => { |
| | | state.isShowSearch = false; |
| | | state.isShowSearch = false; |
| | | }; |
| | | // èåæç´¢æ°æ®è¿æ»¤ |
| | | const menuSearch = (queryString: string, cb: Function) => { |
| | | let options = state.menuList.filter((item) => { |
| | | return item.title.indexOf(queryString) > -1; |
| | | }); |
| | | cb(options); |
| | | let options = state.menuList.filter((item) => { |
| | | return item.title.indexOf(queryString) > -1; |
| | | }); |
| | | cb(options); |
| | | }; |
| | | |
| | | // Filter out the routes that can be displayed in the sidebar |
| | | // And generate the internationalized title |
| | | const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => { |
| | | let res: Router = [] |
| | | routes.forEach(r => { |
| | | // skip hidden router |
| | | if (!r.hidden) { |
| | | const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path; |
| | | const data: any = { |
| | | path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path, |
| | | icon: r.meta?.icon, |
| | | title: [...prefixTitle] |
| | | } |
| | | if (r.meta && r.meta.title) { |
| | | data.title = [...data.title, r.meta.title]; |
| | | if (r.redirect !== 'noRedirect') { |
| | | // only push the routes with title |
| | | // special case: need to exclude parent router without redirect |
| | | res.push(data); |
| | | } |
| | | } |
| | | // recursive child routes |
| | | if (r.children) { |
| | | const tempRoutes = generateRoutes(r.children, data.path, data.title); |
| | | if (tempRoutes.length >= 1) { |
| | | res = [...res, ...tempRoutes]; |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | res.forEach((item: any) => { |
| | | if (item.title instanceof Array) { |
| | | item.title = item.title.join('/'); |
| | | } |
| | | }); |
| | | return res; |
| | | } |
| | | const generateRoutes = (routes: RouteRecordRaw[], basePath = '', prefixTitle: string[] = []) => { |
| | | let res: Router = []; |
| | | routes.forEach((r) => { |
| | | // skip hidden router |
| | | if (!r.hidden) { |
| | | const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path; |
| | | const data: any = { |
| | | path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path, |
| | | icon: r.meta?.icon, |
| | | title: [...prefixTitle] |
| | | }; |
| | | if (r.meta && r.meta.title) { |
| | | data.title = [...data.title, r.meta.title]; |
| | | if (r.redirect !== 'noRedirect') { |
| | | // only push the routes with title |
| | | // special case: need to exclude parent router without redirect |
| | | res.push(data); |
| | | } |
| | | } |
| | | // recursive child routes |
| | | if (r.children) { |
| | | const tempRoutes = generateRoutes(r.children, data.path, data.title); |
| | | if (tempRoutes.length >= 1) { |
| | | res = [...res, ...tempRoutes]; |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | res.forEach((item: any) => { |
| | | if (item.title instanceof Array) { |
| | | item.title = item.title.join('/'); |
| | | } |
| | | }); |
| | | return res; |
| | | }; |
| | | // å½åèåé䏿¶ |
| | | const onHandleSelect = (val: any) => { |
| | | const paths = val.path; |
| | | if (isHttp(paths)) { |
| | | // http(s):// è·¯å¾æ°çªå£æå¼ |
| | | const pindex = paths.indexOf("http"); |
| | | window.open(paths.substring(pindex, paths.length), "_blank"); |
| | | } else { |
| | | router.push(paths); |
| | | } |
| | | state.menuQuery = '' |
| | | closeSearch(); |
| | | |
| | | const paths = val.path; |
| | | if (isHttp(paths)) { |
| | | // http(s):// è·¯å¾æ°çªå£æå¼ |
| | | const pindex = paths.indexOf('http'); |
| | | window.open(paths.substring(pindex, paths.length), '_blank'); |
| | | } else { |
| | | router.push(paths); |
| | | } |
| | | state.menuQuery = ''; |
| | | closeSearch(); |
| | | }; |
| | | |
| | | // æ´é²åé |
| | | defineExpose({ |
| | | openSearch |
| | | openSearch |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .layout-search-dialog { |
| | | position: relative; |
| | | :deep(.el-dialog) { |
| | | .el-dialog__header, |
| | | .el-dialog__body { |
| | | display: none; |
| | | } |
| | | .el-dialog__footer { |
| | | width: 100%; |
| | | position: absolute; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | top: -53vh; |
| | | } |
| | | } |
| | | :deep(.el-autocomplete) { |
| | | width: 560px; |
| | | position: absolute; |
| | | top: 150px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | } |
| | | position: relative; |
| | | :deep(.el-dialog) { |
| | | padding: 0; |
| | | .el-dialog__header, |
| | | .el-dialog__body { |
| | | display: none; |
| | | } |
| | | .el-dialog__footer { |
| | | width: 100%; |
| | | position: absolute; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | top: -53vh; |
| | | } |
| | | } |
| | | :deep(.el-autocomplete) { |
| | | width: 560px; |
| | | position: absolute; |
| | | top: 150px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="layout-navbars-breadcrumb-user-news" v-loading="state.loading"> |
| | | <div v-loading="state.loading" class="layout-navbars-breadcrumb-user-news"> |
| | | <div class="head-box"> |
| | | <div class="head-box-title">éç¥å
Œ</div> |
| | | <div class="head-box-btn" @click="readAll">å
¨é¨å·²è¯»</div> |
| | | </div> |
| | | <div class="content-box" v-loading="state.loading"> |
| | | <div v-loading="state.loading" class="content-box"> |
| | | <template v-if="newsList.length > 0"> |
| | | <div class="content-box-item" v-for="(v, k) in newsList" :key="k" @click="onNewsClick(k)"> |
| | | <div v-for="(v, k) in newsList" :key="k" class="content-box-item" @click="onNewsClick(k)"> |
| | | <div class="item-conten"> |
| | | <div>{{ v.message }}</div> |
| | | <div class="content-box-msg"></div> |
| | |
| | | <span v-else class="el-tag el-tag--danger el-tag--mini read">æªè¯»</span> |
| | | </div> |
| | | </template> |
| | | <el-empty :description="'æ¶æ¯ä¸ºç©º'" v-else></el-empty> |
| | | <el-empty v-else :description="'æ¶æ¯ä¸ºç©º'"></el-empty> |
| | | </div> |
| | | <div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">åå¾gitee</div> |
| | | <div v-if="newsList.length > 0" class="foot-box" @click="onGoToGiteeClick">åå¾gitee</div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts" name="layoutBreadcrumbUserNews"> |
| | | import { ref } from "vue"; |
| | | import { storeToRefs } from 'pinia' |
| | | import { nextTick, onMounted, reactive } from "vue"; |
| | | import { storeToRefs } from 'pinia'; |
| | | import useNoticeStore from '@/store/modules/notice'; |
| | | |
| | | const noticeStore = storeToRefs(useNoticeStore()); |
| | | const {readAll} = useNoticeStore(); |
| | | const { readAll } = useNoticeStore(); |
| | | |
| | | // å®ä¹åéå
容 |
| | | const state = reactive({ |
| | | loading: false, |
| | | loading: false |
| | | }); |
| | | const newsList =ref([]) as any; |
| | | const newsList = ref([]) as any; |
| | | |
| | | /** |
| | | * åå§åæ°æ® |
| | |
| | | state.loading = false; |
| | | }; |
| | | |
| | | |
| | | //ç¹å»æ¶æ¯ï¼åå
¥å·²è¯» |
| | | const onNewsClick = (item: any) => { |
| | | newsList.value[item].read = true; |
| | |
| | | |
| | | // åå¾éç¥ä¸å¿ç¹å» |
| | | const onGoToGiteeClick = () => { |
| | | window.open("https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/"); |
| | | window.open('https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | <settings ref="settingRef" /> |
| | | </el-scrollbar> --> |
| | | <div :class="{ 'fixed-header': fixedHeader }"> |
| | | <navbar ref="navbarRef" @setLayout="setLayout" /> |
| | | <navbar ref="navbarRef" @set-layout="setLayout" /> |
| | | <tags-view v-if="needTagsView" /> |
| | | </div> |
| | | <app-main /> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import SideBar from './components/Sidebar/index.vue' |
| | | import { AppMain, Navbar, Settings, TagsView } from './components' |
| | | import useAppStore from '@/store/modules/app' |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import SideBar from './components/Sidebar/index.vue'; |
| | | import { AppMain, Navbar, Settings, TagsView } from './components'; |
| | | import useAppStore from '@/store/modules/app'; |
| | | import useSettingsStore from '@/store/modules/settings'; |
| | | import { initWebSocket } from '@/utils/websocket'; |
| | | |
| | | const settingsStore = useSettingsStore() |
| | | const settingsStore = useSettingsStore(); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const sidebar = computed(() => useAppStore().sidebar); |
| | | const device = computed(() => useAppStore().device); |
| | |
| | | const fixedHeader = computed(() => settingsStore.fixedHeader); |
| | | |
| | | const classObj = computed(() => ({ |
| | | hideSidebar: !sidebar.value.opened, |
| | | openSidebar: sidebar.value.opened, |
| | | withoutAnimation: sidebar.value.withoutAnimation, |
| | | mobile: device.value === 'mobile' |
| | | })) |
| | | hideSidebar: !sidebar.value.opened, |
| | | openSidebar: sidebar.value.opened, |
| | | withoutAnimation: sidebar.value.withoutAnimation, |
| | | mobile: device.value === 'mobile' |
| | | })); |
| | | |
| | | const { width } = useWindowSize(); |
| | | const WIDTH = 992; // refer to Bootstrap's responsive design |
| | | |
| | | watchEffect(() => { |
| | | if (device.value === 'mobile' && sidebar.value.opened) { |
| | | useAppStore().closeSideBar({ withoutAnimation: false }) |
| | | } |
| | | if (width.value - 1 < WIDTH) { |
| | | useAppStore().toggleDevice('mobile') |
| | | useAppStore().closeSideBar({ withoutAnimation: true }) |
| | | } else { |
| | | useAppStore().toggleDevice('desktop') |
| | | } |
| | | }) |
| | | if (device.value === 'mobile') { |
| | | useAppStore().closeSideBar({ withoutAnimation: false }); |
| | | } |
| | | if (width.value - 1 < WIDTH) { |
| | | useAppStore().toggleDevice('mobile'); |
| | | useAppStore().closeSideBar({ withoutAnimation: true }); |
| | | } else { |
| | | useAppStore().toggleDevice('desktop'); |
| | | } |
| | | }); |
| | | |
| | | const navbarRef = ref(Navbar); |
| | | const settingRef = ref(Settings); |
| | | const navbarRef = ref<InstanceType<typeof Navbar>>(); |
| | | const settingRef = ref<InstanceType<typeof Settings>>(); |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | navbarRef.value.initTenantList(); |
| | | }) |
| | | }) |
| | | navbarRef.value?.initTenantList(); |
| | | }); |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; |
| | | initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket'); |
| | | }); |
| | | |
| | | const handleClickOutside = () => { |
| | | useAppStore().closeSideBar({ withoutAnimation: false }) |
| | | } |
| | | useAppStore().closeSideBar({ withoutAnimation: false }); |
| | | }; |
| | | |
| | | const setLayout = () => { |
| | | settingRef.value.openSetting(); |
| | | } |
| | | settingRef.value?.openSetting(); |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | @import "@/assets/styles/mixin.scss"; |
| | | @import "@/assets/styles/variables.module.scss"; |
| | | @import '@/assets/styles/mixin.scss'; |
| | | @import '@/assets/styles/variables.module.scss'; |
| | | |
| | | .app-wrapper { |
| | | @include clearfix; |
| | |
| | | import { createApp } from 'vue'; |
| | | // global css |
| | | import 'uno.css'; |
| | | import 'virtual:uno.css'; |
| | | import '@/assets/styles/index.scss'; |
| | | import 'element-plus/theme-chalk/dark/css-vars.css'; |
| | | |
| | |
| | | |
| | | // 注åæä»¶ |
| | | import plugins from './plugins/index'; // plugins |
| | | import { download } from '@/utils/request'; |
| | | |
| | | // é¢è®¾å¨ç» |
| | | import animate from './animate'; |
| | | // é«äº®ç»ä»¶ |
| | | // import 'highlight.js/styles/a11y-light.css'; |
| | | import 'highlight.js/styles/atom-one-dark.css'; |
| | | import 'highlight.js/lib/common'; |
| | | import HighLight from '@highlightjs/vue-plugin'; |
| | | |
| | | // svg徿 |
| | | import 'virtual:svg-icons-register'; |
| | |
| | | // permission control |
| | | import './permission'; |
| | | |
| | | import { useDict } from '@/utils/dict'; |
| | | import { getConfigKey, updateConfigByKey } from '@/api/system/config'; |
| | | import { parseTime, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'; |
| | | |
| | | // å½é
å |
| | | import i18n from '@/lang/index'; |
| | | |
| | | const app = createApp(App); |
| | | // å
¨å±æ¹æ³æè½½ |
| | | app.config.globalProperties.useDict = useDict; |
| | | app.config.globalProperties.getConfigKey = getConfigKey; |
| | | app.config.globalProperties.updateConfigByKey = updateConfigByKey; |
| | | app.config.globalProperties.download = download; |
| | | app.config.globalProperties.parseTime = parseTime; |
| | | app.config.globalProperties.handleTree = handleTree; |
| | | app.config.globalProperties.addDateRange = addDateRange; |
| | | app.config.globalProperties.selectDictLabel = selectDictLabel; |
| | | app.config.globalProperties.selectDictLabels = selectDictLabels; |
| | | app.config.globalProperties.animate = animate; |
| | | // vxeTable |
| | | import VXETable from 'vxe-table'; |
| | | import 'vxe-table/lib/style.css'; |
| | | VXETable.config({ |
| | | zIndex: 999999 |
| | | }); |
| | | |
| | | // ä¿®æ¹ el-dialog é»è®¤ç¹å»é®ç
§ä¸ºä¸å
³é |
| | | import { ElDialog } from 'element-plus'; |
| | | ElDialog.props.closeOnClickModal.default = false; |
| | | |
| | | const app = createApp(App); |
| | | |
| | | app.use(HighLight); |
| | | app.use(ElementIcons); |
| | | app.use(router); |
| | | app.use(store); |
| | | app.use(i18n); |
| | | app.use(VXETable); |
| | | app.use(plugins); |
| | | // èªå®ä¹æä»¤ |
| | | directive(app); |
| | |
| | | router.beforeEach(async (to, from, next) => { |
| | | NProgress.start(); |
| | | if (getToken()) { |
| | | to.meta.title && useSettingsStore().setTitle(to.meta.title as string); |
| | | to.meta.title && useSettingsStore().setTitle(to.meta.title); |
| | | /* has token*/ |
| | | if (to.path === '/login') { |
| | | next({ path: '/' }); |
| | | NProgress.done(); |
| | | } else if (whiteList.indexOf(to.path) !== -1) { |
| | | next() |
| | | } else if (whiteList.indexOf(to.path as string) !== -1) { |
| | | next(); |
| | | } else { |
| | | if (useUserStore().roles.length === 0) { |
| | | isRelogin.show = true; |
| | |
| | | router.addRoute(route); // å¨ææ·»å å¯è®¿é®è·¯ç±è¡¨ |
| | | } |
| | | }); |
| | | next({ ...to, replace: true }); // hackæ¹æ³ ç¡®ä¿addRoutes已宿 |
| | | next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hackæ¹æ³ ç¡®ä¿addRoutes已宿 |
| | | } |
| | | } else { |
| | | next(); |
| | |
| | | } |
| | | } else { |
| | | // 没ætoken |
| | | if (whiteList.indexOf(to.path) !== -1) { |
| | | if (whiteList.indexOf(to.path as string) !== -1) { |
| | | // å¨å
ç»å½ç½ååï¼ç´æ¥è¿å
¥ |
| | | next(); |
| | | } else { |
| | | next(`/login?redirect=${to.fullPath}`); // å¦åå
¨é¨éå®åå°ç»å½é¡µ |
| | | const redirect = encodeURIComponent(to.fullPath || '/'); |
| | | next(`/login?redirect=${redirect}`) // å¦åå
¨é¨éå®åå°ç»å½é¡µ |
| | | NProgress.done(); |
| | | } |
| | | } |
| | |
| | | import download from './download'; |
| | | import cache from './cache'; |
| | | import auth from './auth'; |
| | | // é¢è®¾å¨ç» |
| | | import animate from '@/animate'; |
| | | |
| | | import { download as dl } from '@/utils/request'; |
| | | import { useDict } from '@/utils/dict'; |
| | | import { getConfigKey, updateConfigByKey } from '@/api/system/config'; |
| | | import { parseTime, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'; |
| | | |
| | | import { App } from 'vue'; |
| | | |
| | |
| | | |
| | | // 认è¯å¯¹è±¡ |
| | | app.config.globalProperties.$auth = auth; |
| | | |
| | | // å
¨å±æ¹æ³æè½½ |
| | | app.config.globalProperties.useDict = useDict; |
| | | app.config.globalProperties.getConfigKey = getConfigKey; |
| | | app.config.globalProperties.updateConfigByKey = updateConfigByKey; |
| | | app.config.globalProperties.download = dl; |
| | | app.config.globalProperties.parseTime = parseTime; |
| | | app.config.globalProperties.handleTree = handleTree; |
| | | app.config.globalProperties.addDateRange = addDateRange; |
| | | app.config.globalProperties.selectDictLabel = selectDictLabel; |
| | | app.config.globalProperties.selectDictLabels = selectDictLabels; |
| | | app.config.globalProperties.animate = animate; |
| | | } |
| | |
| | | import { useTagsViewStore } from '@/store/modules/tagsView'; |
| | | import router from '@/router'; |
| | | import { TagView, RouteLocationRaw } from 'vue-router'; |
| | | import { RouteLocationMatched, RouteLocationNormalized } from 'vue-router'; |
| | | import useTagsViewStore from '@/store/modules/tagsView'; |
| | | |
| | | export default { |
| | | /** |
| | | * å·æ°å½åtabé¡µç¾ |
| | | * @param obj æ ç¾å¯¹è±¡ |
| | | */ |
| | | async refreshPage(obj?: TagView): Promise<void> { |
| | | async refreshPage(obj?: RouteLocationNormalized): Promise<void> { |
| | | const { path, query, matched } = router.currentRoute.value; |
| | | if (obj === undefined) { |
| | | matched.forEach((m) => { |
| | | matched.forEach((m: RouteLocationMatched) => { |
| | | if (m.components && m.components.default && m.components.default.name) { |
| | | if (!['Layout', 'ParentView'].includes(m.components.default.name)) { |
| | | obj = { name: m.components.default.name, path: path, query: query }; |
| | | obj = { |
| | | name: m.components.default.name, |
| | | path: path, |
| | | query: query, |
| | | matched: undefined, |
| | | fullPath: undefined, |
| | | hash: undefined, |
| | | params: undefined, |
| | | redirectedFrom: undefined, |
| | | meta: undefined |
| | | }; |
| | | } |
| | | } |
| | | }); |
| | |
| | | }); |
| | | }, |
| | | // å
³éå½åtab页ç¾ï¼æå¼æ°é¡µç¾ |
| | | closeOpenPage(obj: RouteLocationRaw): void { |
| | | closeOpenPage(obj: RouteLocationNormalized): void { |
| | | useTagsViewStore().delView(router.currentRoute.value); |
| | | if (obj !== undefined) { |
| | | router.push(obj); |
| | | } |
| | | }, |
| | | // å
³éæå®tabé¡µç¾ |
| | | async closePage(obj?: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] } | any> { |
| | | async closePage(obj?: RouteLocationNormalized): Promise<{ visitedViews: RouteLocationNormalized[]; cachedViews: string[] } | any> { |
| | | if (obj === undefined) { |
| | | // prettier-ignore |
| | | const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any |
| | | const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) |
| | | const latestView = visitedViews.slice(-1)[0]; |
| | | if (latestView) { |
| | | return router.push(latestView.fullPath); |
| | |
| | | return useTagsViewStore().delAllViews(); |
| | | }, |
| | | // å
³é左侧tabé¡µç¾ |
| | | closeLeftPage(obj?: TagView) { |
| | | closeLeftPage(obj?: RouteLocationNormalized) { |
| | | return useTagsViewStore().delLeftTags(obj || router.currentRoute.value); |
| | | }, |
| | | // å
³éå³ä¾§tabé¡µç¾ |
| | | closeRightPage(obj?: TagView) { |
| | | closeRightPage(obj?: RouteLocationNormalized) { |
| | | return useTagsViewStore().delRightTags(obj || router.currentRoute.value); |
| | | }, |
| | | // å
³éå
¶ä»tabé¡µç¾ |
| | | closeOtherPage(obj?: TagView) { |
| | | closeOtherPage(obj?: RouteLocationNormalized) { |
| | | return useTagsViewStore().delOthersViews(obj || router.currentRoute.value); |
| | | }, |
| | | /** |
| | |
| | | * ä¿®æ¹tabé¡µç¾ |
| | | * @param obj æ ç¾å¯¹è±¡ |
| | | */ |
| | | updatePage(obj: TagView) { |
| | | updatePage(obj: RouteLocationNormalized) { |
| | | return useTagsViewStore().updateVisitedView(obj); |
| | | } |
| | | }; |
| | |
| | | import { createWebHistory, createRouter, RouteOption } from 'vue-router'; |
| | | import { createWebHistory, createRouter, RouteRecordRaw } from 'vue-router'; |
| | | /* Layout */ |
| | | import Layout from '@/layout/index.vue'; |
| | | |
| | |
| | | */ |
| | | |
| | | // å
Œ
±è·¯ç± |
| | | export const constantRoutes: RouteOption[] = [ |
| | | export const constantRoutes: RouteRecordRaw[] = [ |
| | | { |
| | | path: '/redirect', |
| | | component: Layout, |
| | |
| | | ]; |
| | | |
| | | // å¨æè·¯ç±ï¼åºäºç¨æ·æé卿å»å è½½ |
| | | export const dynamicRoutes: RouteOption[] = [ |
| | | export const dynamicRoutes: RouteRecordRaw[] = [ |
| | | { |
| | | path: '/system/user-auth', |
| | | component: Layout, |
| | |
| | | meta: { title: 'ä¿®æ¹çæé
ç½®', activeMenu: '/tool/gen', icon: '' } |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | path: '/demo/leaveEdit', |
| | | component: Layout, |
| | | hidden: true, |
| | | permissions: ['demo:leave:edit'], |
| | | children: [ |
| | | { |
| | | path: 'index', |
| | | component: () => import('@/views/workflow/leave/leaveEdit.vue'), |
| | | name: 'leaveEdit', |
| | | meta: { title: '请åç³è¯·', activeMenu: '/demo/leave', noCache: true } |
| | | } |
| | | ] |
| | | } |
| | | ]; |
| | | |
| | |
| | | import { LanguageEnum } from '@/enums/LanguageEnum'; |
| | | |
| | | const setting: DefaultSettings = { |
| | | /** |
| | | * ç½é¡µæ é¢ |
| | |
| | | |
| | | animationEnable: false, |
| | | |
| | | dark: false |
| | | dark: false, |
| | | language: LanguageEnum.zh_CN, |
| | | |
| | | size: 'default', |
| | | |
| | | layout: '' |
| | | }; |
| | | export default setting; |
| | |
| | | hide: false |
| | | }); |
| | | const device = ref<string>('desktop'); |
| | | const size = useStorage('size', 'default'); |
| | | const size = useStorage<'large' | 'default' | 'small'>('size', 'default'); |
| | | |
| | | // è¯è¨ |
| | | const language = useStorage('language', 'zh_CN'); |
| | |
| | | const toggleDevice = (d: string): void => { |
| | | device.value = d; |
| | | }; |
| | | const setSize = (s: string): void => { |
| | | const setSize = (s: 'large' | 'default' | 'small'): void => { |
| | | size.value = s; |
| | | }; |
| | | const toggleSideBarHide = (status: boolean): void => { |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { Modeler, Modeling, Canvas, ElementRegistry, Moddle, BpmnFactory } from 'bpmn'; |
| | | |
| | | type ModelerStore = { |
| | | modeler: Modeler | undefined; |
| | | moddle: Moddle | undefined; |
| | | modeling: Modeling | undefined; |
| | | canvas: Canvas | undefined; |
| | | elementRegistry: ElementRegistry | undefined; |
| | | bpmnFactory: BpmnFactory | undefined; |
| | | // æµç¨å®ä¹æ ¹èç¹ä¿¡æ¯ |
| | | procDefId: string | undefined; |
| | | procDefName: string | undefined; |
| | | }; |
| | | |
| | | const defaultState: ModelerStore = { |
| | | modeler: undefined, |
| | | moddle: undefined, |
| | | modeling: undefined, |
| | | canvas: undefined, |
| | | elementRegistry: undefined, |
| | | bpmnFactory: undefined, |
| | | procDefId: undefined, |
| | | procDefName: undefined |
| | | }; |
| | | export const useModelerStore = defineStore('modeler', () => { |
| | | let modeler = defaultState.modeler; |
| | | let moddle = defaultState.moddle; |
| | | let modeling = defaultState.modeling; |
| | | let canvas = defaultState.canvas; |
| | | let elementRegistry = defaultState.elementRegistry; |
| | | let bpmnFactory = defaultState.bpmnFactory; |
| | | const procDefId = ref(defaultState.procDefId); |
| | | const procDefName = ref(defaultState.procDefName); |
| | | |
| | | const getModeler = () => modeler; |
| | | const getModdle = () => moddle; |
| | | const getModeling = (): Modeling | undefined => modeling; |
| | | const getCanvas = (): Canvas | undefined => canvas; |
| | | const getElRegistry = (): ElementRegistry | undefined => elementRegistry; |
| | | const getBpmnFactory = (): BpmnFactory | undefined => bpmnFactory; |
| | | const getProcDefId = (): string | undefined => procDefId.value; |
| | | const getProcDefName = (): string | undefined => procDefName.value; |
| | | |
| | | // è®¾ç½®æ ¹èç¹ |
| | | const setModeler = (modelers: Modeler | undefined) => { |
| | | if (modelers) { |
| | | modeler = modelers; |
| | | modeling = modelers.get<Modeling>('modeling'); |
| | | moddle = modelers.get<Moddle>('moddle'); |
| | | canvas = modelers.get<Canvas>('canvas'); |
| | | bpmnFactory = modelers.get<BpmnFactory>('bpmnFactory'); |
| | | elementRegistry = modelers.get<ElementRegistry>('elementRegistry'); |
| | | } else { |
| | | modeling = moddle = canvas = elementRegistry = bpmnFactory = undefined; |
| | | } |
| | | }; |
| | | // 设置æµç¨å®ä¹æ ¹èç¹ä¿¡æ¯ |
| | | const setProcDef = (modeler: Modeler | undefined) => { |
| | | procDefId.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('id'); |
| | | procDefName.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('name'); |
| | | }; |
| | | |
| | | return { |
| | | getModeler, |
| | | getModdle, |
| | | getModeling, |
| | | getCanvas, |
| | | getElRegistry, |
| | | getBpmnFactory, |
| | | getProcDefId, |
| | | getProcDefName, |
| | | setModeler, |
| | | setProcDef |
| | | }; |
| | | }); |
| | | export default useModelerStore; |
| | |
| | | |
| | | //å®ç°å
¨é¨å·²è¯» |
| | | const readAll = () => { |
| | | state.notices.forEach((item) => { |
| | | state.notices.forEach((item: any) => { |
| | | item.read = true; |
| | | }); |
| | | }; |
| | |
| | | import router, { constantRoutes, dynamicRoutes } from '@/router'; |
| | | import store from '@/store'; |
| | | import { getRouters } from '@/api/menu'; |
| | | import auth from '@/plugins/auth'; |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | import Layout from '@/layout/index.vue'; |
| | | import ParentView from '@/components/ParentView/index.vue'; |
| | | import InnerLink from '@/layout/components/InnerLink/index.vue'; |
| | | import auth from '@/plugins/auth'; |
| | | import { RouteOption } from 'vue-router'; |
| | | |
| | | // å¹é
viewsé颿æç.vueæä»¶ |
| | | const modules = import.meta.glob('./../../views/**/*.vue'); |
| | | |
| | | export const usePermissionStore = defineStore('permission', () => { |
| | | const routes = ref<RouteOption[]>([]); |
| | | const addRoutes = ref<RouteOption[]>([]); |
| | | const defaultRoutes = ref<RouteOption[]>([]); |
| | | const topbarRouters = ref<RouteOption[]>([]); |
| | | const sidebarRouters = ref<RouteOption[]>([]); |
| | | const routes = ref<RouteRecordRaw[]>([]); |
| | | const addRoutes = ref<RouteRecordRaw[]>([]); |
| | | const defaultRoutes = ref<RouteRecordRaw[]>([]); |
| | | const topbarRouters = ref<RouteRecordRaw[]>([]); |
| | | const sidebarRouters = ref<RouteRecordRaw[]>([]); |
| | | |
| | | const setRoutes = (newRoutes: RouteOption[]): void => { |
| | | const getRoutes = (): RouteRecordRaw[] => { |
| | | return routes.value; |
| | | }; |
| | | const getSidebarRoutes = (): RouteRecordRaw[] => { |
| | | return sidebarRouters.value; |
| | | }; |
| | | const getTopbarRoutes = (): RouteRecordRaw[] => { |
| | | return topbarRouters.value; |
| | | }; |
| | | |
| | | const setRoutes = (newRoutes: RouteRecordRaw[]): void => { |
| | | addRoutes.value = newRoutes; |
| | | routes.value = constantRoutes.concat(newRoutes); |
| | | }; |
| | | const setDefaultRoutes = (routes: RouteOption[]): void => { |
| | | const setDefaultRoutes = (routes: RouteRecordRaw[]): void => { |
| | | defaultRoutes.value = constantRoutes.concat(routes); |
| | | }; |
| | | const setTopbarRoutes = (routes: RouteOption[]): void => { |
| | | const setTopbarRoutes = (routes: RouteRecordRaw[]): void => { |
| | | topbarRouters.value = routes; |
| | | }; |
| | | const setSidebarRouters = (routes: RouteOption[]): void => { |
| | | const setSidebarRouters = (routes: RouteRecordRaw[]): void => { |
| | | sidebarRouters.value = routes; |
| | | }; |
| | | const generateRoutes = async (): Promise<RouteOption[]> => { |
| | | const generateRoutes = async (): Promise<RouteRecordRaw[]> => { |
| | | const res = await getRouters(); |
| | | const { data } = res; |
| | | const sdata = JSON.parse(JSON.stringify(data)); |
| | |
| | | setSidebarRouters(constantRoutes.concat(sidebarRoutes)); |
| | | setDefaultRoutes(sidebarRoutes); |
| | | setTopbarRoutes(defaultRoutes); |
| | | return new Promise<RouteOption[]>((resolve) => resolve(rewriteRoutes)); |
| | | return new Promise<RouteRecordRaw[]>((resolve) => resolve(rewriteRoutes)); |
| | | }; |
| | | |
| | | /** |
| | |
| | | * @param lastRouter ä¸ä¸çº§è·¯ç± |
| | | * @param type æ¯å¦æ¯éåè·¯ç± |
| | | */ |
| | | const filterAsyncRouter = (asyncRouterMap: RouteOption[], lastRouter?: RouteOption, type = false): RouteOption[] => { |
| | | const filterAsyncRouter = (asyncRouterMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw, type = false): RouteRecordRaw[] => { |
| | | return asyncRouterMap.filter((route) => { |
| | | if (type && route.children) { |
| | | route.children = filterChildren(route.children, undefined); |
| | | } |
| | | if (route.component) { |
| | | // Layout ParentView ç»ä»¶ç¹æ®å¤ç |
| | | if (route.component === 'Layout') { |
| | | route.component = Layout; |
| | | } else if (route.component === 'ParentView') { |
| | | route.component = ParentView; |
| | | } else if (route.component === 'InnerLink') { |
| | | route.component = InnerLink; |
| | | } else { |
| | | route.component = loadView(route.component); |
| | | } |
| | | // Layout ParentView ç»ä»¶ç¹æ®å¤ç |
| | | if (route.component?.toString() === 'Layout') { |
| | | route.component = Layout; |
| | | } else if (route.component?.toString() === 'ParentView') { |
| | | route.component = ParentView; |
| | | } else if (route.component?.toString() === 'InnerLink') { |
| | | route.component = InnerLink; |
| | | } else { |
| | | route.component = loadView(route.component); |
| | | } |
| | | if (route.children != null && route.children && route.children.length) { |
| | | route.children = filterAsyncRouter(route.children, route, type); |
| | |
| | | return true; |
| | | }); |
| | | }; |
| | | const filterChildren = (childrenMap: RouteOption[], lastRouter?: RouteOption): RouteOption[] => { |
| | | let children: RouteOption[] = []; |
| | | const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => { |
| | | let children: RouteRecordRaw[] = []; |
| | | childrenMap.forEach((el) => { |
| | | if (el.children && el.children.length) { |
| | | if (el.component === 'ParentView' && !lastRouter) { |
| | | if (el.component?.toString() === 'ParentView' && !lastRouter) { |
| | | el.children.forEach((c) => { |
| | | c.path = el.path + '/' + c.path; |
| | | if (c.children && c.children.length) { |
| | |
| | | if (lastRouter) { |
| | | el.path = lastRouter.path + '/' + el.path; |
| | | if (el.children && el.children.length) { |
| | | children = children.concat(filterChildren(el.children, el)) |
| | | return |
| | | children = children.concat(filterChildren(el.children, el)); |
| | | return; |
| | | } |
| | | } |
| | | children = children.concat(el); |
| | | }); |
| | | return children; |
| | | }; |
| | | return { routes, setRoutes, generateRoutes, setSidebarRouters, topbarRouters, sidebarRouters, defaultRoutes }; |
| | | return { |
| | | routes, |
| | | topbarRouters, |
| | | sidebarRouters, |
| | | defaultRoutes, |
| | | |
| | | getRoutes, |
| | | getSidebarRoutes, |
| | | getTopbarRoutes, |
| | | |
| | | setRoutes, |
| | | generateRoutes, |
| | | setSidebarRouters |
| | | }; |
| | | }); |
| | | |
| | | // å¨æè·¯ç±éåï¼éªè¯æ¯å¦å
·å¤æé |
| | | export const filterDynamicRoutes = (routes: RouteOption[]) => { |
| | | const res: RouteOption[] = []; |
| | | export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => { |
| | | const res: RouteRecordRaw[] = []; |
| | | routes.forEach((route) => { |
| | | if (route.permissions) { |
| | | if (auth.hasPermiOr(route.permissions)) { |
| | |
| | | import { defineStore } from 'pinia'; |
| | | import defaultSettings from '@/settings'; |
| | | import { SettingTypeEnum } from '@/enums/SettingTypeEnum'; |
| | | import { useDynamicTitle } from '@/utils/dynamicTitle'; |
| | | import { Ref } from 'vue'; |
| | | |
| | | export const useSettingsStore = defineStore('setting', () => { |
| | | const storageSetting = JSON.parse(localStorage.getItem('layout-setting') || '{}'); |
| | | const storageSetting = useStorage<LayoutSetting>('layout-setting', { |
| | | topNav: defaultSettings.topNav, |
| | | tagsView: defaultSettings.tagsView, |
| | | fixedHeader: defaultSettings.fixedHeader, |
| | | sidebarLogo: defaultSettings.sidebarLogo, |
| | | dynamicTitle: defaultSettings.dynamicTitle, |
| | | sideTheme: defaultSettings.sideTheme, |
| | | theme: defaultSettings.theme |
| | | }); |
| | | const title = ref<string>(defaultSettings.title); |
| | | const theme = ref<string>(storageSetting.value.theme); |
| | | const sideTheme = ref<string>(storageSetting.value.sideTheme); |
| | | const showSettings = ref<boolean>(defaultSettings.showSettings); |
| | | const topNav = ref<boolean>(storageSetting.value.topNav); |
| | | const tagsView = ref<boolean>(storageSetting.value.tagsView); |
| | | const fixedHeader = ref<boolean>(storageSetting.value.fixedHeader); |
| | | const sidebarLogo = ref<boolean>(storageSetting.value.sidebarLogo); |
| | | const dynamicTitle = ref<boolean>(storageSetting.value.dynamicTitle); |
| | | const animationEnable = ref<boolean>(defaultSettings.animationEnable); |
| | | const dark = ref<boolean>(defaultSettings.dark); |
| | | |
| | | const prop: { [key: string]: Ref<any> } = { |
| | | title: ref<string>(''), |
| | | theme: ref<string>(storageSetting.theme || defaultSettings.theme), |
| | | sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme), |
| | | showSettings: ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings), |
| | | topNav: ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav), |
| | | tagsView: ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView), |
| | | fixedHeader: ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader), |
| | | sidebarLogo: ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo), |
| | | dynamicTitle: ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle), |
| | | animationEnable: ref<boolean>(storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable), |
| | | dark: ref<boolean>(storageSetting.dark || defaultSettings.dark) |
| | | }; |
| | | |
| | | const { title, theme, sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, animationEnable, dark } = prop; |
| | | |
| | | // actions |
| | | const changeSetting = (param: { key: SettingTypeEnum; value: any }) => { |
| | | const { key, value } = param; |
| | | if (key in prop) { |
| | | prop[key].value = value; |
| | | } |
| | | }; |
| | | const setTitle = (value: string) => { |
| | | title.value = value; |
| | | useDynamicTitle(); |
| | |
| | | dynamicTitle, |
| | | animationEnable, |
| | | dark, |
| | | changeSetting, |
| | | setTitle |
| | | }; |
| | | }); |
| | |
| | | import { TagView, RouteRecordNormalized } from 'vue-router'; |
| | | import { RouteLocationNormalized } from 'vue-router'; |
| | | |
| | | export const useTagsViewStore = defineStore('tagsView', () => { |
| | | const visitedViews = ref<TagView[]>([]); |
| | | const visitedViews = ref<RouteLocationNormalized[]>([]); |
| | | const cachedViews = ref<string[]>([]); |
| | | const iframeViews = ref<TagView[]>([]); |
| | | const iframeViews = ref<RouteLocationNormalized[]>([]); |
| | | |
| | | const addView = (view: TagView) => { |
| | | const getVisitedViews = (): RouteLocationNormalized[] => { |
| | | return visitedViews.value; |
| | | }; |
| | | const getIframeViews = (): RouteLocationNormalized[] => { |
| | | return iframeViews.value; |
| | | }; |
| | | const getCachedViews = (): string[] => { |
| | | return cachedViews.value; |
| | | }; |
| | | |
| | | const addView = (view: RouteLocationNormalized) => { |
| | | addVisitedView(view); |
| | | addCachedView(view); |
| | | }; |
| | | |
| | | const addIframeView = (view: TagView): void => { |
| | | if (iframeViews.value.some((v) => v.path === view.path)) return; |
| | | const addIframeView = (view: RouteLocationNormalized): void => { |
| | | if (iframeViews.value.some((v: RouteLocationNormalized) => v.path === view.path)) return; |
| | | iframeViews.value.push( |
| | | Object.assign({}, view, { |
| | | title: view.meta?.title || 'no-name' |
| | | }) |
| | | ); |
| | | }; |
| | | const delIframeView = (view: TagView): Promise<TagView[]> => { |
| | | const delIframeView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | iframeViews.value = iframeViews.value.filter((item) => item.path !== view.path); |
| | | iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path); |
| | | resolve([...iframeViews.value]); |
| | | }); |
| | | }; |
| | | const addVisitedView = (view: TagView): void => { |
| | | if (visitedViews.value.some((v) => v.path === view.path)) return; |
| | | const addVisitedView = (view: RouteLocationNormalized): void => { |
| | | if (visitedViews.value.some((v: RouteLocationNormalized) => v.path === view.path)) return; |
| | | visitedViews.value.push( |
| | | Object.assign({}, view, { |
| | | title: view.meta?.title || 'no-name' |
| | | }) |
| | | ); |
| | | }; |
| | | const delView = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { |
| | | const delView = ( |
| | | view: RouteLocationNormalized |
| | | ): Promise<{ |
| | | visitedViews: RouteLocationNormalized[]; |
| | | cachedViews: string[]; |
| | | }> => { |
| | | return new Promise((resolve) => { |
| | | delVisitedView(view); |
| | | if (!isDynamicRoute(view)) { |
| | |
| | | }); |
| | | }; |
| | | |
| | | const delVisitedView = (view: TagView): Promise<TagView[]> => { |
| | | const delVisitedView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | for (const [i, v] of visitedViews.value.entries()) { |
| | | if (v.path === view.path) { |
| | |
| | | resolve([...visitedViews.value]); |
| | | }); |
| | | }; |
| | | const delCachedView = (view?: TagView): Promise<string[]> => { |
| | | const delCachedView = (view?: RouteLocationNormalized): Promise<string[]> => { |
| | | let viewName = ''; |
| | | if (view) { |
| | | viewName = view.name as string; |
| | |
| | | resolve([...cachedViews.value]); |
| | | }); |
| | | }; |
| | | const delOthersViews = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { |
| | | const delOthersViews = ( |
| | | view: RouteLocationNormalized |
| | | ): Promise<{ |
| | | visitedViews: RouteLocationNormalized[]; |
| | | cachedViews: string[]; |
| | | }> => { |
| | | return new Promise((resolve) => { |
| | | delOthersVisitedViews(view); |
| | | delOthersCachedViews(view); |
| | |
| | | }); |
| | | }; |
| | | |
| | | const delOthersVisitedViews = (view: TagView): Promise<TagView[]> => { |
| | | const delOthersVisitedViews = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | visitedViews.value = visitedViews.value.filter((v) => { |
| | | visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => { |
| | | return v.meta?.affix || v.path === view.path; |
| | | }); |
| | | resolve([...visitedViews.value]); |
| | | }); |
| | | }; |
| | | const delOthersCachedViews = (view: TagView): Promise<string[]> => { |
| | | const delOthersCachedViews = (view: RouteLocationNormalized): Promise<string[]> => { |
| | | const viewName = view.name as string; |
| | | return new Promise((resolve) => { |
| | | const index = cachedViews.value.indexOf(viewName); |
| | |
| | | }); |
| | | }; |
| | | |
| | | const delAllViews = (): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => { |
| | | const delAllViews = (): Promise<{ visitedViews: RouteLocationNormalized[]; cachedViews: string[] }> => { |
| | | return new Promise((resolve) => { |
| | | delAllVisitedViews(); |
| | | delAllCachedViews(); |
| | |
| | | }); |
| | | }); |
| | | }; |
| | | const delAllVisitedViews = (): Promise<TagView[]> => { |
| | | const delAllVisitedViews = (): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | visitedViews.value = visitedViews.value.filter((tag) => tag.meta?.affix); |
| | | visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix); |
| | | resolve([...visitedViews.value]); |
| | | }); |
| | | }; |
| | |
| | | }); |
| | | }; |
| | | |
| | | const updateVisitedView = (view: TagView): void => { |
| | | const updateVisitedView = (view: RouteLocationNormalized): void => { |
| | | for (let v of visitedViews.value) { |
| | | if (v.path === view.path) { |
| | | v = Object.assign(v, view); |
| | |
| | | } |
| | | } |
| | | }; |
| | | const delRightTags = (view: TagView): Promise<TagView[]> => { |
| | | const delRightTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | const index = visitedViews.value.findIndex((v) => v.path === view.path); |
| | | const index = visitedViews.value.findIndex((v: RouteLocationNormalized) => v.path === view.path); |
| | | if (index === -1) { |
| | | return; |
| | | } |
| | | visitedViews.value = visitedViews.value.filter((item, idx) => { |
| | | visitedViews.value = visitedViews.value.filter((item: RouteLocationNormalized, idx: number) => { |
| | | if (idx <= index || (item.meta && item.meta.affix)) { |
| | | return true; |
| | | } |
| | |
| | | resolve([...visitedViews.value]); |
| | | }); |
| | | }; |
| | | const delLeftTags = (view: TagView): Promise<TagView[]> => { |
| | | const delLeftTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => { |
| | | return new Promise((resolve) => { |
| | | const index = visitedViews.value.findIndex((v) => v.path === view.path); |
| | | const index = visitedViews.value.findIndex((v: RouteLocationNormalized) => v.path === view.path); |
| | | if (index === -1) { |
| | | return; |
| | | } |
| | | visitedViews.value = visitedViews.value.filter((item, idx) => { |
| | | visitedViews.value = visitedViews.value.filter((item: RouteLocationNormalized, idx: number) => { |
| | | if (idx >= index || (item.meta && item.meta.affix)) { |
| | | return true; |
| | | } |
| | |
| | | }); |
| | | }; |
| | | |
| | | const addCachedView = (view: TagView): void => { |
| | | const addCachedView = (view: RouteLocationNormalized): void => { |
| | | const viewName = view.name as string; |
| | | if (!viewName) return; |
| | | if (cachedViews.value.includes(viewName)) return; |
| | |
| | | } |
| | | }; |
| | | |
| | | const isDynamicRoute = (view: any): boolean => { |
| | | const isDynamicRoute = (view: RouteLocationNormalized): boolean => { |
| | | // æ£æ¥å¹é
çè·¯ç±è®°å½ä¸æ¯å¦æå¨ææ®µ |
| | | return view.matched.some((m: RouteRecordNormalized) => m.path.includes(':')); |
| | | return view.matched.some((m) => m.path.includes(':')); |
| | | }; |
| | | |
| | | return { |
| | | visitedViews, |
| | | cachedViews, |
| | | iframeViews, |
| | | |
| | | getVisitedViews, |
| | | getIframeViews, |
| | | getCachedViews, |
| | | |
| | | addVisitedView, |
| | | addCachedView, |
| | | delVisitedView, |
| | |
| | | delIframeView |
| | | }; |
| | | }); |
| | | |
| | | export default useTagsViewStore; |
| | |
| | | import { to } from 'await-to-js'; |
| | | import defAva from '@/assets/images/profile.jpg'; |
| | | import store from '@/store'; |
| | | import { getToken, removeToken, setToken } from '@/utils/auth'; |
| | | import { login as loginApi, logout as logoutApi, getInfo as getUserInfo } from '@/api/login'; |
| | | import { LoginData } from '@/api/types'; |
| | | import defAva from '@/assets/images/profile.jpg'; |
| | | import store from '@/store'; |
| | | |
| | | export const useUserStore = defineStore('user', () => { |
| | | const token = ref(getToken()); |
| | |
| | | import axios from 'axios'; |
| | | |
| | | export {}; |
| | | declare module 'axios' { |
| | | export interface AxiosResponse<T = any> { |
| | | interface AxiosResponse<T = any> { |
| | | code: number; |
| | | msg: string; |
| | | rows: T; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { MessageApiInjection } from 'naive-ui/lib/message/src/MessageProvider'; |
| | | |
| | | declare global { |
| | | interface Window { |
| | | bpmnInstances: any; |
| | | __messageBox: MessageApiInjection; |
| | | URL: any; |
| | | } |
| | | } |
| | | |
| | | declare interface Window { |
| | | bpmnInstances: any; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'bpmn' { |
| | | import type modeler from 'bpmn-js/lib/Modeler'; |
| | | import type modeling from 'bpmn-js/lib/features/modeling/Modeling'; |
| | | import type canvas from 'diagram-js/lib/core/Canvas'; |
| | | import type elementRegistry from 'diagram-js/lib/core/ElementRegistry'; |
| | | import type bpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | |
| | | export type Modeler = modeler; |
| | | export type Modeling = modeling; |
| | | export type Canvas = canvas; |
| | | export type ElementRegistry = elementRegistry; |
| | | export type Moddle = import('moddle').Moddle; |
| | | export type ModdleElement = import('moddle').ModdleElement; |
| | | export type BpmnFactory = bpmnFactory; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'moddle' { |
| | | import type { Element as element } from 'bpmn-js/lib/model/Types'; |
| | | |
| | | export type Element = { |
| | | get<T>(name: string): T; |
| | | |
| | | set(name: string, value: any): void; |
| | | } & element; |
| | | |
| | | export interface ModdleElement extends Element { |
| | | $model: Moddle; |
| | | readonly $type: string; |
| | | $attrs: object | {}; |
| | | $parent: any; |
| | | businessObject: ModdleElement; |
| | | type: string; |
| | | |
| | | [field: string]: any; |
| | | |
| | | hasType(element: ModdleElement, type?: string): boolean; |
| | | } |
| | | |
| | | export interface Package { |
| | | name: string; |
| | | prefix: string; |
| | | } |
| | | |
| | | export interface Moddle { |
| | | typeCache: Record<string, ModdleElement>; |
| | | |
| | | getPackage: typeof Registry.prototype.getPackage; |
| | | |
| | | getPackages: typeof Registry.prototype.getPackages; |
| | | |
| | | create(type: string, attrs?: any): ModdleElement; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'bpmnDesign' { |
| | | import { AllocationTypeEnum, SpecifyDescEnum, MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
| | | |
| | | export interface ParamVO { |
| | | type: string; |
| | | name: string; |
| | | value: string; |
| | | } |
| | | |
| | | export interface TaskListenerVO { |
| | | event: string; |
| | | type: string; |
| | | name: string; |
| | | className: string; |
| | | params: ParamVO[]; |
| | | } |
| | | |
| | | export interface ExecutionListenerVO { |
| | | event: string; |
| | | type: string; |
| | | className: string; |
| | | params: ParamVO[]; |
| | | } |
| | | |
| | | interface BasePanel { |
| | | id: string; |
| | | name: string; |
| | | } |
| | | export interface ProcessPanel extends BasePanel {} |
| | | |
| | | export interface TaskPanel extends BasePanel { |
| | | allocationType: AllocationTypeEnum; |
| | | specifyDesc: SpecifyDescEnum; |
| | | multiInstanceType: MultiInstanceTypeEnum; |
| | | async?: boolean; |
| | | priority?: number; |
| | | formKey?: string; |
| | | skipExpression?: string; |
| | | isForCompensation?: boolean; |
| | | triggerServiceTask?: boolean; |
| | | autoStoreVariables?: boolean; |
| | | ruleVariablesInput?: string; |
| | | excludeTaskListener?: boolean; |
| | | exclude?: boolean; |
| | | class?: string; |
| | | dueDate?: string; |
| | | fixedAssignee?: string; |
| | | |
| | | candidateUsers?: string; |
| | | assignee?: string; |
| | | candidateGroups?: string; |
| | | collection?: string; |
| | | elementVariable?: string; |
| | | completionCondition?: string; |
| | | isSequential?: boolean; |
| | | |
| | | loopCharacteristics?: { |
| | | collection: string; |
| | | elementVariable: string; |
| | | isSequential: boolean; |
| | | completionCondition: { |
| | | body: string; |
| | | }; |
| | | }; |
| | | } |
| | | |
| | | export interface StartEndPanel extends BasePanel {} |
| | | export interface GatewayPanel extends BasePanel {} |
| | | export interface SequenceFlowPanel extends BasePanel { |
| | | conditionExpression: { |
| | | body: string; |
| | | }; |
| | | conditionExpressionValue: string; |
| | | skipExpression: string; |
| | | } |
| | | |
| | | export interface ParticipantPanel extends BasePanel {} |
| | | export interface SubProcessPanel extends BasePanel { |
| | | multiInstanceType: MultiInstanceTypeEnum; |
| | | collection?: string; |
| | | elementVariable?: string; |
| | | completionCondition?: string; |
| | | loopCharacteristics?: { |
| | | collection: string; |
| | | elementVariable: string; |
| | | isSequential: boolean; |
| | | completionCondition: { |
| | | body: string; |
| | | }; |
| | | }; |
| | | } |
| | | } |
| | |
| | | import type * as ep from 'element-plus'; |
| | | declare global { |
| | | declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary'; |
| | | declare type ElFormInstance = InstanceType<typeof ep.ElForm>; |
| | | declare type ElTableInstance = InstanceType<typeof ep.ElTable>; |
| | | declare type ElTagType = 'primary' | 'success' | 'info' | 'warning' | 'danger'; |
| | | declare type ElFormInstance = ep.FormInstance; |
| | | declare type ElTableInstance = ep.TableInstance; |
| | | declare type ElUploadInstance = ep.UploadInstance; |
| | | declare type ElScrollbarInstance = ep.ScrollbarInstance; |
| | | declare type ElInputInstance = ep.InputInstance; |
| | | declare type ElInputNumberInstance = ep.InputNumberInstance; |
| | | declare type ElRadioInstance = ep.RadioInstance; |
| | | declare type ElRadioGroupInstance = ep.RadioGroupInstance; |
| | | declare type ElRadioButtonInstance = ep.RadioButtonInstance; |
| | | declare type ElCheckboxInstance = ep.CheckboxInstance; |
| | | declare type ElSwitchInstance = ep.SwitchInstance; |
| | | declare type ElCascaderInstance = ep.CascaderInstance; |
| | | declare type ElColorPickerInstance = ep.ColorPickerInstance; |
| | | declare type ElRateInstance = ep.RateInstance; |
| | | declare type ElSliderInstance = ep.SliderInstance; |
| | | |
| | | declare type ElTreeInstance = InstanceType<typeof ep.ElTree>; |
| | | declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>; |
| | | declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>; |
| | | declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>; |
| | | declare type ElCardInstance = InstanceType<typeof ep.ElCard>; |
| | | declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>; |
| | | declare type ElInputInstance = InstanceType<typeof ep.ElInput>; |
| | | declare type ElInputNumberInstance = InstanceType<typeof ep.ElInputNumber>; |
| | | declare type ElRadioInstance = InstanceType<typeof ep.ElRadio>; |
| | | declare type ElRadioGroupInstance = InstanceType<typeof ep.ElRadioGroup>; |
| | | declare type ElRadioButtonInstance = InstanceType<typeof ep.ElRadioButton>; |
| | | declare type ElCheckboxInstance = InstanceType<typeof ep.ElCheckbox>; |
| | | declare type ElCheckboxGroupInstance = InstanceType<typeof ep.ElCheckboxGroup>; |
| | | declare type ElSwitchInstance = InstanceType<typeof ep.ElSwitch>; |
| | | declare type ElDatePickerInstance = InstanceType<typeof ep.ElDatePicker>; |
| | | declare type ElTimePickerInstance = InstanceType<typeof ep.ElTimePicker>; |
| | | declare type ElTimeSelectInstance = InstanceType<typeof ep.ElTimeSelect>; |
| | | declare type ElCascaderInstance = InstanceType<typeof ep.ElCascader>; |
| | | declare type ElColorPickerInstance = InstanceType<typeof ep.ElColorPicker>; |
| | | declare type ElRateInstance = InstanceType<typeof ep.ElRate>; |
| | | declare type ElSliderInstance = InstanceType<typeof ep.ElSlider>; |
| | | declare type ElScrollbarInstance = InstanceType<typeof ep.ElScrollbar>; |
| | | |
| | | declare type TransferKey = ep.TransferKey; |
| | | declare type CheckboxValueType = ep.CheckboxValueType; |
| | | declare type ElFormRules = ep.FormRules; |
| | | declare type DateModelType = ep.DateModelType; |
| | | declare type UploadFile = typeof ep.UploadFile; |
| | | declare type UploadFile = ep.UploadFile; |
| | | } |
| | |
| | | declare module '*.vue' { |
| | | import { DefineComponent } from 'vue'; |
| | | const component: DefineComponent<{}, {}, any>; |
| | | export default component; |
| | | } |
| | | declare module '*.avif' { |
| | | const src: string; |
| | | export default src; |
| | | const Component: DefineComponent<{}, {}, any>; |
| | | export default Component; |
| | | } |
| | | |
| | | declare module '*.bmp' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.gif' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.jpg' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.jpeg' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.png' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.webp' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.svg' { |
| | | const src: string; |
| | | export default src; |
| | | } |
| | | |
| | | declare module '*.module.css' { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |
| | | |
| | | declare module '*.module.scss' { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |
| | | |
| | | declare module '*.module.sass' { |
| | | const classes: { readonly [key: string]: string }; |
| | | export default classes; |
| | | } |
| | | // ç¯å¢åé |
| | | interface ImportMetaEnv { |
| | | VITE_APP_TITLE: string; |
| | |
| | | VITE_APP_CONTEXT_PATH: string; |
| | | VITE_APP_MONITRO_ADMIN: string; |
| | | VITE_APP_POWERJOB_ADMIN: string; |
| | | VITE_APP_EASYRETRY_ADMIN: string; |
| | | VITE_APP_ENV: string; |
| | | VITE_APP_ENCRYPT: string; |
| | | VITE_APP_RSA_PUBLIC_KEY: string; |
| | | VITE_APP_RSA_PRIVATE_KEY: string; |
| | | VITE_APP_CLIENT_ID: string; |
| | |
| | | import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue'; |
| | | import type { PropType as VuePropType, ComponentInternalInstance as ComponentInstance } from 'vue'; |
| | | import { LanguageEnum } from '@/enums/LanguageEnum'; |
| | | |
| | | declare global { |
| | | /** vue Instance */ |
| | |
| | | /** æ¯å¦ç¦ç¨ä¸ä¼ */ |
| | | isUploading: boolean; |
| | | |
| | | updateSupport: number; |
| | | |
| | | /** å
¶ä»åæ° */ |
| | | [key: string]: any; |
| | | } |
| | |
| | | pageNum: number; |
| | | pageSize: number; |
| | | } |
| | | declare interface LayoutSetting { |
| | | /** |
| | | * æ¯å¦æ¾ç¤ºé¡¶é¨å¯¼èª |
| | | */ |
| | | topNav: boolean; |
| | | |
| | | /** |
| | | * æ¯å¦æ¾ç¤ºå¤æ ç¾å¯¼èª |
| | | */ |
| | | tagsView: boolean; |
| | | /** |
| | | * æ¯å¦åºå®å¤´é¨ |
| | | */ |
| | | fixedHeader: boolean; |
| | | /** |
| | | * æ¯å¦æ¾ç¤ºä¾§è¾¹æ Logo |
| | | */ |
| | | sidebarLogo: boolean; |
| | | /** |
| | | * æ¯å¦æ¾ç¤ºå¨ææ é¢ |
| | | */ |
| | | dynamicTitle: boolean; |
| | | /** |
| | | * ä¾§è¾¹æ ä¸»é¢ theme-dark | theme-light |
| | | */ |
| | | sideTheme: string; |
| | | /** |
| | | * 䏻颿¨¡å¼ |
| | | */ |
| | | theme: string; |
| | | } |
| | | |
| | | declare interface DefaultSettings extends LayoutSetting { |
| | | /** |
| | | * ç½é¡µæ é¢ |
| | | */ |
| | | title: string; |
| | | |
| | | /** |
| | | * æ¯å¦æ¾ç¤ºç³»ç»å¸å±è®¾ç½® |
| | | */ |
| | | showSettings: boolean; |
| | | |
| | | /** |
| | | * å¯¼èªæ å¸å± |
| | | */ |
| | | layout: string; |
| | | |
| | | /** |
| | | * å¸å±å¤§å° |
| | | */ |
| | | size: 'large' | 'default' | 'small'; |
| | | |
| | | /** |
| | | * è¯è¨ |
| | | */ |
| | | language: LanguageEnum; |
| | | |
| | | /** |
| | | * æ¯å¦å¯ç¨å¨ç»ææ |
| | | */ |
| | | animationEnable: boolean; |
| | | /** |
| | | * æ¯å¦å¯ç¨æé»æ¨¡å¼ |
| | | * |
| | | * true:æé»æ¨¡å¼ |
| | | * false: æäº®æ¨¡å¼ |
| | | */ |
| | | dark: boolean; |
| | | |
| | | errorLog: string; |
| | | } |
| | | } |
| | | export {}; |
| | |
| | | import type modal from '@/plugins/modal'; |
| | | import type tab from '@/plugins/tab'; |
| | | import type download from '@/plugins/download'; |
| | | import type auth from '@/plugins/auth'; |
| | | import type cache from '@/plugins/cache'; |
| | | import type animate from '@/animate'; |
| | | import type { useDict } from '@/utils/dict'; |
| | | import type { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi'; |
| | | import type { getConfigKey, updateConfigByKey } from '@/api/system/config'; |
| | | import type { download as rd } from '@/utils/request'; |
| | | import modal from '@/plugins/modal'; |
| | | import tab from '@/plugins/tab'; |
| | | import download from '@/plugins/download'; |
| | | import auth from '@/plugins/auth'; |
| | | import cache from '@/plugins/cache'; |
| | | import animate from '@/animate'; |
| | | import { useDict } from '@/utils/dict'; |
| | | import { handleTree, addDateRange, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi'; |
| | | import { getConfigKey, updateConfigByKey } from '@/api/system/config'; |
| | | import { download as rd } from '@/utils/request'; |
| | | |
| | | declare module '@vue/runtime-core' { |
| | | export {}; |
| | | |
| | | declare module 'vue' { |
| | | interface ComponentCustomProperties { |
| | | // å
¨å±æ¹æ³å£°æ |
| | | $modal: typeof modal; |
| | |
| | | parseTime: typeof parseTime; |
| | | } |
| | | } |
| | | |
| | | declare module 'vform3-builds' { |
| | | const content: any; |
| | | export = content; |
| | | } |
| | |
| | | import { RouteRecordRaw } from 'vue-router'; |
| | | |
| | | import { LocationQuery, type RouteMeta as VRouteMeta } from 'vue-router'; |
| | | declare module 'vue-router' { |
| | | declare type RouteOption = { |
| | | hidden?: boolean; |
| | | interface RouteMeta extends VRouteMeta { |
| | | link?: string; |
| | | title?: string; |
| | | affix?: boolean; |
| | | noCache?: boolean; |
| | | activeMenu?: string; |
| | | icon?: string; |
| | | breadcrumb?: boolean; |
| | | } |
| | | |
| | | interface _RouteRecordBase { |
| | | hidden?: boolean | string | number; |
| | | permissions?: string[]; |
| | | roles?: string[]; |
| | | component?: any; |
| | | children?: RouteOption[]; |
| | | alwaysShow?: boolean; |
| | | parentPath?: string; |
| | | meta?: { |
| | | title: string; |
| | | icon: string; |
| | | }; |
| | | query?: string; |
| | | } & RouteRecordRaw; |
| | | |
| | | declare interface _RouteLocationBase { |
| | | children?: RouteOption[]; |
| | | parentPath?: string; |
| | | } |
| | | |
| | | declare interface RouteLocationOptions { |
| | | fullPath?: string; |
| | | } |
| | | |
| | | declare interface TagView extends Partial<_RouteLocationBase> { |
| | | interface _RouteLocationBase { |
| | | children?: _RouteRecordBase[]; |
| | | path?: string; |
| | | title?: string; |
| | | meta?: { |
| | | link?: string; |
| | | title?: string; |
| | | affix?: boolean; |
| | | noCache?: boolean; |
| | | }; |
| | | } |
| | | |
| | | interface TagView { |
| | | fullPath?: string; |
| | | name?: string; |
| | | path?: string; |
| | | title?: string; |
| | | meta?: RouteMeta; |
| | | query?: LocationQuery; |
| | | } |
| | | } |
| | | |
| | | export {}; |
| | |
| | | * @returns {Array} |
| | | */ |
| | | export const cleanArray = (actual: Array<any>) => { |
| | | const newArray = []; |
| | | const newArray: any[] = []; |
| | | for (let i = 0; i < actual.length; i++) { |
| | | if (actual[i]) { |
| | | newArray.push(actual[i]); |
| | |
| | | |
| | | type PropTypes = VueTypesInterface & { |
| | | readonly style: VueTypeValidableDef<CSSProperties>; |
| | | readonly fieldOption: VueTypeValidableDef<Array<FieldOption>>; |
| | | }; |
| | | |
| | | const propTypes = createTypes({ |
| | |
| | | // 对åºå½é
åèµæºæä»¶åç¼ |
| | | config.headers['Content-Language'] = getLanguage(); |
| | | |
| | | const isToken = (config.headers || {}).isToken === false; |
| | | const isToken = config.headers?.isToken === false; |
| | | // æ¯å¦éè¦é²æ¢æ°æ®éå¤æäº¤ |
| | | const isRepeatSubmit = (config.headers || {}).repeatSubmit === false; |
| | | const isRepeatSubmit = config.headers?.repeatSubmit === false; |
| | | // æ¯å¦éè¦å å¯ |
| | | const isEncrypt = (config.headers || {}).isEncrypt === 'true'; |
| | | const isEncrypt = config.headers?.isEncrypt === 'true'; |
| | | |
| | | if (getToken() && !isToken) { |
| | | config.headers['Authorization'] = 'Bearer ' + getToken(); // 让æ¯ä¸ªè¯·æ±æºå¸¦èªå®ä¹token è¯·æ ¹æ®å®é
æ
åµèªè¡ä¿®æ¹ |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | // å½å¼å¯åæ°å å¯ |
| | | if (isEncrypt && (config.method === 'post' || config.method === 'put')) { |
| | | // çæä¸ä¸ª AES å¯é¥ |
| | | const aesKey = generateAesKey(); |
| | | config.headers[encryptHeader] = encrypt(encryptBase64(aesKey)); |
| | | config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey); |
| | | if (import.meta.env.VITE_APP_ENCRYPT === 'true') { |
| | | // å½å¼å¯åæ°å å¯ |
| | | if (isEncrypt && (config.method === 'post' || config.method === 'put')) { |
| | | // çæä¸ä¸ª AES å¯é¥ |
| | | const aesKey = generateAesKey(); |
| | | config.headers[encryptHeader] = encrypt(encryptBase64(aesKey)); |
| | | config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey); |
| | | } |
| | | } |
| | | // FormDataæ°æ®å»è¯·æ±å¤´Content-Type |
| | | if (config.data instanceof FormData) { |
| | |
| | | return config; |
| | | }, |
| | | (error: any) => { |
| | | console.log(error); |
| | | return Promise.reject(error); |
| | | } |
| | | ); |
| | |
| | | // ååºæ¦æªå¨ |
| | | service.interceptors.response.use( |
| | | (res: AxiosResponse) => { |
| | | // å å¯åç AES ç§é¥ |
| | | const keyStr = res.headers[encryptHeader]; |
| | | // å å¯ |
| | | if (keyStr != null && keyStr != '') { |
| | | const data = res.data; |
| | | // 请æ±ä½ AES è§£å¯ |
| | | const base64Str = decrypt(keyStr); |
| | | // base64 è§£ç å¾å°è¯·æ±å¤´ç AES ç§é¥ |
| | | const aesKey = decryptBase64(base64Str.toString()); |
| | | // aesKey è§£ç data |
| | | const decryptData = decryptWithAes(data, aesKey); |
| | | // å°ç»æ (å¾å°çæ¯ JSON å符串) 转为 JSON |
| | | res.data = JSON.parse(decryptData); |
| | | if (import.meta.env.VITE_APP_ENCRYPT === 'true') { |
| | | // å å¯åç AES ç§é¥ |
| | | const keyStr = res.headers[encryptHeader]; |
| | | // å å¯ |
| | | if (keyStr != null && keyStr != '') { |
| | | const data = res.data; |
| | | // 请æ±ä½ AES è§£å¯ |
| | | const base64Str = decrypt(keyStr); |
| | | // base64 è§£ç å¾å°è¯·æ±å¤´ç AES ç§é¥ |
| | | const aesKey = decryptBase64(base64Str.toString()); |
| | | // aesKey è§£ç data |
| | | const decryptData = decryptWithAes(data, aesKey); |
| | | // å°ç»æ (å¾å°çæ¯ JSON å符串) 转为 JSON |
| | | res.data = JSON.parse(decryptData); |
| | | } |
| | | } |
| | | // æªè®¾ç½®ç¶æç åé»è®¤æåç¶æ |
| | | const code = res.data.code || HttpStatus.SUCCESS; |
| | |
| | | } |
| | | return Promise.reject('æ æçä¼è¯ï¼æè
ä¼è¯å·²è¿æï¼è¯·éæ°ç»å½ã'); |
| | | } else if (code === HttpStatus.SERVER_ERROR) { |
| | | console.log(msg); |
| | | ElMessage({ message: msg, type: 'error' }); |
| | | return Promise.reject(new Error(msg)); |
| | | } else if (code === HttpStatus.WARN) { |
| | |
| | | if (value === undefined) { |
| | | return ''; |
| | | } |
| | | const actions = []; |
| | | const actions: Array<string | number> = []; |
| | | Object.keys(datas).some((key) => { |
| | | if (datas[key].value == '' + value) { |
| | | actions.push(datas[key].label); |
| | |
| | | export const blobValidate = (data: any) => { |
| | | return data.type !== 'application/json'; |
| | | }; |
| | | |
| | | export default { |
| | | handleTree |
| | | }; |
| | |
| | | */ |
| | | |
| | | import { getToken } from '@/utils/auth'; |
| | | import { ElNotification } from 'element-plus'; |
| | | import useNoticeStore from '@/store/modules/notice'; |
| | | import { ElNotification } from "element-plus"; |
| | | |
| | | const { addNotice } = useNoticeStore(); |
| | | |
| | | let socketUrl: any = ''; // socketå°å |
| | | let websocket: any = null; // websocket å®ä¾ |
| | |
| | | if (e.data.indexOf('ping') > 0) { |
| | | return; |
| | | } |
| | | addNotice({ |
| | | useNoticeStore().addNotice({ |
| | | message: e.data, |
| | | read: false, |
| | | time: new Date().toLocaleString() |
| | |
| | | message: e.data, |
| | | type: 'success', |
| | | duration: 3000 |
| | | }) |
| | | }); |
| | | return e.data; |
| | | }; |
| | | }; |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="é¨é¨id" prop="deptId"> |
| | | <el-input v-model="queryParams.deptId" placeholder="请è¾å
¥é¨é¨id" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.deptId" placeholder="请è¾å
¥é¨é¨id" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨æ·id" prop="userId"> |
| | | <el-input v-model="queryParams.userId" placeholder="请è¾å
¥ç¨æ·id" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.userId" placeholder="请è¾å
¥ç¨æ·id" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æåºå·" prop="orderNum"> |
| | | <el-input v-model="queryParams.orderNum" placeholder="请è¾å
¥æåºå·" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.orderNum" placeholder="请è¾å
¥æåºå·" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="keyé®" prop="testKey"> |
| | | <el-input v-model="queryParams.testKey" placeholder="请è¾å
¥keyé®" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.testKey" placeholder="请è¾å
¥keyé®" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å¼" prop="value"> |
| | | <el-input v-model="queryParams.value" placeholder="请è¾å
¥å¼" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.value" placeholder="请è¾å
¥å¼" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['demo:demo:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">ä¿®æ¹</el-button> |
| | | <el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">ä¿®æ¹</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']" |
| | | <el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" |
| | | >å é¤</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['demo:demo:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="主é®" align="center" prop="id" v-if="true" /> |
| | | <el-table-column v-if="true" label="主é®" align="center" prop="id" /> |
| | | <el-table-column label="é¨é¨id" align="center" prop="deptId" /> |
| | | <el-table-column label="ç¨æ·id" align="center" prop="userId" /> |
| | | <el-table-column label="æåºå·" align="center" prop="orderNum" /> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:demo:edit']"></el-button> |
| | | <el-button v-hasPermi="['demo:demo:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:demo:remove']"></el-button> |
| | | <el-button v-hasPermi="['demo:demo:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹æµè¯åå¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="é¨é¨id" prop="deptId"> |
| | | <el-input v-model="form.deptId" placeholder="请è¾å
¥é¨é¨id" /> |
| | |
| | | userId: undefined, |
| | | orderNum: undefined, |
| | | testKey: undefined, |
| | | value: undefined, |
| | | } |
| | | value: undefined |
| | | }; |
| | | const data = reactive<PageData<DemoForm, DemoQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | userId: undefined, |
| | | orderNum: undefined, |
| | | testKey: undefined, |
| | | value: undefined, |
| | | value: undefined |
| | | }, |
| | | rules: { |
| | | id: [ |
| | | { required: true, message: "主é®ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | deptId: [ |
| | | { required: true, message: "é¨é¨idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | userId: [ |
| | | { required: true, message: "ç¨æ·idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | orderNum: [ |
| | | { required: true, message: "æåºå·ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | testKey: [ |
| | | { required: true, message: "keyé®ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | value: [ |
| | | { required: true, message: "å¼ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | id: [{ required: true, message: '主é®ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | deptId: [{ required: true, message: 'é¨é¨idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | userId: [{ required: true, message: 'ç¨æ·idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | orderNum: [{ required: true, message: 'æåºå·ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | testKey: [{ required: true, message: 'keyé®ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | value: [{ required: true, message: 'å¼ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | demoList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | demoFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: DemoVO[]) => { |
| | | ids.value = selection.map(item => item.id); |
| | | ids.value = selection.map((item) => item.id); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å æµè¯å"; |
| | | } |
| | | dialog.title = 'æ·»å æµè¯å'; |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: DemoVO) => { |
| | | reset(); |
| | | const _id = row?.id || ids.value[0] |
| | | const _id = row?.id || ids.value[0]; |
| | | const res = await getDemo(_id); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹æµè¯å"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹æµè¯å'; |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (form.value.id) { |
| | | await updateDemo(form.value).finally(() => buttonLoading.value = false); |
| | | await updateDemo(form.value).finally(() => (buttonLoading.value = false)); |
| | | } else { |
| | | await addDemo(form.value).finally(() => buttonLoading.value = false); |
| | | await addDemo(form.value).finally(() => (buttonLoading.value = false)); |
| | | } |
| | | proxy?.$modal.msgSuccess("ä¿®æ¹æå"); |
| | | proxy?.$modal.msgSuccess('ä¿®æ¹æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: DemoVO) => { |
| | | const _ids = row?.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿µè¯åç¼å·ä¸º"' + _ids + '"çæ°æ®é¡¹ï¼').finally(() => loading.value = false); |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿µè¯åç¼å·ä¸º"' + _ids + '"çæ°æ®é¡¹ï¼').finally(() => (loading.value = false)); |
| | | await delDemo(_ids); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | await getList(); |
| | | } |
| | | }; |
| | | |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download('demo/demo/export', { |
| | | ...queryParams.value |
| | | }, `demo_${new Date().getTime()}.xlsx`) |
| | | } |
| | | proxy?.download( |
| | | 'demo/demo/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `demo_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="æ èç¹å" prop="treeName"> |
| | | <el-input v-model="queryParams.treeName" placeholder="请è¾å
¥æ èç¹å" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.treeName" placeholder="请è¾å
¥æ èç¹å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['demo:tree:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['demo:tree:add']" type="primary" plain icon="Plus" @click="handleAdd()">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">å±å¼/æå </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | <el-table |
| | | ref="treeTableRef" |
| | | v-loading="loading" |
| | | :data="treeList" |
| | | row-key="id" |
| | | :default-expand-all="isExpandAll" |
| | | :tree-props="{children: 'children', hasChildren: 'hasChildren'}" |
| | | ref="treeTableRef" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | > |
| | | <el-table-column label="ç¶id" align="center" prop="parentId" /> |
| | | <el-table-column label="é¨é¨id" align="center" prop="deptId" /> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['demo:tree:edit']" /> |
| | | <el-button v-hasPermi="['demo:tree:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="æ°å¢" placement="top"> |
| | | <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['demo:tree:add']" /> |
| | | <el-button v-hasPermi="['demo:tree:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['demo:tree:remove']" /> |
| | | <el-button v-hasPermi="['demo:tree:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹æµè¯æ å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="treeFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="ç¶id" prop="parentId"> |
| | | <el-tree-select |
| | |
| | | </template> |
| | | |
| | | <script setup name="Tree" lang="ts"> |
| | | import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree"; |
| | | import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree'; |
| | | import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types'; |
| | | |
| | | |
| | | type TreeOption = { |
| | | id: number; |
| | | treeName: string; |
| | | children?: TreeOption[]; |
| | | } |
| | | }; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance;; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const treeList = ref<TreeVO[]>([]); |
| | | const treeOptions = ref<TreeOption[]>([]); |
| | |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const treeFormRef = ref<ElFormInstance>(); |
| | | const treeTableRef = ref<ElTableInstance>() |
| | | const treeTableRef = ref<ElTableInstance>(); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | | visible: false, |
| | | title: '' |
| | | }); |
| | | |
| | | |
| | | const initFormData: TreeForm = { |
| | | id: undefined, |
| | | parentId: undefined, |
| | | deptId: undefined, |
| | | userId: undefined, |
| | | treeName: undefined, |
| | | } |
| | | id: undefined, |
| | | parentId: undefined, |
| | | deptId: undefined, |
| | | userId: undefined, |
| | | treeName: undefined |
| | | }; |
| | | |
| | | const data = reactive<PageData<TreeForm, TreeQuery>>({ |
| | | form: {...initFormData}, |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | parentId: undefined, |
| | | deptId: undefined, |
| | | userId: undefined, |
| | | treeName: undefined, |
| | | treeName: undefined |
| | | }, |
| | | rules: { |
| | | id: [ |
| | | { required: true, message: "主é®ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | parentId: [ |
| | | { required: true, message: "ç¶idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | deptId: [ |
| | | { required: true, message: "é¨é¨idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | userId: [ |
| | | { required: true, message: "ç¨æ·idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | treeName: [ |
| | | { required: true, message: "å¼ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | id: [{ required: true, message: '主é®ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | parentId: [{ required: true, message: 'ç¶idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | deptId: [{ required: true, message: 'é¨é¨idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | userId: [{ required: true, message: 'ç¨æ·idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | treeName: [{ required: true, message: 'å¼ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await listTree(queryParams.value); |
| | | const data = proxy?.handleTree<TreeVO>(res.data, "id", "parentId"); |
| | | const data = proxy?.handleTree<TreeVO>(res.data, 'id', 'parentId'); |
| | | if (data) { |
| | | treeList.value = data; |
| | | loading.value = false; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | /** æ¥è¯¢æµè¯æ 䏿æ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listTree(); |
| | | treeOptions.value = []; |
| | | const data: TreeOption = { id: 0, treeName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<TreeOption>(res.data, "id", "parentId"); |
| | | data.children = proxy?.handleTree<TreeOption>(res.data, 'id', 'parentId'); |
| | | treeOptions.value.push(data); |
| | | } |
| | | }; |
| | | |
| | | // åæ¶æé® |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | |
| | | // 表åéç½® |
| | | const reset = () => { |
| | | form.value = {...initFormData} |
| | | form.value = { ...initFormData }; |
| | | treeFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = (row?: TreeVO) => { |
| | |
| | | form.value.parentId = 0; |
| | | } |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å æµè¯æ "; |
| | | } |
| | | dialog.title = 'æ·»å æµè¯æ '; |
| | | }; |
| | | |
| | | /** å±å¼/æå æä½ */ |
| | | const handleToggleExpandAll = () => { |
| | | isExpandAll.value = !isExpandAll.value; |
| | | toggleExpandAll(treeList.value, isExpandAll.value) |
| | | } |
| | | toggleExpandAll(treeList.value, isExpandAll.value); |
| | | }; |
| | | |
| | | /** å±å¼/æå æä½ */ |
| | | const toggleExpandAll = (data: TreeVO[], status: boolean) => { |
| | | data.forEach((item) => { |
| | | treeTableRef.value?.toggleRowExpansion(item, status) |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status) |
| | | }) |
| | | } |
| | | treeTableRef.value?.toggleRowExpansion(item, status); |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); |
| | | }); |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row: TreeVO) => { |
| | |
| | | const res = await getTree(row.id); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹æµè¯æ "; |
| | | } |
| | | dialog.title = 'ä¿®æ¹æµè¯æ '; |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (form.value.id) { |
| | | await updateTree(form.value).finally(() => buttonLoading.value = false); |
| | | await updateTree(form.value).finally(() => (buttonLoading.value = false)); |
| | | } else { |
| | | await addTree(form.value).finally(() => buttonLoading.value = false); |
| | | await addTree(form.value).finally(() => (buttonLoading.value = false)); |
| | | } |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: TreeVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿µè¯æ ç¼å·ä¸º"' + row.id + '"çæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | await delTree(row.id).finally(() => loading.value = false); |
| | | await delTree(row.id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | |
| | | let { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const errGif = ref(errImage + "?" + +new Date()); |
| | | const errGif = ref(errImage + '?' + +new Date()); |
| | | |
| | | function back() { |
| | | if (proxy?.$route.query.noGoBack) { |
| | | proxy.$router.push({ path: "/" }); |
| | | proxy.$router.push({ path: '/' }); |
| | | } else { |
| | | proxy?.$router.go(-1); |
| | | } |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | let message = computed(() => { |
| | | return 'æ¾ä¸å°ç½é¡µï¼' |
| | | }) |
| | | return 'æ¾ä¸å°ç½é¡µï¼'; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .wscn-http404-container{ |
| | | transform: translate(-50%,-50%); |
| | | .wscn-http404-container { |
| | | transform: translate(-50%, -50%); |
| | | position: absolute; |
| | | top: 40%; |
| | | left: 50%; |
| | |
| | | * åå¸å¼é Lock4j 注解éãå·¥å
·é å¤ç§å¤æ ·<br /> |
| | | * åå¸å¼å¹ç Lock4j åºäºåå¸å¼éå®ç°<br /> |
| | | * åå¸å¼é¾è·¯è¿½è¸ª SkyWalking æ¯æé¾è·¯è¿½è¸ªãç½æ ¼åæã度éèåãå¯è§å<br /> |
| | | * åå¸å¼ä»»å¡è°åº¦ PowerJob 髿§è½ é«å¯é ææ©å±<br /> |
| | | * åå¸å¼ä»»å¡è°åº¦ SnailJob 髿§è½ é«å¯é ææ©å±<br /> |
| | | * æä»¶åå¨ Minio æ¬å°åå¨<br /> |
| | | * æä»¶åå¨ ä¸çãé¿éãè
¾è®¯ äºåå¨<br /> |
| | | * çæ§æ¡æ¶ SpringBoot-Admin å
¨æ¹ä½æå¡çæ§<br /> |
| | |
| | | * é¨ç½²æ¹å¼ Docker 容å¨ç¼æ ä¸é®é¨ç½²ä¸å¡é群<br /> |
| | | * å½é
å SpringMessage Springæ åå½é
åæ¹æ¡<br /> |
| | | </p> |
| | | <p><b>å½åçæ¬:</b> <span>v5.1.2</span></p> |
| | | <p><b>å½åçæ¬:</b> <span>v5.2.0-BETA</span></p> |
| | | <p> |
| | | <el-tag type="danger">¥å
è´¹å¼æº</el-tag> |
| | | </p> |
| | |
| | | * åå¸å¼çæ§ PrometheusãGrafana å
¨æ¹ä½æ§è½çæ§<br /> |
| | | * å
¶ä½ä¸ Vue çæ¬ä¸è´<br /> |
| | | </p> |
| | | <p><b>å½åçæ¬:</b> <span>v2.1.2</span></p> |
| | | <p><b>å½åçæ¬:</b> <span>v2.2.0-BETA</span></p> |
| | | <p> |
| | | <el-tag type="danger">¥å
è´¹å¼æº</el-tag> |
| | | </p> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Index" lang="ts"> |
| | | import { initWebSocket } from '@/utils/websocket'; |
| | | |
| | | onMounted(() => { |
| | | let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://' |
| | | initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket"); |
| | | }); |
| | | |
| | | const goTarget = (url:string) => { |
| | | window.open(url, '__blank') |
| | | } |
| | | const goTarget = (url: string) => { |
| | | window.open(url, '__blank'); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | margin: 0; |
| | | } |
| | | |
| | | font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif; |
| | | font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; |
| | | font-size: 13px; |
| | | color: #676a6c; |
| | | overflow-x: hidden; |
| | |
| | | <div class="login"> |
| | | <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> |
| | | <h3 class="title">RuoYi-Vue-Pluså¤ç§æ·ç®¡çç³»ç»</h3> |
| | | <el-form-item prop="tenantId" v-if="tenantEnabled"> |
| | | <el-form-item v-if="tenantEnabled" prop="tenantId"> |
| | | <el-select v-model="loginForm.tenantId" filterable placeholder="è¯·éæ©/è¾å
¥å
¬å¸åç§°" style="width: 100%"> |
| | | <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option> |
| | | <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> |
| | |
| | | <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="code" v-if="captchaEnabled"> |
| | | <el-form-item v-if="captchaEnabled" prop="code"> |
| | | <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="éªè¯ç " style="width: 63%" @keyup.enter="handleLogin"> |
| | | <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | <div class="login-code"> |
| | | <img :src="codeUrl" @click="getCode" class="login-code-img" /> |
| | | <img :src="codeUrl" class="login-code-img" @click="getCode" /> |
| | | </div> |
| | | </el-form-item> |
| | | <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">è®°ä½å¯ç </el-checkbox> |
| | | <el-form-item style="float: right;"> |
| | | <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">è®°ä½å¯ç </el-checkbox> |
| | | <el-form-item style="float: right"> |
| | | <el-button circle title="微信ç»å½" @click="doSocialLogin('wechat')"> |
| | | <svg-icon icon-class="wechat" /> |
| | | </el-button> |
| | | <el-button circle title="MaxKeyç»å½" @click="doSocialLogin('maxkey')"> |
| | | <svg-icon icon-class="maxkey" /> |
| | | </el-button> |
| | | <el-button circle title="TopIamç»å½" @click="doSocialLogin('topiam')"> |
| | | <svg-icon icon-class="topiam" /> |
| | | </el-button> |
| | | <el-button circle title="Giteeç»å½" @click="doSocialLogin('gitee')"> |
| | | <svg-icon icon-class="gitee" /> |
| | |
| | | <svg-icon icon-class="github" /> |
| | | </el-button> |
| | | </el-form-item> |
| | | <el-form-item style="width:100%;"> |
| | | <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin"> |
| | | <el-form-item style="width: 100%"> |
| | | <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin"> |
| | | <span v-if="!loading">ç» å½</span> |
| | | <span v-else>ç» å½ ä¸...</span> |
| | | </el-button> |
| | | <div style="float: right;" v-if="register"> |
| | | <div v-if="register" style="float: right"> |
| | | <router-link class="link-type" :to="'/register'">ç«å³æ³¨å</router-link> |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <!-- åºé¨ --> |
| | | <div class="el-login-footer"> |
| | | <span>Copyright © 2018-2023 ç¯ççç®åLi All Rights Reserved.</span> |
| | | <span>Copyright © 2018-2024 ç¯ççç®åLi All Rights Reserved.</span> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | import { useUserStore } from '@/store/modules/user'; |
| | | import { LoginData, TenantVO } from '@/api/types'; |
| | | import { to } from 'await-to-js'; |
| | | import { HttpStatus } from "@/enums/RespEnum"; |
| | | import { HttpStatus } from '@/enums/RespEnum'; |
| | | |
| | | const userStore = useUserStore(); |
| | | const router = useRouter(); |
| | |
| | | } as LoginData); |
| | | |
| | | const loginRules: ElFormRules = { |
| | | tenantId: [{ required: true, trigger: "blur", message: "请è¾å
¥æ¨çç§æ·ç¼å·" }], |
| | | tenantId: [{ required: true, trigger: 'blur', message: '请è¾å
¥æ¨çç§æ·ç¼å·' }], |
| | | username: [{ required: true, trigger: 'blur', message: '请è¾å
¥æ¨çè´¦å·' }], |
| | | password: [{ required: true, trigger: 'blur', message: '请è¾å
¥æ¨çå¯ç ' }], |
| | | code: [{ required: true, trigger: 'change', message: '请è¾å
¥éªè¯ç ' }] |
| | |
| | | // ç§æ·å¼å
³ |
| | | const tenantEnabled = ref(true); |
| | | |
| | | |
| | | // 注åå¼å
³ |
| | | const register = ref(false); |
| | | const redirect = ref(undefined); |
| | |
| | | // ç§æ·å表 |
| | | const tenantList = ref<TenantVO[]>([]); |
| | | |
| | | watch(() => router.currentRoute.value, (newRoute: any) => { |
| | | redirect.value = newRoute.query && newRoute.query.redirect; |
| | | }, { immediate: true }); |
| | | watch( |
| | | () => router.currentRoute.value, |
| | | (newRoute: any) => { |
| | | redirect.value = newRoute.query && newRoute.query.redirect; |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | const handleLogin = () => { |
| | | loginRef.value?.validate(async (valid: boolean, fields: any) => { |
| | |
| | | loading.value = true; |
| | | // å¾éäºéè¦è®°ä½å¯ç è®¾ç½®å¨ localStorage ä¸è®¾ç½®è®°ä½ç¨æ·ååå¯ç |
| | | if (loginForm.value.rememberMe) { |
| | | localStorage.setItem("tenantId", String(loginForm.value.tenantId)); |
| | | localStorage.setItem('tenantId', String(loginForm.value.tenantId)); |
| | | localStorage.setItem('username', String(loginForm.value.username)); |
| | | localStorage.setItem('password', String(loginForm.value.password)); |
| | | localStorage.setItem('rememberMe', String(loginForm.value.rememberMe)); |
| | | } else { |
| | | // å¦åç§»é¤ |
| | | localStorage.removeItem("tenantId"); |
| | | localStorage.removeItem('tenantId'); |
| | | localStorage.removeItem('username'); |
| | | localStorage.removeItem('password'); |
| | | localStorage.removeItem('rememberMe'); |
| | |
| | | // è°ç¨actionçç»å½æ¹æ³ |
| | | const [err] = await to(userStore.login(loginForm.value)); |
| | | if (!err) { |
| | | await router.push({ path: redirect.value || '/' }); |
| | | const redirectUrl = redirect.value || '/'; |
| | | await router.push(redirectUrl); |
| | | loading.value = false; |
| | | } else { |
| | | loading.value = false; |
| | |
| | | }; |
| | | |
| | | const getLoginData = () => { |
| | | const tenantId = localStorage.getItem("tenantId"); |
| | | const tenantId = localStorage.getItem('tenantId'); |
| | | const username = localStorage.getItem('username'); |
| | | const password = localStorage.getItem('password'); |
| | | const rememberMe = localStorage.getItem('rememberMe'); |
| | |
| | | password: password === null ? String(loginForm.value.password) : String(password), |
| | | rememberMe: rememberMe === null ? false : Boolean(rememberMe) |
| | | } as LoginData; |
| | | } |
| | | |
| | | }; |
| | | |
| | | /** |
| | | * è·åç§æ·å表 |
| | |
| | | loginForm.value.tenantId = tenantList.value[0].tenantId; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | //æ£æµç§æ·éæ©æ¡çåå |
| | | watch(() => loginForm.value.tenantId, () => { |
| | | localStorage.setItem("tenantId", String(loginForm.value.tenantId)) |
| | | }); |
| | | watch( |
| | | () => loginForm.value.tenantId, |
| | | () => { |
| | | localStorage.setItem('tenantId', String(loginForm.value.tenantId)); |
| | | } |
| | | ); |
| | | |
| | | /** |
| | | * ç¬¬ä¸æ¹ç»å½ |
| | |
| | | }); |
| | | }; |
| | | |
| | | |
| | | |
| | | onMounted(() => { |
| | | getCode(); |
| | | initTenantList(); |
| | |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 100%; |
| | | background-image: url("../assets/images/login-background.jpg"); |
| | | background-image: url('../assets/images/login-background.jpg'); |
| | | background-size: cover; |
| | | } |
| | | |
| | |
| | | <el-col :span="24" class="card-box"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <Monitor style="width: 1em; height: 1em; vertical-align: middle;" /> |
| | | <span style="vertical-align: middle;">åºæ¬ä¿¡æ¯</span> |
| | | <Monitor style="width: 1em; height: 1em; vertical-align: middle" /> |
| | | <span style="vertical-align: middle">åºæ¬ä¿¡æ¯</span> |
| | | </template> |
| | | |
| | | <div class="el-table el-table--enable-row-hover el-table--medium"> |
| | |
| | | <div class="cell">Redisçæ¬</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.redis_version }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">è¿è¡æ¨¡å¼</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.redis_mode === "standalone" ? "åæº" : "é群" }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.redis_mode === 'standalone' ? 'åæº' : 'é群' }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">端å£</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.tcp_port }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">客æ·ç«¯æ°</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.connected_clients }}</div> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | |
| | | <div class="cell">è¿è¡æ¶é´(天)</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.uptime_in_days }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">使ç¨å
å</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.used_memory_human }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">使ç¨CPU</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div> |
| | | <div v-if="cache.info" class="cell">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">å
åé
ç½®</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.maxmemory_human }}</div> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | |
| | | <div class="cell">AOFæ¯å¦å¼å¯</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.aof_enabled === "0" ? "å¦" : "æ¯" }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.aof_enabled === '0' ? 'å¦' : 'æ¯' }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">RDBæ¯å¦æå</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div> |
| | | <div v-if="cache.info" class="cell">{{ cache.info.rdb_last_bgsave_status }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">Keyæ°é</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.dbSize">{{ cache.dbSize }}</div> |
| | | <div v-if="cache.dbSize" class="cell">{{ cache.dbSize }}</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell">ç½ç»å
¥å£/åºå£</div> |
| | | </td> |
| | | <td class="el-table__cell is-leaf"> |
| | | <div class="cell" v-if="cache.info"> |
| | | <div v-if="cache.info" class="cell"> |
| | | {{ cache.info.instantaneous_input_kbps }}kps/{{ cache.info.instantaneous_output_kbps }}kps |
| | | </div> |
| | | </td> |
| | |
| | | <el-col :span="12" class="card-box"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <PieChart style="width: 1em; height: 1em; vertical-align: middle;" /> |
| | | <span style="vertical-align: middle;">å½ä»¤ç»è®¡</span> |
| | | <PieChart style="width: 1em; height: 1em; vertical-align: middle" /> |
| | | <span style="vertical-align: middle">å½ä»¤ç»è®¡</span> |
| | | </template> |
| | | <div class="el-table el-table--enable-row-hover el-table--medium"> |
| | | <div ref="commandstats" style="height: 420px" /> |
| | |
| | | <el-col :span="12" class="card-box"> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">å
åä¿¡æ¯</span> |
| | | <Odometer style="width: 1em; height: 1em; vertical-align: middle" /> <span style="vertical-align: middle">å
åä¿¡æ¯</span> |
| | | </template> |
| | | <div class="el-table el-table--enable-row-hover el-table--medium"> |
| | | <div ref="usedmemory" style="height: 420px" /> |
| | |
| | | <script setup name="Cache" lang="ts"> |
| | | import { getCache } from '@/api/monitor/cache'; |
| | | import * as echarts from 'echarts'; |
| | | import { CacheVO } from '@/api/monitor/cache/types'; |
| | | |
| | | const cache = ref<any>({}); |
| | | const cache = ref<Partial<CacheVO>>({}); |
| | | const commandstats = ref(); |
| | | const usedmemory = ref(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const getList = async () => { |
| | | proxy?.$modal.loading("æ£å¨å è½½ç¼åçæ§æ°æ®ï¼è¯·ç¨åï¼"); |
| | | proxy?.$modal.loading('æ£å¨å è½½ç¼åçæ§æ°æ®ï¼è¯·ç¨åï¼'); |
| | | const res = await getCache(); |
| | | proxy?.$modal.closeLoading(); |
| | | cache.value = res.data; |
| | | const commandstatsIntance = echarts.init(commandstats.value, "macarons"); |
| | | const commandstatsIntance = echarts.init(commandstats.value, 'macarons'); |
| | | commandstatsIntance.setOption({ |
| | | tooltip: { |
| | | trigger: "item", |
| | | formatter: "{a} <br/>{b} : {c} ({d}%)" |
| | | trigger: 'item', |
| | | formatter: '{a} <br/>{b} : {c} ({d}%)' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "å½ä»¤", |
| | | type: "pie", |
| | | roseType: "radius", |
| | | name: 'å½ä»¤', |
| | | type: 'pie', |
| | | roseType: 'radius', |
| | | radius: [15, 95], |
| | | center: ["50%", "38%"], |
| | | center: ['50%', '38%'], |
| | | data: res.data.commandStats, |
| | | animationEasing: "cubicInOut", |
| | | animationEasing: 'cubicInOut', |
| | | animationDuration: 1000 |
| | | } |
| | | ] |
| | | }); |
| | | const usedmemoryInstance = echarts.init(usedmemory.value, "macarons"); |
| | | const usedmemoryInstance = echarts.init(usedmemory.value, 'macarons'); |
| | | usedmemoryInstance.setOption({ |
| | | tooltip: { |
| | | formatter: "{b} <br/>{a} : " + cache.value.info.used_memory_human |
| | | formatter: '{b} <br/>{a} : ' + cache.value.info.used_memory_human |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "å³°å¼", |
| | | type: "gauge", |
| | | name: 'å³°å¼', |
| | | type: 'gauge', |
| | | min: 0, |
| | | max: 1000, |
| | | detail: { |
| | |
| | | data: [ |
| | | { |
| | | value: parseFloat(cache.value.info.used_memory_human), |
| | | name: "å
åæ¶è" |
| | | name: 'å
åæ¶è' |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | }) |
| | | window.addEventListener("resize",()=>{ |
| | | commandstatsIntance.resize() |
| | | usedmemoryInstance.resize() |
| | | }); |
| | | } |
| | | window.addEventListener('resize', () => { |
| | | commandstatsIntance.resize(); |
| | | usedmemoryInstance.resize(); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="ç»å½å°å" prop="ipaddr"> |
| | | <el-input v-model="queryParams.ipaddr" placeholder="请è¾å
¥ç»å½å°å" clearable style="width: 240px;" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.ipaddr" placeholder="请è¾å
¥ç»å½å°å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable style="width: 240px;" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="ç»å½ç¶æ" clearable style="width: 240px"> |
| | | <el-select v-model="queryParams.status" placeholder="ç»å½ç¶æ" clearable > |
| | | <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:logininfor:remove']"> |
| | | <el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" @click="handleClean" v-hasPermi="['monitor:logininfor:remove']">æ¸
空</el-button> |
| | | <el-button v-hasPermi="['monitor:logininfor:remove']" type="danger" plain icon="Delete" @click="handleClean">æ¸
空</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock" v-hasPermi="['monitor:logininfor:unlock']"> |
| | | <el-button v-hasPermi="['monitor:logininfor:unlock']" type="primary" plain icon="Unlock" :disabled="single" @click="handleUnlock"> |
| | | è§£é |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:logininfor:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['monitor:logininfor:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | |
| | | ref="loginInfoTableRef" |
| | | v-loading="loading" |
| | | :data="loginInfoList" |
| | | @selection-change="handleSelectionChange" |
| | | :default-sort="defaultSort" |
| | | @selection-change="handleSelectionChange" |
| | | @sort-change="handleSortChange" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="Logininfor" lang="ts"> |
| | | import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo"; |
| | | import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types"; |
| | | import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from '@/api/monitor/loginInfo'; |
| | | import { LoginInfoQuery, LoginInfoVO } from '@/api/monitor/loginInfo/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type")); |
| | | const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status")); |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type')); |
| | | const { sys_common_status } = toRefs<any>(proxy?.useDict('sys_common_status')); |
| | | |
| | | const loginInfoList = ref<LoginInfoVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | const multiple = ref(true); |
| | | const selectName = ref<Array<string>>([]); |
| | | const total = ref(0); |
| | | const dateRange = ref<[DateModelType,DateModelType]>(['', '']); |
| | | const defaultSort = ref<any>({ prop: "loginTime", order: "descending" }); |
| | | const dateRange = ref<[DateModelType, DateModelType]>(['', '']); |
| | | const defaultSort = ref<any>({ prop: 'loginTime', order: 'descending' }); |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const loginInfoTableRef = ref<ElTableInstance>(); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<LoginInfoQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | ipaddr: '', |
| | | userName: '', |
| | | status: '', |
| | | orderByColumn: defaultSort.value.prop, |
| | | isAsc: defaultSort.value.order |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | ipaddr: '', |
| | | userName: '', |
| | | status: '', |
| | | orderByColumn: defaultSort.value.prop, |
| | | isAsc: defaultSort.value.order |
| | | }); |
| | | |
| | | /** æ¥è¯¢ç»å½æ¥å¿å表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value)); |
| | | loginInfoList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | loading.value = true; |
| | | const res = await list(proxy?.addDateRange(queryParams.value, dateRange.value)); |
| | | loginInfoList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order); |
| | | } |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order); |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: LoginInfoVO[]) => { |
| | | ids.value = selection.map(item => item.infoId); |
| | | multiple.value = !selection.length; |
| | | single.value = selection.length != 1; |
| | | selectName.value = selection.map(item => item.userName); |
| | | } |
| | | ids.value = selection.map((item) => item.infoId); |
| | | multiple.value = !selection.length; |
| | | single.value = selection.length != 1; |
| | | selectName.value = selection.map((item) => item.userName); |
| | | }; |
| | | /** æåºè§¦åäºä»¶ */ |
| | | const handleSortChange = (column: any) => { |
| | | queryParams.value.orderByColumn = column.prop; |
| | | queryParams.value.isAsc = column.order; |
| | | getList(); |
| | | } |
| | | queryParams.value.orderByColumn = column.prop; |
| | | queryParams.value.isAsc = column.order; |
| | | getList(); |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: LoginInfoVO) => { |
| | | const infoIds = row?.infoId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤è®¿é®ç¼å·ä¸º"' + infoIds + '"çæ°æ®é¡¹?'); |
| | | await delLoginInfo(infoIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | const infoIds = row?.infoId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤è®¿é®ç¼å·ä¸º"' + infoIds + '"çæ°æ®é¡¹?'); |
| | | await delLoginInfo(infoIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | /** æ¸
空æé®æä½ */ |
| | | const handleClean = async () => { |
| | | await proxy?.$modal.confirm("æ¯å¦ç¡®è®¤æ¸
空ææç»å½æ¥å¿æ°æ®é¡¹?"); |
| | | await cleanLoginInfo(); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("æ¸
空æå"); |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ¸
空ææç»å½æ¥å¿æ°æ®é¡¹?'); |
| | | await cleanLoginInfo(); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('æ¸
空æå'); |
| | | }; |
| | | /** è§£éæé®æä½ */ |
| | | const handleUnlock = async () => { |
| | | const username = selectName.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤è§£éç¨æ·"' + username + '"æ°æ®é¡¹?'); |
| | | await unlockLoginInfo(username); |
| | | proxy?.$modal.msgSuccess("ç¨æ·" + username + "è§£éæå"); |
| | | } |
| | | const username = selectName.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤è§£éç¨æ·"' + username + '"æ°æ®é¡¹?'); |
| | | await unlockLoginInfo(username); |
| | | proxy?.$modal.msgSuccess('ç¨æ·' + username + 'è§£éæå'); |
| | | }; |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("monitor/logininfor/export", { |
| | | ...queryParams.value, |
| | | }, `config_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'monitor/logininfor/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `config_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | getList(); |
| | | }); |
| | | </script> |
| | |
| | | <div class="p-2"> |
| | | <div class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="ç»å½å°å" prop="ipaddr"> |
| | | <el-input v-model="queryParams.ipaddr" placeholder="请è¾å
¥ç»å½å°å" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.ipaddr" placeholder="请è¾å
¥ç»å½å°å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | |
| | | <el-table |
| | | v-loading="loading" |
| | | :data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)" |
| | | style="width: 100%;" |
| | | style="width: 100%" |
| | | > |
| | | <el-table-column label="åºå·" width="50" type="index" align="center"> |
| | | <template #default="scope"> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="强é" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleForceLogout(scope.row)" v-hasPermi="['monitor:online:forceLogout']"> |
| | | <el-button v-hasPermi="['monitor:online:forceLogout']" link type="primary" icon="Delete" @click="handleForceLogout(scope.row)"> |
| | | </el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" /> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="Online" lang="ts"> |
| | | import { forceLogout, list as initData } from "@/api/monitor/online"; |
| | | import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types"; |
| | | import api from "@/api/system/user"; |
| | | import {to} from "await-to-js"; |
| | | import { forceLogout, list as initData } from '@/api/monitor/online'; |
| | | import { OnlineQuery, OnlineVO } from '@/api/monitor/online/types'; |
| | | import api from '@/api/system/user'; |
| | | import { to } from 'await-to-js'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type")); |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type')); |
| | | |
| | | const onlineList = ref<OnlineVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | onlineList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** 强éæé®æä½ */ |
| | | const handleForceLogout = async (row: OnlineVO) => { |
| | | const [err] = await to(proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å¼ºéå称为"' + row.userName + '"çç¨æ·?') as any); |
| | | if (!err) { |
| | | await forceLogout(row.tokenId); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="æä½å°å" prop="operIp"> |
| | | <el-input v-model="queryParams.operIp" placeholder="请è¾å
¥æä½å°å" clearable style="width: 240px;" @keyup.enter="handleQuery"/> |
| | | <el-input v-model="queryParams.operIp" placeholder="请è¾å
¥æä½å°å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³»ç»æ¨¡å" prop="title"> |
| | | <el-input v-model="queryParams.title" placeholder="请è¾å
¥ç³»ç»æ¨¡å" clearable style="width: 240px;" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.title" placeholder="请è¾å
¥ç³»ç»æ¨¡å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æä½äººå" prop="operName"> |
| | | <el-input v-model="queryParams.operName" placeholder="请è¾å
¥æä½äººå" clearable style="width: 240px;" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.operName" placeholder="请è¾å
¥æä½äººå" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="businessType"> |
| | | <el-select v-model="queryParams.businessType" placeholder="æä½ç±»å" clearable style="width: 240px"> |
| | | <el-select v-model="queryParams.businessType" placeholder="æä½ç±»å" clearable > |
| | | <el-option v-for="dict in sys_oper_type" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="æä½ç¶æ" clearable style="width: 240px"> |
| | | <el-select v-model="queryParams.status" placeholder="æä½ç¶æ" clearable > |
| | | <el-option v-for="dict in sys_common_status" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['monitor:operlog:remove']"> |
| | | <el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="WarnTriangleFilled" @click="handleClean" v-hasPermi="['monitor:operlog:remove']">æ¸
空</el-button> |
| | | <el-button v-hasPermi="['monitor:operlog:remove']" type="danger" plain icon="WarnTriangleFilled" @click="handleClean">æ¸
空</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['monitor:operlog:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['monitor:operlog:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | |
| | | ref="operLogTableRef" |
| | | v-loading="loading" |
| | | :data="operlogList" |
| | | @selection-change="handleSelectionChange" |
| | | :default-sort="defaultSort" |
| | | @selection-change="handleSelectionChange" |
| | | @sort-change="handleSortChange" |
| | | > |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | |
| | | <el-table-column label="æä½" fixed="right" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="详ç»" placement="top"> |
| | | <el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:operlog:query']"> </el-button> |
| | | <el-button v-hasPermi="['monitor:operlog:query']" link type="primary" icon="View" @click="handleView(scope.row)"> </el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æä½æ¥å¿è¯¦ç» --> |
| | | <el-dialog title="æä½æ¥å¿è¯¦ç»" v-model="dialog.visible" width="700px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" title="æä½æ¥å¿è¯¦ç»" width="700px" append-to-body> |
| | | <el-form :model="form" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç»å½ä¿¡æ¯ï¼">{{ form.operName }} / {{form.deptName}} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item> |
| | | <el-form-item label="ç»å½ä¿¡æ¯ï¼">{{ form.operName }} / {{ form.deptName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="请æ±ä¿¡æ¯ï¼">{{ form.requestMethod }} {{ form.operUrl }}</el-form-item> |
| | |
| | | <el-form-item label="æä½æ¶é´ï¼">{{ parseTime(form.operTime) }}</el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å¼å¸¸ä¿¡æ¯ï¼" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item> |
| | | <el-form-item v-if="form.status === 1" label="å¼å¸¸ä¿¡æ¯ï¼">{{ form.errorMsg }}</el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | |
| | | import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type", "sys_common_status")); |
| | | const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict('sys_oper_type', 'sys_common_status')); |
| | | |
| | | const operlogList = ref<OperLogVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | const dateRange = ref<[DateModelType, DateModelType]>(['', '']); |
| | | const defaultSort = ref<any>({ prop: "operTime", order: "descending" }); |
| | | const defaultSort = ref<any>({ prop: 'operTime', order: 'descending' }); |
| | | |
| | | const operLogTableRef = ref<ElTableInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | |
| | | visible: false, |
| | | title: '' |
| | | }); |
| | | |
| | | |
| | | const data = reactive<PageData<OperLogForm, OperLogQuery>>({ |
| | | form: { |
| | |
| | | operlogList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** æä½æ¥å¿ç±»ååå
¸ç¿»è¯ */ |
| | | const typeFormat = (row: OperLogForm) => { |
| | | return proxy?.selectDictLabel(sys_oper_type.value, row.businessType); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order); |
| | | } |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: OperLogVO[]) => { |
| | | ids.value = selection.map(item => item.operId); |
| | | ids.value = selection.map((item) => item.operId); |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** æåºè§¦åäºä»¶ */ |
| | | const handleSortChange = (column: any) => { |
| | | queryParams.value.orderByColumn = column.prop; |
| | | queryParams.value.isAsc = column.order; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** è¯¦ç»æé®æä½ */ |
| | | const handleView = (row: OperLogVO) => { |
| | | dialog.visible = true; |
| | | form.value = row; |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: OperLogVO) => { |
| | | const operIds = row?.operId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿¥å¿ç¼å·ä¸º"' + operIds + '"çæ°æ®é¡¹?'); |
| | | await delOperlog(operIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | /** æ¸
空æé®æä½ */ |
| | | const handleClean = async () => { |
| | | await proxy?.$modal.confirm("æ¯å¦ç¡®è®¤æ¸
ç©ºæææä½æ¥å¿æ°æ®é¡¹?"); |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ¸
ç©ºæææä½æ¥å¿æ°æ®é¡¹?'); |
| | | await cleanOperlog(); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("æ¸
空æå"); |
| | | } |
| | | proxy?.$modal.msgSuccess('æ¸
空æå'); |
| | | }; |
| | | |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("monitor/operlog/export", { |
| | | ...queryParams.value, |
| | | }, `config_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'monitor/operlog/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `config_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
ÎļþÃû´Ó src/views/monitor/powerjob/index.vue ÐÞ¸Ä |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | const url = ref(import.meta.env.VITE_APP_POWERJOB_ADMIN); |
| | | const url = ref(import.meta.env.VITE_APP_SNAILJOB_ADMIN); |
| | | </script> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { useRoute, useRouter } from 'vue-router' |
| | | import { useRoute, useRouter } from 'vue-router'; |
| | | |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | const { params, query } = route |
| | | const { path } = params |
| | | const { params, query } = route; |
| | | const { path } = params; |
| | | |
| | | router.replace({ path: '/' + path, query }) |
| | | router.replace({ path: '/' + path, query }); |
| | | </script> |
| | |
| | | <div class="register"> |
| | | <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form"> |
| | | <h3 class="title">RuoYi-Vue-Pluså¤ç§æ·ç®¡çç³»ç»</h3> |
| | | <el-form-item prop="tenantId" v-if="tenantEnabled"> |
| | | <el-form-item v-if="tenantEnabled" prop="tenantId"> |
| | | <el-select v-model="registerForm.tenantId" filterable placeholder="è¯·éæ©/è¾å
¥å
¬å¸åç§°" style="width: 100%"> |
| | | <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option> |
| | | <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> |
| | |
| | | <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="code" v-if="captchaEnabled"> |
| | | <el-input size="large" v-model="registerForm.code" auto-complete="off" placeholder="éªè¯ç " style="width: 63%" @keyup.enter="handleRegister"> |
| | | <el-form-item v-if="captchaEnabled" prop="code"> |
| | | <el-input v-model="registerForm.code" size="large" auto-complete="off" placeholder="éªè¯ç " style="width: 63%" @keyup.enter="handleRegister"> |
| | | <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> |
| | | </el-input> |
| | | <div class="register-code"> |
| | | <img :src="codeUrl" @click="getCode" class="register-code-img" /> |
| | | <img :src="codeUrl" class="register-code-img" @click="getCode" /> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item style="width:100%;"> |
| | | <el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleRegister"> |
| | | <el-form-item style="width: 100%"> |
| | | <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleRegister"> |
| | | <span v-if="!loading">注 å</span> |
| | | <span v-else>注 å ä¸...</span> |
| | | </el-button> |
| | | <div style="float: right;"> |
| | | <div style="float: right"> |
| | | <router-link class="link-type" :to="'/login'">使ç¨å·²æè´¦æ·ç»å½</router-link> |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <!-- åºé¨ --> |
| | | <div class="el-register-footer"> |
| | | <span>Copyright © 2018-2023 ç¯ççç®åLi All Rights Reserved.</span> |
| | | <span>Copyright © 2018-2024 ç¯ççç®åLi All Rights Reserved.</span> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | const router = useRouter(); |
| | | |
| | | const registerForm = ref<RegisterForm>({ |
| | | tenantId: "", |
| | | username: "", |
| | | password: "", |
| | | confirmPassword: "", |
| | | code: "", |
| | | uuid: "", |
| | | userType: "sys_user" |
| | | tenantId: '', |
| | | username: '', |
| | | password: '', |
| | | confirmPassword: '', |
| | | code: '', |
| | | uuid: '', |
| | | userType: 'sys_user' |
| | | }); |
| | | |
| | | // ç§æ·å¼å
³ |
| | | const tenantEnabled = ref(true); |
| | | |
| | | |
| | | const equalToPassword = (rule: any, value: string, callback: any) => { |
| | | if (registerForm.value.password !== value) { |
| | | callback(new Error("两次è¾å
¥çå¯ç ä¸ä¸è´")); |
| | | callback(new Error('两次è¾å
¥çå¯ç ä¸ä¸è´')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | |
| | | const registerRules: ElFormRules = { |
| | | tenantId: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çç§æ·ç¼å·" } |
| | | ], |
| | | tenantId: [{ required: true, trigger: 'blur', message: '请è¾å
¥æ¨çç§æ·ç¼å·' }], |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çè´¦å·" }, |
| | | { min: 2, max: 20, message: "ç¨æ·è´¦å·é¿åº¦å¿
é¡»ä»äº 2 å 20 ä¹é´", trigger: "blur" } |
| | | { required: true, trigger: 'blur', message: '请è¾å
¥æ¨çè´¦å·' }, |
| | | { min: 2, max: 20, message: 'ç¨æ·è´¦å·é¿åº¦å¿
é¡»ä»äº 2 å 20 ä¹é´', trigger: 'blur' } |
| | | ], |
| | | password: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çå¯ç " }, |
| | | { min: 5, max: 20, message: "ç¨æ·å¯ç é¿åº¦å¿
é¡»ä»äº 5 å 20 ä¹é´", trigger: "blur" } |
| | | { required: true, trigger: 'blur', message: '请è¾å
¥æ¨çå¯ç ' }, |
| | | { min: 5, max: 20, message: 'ç¨æ·å¯ç é¿åº¦å¿
é¡»ä»äº 5 å 20 ä¹é´', trigger: 'blur' }, |
| | | { pattern: /^[^<>"'|\\]+$/, message: 'ä¸è½å
å«éæ³å符ï¼< > " \' \\\ |', trigger: 'blur' } |
| | | ], |
| | | confirmPassword: [ |
| | | { required: true, trigger: "blur", message: "è¯·åæ¬¡è¾å
¥æ¨çå¯ç " }, |
| | | { required: true, validator: equalToPassword, trigger: "blur" } |
| | | { required: true, trigger: 'blur', message: 'è¯·åæ¬¡è¾å
¥æ¨çå¯ç ' }, |
| | | { required: true, validator: equalToPassword, trigger: 'blur' } |
| | | ], |
| | | code: [{ required: true, trigger: "change", message: "请è¾å
¥éªè¯ç " }] |
| | | code: [{ required: true, trigger: 'change', message: '请è¾å
¥éªè¯ç ' }] |
| | | }; |
| | | const codeUrl = ref(""); |
| | | const codeUrl = ref(''); |
| | | const loading = ref(false); |
| | | const captchaEnabled = ref(true); |
| | | const registerRef = ref<ElFormInstance>(); |
| | |
| | | const [err] = await to(register(registerForm.value)); |
| | | if (!err) { |
| | | const username = registerForm.value.username; |
| | | await ElMessageBox.alert("<font color='red'>æåä½ ï¼æ¨çè´¦å· " + username + " 注åæåï¼</font>", "ç³»ç»æç¤º", { |
| | | await ElMessageBox.alert("<font color='red'>æåä½ ï¼æ¨çè´¦å· " + username + ' 注åæåï¼</font>', 'ç³»ç»æç¤º', { |
| | | dangerouslyUseHTMLString: true, |
| | | type: "success", |
| | | type: 'success' |
| | | }); |
| | | await router.push("/login"); |
| | | await router.push('/login'); |
| | | } else { |
| | | loading.value = false; |
| | | if (captchaEnabled) { |
| | | if (captchaEnabled.value) { |
| | | getCode(); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const getCode = async () => { |
| | | const res = await getCodeImg(); |
| | |
| | | registerForm.value.tenantId = tenantList.value[0].tenantId; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getCode(); |
| | | initTenantList(); |
| | | }) |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 100%; |
| | | background-image: url("../assets/images/login-background.jpg"); |
| | | background-image: url('../assets/images/login-background.jpg'); |
| | | background-size: cover; |
| | | } |
| | | |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="search" v-show="showSearch"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px"> |
| | | <div v-show="showSearch" class="search"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="客æ·ç«¯key" prop="clientKey"> |
| | | <el-input v-model="queryParams.clientKey" placeholder="请è¾å
¥å®¢æ·ç«¯key" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.clientKey" placeholder="请è¾å
¥å®¢æ·ç«¯key" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="客æ·ç«¯ç§é¥" prop="clientSecret"> |
| | | <el-input v-model="queryParams.clientSecret" placeholder="请è¾å
¥å®¢æ·ç«¯ç§é¥" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.clientSecret" placeholder="请è¾å
¥å®¢æ·ç«¯ç§é¥" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="ç¶æ" clearable> |
| | | <el-select v-model="queryParams.status" placeholder="ç¶æ" clearable > |
| | | <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:client:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:client:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:client:edit']"> |
| | | <el-button v-hasPermi="['system:client:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"> |
| | | ä¿®æ¹ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:client:remove']"> |
| | | <el-button v-hasPermi="['system:client:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:client:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['system:client:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="id" align="center" prop="id" v-if="true" /> |
| | | <el-table-column v-if="true" label="id" align="center" prop="id" /> |
| | | <el-table-column label="客æ·ç«¯id" align="center" prop="clientId" /> |
| | | <el-table-column label="客æ·ç«¯key" align="center" prop="clientKey" /> |
| | | <el-table-column label="客æ·ç«¯ç§é¥" align="center" prop="clientSecret" /> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="Tokenæ´»è·è¶
æ¶æ¶é´" align="center" prop="activeTimeout" /> |
| | | <el-table-column label="Tokenåºå®è¶
æ¶æ¶é´" align="center" prop="timeout" /> |
| | | <el-table-column label="ç¶æ" align="center" key="status"> |
| | | <el-table-column key="status" label="ç¶æ" align="center"> |
| | | <template #default="scope"> |
| | | <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> |
| | | </template> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:client:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:client:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:client:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:client:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹å®¢æ·ç«¯ç®¡çå¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="clientFormRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-form-item label="客æ·ç«¯key" prop="clientKey"> |
| | | <el-input v-model="form.clientKey" :disabled="form.id != null" placeholder="请è¾å
¥å®¢æ·ç«¯key" /> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value"> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value"> |
| | | {{ dict.label }} |
| | | </el-radio> |
| | | </el-radio-group> |
| | |
| | | import { ClientVO, ClientQuery, ClientForm } from '@/api/system/client/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable")); |
| | | const { sys_grant_type } = toRefs<any>(proxy?.useDict("sys_grant_type")); |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type")); |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); |
| | | const { sys_grant_type } = toRefs<any>(proxy?.useDict('sys_grant_type')); |
| | | const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type')); |
| | | |
| | | const clientList = ref<ClientVO[]>([]); |
| | | const buttonLoading = ref(false); |
| | |
| | | deviceType: undefined, |
| | | activeTimeout: undefined, |
| | | timeout: undefined, |
| | | status: undefined, |
| | | } |
| | | status: undefined |
| | | }; |
| | | const data = reactive<PageData<ClientForm, ClientQuery>>({ |
| | | form: {...initFormData}, |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | |
| | | deviceType: undefined, |
| | | activeTimeout: undefined, |
| | | timeout: undefined, |
| | | status: undefined, |
| | | status: undefined |
| | | }, |
| | | rules: { |
| | | id: [ |
| | | { required: true, message: "idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | clientId: [ |
| | | { required: true, message: "客æ·ç«¯idä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | clientKey: [ |
| | | { required: true, message: "客æ·ç«¯keyä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | clientSecret: [ |
| | | { required: true, message: "客æ·ç«¯ç§é¥ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ], |
| | | grantTypeList: [ |
| | | { required: true, message: "ææç±»åä¸è½ä¸ºç©º", trigger: "change" } |
| | | ], |
| | | deviceType: [ |
| | | { required: true, message: "设å¤ç±»åä¸è½ä¸ºç©º", trigger: "change" } |
| | | ], |
| | | id: [{ required: true, message: 'idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | clientId: [{ required: true, message: '客æ·ç«¯idä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | clientKey: [{ required: true, message: '客æ·ç«¯keyä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | clientSecret: [{ required: true, message: '客æ·ç«¯ç§é¥ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | grantTypeList: [{ required: true, message: 'ææç±»åä¸è½ä¸ºç©º', trigger: 'change' }], |
| | | deviceType: [{ required: true, message: '设å¤ç±»åä¸è½ä¸ºç©º', trigger: 'change' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | clientList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = {...initFormData}; |
| | | form.value = { ...initFormData }; |
| | | clientFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: ClientVO[]) => { |
| | | ids.value = selection.map(item => item.id); |
| | | ids.value = selection.map((item) => item.id); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å 客æ·ç«¯ç®¡ç"; |
| | | } |
| | | dialog.title = 'æ·»å 客æ·ç«¯ç®¡ç'; |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: ClientVO) => { |
| | | reset(); |
| | | const _id = row?.id || ids.value[0] |
| | | const _id = row?.id || ids.value[0]; |
| | | const res = await getClient(_id); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹å®¢æ·ç«¯ç®¡ç"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹å®¢æ·ç«¯ç®¡ç'; |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (form.value.id) { |
| | | await updateClient(form.value).finally(() => buttonLoading.value = false); |
| | | await updateClient(form.value).finally(() => (buttonLoading.value = false)); |
| | | } else { |
| | | await addClient(form.value).finally(() => buttonLoading.value = false); |
| | | await addClient(form.value).finally(() => (buttonLoading.value = false)); |
| | | } |
| | | proxy?.$modal.msgSuccess("ä¿®æ¹æå"); |
| | | proxy?.$modal.msgSuccess('ä¿®æ¹æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: ClientVO) => { |
| | | const _ids = row?.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å®¢æ·ç«¯ç®¡çç¼å·ä¸º"' + _ids + '"çæ°æ®é¡¹ï¼').finally(() => loading.value = false); |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å®¢æ·ç«¯ç®¡çç¼å·ä¸º"' + _ids + '"çæ°æ®é¡¹ï¼').finally(() => (loading.value = false)); |
| | | await delClient(_ids); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | await getList(); |
| | | } |
| | | }; |
| | | |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download('system/client/export', { |
| | | ...queryParams.value |
| | | }, `client_${new Date().getTime()}.xlsx`) |
| | | } |
| | | proxy?.download( |
| | | 'system/client/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `client_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | /** ç¶æä¿®æ¹ */ |
| | | const handleStatusChange = async (row: ClientVO) => { |
| | | let text = row.status === "0" ? "å¯ç¨" : "åç¨" |
| | | let text = row.status === '0' ? 'å¯ç¨' : 'åç¨'; |
| | | try { |
| | | await proxy?.$modal.confirm('确认è¦"' + text + '"å?'); |
| | | await changeStatus(row.id, row.status); |
| | | proxy?.$modal.msgSuccess(text + "æå"); |
| | | await changeStatus(row.clientId, row.status); |
| | | proxy?.$modal.msgSuccess(text + 'æå'); |
| | | } catch (err) { |
| | | row.status = row.status === "0" ? "1" : "0"; |
| | | row.status = row.status === '0' ? '1' : '0'; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="åæ°åç§°" prop="configName"> |
| | | <el-input v-model="queryParams.configName" placeholder="请è¾å
¥åæ°åç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.configName" placeholder="请è¾å
¥åæ°åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åæ°é®å" prop="configKey"> |
| | | <el-input v-model="queryParams.configKey" placeholder="请è¾å
¥åæ°é®å" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.configKey" placeholder="请è¾å
¥åæ°é®å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç³»ç»å
ç½®" prop="configType"> |
| | | <el-select v-model="queryParams.configType" placeholder="ç³»ç»å
ç½®" clearable> |
| | | <el-select v-model="queryParams.configType" placeholder="ç³»ç»å
ç½®" clearable > |
| | | <el-option v-for="dict in sys_yes_no" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="å建æ¶é´" style="width: 308px;"> |
| | | <el-form-item label="å建æ¶é´" style="width: 308px"> |
| | | <el-date-picker |
| | | v-model="dateRange" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:config:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:config:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:config:edit']"> |
| | | <el-button v-hasPermi="['system:config:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"> |
| | | ä¿®æ¹ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:config:remove']"> |
| | | <el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:config:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['system:config:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:config:remove']">å·æ°ç¼å</el-button> |
| | | <el-button v-hasPermi="['system:config:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">å·æ°ç¼å</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="忰䏻é®" align="center" prop="configId" v-if="false" /> |
| | | <el-table-column v-if="false" label="忰䏻é®" align="center" prop="configId" /> |
| | | <el-table-column label="åæ°åç§°" align="center" prop="configName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="åæ°é®å" align="center" prop="configKey" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="åæ°é®å¼" align="center" prop="configValue" :show-overflow-tooltip="true" /> |
| | |
| | | <el-table-column label="æä½" align="center" width="150" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:config:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:config:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:config:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:config:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | |
| | | <!-- æ·»å æä¿®æ¹åæ°é
ç½®å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="configFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="åæ°åç§°" prop="configName"> |
| | | <el-input v-model="form.configName" placeholder="请è¾å
¥åæ°åç§°" /> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="ç³»ç»å
ç½®" prop="configType"> |
| | | <el-radio-group v-model="form.configType"> |
| | | <el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio> |
| | | <el-radio v-for="dict in sys_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Config" lang="ts"> |
| | | import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config"; |
| | | import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types"; |
| | | import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from '@/api/system/config'; |
| | | import { ConfigForm, ConfigQuery, ConfigVO } from '@/api/system/config/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no")); |
| | | const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no')); |
| | | |
| | | const configList = ref<ConfigVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | configName: '', |
| | | configKey: '', |
| | | configValue: '', |
| | | configType: "Y", |
| | | configType: 'Y', |
| | | remark: '' |
| | | } |
| | | }; |
| | | const data = reactive<PageData<ConfigForm, ConfigQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | pageSize: 10, |
| | | configName: '', |
| | | configKey: '', |
| | | configType: '', |
| | | configType: '' |
| | | }, |
| | | rules: { |
| | | configName: [{ required: true, message: "åæ°åç§°ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | configKey: [{ required: true, message: "åæ°é®åä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | configValue: [{ required: true, message: "åæ°é®å¼ä¸è½ä¸ºç©º", trigger: "blur" }] |
| | | configName: [{ required: true, message: 'åæ°åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | configKey: [{ required: true, message: 'åæ°é®åä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | configValue: [{ required: true, message: 'åæ°é®å¼ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | configList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | configFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: ConfigVO[]) => { |
| | | ids.value = selection.map(item => item.configId); |
| | | ids.value = selection.map((item) => item.configId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å åæ°"; |
| | | } |
| | | dialog.title = 'æ·»å åæ°'; |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: ConfigVO) => { |
| | | reset(); |
| | |
| | | const res = await getConfig(configId); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹åæ°"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹åæ°'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | configFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.configId ? await updateConfig(form.value) : await addConfig(form.value); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: ConfigVO) => { |
| | | const configIds = row?.configId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤åæ°ç¼å·ä¸º"' + configIds + '"çæ°æ®é¡¹ï¼'); |
| | | await delConfig(configIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("system/config/export", { |
| | | ...queryParams.value |
| | | }, `config_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'system/config/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `config_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | /** å·æ°ç¼åæé®æä½ */ |
| | | const handleRefreshCache = async () => { |
| | | await refreshCache(); |
| | | proxy?.$modal.msgSuccess("å·æ°ç¼åæå"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å·æ°ç¼åæå'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="é¨é¨åç§°" prop="deptName"> |
| | | <el-input v-model="queryParams.deptName" placeholder="请è¾å
¥é¨é¨åç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.deptName" placeholder="请è¾å
¥é¨é¨åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å«ç¼ç " prop="deptCategory"> |
| | | <el-input v-model="queryParams.deptCategory" placeholder="请è¾å
¥ç±»å«ç¼ç " clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="é¨é¨ç¶æ" clearable> |
| | | <el-select v-model="queryParams.status" placeholder="é¨é¨ç¶æ" clearable > |
| | | <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:dept:add']">æ°å¢ </el-button> |
| | | <el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">æ°å¢ </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">å±å¼/æå </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table |
| | | ref="deptTableRef" |
| | | v-loading="loading" |
| | | :data="deptList" |
| | | row-key="deptId" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | ref="deptTableRef" |
| | | :default-expand-all="isExpandAll" |
| | | > |
| | | <el-table-column prop="deptName" label="é¨é¨åç§°" width="260"></el-table-column> |
| | | <el-table-column prop="deptCategory" align="center" label="ç±»å«ç¼ç " width="200"></el-table-column> |
| | | <el-table-column prop="orderNum" align="center" label="æåº" width="200"></el-table-column> |
| | | <el-table-column prop="status" align="center" label="ç¶æ" width="100"> |
| | | <template #default="scope"> |
| | |
| | | <el-table-column fixed="right" align="center" label="æä½"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dept:edit']" /> |
| | | <el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="æ°å¢" placement="top"> |
| | | <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:dept:add']" /> |
| | | <el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dept:remove']" /> |
| | | <el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-body width="600px"> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="600px"> |
| | | <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-row> |
| | | <el-col :span="24" v-if="form.parentId !== 0"> |
| | | <el-col v-if="form.parentId !== 0" :span="24"> |
| | | <el-form-item label="ä¸çº§é¨é¨" prop="parentId"> |
| | | <el-tree-select |
| | | v-model="form.parentId" |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="é¨é¨åç§°" prop="deptName"> |
| | | <el-input v-model="form.deptName" placeholder="请è¾å
¥é¨é¨åç§°" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç±»å«ç¼ç " prop="deptCategory"> |
| | | <el-input v-model="form.deptCategory" placeholder="请è¾å
¥ç±»å«ç¼ç " /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="é¨é¨ç¶æ"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label |
| | | }}</el-radio> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Dept" lang="ts"> |
| | | import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept" |
| | | import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types"; |
| | | import {UserVO} from "@/api/system/user/types"; |
| | | import {listUserByDeptId} from "@/api/system/user"; |
| | | import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from '@/api/system/dept'; |
| | | import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { listUserByDeptId } from '@/api/system/user'; |
| | | |
| | | interface DeptOptionsType { |
| | | deptId: number | string; |
| | | deptName: string; |
| | | children: DeptOptionsType[]; |
| | | |
| | | } |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable")); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); |
| | | |
| | | const deptList = ref<DeptVO[]>([]) |
| | | const loading = ref(true) |
| | | const showSearch = ref(true) |
| | | const deptOptions = ref<DeptOptionsType[]>([]) |
| | | const isExpandAll = ref(true) |
| | | const deptList = ref<DeptVO[]>([]); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const deptOptions = ref<DeptOptionsType[]>([]); |
| | | const isExpandAll = ref(true); |
| | | const deptUserList = ref<UserVO[]>([]); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | |
| | | deptId: undefined, |
| | | parentId: undefined, |
| | | deptName: undefined, |
| | | deptCategory: undefined, |
| | | orderNum: 0, |
| | | leader: undefined, |
| | | phone: undefined, |
| | | email: undefined, |
| | | status: "0" |
| | | } |
| | | const data = reactive<PageData<DeptForm, DeptQuery>>({ |
| | | status: '0' |
| | | }; |
| | | const initData: PageData<DeptForm, DeptQuery> = { |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | deptName: undefined, |
| | | deptCategory: undefined, |
| | | status: undefined |
| | | }, |
| | | rules: { |
| | | parentId: [{ required: true, message: "ä¸çº§é¨é¨ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | deptName: [{ required: true, message: "é¨é¨åç§°ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | orderNum: [{ required: true, message: "æ¾ç¤ºæåºä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | email: [{ type: "email", message: "请è¾å
¥æ£ç¡®çé®ç®±å°å", trigger: ["blur", "change"] }], |
| | | phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请è¾å
¥æ£ç¡®çææºå·ç ", trigger: "blur" }] |
| | | }, |
| | | }) |
| | | parentId: [{ required: true, message: 'ä¸çº§é¨é¨ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | deptName: [{ required: true, message: 'é¨é¨åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | orderNum: [{ required: true, message: 'æ¾ç¤ºæåºä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | email: [{ type: 'email', message: '请è¾å
¥æ£ç¡®çé®ç®±å°å', trigger: ['blur', 'change'] }], |
| | | phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请è¾å
¥æ£ç¡®çææºå·ç ', trigger: 'blur' }] |
| | | } |
| | | }; |
| | | const data = reactive<PageData<DeptForm, DeptQuery>>(initData); |
| | | |
| | | const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data) |
| | | const { queryParams, form, rules } = toRefs<PageData<DeptForm, DeptQuery>>(data); |
| | | |
| | | /** æ¥è¯¢èåå表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await listDept(queryParams.value); |
| | | const data = proxy?.handleTree<DeptVO>(res.data, "deptId") |
| | | const data = proxy?.handleTree<DeptVO>(res.data, 'deptId'); |
| | | if (data) { |
| | | deptList.value = data |
| | | deptList.value = data; |
| | | } |
| | | loading.value = false |
| | | } |
| | | loading.value = false; |
| | | }; |
| | | |
| | | /** æ¥è¯¢å½åé¨é¨çææç¨æ· */ |
| | | async function getDeptAllUser(deptId: any) { |
| | | if (deptId !== null && deptId !== "" && deptId !== undefined) { |
| | | if (deptId !== null && deptId !== '' && deptId !== undefined) { |
| | | const res = await listUserByDeptId(deptId); |
| | | deptUserList.value = res.data; |
| | | } |
| | |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset() |
| | | dialog.visible = false |
| | | } |
| | | reset(); |
| | | dialog.visible = false; |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | deptFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery() |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** å±å¼/æå æä½ */ |
| | | const handleToggleExpandAll = () => { |
| | | isExpandAll.value = !isExpandAll.value; |
| | | toggleExpandAll(deptList.value, isExpandAll.value) |
| | | } |
| | | toggleExpandAll(deptList.value, isExpandAll.value); |
| | | }; |
| | | /** å±å¼/æå ææ */ |
| | | const toggleExpandAll = (data: DeptVO[], status: boolean) => { |
| | | data.forEach((item) => { |
| | | deptTableRef.value?.toggleRowExpansion(item, status) |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status) |
| | | }) |
| | | } |
| | | deptTableRef.value?.toggleRowExpansion(item, status); |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); |
| | | }); |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = async (row?: DeptVO) => { |
| | | reset(); |
| | | const res = await listDept(); |
| | | const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId"); |
| | | const data = proxy?.handleTree<DeptOptionsType>(res.data, 'deptId'); |
| | | if (data) { |
| | | deptOptions.value = data |
| | | deptOptions.value = data; |
| | | if (row && row.deptId) { |
| | | form.value.parentId = row?.deptId; |
| | | } |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å é¨é¨"; |
| | | dialog.title = 'æ·»å é¨é¨'; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row: DeptVO) => { |
| | |
| | | //æ¥è¯¢å½åé¨é¨ææç¨æ· |
| | | getDeptAllUser(row.deptId); |
| | | const res = await getDept(row.deptId); |
| | | form.value = res.data |
| | | form.value = res.data; |
| | | const response = await listDeptExcludeChild(row.deptId); |
| | | const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId") |
| | | const data = proxy?.handleTree<DeptOptionsType>(response.data, 'deptId'); |
| | | if (data) { |
| | | deptOptions.value = data; |
| | | if (data.length === 0) { |
| | |
| | | } |
| | | } |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹é¨é¨"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹é¨é¨'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | deptFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.deptId ? await updateDept(form.value) : await addDept(form.value); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: DeptVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å称为"' + row.deptName + '"çæ°æ®é¡¹?'); |
| | | await delDept(row.deptId); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="åå
¸åç§°" prop="dictType"> |
| | | <el-select v-model="queryParams.dictType" style="width: 200px"> |
| | | <el-select v-model="queryParams.dictType"> |
| | | <el-option v-for="item in typeOptions" :key="item.dictId" :label="item.dictName" :value="item.dictType" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="åå
¸æ ç¾" prop="dictLabel"> |
| | | <el-input v-model="queryParams.dictLabel" placeholder="请è¾å
¥åå
¸æ ç¾" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.dictLabel" placeholder="请è¾å
¥åå
¸æ ç¾" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">ä¿®æ¹</el-button> |
| | | <el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">ä¿®æ¹</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']"> |
| | | <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Close" @click="handleClose">å
³é</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="åå
¸ç¼ç " align="center" prop="dictCode" v-if="false" /> |
| | | <el-table-column v-if="false" label="åå
¸ç¼ç " align="center" prop="dictCode" /> |
| | | <el-table-column label="åå
¸æ ç¾" align="center" prop="dictLabel"> |
| | | <template #default="scope"> |
| | | <span v-if="(scope.row.listClass === '' || scope.row.listClass === 'default') && (scope.row.cssClass === '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span> |
| | | <el-tag v-else :type="(scope.row.listClass === 'primary' || scope.row.listClass === 'default') ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag> |
| | | <span |
| | | v-if="(scope.row.listClass === '' || scope.row.listClass === 'default') && (scope.row.cssClass === '' || scope.row.cssClass == null)" |
| | | >{{ scope.row.dictLabel }}</span |
| | | > |
| | | <el-tag |
| | | v-else |
| | | :type="scope.row.listClass === 'primary' || scope.row.listClass === 'default' ? 'primary' : scope.row.listClass" |
| | | :class="scope.row.cssClass" |
| | | >{{ scope.row.dictLabel }}</el-tag |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åå
¸é®å¼" align="center" prop="dictValue" /> |
| | |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹åæ°é
ç½®å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="dataFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="åå
¸ç±»å"> |
| | | <el-input v-model="form.dictType" :disabled="true" /> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Data" lang="ts"> |
| | | import useDictStore from '@/store/modules/dict' |
| | | import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type"; |
| | | import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"; |
| | | import useDictStore from '@/store/modules/dict'; |
| | | import { optionselect as getDictOptionselect, getType } from '@/api/system/dict/type'; |
| | | import { listData, getData, delData, addData, updateData } from '@/api/system/dict/data'; |
| | | import { DictTypeVO } from '@/api/system/dict/type/types'; |
| | | import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types"; |
| | | import { DictDataForm, DictDataQuery, DictDataVO } from '@/api/system/dict/data/types'; |
| | | import { RouteLocationNormalized } from 'vue-router'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const route = useRoute(); |
| | | |
| | | const dataList = ref<DictDataVO[]>([]); |
| | |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | const defaultDictType = ref(""); |
| | | const defaultDictType = ref(''); |
| | | const typeOptions = ref<DictTypeVO[]>([]); |
| | | |
| | | const dataFormRef = ref<ElFormInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | |
| | | }); |
| | | |
| | | // æ°æ®æ ç¾åæ¾æ ·å¼ |
| | | const listClassOptions = ref<Array<{ value: string, label: string }>>([ |
| | | { value: "default", label: "é»è®¤" }, |
| | | { value: "primary", label: "主è¦" }, |
| | | { value: "success", label: "æå" }, |
| | | { value: "info", label: "ä¿¡æ¯" }, |
| | | { value: "warning", label: "è¦å" }, |
| | | { value: "danger", label: "å±é©" } |
| | | const listClassOptions = ref<Array<{ value: string; label: string }>>([ |
| | | { value: 'default', label: 'é»è®¤' }, |
| | | { value: 'primary', label: '主è¦' }, |
| | | { value: 'success', label: 'æå' }, |
| | | { value: 'info', label: 'ä¿¡æ¯' }, |
| | | { value: 'warning', label: 'è¦å' }, |
| | | { value: 'danger', label: 'å±é©' } |
| | | ]); |
| | | |
| | | const initFormData: DictDataForm = { |
| | |
| | | dictLabel: '', |
| | | dictValue: '', |
| | | cssClass: '', |
| | | listClass: "default", |
| | | listClass: 'primary', |
| | | dictSort: 0, |
| | | remark: '' |
| | | } |
| | | }; |
| | | const data = reactive<PageData<DictDataForm, DictDataQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | dictLabel: '' |
| | | }, |
| | | rules: { |
| | | dictLabel: [{ required: true, message: "æ°æ®æ ç¾ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | dictValue: [{ required: true, message: "æ°æ®é®å¼ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | dictSort: [{ required: true, message: "æ°æ®é¡ºåºä¸è½ä¸ºç©º", trigger: "blur" }] |
| | | dictLabel: [{ required: true, message: 'æ°æ®æ ç¾ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | dictValue: [{ required: true, message: 'æ°æ®é®å¼ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | dictSort: [{ required: true, message: 'æ°æ®é¡ºåºä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | queryParams.value.dictType = data.dictType; |
| | | defaultDictType.value = data.dictType; |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | /** æ¥è¯¢åå
¸ç±»åå表 */ |
| | | const getTypeList = async () => { |
| | | const res = await getDictOptionselect() |
| | | const res = await getDictOptionselect(); |
| | | typeOptions.value = res.data; |
| | | } |
| | | }; |
| | | /** æ¥è¯¢åå
¸æ°æ®å表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | |
| | | dataList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | dialog.visible = false; |
| | | reset(); |
| | | } |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | dataFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** è¿åæé®æä½ */ |
| | | const handleClose = () => { |
| | | const obj = { path: "/system/dict" }; |
| | | const obj: RouteLocationNormalized = { |
| | | fullPath: '', |
| | | hash: '', |
| | | matched: [], |
| | | meta: undefined, |
| | | name: undefined, |
| | | params: undefined, |
| | | query: undefined, |
| | | redirectedFrom: undefined, |
| | | path: '/system/dict' |
| | | }; |
| | | proxy?.$tab.closeOpenPage(obj); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.dictType = defaultDictType.value; |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | form.value.dictType = queryParams.value.dictType; |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å åå
¸æ°æ®"; |
| | | } |
| | | dialog.title = 'æ·»å åå
¸æ°æ®'; |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: DictDataVO[]) => { |
| | | ids.value = selection.map(item => item.dictCode); |
| | | ids.value = selection.map((item) => item.dictCode); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: DictDataVO) => { |
| | | reset(); |
| | |
| | | const res = await getData(dictCode); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹åå
¸æ°æ®"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹åå
¸æ°æ®'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | dataFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.dictCode ? await updateData(form.value) : await addData(form.value); |
| | | useDictStore().removeDict(queryParams.value.dictType); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: DictDataVO) => { |
| | | const dictCodes = row?.dictCode || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤åå
¸ç¼ç 为"' + dictCodes + '"çæ°æ®é¡¹ï¼'); |
| | | await delData(dictCodes); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | useDictStore().removeDict(queryParams.value.dictType); |
| | | |
| | | } |
| | | }; |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("system/dict/data/export", { |
| | | ...queryParams.value |
| | | }, `dict_data_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'system/dict/data/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `dict_data_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTypes(route.params && route.params.dictId as string); |
| | | getTypes(route.params && (route.params.dictId as string)); |
| | | getTypeList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="åå
¸åç§°" prop="dictName"> |
| | | <el-input v-model="queryParams.dictName" placeholder="请è¾å
¥åå
¸åç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.dictName" placeholder="请è¾å
¥åå
¸åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åå
¸ç±»å" prop="dictType"> |
| | | <el-input v-model="queryParams.dictType" placeholder="请è¾å
¥åå
¸ç±»å" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.dictType" placeholder="请è¾å
¥åå
¸ç±»å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å建æ¶é´" style="width: 308px"> |
| | | <el-date-picker |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:dict:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:dict:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:dict:edit']">ä¿®æ¹</el-button> |
| | | <el-button v-hasPermi="['system:dict:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">ä¿®æ¹</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:dict:remove']"> |
| | | <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:dict:export']">导åº</el-button> |
| | | <el-button v-hasPermi="['system:dict:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Refresh" @click="handleRefreshCache" v-hasPermi="['system:dict:remove']">å·æ°ç¼å</el-button> |
| | | <el-button v-hasPermi="['system:dict:remove']" type="danger" plain icon="Refresh" @click="handleRefreshCache">å·æ°ç¼å</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="åå
¸ç¼å·" align="center" prop="dictId" v-if="false" /> |
| | | <el-table-column v-if="false" label="åå
¸ç¼å·" align="center" prop="dictId" /> |
| | | <el-table-column label="åå
¸åç§°" align="center" prop="dictName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="åå
¸ç±»å" align="center" :show-overflow-tooltip="true"> |
| | | <template #default="scope"> |
| | |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:dict:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:dict:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:dict:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:dict:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹åæ°é
ç½®å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="åå
¸åç§°" prop="dictName"> |
| | | <el-input v-model="form.dictName" placeholder="请è¾å
¥åå
¸åç§°" /> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Dict" lang="ts"> |
| | | import useDictStore from '@/store/modules/dict' |
| | | import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type"; |
| | | import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types"; |
| | | import useDictStore from '@/store/modules/dict'; |
| | | import { listType, getType, delType, addType, updateType, refreshCache } from '@/api/system/dict/type'; |
| | | import { DictTypeForm, DictTypeQuery, DictTypeVO } from '@/api/system/dict/type/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | |
| | | const dictFormRef = ref<ElFormInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | |
| | | dictName: '', |
| | | dictType: '', |
| | | remark: '' |
| | | } |
| | | }; |
| | | const data = reactive<PageData<DictTypeForm, DictTypeQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | dictType: '' |
| | | }, |
| | | rules: { |
| | | dictName: [{ required: true, message: "åå
¸åç§°ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | dictType: [{ required: true, message: "åå
¸ç±»åä¸è½ä¸ºç©º", trigger: "blur" }] |
| | | }, |
| | | dictName: [{ required: true, message: 'åå
¸åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | dictType: [{ required: true, message: 'åå
¸ç±»åä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | |
| | | /** æ¥è¯¢åå
¸ç±»åå表 */ |
| | | const getList = () => { |
| | | loading.value = true; |
| | | listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then(res => { |
| | | listType(proxy?.addDateRange(queryParams.value, dateRange.value)).then((res) => { |
| | | typeList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | }); |
| | | } |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | dictFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | dateRange.value = ['', '']; |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å åå
¸ç±»å"; |
| | | } |
| | | dialog.title = 'æ·»å åå
¸ç±»å'; |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: DictTypeVO[]) => { |
| | | ids.value = selection.map(item => item.dictId); |
| | | ids.value = selection.map((item) => item.dictId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: DictTypeVO) => { |
| | | reset(); |
| | |
| | | const res = await getType(dictId); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹åå
¸ç±»å"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹åå
¸ç±»å'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | dictFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.dictId ? await updateType(form.value) : await addType(form.value); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: DictTypeVO) => { |
| | | const dictIds = row?.dictId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤åå
¸ç¼å·ä¸º"' + dictIds + '"çæ°æ®é¡¹ï¼'); |
| | | await delType(dictIds); |
| | | getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("system/dict/type/export", { |
| | | ...queryParams.value |
| | | }, `dict_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'system/dict/type/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `dict_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | /** å·æ°ç¼åæé®æä½ */ |
| | | const handleRefreshCache = async () => { |
| | | await refreshCache(); |
| | | proxy?.$modal.msgSuccess("å·æ°æå"); |
| | | proxy?.$modal.msgSuccess('å·æ°æå'); |
| | | useDictStore().cleanDict(); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="èååç§°" prop="menuName"> |
| | | <el-input v-model="queryParams.menuName" placeholder="请è¾å
¥èååç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.menuName" placeholder="请è¾å
¥èååç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="èåç¶æ" clearable> |
| | | <el-select v-model="queryParams.status" placeholder="èåç¶æ" clearable > |
| | | <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['system:menu:add']">æ°å¢ </el-button> |
| | | <el-button v-hasPermi="['system:menu:add']" type="primary" plain icon="Plus" @click="handleAdd()">æ°å¢ </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">å±å¼/æå </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table |
| | | ref="menuTableRef" |
| | | v-loading="loading" |
| | | :data="menuList" |
| | | row-key="menuId" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | ref="menuTableRef" |
| | | :default-expand-all="isExpandAll" |
| | | > |
| | | <el-table-column prop="menuName" label="èååç§°" :show-overflow-tooltip="true" width="160"></el-table-column> |
| | |
| | | <el-table-column fixed="right" label="æä½" width="180"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']" /> |
| | | <el-button v-hasPermi="['system:menu:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="æ°å¢" placement="top"> |
| | | <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']" /> |
| | | <el-button v-hasPermi="['system:menu:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']" /> |
| | | <el-button v-hasPermi="['system:menu:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" destroy-on-close append-to-bod width="750px"> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-bod width="750px"> |
| | | <el-form ref="menuFormRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | |
| | | <el-col :span="24"> |
| | | <el-form-item label="èåç±»å" prop="menuType"> |
| | | <el-radio-group v-model="form.menuType"> |
| | | <el-radio label="M">ç®å½</el-radio> |
| | | <el-radio label="C">èå</el-radio> |
| | | <el-radio label="F">æé®</el-radio> |
| | | <el-radio value="M">ç®å½</el-radio> |
| | | <el-radio value="C">èå</el-radio> |
| | | <el-radio value="F">æé®</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24" v-if="form.menuType !== 'F'"> |
| | | <el-col v-if="form.menuType !== 'F'" :span="24"> |
| | | <el-form-item label="èå徿 " prop="icon"> |
| | | <!-- 徿 éæ©å¨ --> |
| | | <icon-select v-model="form.icon" /> |
| | |
| | | <el-input-number v-model="form.orderNum" controls-position="right" :min="0" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType !== 'F'"> |
| | | <el-col v-if="form.menuType !== 'F'" :span="12"> |
| | | <el-form-item> |
| | | <template #label> |
| | | <span> |
| | |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType !== 'F'"> |
| | | <el-col v-if="form.menuType !== 'F'" :span="12"> |
| | | <el-form-item prop="path"> |
| | | <template #label> |
| | | <span> |
| | |
| | | <el-input v-model="form.path" placeholder="请è¾å
¥è·¯ç±å°å" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType === 'C'"> |
| | | <el-col v-if="form.menuType === 'C'" :span="12"> |
| | | <el-form-item prop="component"> |
| | | <template #label> |
| | | <span> |
| | |
| | | <el-input v-model="form.component" placeholder="请è¾å
¥ç»ä»¶è·¯å¾" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType !== 'M'"> |
| | | <el-col v-if="form.menuType !== 'M'" :span="12"> |
| | | <el-form-item> |
| | | <el-input v-model="form.perms" placeholder="请è¾å
¥æéæ è¯" maxlength="100" /> |
| | | <template #label> |
| | |
| | | </template> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType === 'C'"> |
| | | <el-col v-if="form.menuType === 'C'" :span="12"> |
| | | <el-form-item> |
| | | <el-input v-model="form.queryParam" placeholder="请è¾å
¥è·¯ç±åæ°" maxlength="255" /> |
| | | <template #label> |
| | |
| | | </template> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType === 'C'"> |
| | | <el-col v-if="form.menuType === 'C'" :span="12"> |
| | | <el-form-item> |
| | | <template #label> |
| | | <span> |
| | |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.menuType !== 'F'"> |
| | | <el-col v-if="form.menuType !== 'F'" :span="12"> |
| | | <el-form-item> |
| | | <template #label> |
| | | <span> |
| | |
| | | children: MenuOptionsType[] | undefined; |
| | | } |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance |
| | | const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_show_hide", "sys_normal_disable")); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_show_hide, sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_show_hide', 'sys_normal_disable')); |
| | | |
| | | const menuList = ref<MenuVO[]>([]) |
| | | const loading = ref(true) |
| | | const showSearch = ref(true) |
| | | const menuOptions = ref<MenuOptionsType[]>([]) |
| | | const isExpandAll = ref(false) |
| | | const menuList = ref<MenuVO[]>([]); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const menuOptions = ref<MenuOptionsType[]>([]); |
| | | const isExpandAll = ref(false); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | |
| | | icon: '', |
| | | menuType: MenuTypeEnum.M, |
| | | orderNum: 1, |
| | | isFrame: "1", |
| | | isCache: "0", |
| | | visible: "0", |
| | | status: "0" |
| | | } |
| | | isFrame: '1', |
| | | isCache: '0', |
| | | visible: '0', |
| | | status: '0' |
| | | }; |
| | | const data = reactive<PageData<MenuForm, MenuQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | status: undefined |
| | | }, |
| | | rules: { |
| | | menuName: [{ required: true, message: "èååç§°ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | orderNum: [{ required: true, message: "èå顺åºä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | path: [{ required: true, message: "è·¯ç±å°åä¸è½ä¸ºç©º", trigger: "blur" }] |
| | | }, |
| | | }) |
| | | menuName: [{ required: true, message: 'èååç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | orderNum: [{ required: true, message: 'èå顺åºä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | path: [{ required: true, message: 'è·¯ç±å°åä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | | const menuTableRef = ref<ElTableInstance>(); |
| | | |
| | | const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data) |
| | | const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data); |
| | | /** æ¥è¯¢èåå表 */ |
| | | const getList = async () => { |
| | | loading.value = true |
| | | loading.value = true; |
| | | const res = await listMenu(queryParams.value); |
| | | const data = proxy?.handleTree<MenuVO>(res.data, "menuId") |
| | | const data = proxy?.handleTree<MenuVO>(res.data, 'menuId'); |
| | | if (data) { |
| | | menuList.value = data |
| | | menuList.value = data; |
| | | } |
| | | loading.value = false |
| | | } |
| | | loading.value = false; |
| | | }; |
| | | /** æ¥è¯¢èå䏿æ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | menuOptions.value = [] |
| | | menuOptions.value = []; |
| | | const response = await listMenu(); |
| | | const menu: MenuOptionsType = { menuId: 0, menuName: "主类ç®", children: [] } |
| | | menu.children = proxy?.handleTree<MenuOptionsType>(response.data, "menuId") |
| | | menuOptions.value.push(menu) |
| | | } |
| | | const menu: MenuOptionsType = { menuId: 0, menuName: '主类ç®', children: [] }; |
| | | menu.children = proxy?.handleTree<MenuOptionsType>(response.data, 'menuId'); |
| | | menuOptions.value.push(menu); |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset() |
| | | dialog.visible = false |
| | | } |
| | | reset(); |
| | | dialog.visible = false; |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | menuFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = (row?: MenuVO) => { |
| | | reset(); |
| | | getTreeselect(); |
| | | row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0; |
| | | row && row.menuId ? (form.value.parentId = row.menuId) : (form.value.parentId = 0); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å èå"; |
| | | } |
| | | dialog.title = 'æ·»å èå'; |
| | | }; |
| | | /** å±å¼/æå æä½ */ |
| | | const handleToggleExpandAll = () => { |
| | | isExpandAll.value = !isExpandAll.value; |
| | | toggleExpandAll(menuList.value, isExpandAll.value) |
| | | } |
| | | toggleExpandAll(menuList.value, isExpandAll.value); |
| | | }; |
| | | /** å±å¼/æå ææ */ |
| | | const toggleExpandAll = (data: MenuVO[], status: boolean) => { |
| | | data.forEach((item: MenuVO) => { |
| | | menuTableRef.value?.toggleRowExpansion(item, status) |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status) |
| | | }) |
| | | } |
| | | menuTableRef.value?.toggleRowExpansion(item, status); |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); |
| | | }); |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row: MenuVO) => { |
| | | reset(); |
| | |
| | | form.value = data; |
| | | } |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹èå"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹èå'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | menuFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }) |
| | | } |
| | | }); |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: MenuVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å称为"' + row.menuName + '"çæ°æ®é¡¹?'); |
| | | await delMenu(row.menuId); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="å
¬åæ é¢" prop="noticeTitle"> |
| | | <el-input v-model="queryParams.noticeTitle" placeholder="请è¾å
¥å
¬åæ é¢" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.noticeTitle" placeholder="请è¾å
¥å
¬åæ é¢" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æä½äººå" prop="createByName"> |
| | | <el-input v-model="queryParams.createByName" placeholder="请è¾å
¥æä½äººå" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.createByName" placeholder="请è¾å
¥æä½äººå" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="noticeType"> |
| | | <el-select v-model="queryParams.noticeType" placeholder="å
¬åç±»å" clearable style="width: 200px"> |
| | | <el-select v-model="queryParams.noticeType" placeholder="å
¬åç±»å" clearable> |
| | | <el-option v-for="dict in sys_notice_type" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:notice:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:notice:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:notice:edit']" |
| | | <el-button v-hasPermi="['system:notice:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" |
| | | >ä¿®æ¹</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:notice:remove']"> |
| | | <el-button v-hasPermi="['system:notice:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="åºå·" align="center" prop="noticeId" width="100" v-if="false" /> |
| | | <el-table-column v-if="false" label="åºå·" align="center" prop="noticeId" width="100" /> |
| | | <el-table-column label="å
¬åæ é¢" align="center" prop="noticeTitle" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="å
¬åç±»å" align="center" prop="noticeType" width="100"> |
| | | <template #default="scope"> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:notice:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:notice:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹å
¬åå¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="780px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="780px" append-to-body> |
| | | <el-form ref="noticeFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç¶æ"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio v-for="dict in sys_notice_status" :key="dict.value" :label="dict.value">{{ dict.label |
| | | }}</el-radio> |
| | | <el-radio v-for="dict in sys_notice_status" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Notice" lang="ts"> |
| | | import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"; |
| | | import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types"; |
| | | import { listNotice, getNotice, delNotice, addNotice, updateNotice } from '@/api/system/notice'; |
| | | import { NoticeForm, NoticeQuery, NoticeVO } from '@/api/system/notice/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type")); |
| | | const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict('sys_notice_status', 'sys_notice_type')); |
| | | |
| | | const noticeList = ref<NoticeVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const noticeFormRef = ref<ElFormInstance>(); |
| | | |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | |
| | | noticeTitle: '', |
| | | noticeType: '', |
| | | noticeContent: '', |
| | | status: "0", |
| | | status: '0', |
| | | remark: '', |
| | | createByName: '' |
| | | } |
| | | }; |
| | | const data = reactive<PageData<NoticeForm, NoticeQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | |
| | | noticeType: '' |
| | | }, |
| | | rules: { |
| | | noticeTitle: [{ required: true, message: "å
¬åæ é¢ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | noticeType: [{ required: true, message: "å
¬åç±»åä¸è½ä¸ºç©º", trigger: "change" }] |
| | | }, |
| | | noticeTitle: [{ required: true, message: 'å
¬åæ é¢ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | noticeType: [{ required: true, message: 'å
¬åç±»åä¸è½ä¸ºç©º', trigger: 'change' }] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | |
| | | noticeList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | noticeFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: NoticeVO[]) => { |
| | | ids.value = selection.map(item => item.noticeId); |
| | | ids.value = selection.map((item) => item.noticeId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å å
Œ"; |
| | | } |
| | | dialog.title = 'æ·»å å
Œ'; |
| | | }; |
| | | /**ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: NoticeVO) => { |
| | | reset(); |
| | |
| | | const { data } = await getNotice(noticeId); |
| | | Object.assign(form.value, data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹å
Œ"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹å
Œ'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | noticeFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value); |
| | | proxy?.$modal.msgSuccess("ä¿®æ¹æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: NoticeVO) => { |
| | | const noticeIds = row?.noticeId || ids.value |
| | | const noticeIds = row?.noticeId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å
¬åç¼å·ä¸º"' + noticeIds + '"çæ°æ®é¡¹ï¼'); |
| | | await delNotice(noticeIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="é
ç½®key" prop="configKey"> |
| | | <el-input v-model="queryParams.configKey" placeholder="é
ç½®key" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.configKey" placeholder="é
ç½®key" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¡¶åç§°" prop="bucketName"> |
| | | <el-input v-model="queryParams.bucketName" placeholder="请è¾å
¥æ¡¶åç§°" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.bucketName" placeholder="请è¾å
¥æ¡¶åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦é»è®¤" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="è¯·éæ©ç¶æ" clearable style="width: 200px"> |
| | | <el-select v-model="queryParams.status" placeholder="è¯·éæ©ç¶æ" clearable> |
| | | <el-option key="0" label="æ¯" value="0" /> |
| | | <el-option key="1" label="å¦" value="1" /> |
| | | </el-select> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:ossConfig:add']">æ°å¢</el-button> |
| | | <el-button v-hasPermi="['system:ossConfig:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:ossConfig:edit']">ä¿®æ¹</el-button> |
| | | <el-button v-hasPermi="['system:ossConfig:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" |
| | | >ä¿®æ¹</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:ossConfig:remove']"> |
| | | <el-button v-hasPermi="['system:ossConfig:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="ossConfigList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="主建" align="center" prop="ossConfigId" v-if="columns[0].visible" /> |
| | | <el-table-column label="é
ç½®key" align="center" prop="configKey" v-if="columns[1].visible" /> |
| | | <el-table-column label="访é®ç«ç¹" align="center" prop="endpoint" v-if="columns[2].visible" width="200" /> |
| | | <el-table-column label="èªå®ä¹åå" align="center" prop="domain" v-if="columns[3].visible" width="200" /> |
| | | <el-table-column label="æ¡¶åç§°" align="center" prop="bucketName" v-if="columns[4].visible" /> |
| | | <el-table-column label="åç¼" align="center" prop="prefix" v-if="columns[5].visible" /> |
| | | <el-table-column label="å" align="center" prop="region" v-if="columns[6].visible" /> |
| | | <el-table-column label="æ¡¶æéç±»å" align="center" prop="accessPolicy" v-if="columns[7].visible"> |
| | | <el-table-column v-if="columns[0].visible" label="主建" align="center" prop="ossConfigId" /> |
| | | <el-table-column v-if="columns[1].visible" label="é
ç½®key" align="center" prop="configKey" /> |
| | | <el-table-column v-if="columns[2].visible" label="访é®ç«ç¹" align="center" prop="endpoint" width="200" /> |
| | | <el-table-column v-if="columns[3].visible" label="èªå®ä¹åå" align="center" prop="domain" width="200" /> |
| | | <el-table-column v-if="columns[4].visible" label="æ¡¶åç§°" align="center" prop="bucketName" /> |
| | | <el-table-column v-if="columns[5].visible" label="åç¼" align="center" prop="prefix" /> |
| | | <el-table-column v-if="columns[6].visible" label="å" align="center" prop="region" /> |
| | | <el-table-column v-if="columns[7].visible" label="æ¡¶æéç±»å" align="center" prop="accessPolicy"> |
| | | <template #default="scope"> |
| | | <el-tag type="warning" v-if="scope.row.accessPolicy === '0'">private</el-tag> |
| | | <el-tag type="success" v-if="scope.row.accessPolicy === '1'">public</el-tag> |
| | | <el-tag type="info" v-if="scope.row.accessPolicy === '2'">custom</el-tag> |
| | | <el-tag v-if="scope.row.accessPolicy === '0'" type="warning">private</el-tag> |
| | | <el-tag v-if="scope.row.accessPolicy === '1'" type="success">public</el-tag> |
| | | <el-tag v-if="scope.row.accessPolicy === '2'" type="info">custom</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¯å¦é»è®¤" align="center" prop="status" v-if="columns[8].visible"> |
| | | <el-table-column v-if="columns[8].visible" label="æ¯å¦é»è®¤" align="center" prop="status"> |
| | | <template #default="scope"> |
| | | <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> |
| | | </template> |
| | |
| | | <el-table-column label="æä½" fixed="right" align="center" width="150" class-name="small-padding"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:ossConfig:edit']"></el-button> |
| | | <el-button v-hasPermi="['system:ossConfig:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:ossConfig:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:ossConfig:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹å¯¹è±¡åå¨é
ç½®å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body> |
| | | <el-form ref="ossConfigFormRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-form-item label="é
ç½®key" prop="configKey"> |
| | | <el-input v-model="form.configKey" placeholder="请è¾å
¥é
ç½®key" /> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦HTTPS"> |
| | | <el-radio-group v-model="form.isHttps"> |
| | | <el-radio v-for="dict in sys_yes_no" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio> |
| | | <el-radio v-for="dict in sys_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="æ¡¶æéç±»å"> |
| | | <el-radio-group v-model="form.accessPolicy"> |
| | | <el-radio label="0">private</el-radio> |
| | | <el-radio label="1">public</el-radio> |
| | | <el-radio label="2">custom</el-radio> |
| | | <el-radio value="0">private</el-radio> |
| | | <el-radio value="1">public</el-radio> |
| | | <el-radio value="2">custom</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="å" prop="region"> |
| | |
| | | </template> |
| | | |
| | | <script setup name="OssConfig" lang="ts"> |
| | | import { |
| | | listOssConfig, |
| | | getOssConfig, |
| | | delOssConfig, |
| | | addOssConfig, |
| | | updateOssConfig, |
| | | changeOssConfigStatus |
| | | } from "@/api/system/ossConfig"; |
| | | import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types"; |
| | | import { listOssConfig, getOssConfig, delOssConfig, addOssConfig, updateOssConfig, changeOssConfigStatus } from '@/api/system/ossConfig'; |
| | | import { OssConfigForm, OssConfigQuery, OssConfigVO } from '@/api/system/ossConfig/types'; |
| | | |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance |
| | | const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no")); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no')); |
| | | |
| | | const ossConfigList = ref<OssConfigVO[]>([]); |
| | | const buttonLoading = ref(false); |
| | |
| | | { key: 8, label: `ç¶æ`, visible: true } |
| | | ]); |
| | | |
| | | |
| | | const initFormData: OssConfigForm = { |
| | | ossConfigId: undefined, |
| | | configKey: '', |
| | |
| | | prefix: '', |
| | | endpoint: '', |
| | | domain: '', |
| | | isHttps: "N", |
| | | accessPolicy: "1", |
| | | isHttps: 'N', |
| | | accessPolicy: '1', |
| | | region: '', |
| | | status: "1", |
| | | remark: '', |
| | | } |
| | | status: '1', |
| | | remark: '' |
| | | }; |
| | | const data = reactive<PageData<OssConfigForm, OssConfigQuery>>({ |
| | | form: { ...initFormData }, |
| | | // æ¥è¯¢åæ° |
| | |
| | | pageSize: 10, |
| | | configKey: '', |
| | | bucketName: '', |
| | | status: '', |
| | | status: '' |
| | | }, |
| | | rules: { |
| | | configKey: [{ required: true, message: "configKeyä¸è½ä¸ºç©º", trigger: "blur" },], |
| | | configKey: [{ required: true, message: 'configKeyä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | accessKey: [ |
| | | { required: true, message: "accessKeyä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | { required: true, message: 'accessKeyä¸è½ä¸ºç©º', trigger: 'blur' }, |
| | | { |
| | | min: 2, |
| | | max: 200, |
| | | message: "accessKeyé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´", |
| | | trigger: "blur", |
| | | }, |
| | | message: 'accessKeyé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´', |
| | | trigger: 'blur' |
| | | } |
| | | ], |
| | | secretKey: [ |
| | | { required: true, message: "secretKeyä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | { required: true, message: 'secretKeyä¸è½ä¸ºç©º', trigger: 'blur' }, |
| | | { |
| | | min: 2, |
| | | max: 100, |
| | | message: "secretKeyé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´", |
| | | trigger: "blur", |
| | | }, |
| | | message: 'secretKeyé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´', |
| | | trigger: 'blur' |
| | | } |
| | | ], |
| | | bucketName: [ |
| | | { required: true, message: "bucketNameä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | { required: true, message: 'bucketNameä¸è½ä¸ºç©º', trigger: 'blur' }, |
| | | { |
| | | min: 2, |
| | | max: 100, |
| | | message: "bucketNameé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´", |
| | | trigger: "blur", |
| | | }, |
| | | message: 'bucketNameé¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´', |
| | | trigger: 'blur' |
| | | } |
| | | ], |
| | | endpoint: [ |
| | | { required: true, message: "endpointä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | { required: true, message: 'endpointä¸è½ä¸ºç©º', trigger: 'blur' }, |
| | | { |
| | | min: 2, |
| | | max: 100, |
| | | message: "endpointåç§°é¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´", |
| | | trigger: "blur", |
| | | }, |
| | | message: 'endpointåç§°é¿åº¦å¿
é¡»ä»äº 2 å 100 ä¹é´', |
| | | trigger: 'blur' |
| | | } |
| | | ], |
| | | accessPolicy: [{ required: true, message: "accessPolicyä¸è½ä¸ºç©º", trigger: "blur" }] |
| | | accessPolicy: [{ required: true, message: 'accessPolicyä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | ossConfigList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | dialog.visible = false; |
| | | reset(); |
| | | } |
| | | }; |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | ossConfigFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | /** éæ©æ¡æ° */ |
| | | const handleSelectionChange = (selection: OssConfigVO[]) => { |
| | | ids.value = selection.map(item => item.ossConfigId); |
| | | ids.value = selection.map((item) => item.ossConfigId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å 对象åå¨é
ç½®"; |
| | | } |
| | | dialog.title = 'æ·»å 对象åå¨é
ç½®'; |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: OssConfigVO) => { |
| | | reset(); |
| | |
| | | const res = await getOssConfig(ossConfigId); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹å¯¹è±¡åå¨é
ç½®"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹å¯¹è±¡åå¨é
ç½®'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | ossConfigFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (form.value.ossConfigId) { |
| | | await updateOssConfig(form.value).finally(() => buttonLoading.value = false); |
| | | await updateOssConfig(form.value).finally(() => (buttonLoading.value = false)); |
| | | } else { |
| | | await addOssConfig(form.value).finally(() => buttonLoading.value = false); |
| | | await addOssConfig(form.value).finally(() => (buttonLoading.value = false)); |
| | | } |
| | | proxy?.$modal.msgSuccess("æ°å¢æå"); |
| | | proxy?.$modal.msgSuccess('æ°å¢æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | /** ç¶æä¿®æ¹ */ |
| | | const handleStatusChange = async (row: OssConfigVO) => { |
| | | let text = row.status === "0" ? "å¯ç¨" : "åç¨"; |
| | | let text = row.status === '0' ? 'å¯ç¨' : 'åç¨'; |
| | | try { |
| | | await proxy?.$modal.confirm('确认è¦"' + text + '""' + row.configKey + '"é
ç½®å?'); |
| | | await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey); |
| | | await getList() |
| | | proxy?.$modal.msgSuccess(text + "æå"); |
| | | } catch { return } finally { |
| | | row.status = row.status === "0" ? "1" : "0"; |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess(text + 'æå'); |
| | | } catch { |
| | | return; |
| | | } finally { |
| | | row.status = row.status === '0' ? '1' : '0'; |
| | | } |
| | | |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: OssConfigVO) => { |
| | | const ossConfigIds = row?.ossConfigId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤OSSé
ç½®ç¼å·ä¸º"' + ossConfigIds + '"çæ°æ®é¡¹?'); |
| | | loading.value = true; |
| | | await delOssConfig(ossConfigIds).finally(() => loading.value = false); |
| | | await delOssConfig(ossConfigIds).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="æä»¶å" prop="fileName"> |
| | | <el-input v-model="queryParams.fileName" placeholder="请è¾å
¥æä»¶å" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.fileName" placeholder="请è¾å
¥æä»¶å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åå" prop="originalName"> |
| | | <el-input v-model="queryParams.originalName" placeholder="请è¾å
¥åå" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.originalName" placeholder="请è¾å
¥åå" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æä»¶åç¼" prop="fileSuffix"> |
| | | <el-input v-model="queryParams.fileSuffix" placeholder="请è¾å
¥æä»¶åç¼" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.fileSuffix" placeholder="请è¾å
¥æä»¶åç¼" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å建æ¶é´"> |
| | | <el-form-item label="å建æ¶é´" style="width: 308px;"> |
| | | <el-date-picker |
| | | v-model="dateRangeCreateTime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item label="æå¡å" prop="service"> |
| | | <el-input v-model="queryParams.service" placeholder="请è¾å
¥æå¡å" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="queryParams.service" placeholder="请è¾å
¥æå¡å" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="search" @click="handleQuery">æç´¢</el-button> |
| | |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Upload" @click="handleFile" v-hasPermi="['system:oss:upload']">ä¸ä¼ æä»¶</el-button> |
| | | <el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleFile">ä¸ä¼ æä»¶</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Upload" @click="handleImage" v-hasPermi="['system:oss:upload']">ä¸ä¼ å¾ç</el-button> |
| | | <el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">ä¸ä¼ å¾ç</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:oss:remove']"> |
| | | <el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | v-hasPermi="['system:oss:edit']" |
| | | :type="previewListResource ? 'danger' : 'warning'" |
| | | plain |
| | | @click="handlePreviewListResource(!previewListResource)" |
| | | v-hasPermi="['system:oss:edit']" |
| | | >é¢è§å¼å
³ : |
| | | {{ |
| | | previewListResource ? "ç¦ç¨" : "å¯ç¨" }}</el-button |
| | | >é¢è§å¼å
³ : {{ previewListResource ? 'ç¦ç¨' : 'å¯ç¨' }}</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="info" plain icon="Operation" @click="handleOssConfig" v-hasPermi="['system:oss:list']">é
置管ç</el-button> |
| | | <el-button v-hasPermi="['system:oss:list']" type="info" plain icon="Operation" @click="handleOssConfig">é
置管ç</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table |
| | | v-if="showTable" |
| | | v-loading="loading" |
| | | :data="ossList" |
| | | @selection-change="handleSelectionChange" |
| | | :header-cell-class-name="handleHeaderClass" |
| | | @selection-change="handleSelectionChange" |
| | | @header-click="handleHeaderCLick" |
| | | v-if="showTable" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="对象åå¨ä¸»é®" align="center" prop="ossId" v-if="false" /> |
| | | <el-table-column v-if="false" label="对象åå¨ä¸»é®" align="center" prop="ossId" /> |
| | | <el-table-column label="æä»¶å" align="center" prop="fileName" /> |
| | | <el-table-column label="åå" align="center" prop="originalName" /> |
| | | <el-table-column label="æä»¶åç¼" align="center" prop="fileSuffix" /> |
| | |
| | | :src="scope.row.url" |
| | | :preview-src-list="[scope.row.url]" |
| | | /> |
| | | <span v-text="scope.row.url" v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" /> |
| | | <span v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource" v-text="scope.row.url" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="180" sortable="custom"> |
| | |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¸è½½" placement="top"> |
| | | <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['system:oss:download']"></el-button> |
| | | <el-button v-hasPermi="['system:oss:download']" link type="primary" icon="Download" @click="handleDownload(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:oss:remove']"></el-button> |
| | | <el-button v-hasPermi="['system:oss:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹OSS对象åå¨å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="æä»¶å"> |
| | | <fileUpload v-model="form.file" v-if="type === 0" /> |
| | | <imageUpload v-model="form.file" v-if="type === 1" /> |
| | | <fileUpload v-if="type === 0" v-model="form.file" /> |
| | | <imageUpload v-if="type === 1" v-model="form.file" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | |
| | | </template> |
| | | |
| | | <script setup name="Oss" lang="ts"> |
| | | import { listOss, delOss } from "@/api/system/oss"; |
| | | import ImagePreview from "@/components/ImagePreview/index.vue"; |
| | | import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types"; |
| | | import { listOss, delOss } from '@/api/system/oss'; |
| | | import ImagePreview from '@/components/ImagePreview/index.vue'; |
| | | import { OssForm, OssQuery, OssVO } from '@/api/system/oss/types'; |
| | | |
| | | const router = useRouter(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | |
| | | const initFormData = { |
| | | file: undefined, |
| | | } |
| | | file: undefined |
| | | }; |
| | | const data = reactive<PageData<OssForm, OssQuery>>({ |
| | | form: { ...initFormData }, |
| | | // æ¥è¯¢åæ° |
| | |
| | | isAsc: defaultSort.value.order |
| | | }, |
| | | rules: { |
| | | file: [ |
| | | { required: true, message: "æä»¶ä¸è½ä¸ºç©º", trigger: "blur" } |
| | | ] |
| | | file: [{ required: true, message: 'æä»¶ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | |
| | | /** æ¥è¯¢OSS对象åå¨å表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await proxy?.getConfigKey("sys.oss.previewListResource"); |
| | | const res = await proxy?.getConfigKey('sys.oss.previewListResource'); |
| | | previewListResource.value = res?.data === undefined ? true : res.data === 'true'; |
| | | const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime")); |
| | | const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime')); |
| | | ossList.value = response.rows; |
| | | total.value = response.total; |
| | | loading.value = false; |
| | | showTable.value = true; |
| | | } |
| | | function checkFileSuffix(fileSuffix: string[]) { |
| | | let arr = ["png", "jpg", "jpeg"]; |
| | | return arr.some(type => { |
| | | return fileSuffix.indexOf(type) > -1; |
| | | }); |
| | | }; |
| | | function checkFileSuffix(fileSuffix: string | string[]) { |
| | | const arr = [".png", ".jpg", ".jpeg"]; |
| | | const suffixArray = Array.isArray(fileSuffix) ? fileSuffix : [fileSuffix]; |
| | | return suffixArray.some(suffix => arr.includes(suffix.toLowerCase())); |
| | | } |
| | | /** åæ¶æé® */ |
| | | function cancel() { |
| | |
| | | } |
| | | /** éæ©æ¡æ° */ |
| | | function handleSelectionChange(selection: OssVO[]) { |
| | | ids.value = selection.map(item => item.ossId); |
| | | ids.value = selection.map((item) => item.ossId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | /** 设置åçæåºä¸ºæä»¬èªå®ä¹çæåº */ |
| | | const handleHeaderClass = ({ column }: any): any => { |
| | | column.order = column.multiOrder |
| | | } |
| | | column.order = column.multiOrder; |
| | | }; |
| | | /** ç¹å»è¡¨å¤´è¿è¡æåº */ |
| | | const handleHeaderCLick = (column: any) => { |
| | | if (column.sortable !== 'custom') { |
| | | return |
| | | return; |
| | | } |
| | | switch (column.multiOrder) { |
| | | case 'descending': |
| | |
| | | column.multiOrder = 'descending'; |
| | | break; |
| | | } |
| | | handleOrderChange(column.property, column.multiOrder) |
| | | } |
| | | handleOrderChange(column.property, column.multiOrder); |
| | | }; |
| | | const handleOrderChange = (prop: string, order: string) => { |
| | | let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(",") : []; |
| | | let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(",") : []; |
| | | let propIndex = orderByArr.indexOf(prop) |
| | | let orderByArr = queryParams.value.orderByColumn ? queryParams.value.orderByColumn.split(',') : []; |
| | | let isAscArr = queryParams.value.isAsc ? queryParams.value.isAsc.split(',') : []; |
| | | let propIndex = orderByArr.indexOf(prop); |
| | | if (propIndex !== -1) { |
| | | if (order) { |
| | | //æåºéå·²åå¨ åªä¿®æ¹æåº |
| | | isAscArr[propIndex] = order; |
| | | } else { |
| | | //妿order为null åå 餿åºå段å屿§ |
| | | isAscArr.splice(propIndex, 1);//å é¤æåº |
| | | orderByArr.splice(propIndex, 1);//å é¤å±æ§ |
| | | isAscArr.splice(propIndex, 1); //å é¤æåº |
| | | orderByArr.splice(propIndex, 1); //å é¤å±æ§ |
| | | } |
| | | } else { |
| | | //æåºéä¸åå¨åæ°å¢æåº |
| | |
| | | isAscArr.push(order); |
| | | } |
| | | //åå¹¶æåº |
| | | queryParams.value.orderByColumn = orderByArr.join(","); |
| | | queryParams.value.isAsc = isAscArr.join(","); |
| | | queryParams.value.orderByColumn = orderByArr.join(','); |
| | | queryParams.value.isAsc = isAscArr.join(','); |
| | | getList(); |
| | | } |
| | | }; |
| | | /** 任塿¥å¿å表æ¥è¯¢ */ |
| | | const handleOssConfig = () => { |
| | | router.push('/system/oss-config/index') |
| | | } |
| | | router.push('/system/oss-config/index'); |
| | | }; |
| | | /** æä»¶æé®æä½ */ |
| | | const handleFile = () => { |
| | | reset(); |
| | | type.value = 0; |
| | | dialog.visible = true; |
| | | dialog.title = "ä¸ä¼ æä»¶"; |
| | | } |
| | | dialog.title = 'ä¸ä¼ æä»¶'; |
| | | }; |
| | | /** å¾çæé®æä½ */ |
| | | const handleImage = () => { |
| | | reset(); |
| | | type.value = 1; |
| | | dialog.visible = true; |
| | | dialog.title = "ä¸ä¼ å¾ç"; |
| | | } |
| | | dialog.title = 'ä¸ä¼ å¾ç'; |
| | | }; |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | dialog.visible = false; |
| | | getList(); |
| | | } |
| | | }; |
| | | /** ä¸è½½æé®æä½ */ |
| | | const handleDownload = (row: OssVO) => { |
| | | proxy?.$download.oss(row.ossId) |
| | | } |
| | | proxy?.$download.oss(row.ossId); |
| | | }; |
| | | /** ç¨æ·ç¶æä¿®æ¹ */ |
| | | const handlePreviewListResource = async (preview: boolean) => { |
| | | let text = preview ? "å¯ç¨" : "åç¨"; |
| | | let text = preview ? 'å¯ç¨' : 'åç¨'; |
| | | try { |
| | | await proxy?.$modal.confirm('确认è¦"' + text + '""é¢è§å表å¾ç"é
ç½®å?'); |
| | | await proxy?.updateConfigByKey("sys.oss.previewListResource", preview); |
| | | await getList() |
| | | proxy?.$modal.msgSuccess(text + "æå"); |
| | | } catch { return } |
| | | } |
| | | await proxy?.updateConfigByKey('sys.oss.previewListResource', preview); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess(text + 'æå'); |
| | | } catch { |
| | | return; |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: OssVO) => { |
| | | const ossIds = row?.ossId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤OSS对象åå¨ç¼å·ä¸º"' + ossIds + '"çæ°æ®é¡¹?'); |
| | | loading.value = true; |
| | | await delOss(ossIds).finally(() => loading.value = false); |
| | | await delOss(ossIds).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }) |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="mb-[10px]" v-show="showSearch"> |
| | | <el-row :gutter="20"> |
| | | <!-- é¨é¨æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70"> |
| | | <el-form-item label="å²ä½ç¼ç " prop="postCode"> |
| | | <el-input v-model="queryParams.postCode" placeholder="请è¾å
¥å²ä½ç¼ç " clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-input v-model="deptName" placeholder="请è¾å
¥é¨é¨åç§°" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="deptTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="deptOptions" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
| | | <el-form-item label="å²ä½ç¼ç " prop="postCode"> |
| | | <el-input v-model="queryParams.postCode" placeholder="请è¾å
¥å²ä½ç¼ç " clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å«ç¼ç " prop="postCategory"> |
| | | <el-input |
| | | v-model="queryParams.postCategory" |
| | | placeholder="请è¾å
¥ç±»å«ç¼ç " |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½åç§°" prop="postName"> |
| | | <el-input v-model="queryParams.postName" placeholder="请è¾å
¥å²ä½åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="é¨é¨" prop="deptId"> |
| | | <el-tree-select |
| | | v-model="queryParams.deptId" |
| | | :data="deptOptions" |
| | | :props="{ value: 'id', label: 'label', children: 'children' }" |
| | | value-key="id" |
| | | placeholder="è¯·éæ©é¨é¨" |
| | | check-strictly |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="å²ä½ç¶æ" clearable> |
| | | <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" |
| | | >ä¿®æ¹</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column v-if="false" label="å²ä½ç¼å·" align="center" prop="postId" /> |
| | | <el-table-column label="å²ä½ç¼ç " align="center" prop="postCode" /> |
| | | <el-table-column label="ç±»å«ç¼ç " align="center" prop="postCategory" /> |
| | | <el-table-column label="å²ä½åç§°" align="center" prop="postName" /> |
| | | <el-table-column label="é¨é¨" align="center" prop="deptName" /> |
| | | <el-table-column label="æåº" align="center" prop="postSort" /> |
| | | <el-table-column label="ç¶æ" align="center" prop="status"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_normal_disable" :value="scope.row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="180"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="180" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button v-hasPermi="['system:post:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button v-hasPermi="['system:post:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | |
| | | <!-- æ·»å æä¿®æ¹å²ä½å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="å²ä½åç§°" prop="postName"> |
| | | <el-input v-model="queryParams.postName" placeholder="请è¾å
¥å²ä½åç§°" clearable style="width: 200px" @keyup.enter="handleQuery" /> |
| | | <el-input v-model="form.postName" placeholder="请è¾å
¥å²ä½åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="å²ä½ç¶æ" clearable style="width: 200px"> |
| | | <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | <el-form-item label="é¨é¨" prop="deptId"> |
| | | <el-tree-select |
| | | v-model="form.deptId" |
| | | :data="deptOptions" |
| | | :props="{ value: 'id', label: 'label', children: 'children' }" |
| | | value-key="id" |
| | | placeholder="è¯·éæ©é¨é¨" |
| | | check-strictly |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | <el-form-item label="å²ä½ç¼ç " prop="postCode"> |
| | | <el-input v-model="form.postCode" placeholder="请è¾å
¥ç¼ç åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å«ç¼ç " prop="postCategory"> |
| | | <el-input v-model="form.postCategory" placeholder="请è¾å
¥ç±»å«ç¼ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½é¡ºåº" prop="postSort"> |
| | | <el-input-number v-model="form.postSort" controls-position="right" :min="0" /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½ç¶æ" prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" placeholder="请è¾å
¥å
容" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:post:add']">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:post:edit']">ä¿®æ¹</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:post:remove']"> |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:post:export']">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="å²ä½ç¼å·" align="center" prop="postId" v-if="false" /> |
| | | <el-table-column label="å²ä½ç¼ç " align="center" prop="postCode" /> |
| | | <el-table-column label="å²ä½åç§°" align="center" prop="postName" /> |
| | | <el-table-column label="å²ä½æåº" align="center" prop="postSort" /> |
| | | <el-table-column label="ç¶æ" align="center" prop="status"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_normal_disable" :value="scope.row.status" /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">ç¡® å®</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="180"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="180" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> |
| | | </el-card> |
| | | |
| | | <!-- æ·»å æä¿®æ¹å²ä½å¯¹è¯æ¡ --> |
| | | <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> |
| | | <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="å²ä½åç§°" prop="postName"> |
| | | <el-input v-model="form.postName" placeholder="请è¾å
¥å²ä½åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½ç¼ç " prop="postCode"> |
| | | <el-input v-model="form.postCode" placeholder="请è¾å
¥ç¼ç åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½é¡ºåº" prop="postSort"> |
| | | <el-input-number v-model="form.postSort" controls-position="right" :min="0" /> |
| | | </el-form-item> |
| | | <el-form-item label="å²ä½ç¶æ" prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" placeholder="请è¾å
¥å
容" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">ç¡® å®</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </el-dialog> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="Post" lang="ts"> |
| | | import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post"; |
| | | import { PostForm, PostQuery, PostVO } from "@/api/system/post/types"; |
| | | import { listPost, addPost, delPost, getPost, updatePost } from '@/api/system/post'; |
| | | import { PostForm, PostQuery, PostVO } from '@/api/system/post/types'; |
| | | import { DeptVO } from '@/api/system/dept/types'; |
| | | import api from '@/api/system/user'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable")); |
| | | const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable')); |
| | | |
| | | const postList = ref<PostVO[]>([]); |
| | | const loading = ref(true); |
| | |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | |
| | | const deptName = ref(''); |
| | | const deptOptions = ref<DeptVO[]>([]); |
| | | const deptTreeRef = ref<ElTreeInstance>(); |
| | | const postFormRef = ref<ElFormInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | |
| | |
| | | |
| | | const initFormData: PostForm = { |
| | | postId: undefined, |
| | | deptId: undefined, |
| | | postCode: '', |
| | | postName: '', |
| | | postCategory: '', |
| | | postSort: 0, |
| | | status: "0", |
| | | status: '0', |
| | | remark: '' |
| | | } |
| | | }; |
| | | |
| | | const data = reactive<PageData<PostForm, PostQuery>>({ |
| | | form: { ...initFormData }, |
| | |
| | | pageSize: 10, |
| | | postCode: '', |
| | | postName: '', |
| | | postCategory: '', |
| | | status: '' |
| | | }, |
| | | rules: { |
| | | postName: [{ required: true, message: "å²ä½åç§°ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | postCode: [{ required: true, message: "å²ä½ç¼ç ä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | postSort: [{ required: true, message: "å²ä½é¡ºåºä¸è½ä¸ºç©º", trigger: "blur" }], |
| | | postName: [{ required: true, message: 'å²ä½åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | postCode: [{ required: true, message: 'å²ä½ç¼ç ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | deptId: [{ required: true, message: 'é¨é¨ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | postSort: [{ required: true, message: 'å²ä½é¡ºåºä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs<PageData<PostForm, PostQuery>>(data); |
| | | |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }; |
| | | |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | deptTreeRef.value?.filter(deptName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | /** æ¥è¯¢é¨é¨ä¸ææ ç»æ */ |
| | | const getTreeSelect = async () => { |
| | | const res = await api.deptTreeSelect(); |
| | | deptOptions.value = res.data; |
| | | }; |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: DeptVO) => { |
| | | queryParams.value.belongDeptId = data.id; |
| | | queryParams.value.deptId = undefined; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** æ¥è¯¢å²ä½å表 */ |
| | | const getList = async () => { |
| | |
| | | postList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | } |
| | | }; |
| | | |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | postFormRef.value?.resetFields(); |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | if (queryParams.value.deptId) { |
| | | queryParams.value.belongDeptId = undefined; |
| | | } |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.deptId = undefined; |
| | | deptTreeRef.value?.setCurrentKey(undefined); |
| | | /** æ¸
空左边é¨é¨æ éä¸å¼ */ |
| | | queryParams.value.belongDeptId = undefined; |
| | | handleQuery(); |
| | | } |
| | | }; |
| | | |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: PostVO[]) => { |
| | | ids.value = selection.map(item => item.postId); |
| | | ids.value = selection.map((item) => item.postId); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | reset(); |
| | | dialog.visible = true; |
| | | dialog.title = "æ·»å å²ä½"; |
| | | } |
| | | dialog.title = 'æ·»å å²ä½'; |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = async (row?: PostVO) => { |
| | | reset(); |
| | |
| | | const res = await getPost(postId); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | dialog.title = "ä¿®æ¹å²ä½"; |
| | | } |
| | | dialog.title = 'ä¿®æ¹å²ä½'; |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | postFormRef.value?.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | form.value.postId ? await updatePost(form.value) : await addPost(form.value); |
| | | proxy?.$modal.msgSuccess("æä½æå"); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: PostVO) => { |
| | | const postIds = row?.postId || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤å²ä½ç¼å·ä¸º"' + postIds + '"çæ°æ®é¡¹ï¼'); |
| | | await delPost(postIds); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess("å 餿å"); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download("system/post/export", { |
| | | ...queryParams.value |
| | | }, `post_${new Date().getTime()}.xlsx`); |
| | | } |
| | | proxy?.download( |
| | | 'system/post/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `post_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTreeSelect(); // åå§åé¨é¨æ°æ® |
| | | getList(); |
| | | }); |
| | | </script> |
src/views/system/role/authUser.vue
src/views/system/role/index.vue
src/views/system/role/selectUser.vue
src/views/system/tenant/index.vue
src/views/system/tenantPackage/index.vue
src/views/system/user/authRole.vue
src/views/system/user/index.vue
src/views/system/user/profile/index.vue
src/views/system/user/profile/onlineDevice.vue
src/views/system/user/profile/resetPwd.vue
src/views/system/user/profile/thirdParty.vue
src/views/system/user/profile/userAvatar.vue
src/views/system/user/profile/userInfo.vue
src/views/tool/gen/basicInfoForm.vue
src/views/tool/gen/editTable.vue
src/views/tool/gen/genInfoForm.vue
src/views/tool/gen/importTable.vue
src/views/tool/gen/index.vue
src/views/workflow/category/index.vue
src/views/workflow/formManage/index.vue
src/views/workflow/leave/index.vue
src/views/workflow/leave/leaveEdit.vue
src/views/workflow/model/index.vue
src/views/workflow/processDefinition/components/processPreview.vue
src/views/workflow/processDefinition/index.vue
src/views/workflow/processInstance/index.vue
src/views/workflow/task/allTaskWaiting.vue
src/views/workflow/task/myDocument.vue
src/views/workflow/task/taskCopyList.vue
src/views/workflow/task/taskFinish.vue
src/views/workflow/task/taskWaiting.vue
tsconfig.json
uno.config.ts
vite.config.ts
vite/plugins/compression.ts
vite/plugins/i18n.ts
vite/plugins/index.ts
vite/plugins/setup-extend.ts
vite/plugins/unocss.ts |