Commit b623cfee by 周海峰

Merge branch 'master' of https://code.palacesun.com/wuchao/nse-ui

parents 13ec4642 5889b974
...@@ -6,3 +6,4 @@ VITE_APP_ENV = 'development' ...@@ -6,3 +6,4 @@ VITE_APP_ENV = 'development'
# 若依管理系统/开发环境 # 若依管理系统/开发环境
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
VITE_APP_BASE_URL = '/'
\ No newline at end of file
...@@ -8,4 +8,6 @@ VITE_APP_ENV = 'production' ...@@ -8,4 +8,6 @@ VITE_APP_ENV = 'production'
VITE_APP_BASE_API = '/prod-api' VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
VITE_APP_BASE_URL = '/'
\ No newline at end of file
...@@ -20,18 +20,23 @@ ...@@ -20,18 +20,23 @@
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "13.3.0", "@vueuse/core": "13.3.0",
"axios": "1.9.0", "axios": "1.9.0",
"buffer": "^6.0.3",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"crypto-js": "^4.2.0",
"echarts": "5.6.0", "echarts": "5.6.0",
"element-plus": "2.9.9", "element-plus": "2.9.9",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.6.2", "fuse.js": "6.6.2",
"gm-crypt": "^0.0.2",
"js-beautify": "1.14.11", "js-beautify": "1.14.11",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
"jsencrypt": "3.3.2", "jsencrypt": "3.3.2",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "3.0.2", "pinia": "3.0.2",
"sm-crypto": "^0.3.13",
"sortablejs": "^1.15.6", "sortablejs": "^1.15.6",
"splitpanes": "4.0.4", "splitpanes": "4.0.4",
"view-ui-plus": "^1.3.20",
"vue": "3.5.16", "vue": "3.5.16",
"vue-cropper": "1.1.1", "vue-cropper": "1.1.1",
"vue-router": "4.5.1", "vue-router": "4.5.1",
......
...@@ -20,9 +20,15 @@ importers: ...@@ -20,9 +20,15 @@ importers:
axios: axios:
specifier: 1.9.0 specifier: 1.9.0
version: 1.9.0 version: 1.9.0
buffer:
specifier: ^6.0.3
version: 6.0.3
clipboard: clipboard:
specifier: 2.0.11 specifier: 2.0.11
version: 2.0.11 version: 2.0.11
crypto-js:
specifier: ^4.2.0
version: 4.2.0
echarts: echarts:
specifier: 5.6.0 specifier: 5.6.0
version: 5.6.0 version: 5.6.0
...@@ -35,6 +41,9 @@ importers: ...@@ -35,6 +41,9 @@ importers:
fuse.js: fuse.js:
specifier: 6.6.2 specifier: 6.6.2
version: 6.6.2 version: 6.6.2
gm-crypt:
specifier: ^0.0.2
version: 0.0.2
js-beautify: js-beautify:
specifier: 1.14.11 specifier: 1.14.11
version: 1.14.11 version: 1.14.11
...@@ -50,12 +59,18 @@ importers: ...@@ -50,12 +59,18 @@ importers:
pinia: pinia:
specifier: 3.0.2 specifier: 3.0.2
version: 3.0.2(vue@3.5.16) version: 3.0.2(vue@3.5.16)
sm-crypto:
specifier: ^0.3.13
version: 0.3.13
sortablejs: sortablejs:
specifier: ^1.15.6 specifier: ^1.15.6
version: 1.15.6 version: 1.15.6
splitpanes: splitpanes:
specifier: 4.0.4 specifier: 4.0.4
version: 4.0.4(vue@3.5.16) version: 4.0.4(vue@3.5.16)
view-ui-plus:
specifier: ^1.3.20
version: 1.3.20
vue: vue:
specifier: 3.5.16 specifier: 3.5.16
version: 3.5.16 version: 3.5.16
...@@ -359,56 +374,67 @@ packages: ...@@ -359,56 +374,67 @@ packages:
resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==} resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.46.3': '@rollup/rollup-linux-arm-musleabihf@4.46.3':
resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==} resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.46.3': '@rollup/rollup-linux-arm64-gnu@4.46.3':
resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==} resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.46.3': '@rollup/rollup-linux-arm64-musl@4.46.3':
resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==} resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.46.3': '@rollup/rollup-linux-loongarch64-gnu@4.46.3':
resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==} resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.46.3': '@rollup/rollup-linux-ppc64-gnu@4.46.3':
resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==} resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.46.3': '@rollup/rollup-linux-riscv64-gnu@4.46.3':
resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==} resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.46.3': '@rollup/rollup-linux-riscv64-musl@4.46.3':
resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==} resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.46.3': '@rollup/rollup-linux-s390x-gnu@4.46.3':
resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==} resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.46.3': '@rollup/rollup-linux-x64-gnu@4.46.3':
resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==} resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.46.3': '@rollup/rollup-linux-x64-musl@4.46.3':
resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==} resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.46.3': '@rollup/rollup-win32-arm64-msvc@4.46.3':
resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==} resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==}
...@@ -608,6 +634,9 @@ packages: ...@@ -608,6 +634,9 @@ packages:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
async-validator@3.5.2:
resolution: {integrity: sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==}
async-validator@4.2.5: async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
...@@ -629,10 +658,16 @@ packages: ...@@ -629,10 +658,16 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
base@0.11.2: base@0.11.2:
resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
batch-processor@1.0.0:
resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==}
big.js@5.2.2: big.js@5.2.2:
resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
...@@ -659,6 +694,9 @@ packages: ...@@ -659,6 +694,9 @@ packages:
buffer-builder@0.2.0: buffer-builder@0.2.0:
resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==}
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
cache-base@1.0.1: cache-base@1.0.1:
resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -744,10 +782,16 @@ packages: ...@@ -744,10 +782,16 @@ packages:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
countup.js@1.9.3:
resolution: {integrity: sha512-UHf2P/mFKaESqdPq+UdBJm/1y8lYdlcDd0nTZHNC8cxWoJwZr1Eldm1PpWui446vDl5Pd8PtRYkr3q6K4+Qa5A==}
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
css-select@4.3.0: css-select@4.3.0:
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
...@@ -806,6 +850,10 @@ packages: ...@@ -806,6 +850,10 @@ packages:
resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
deepmerge@2.2.1:
resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==}
engines: {node: '>=0.10.0'}
define-data-property@1.1.4: define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
...@@ -878,6 +926,9 @@ packages: ...@@ -878,6 +926,9 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.2.0 vue: ^3.2.0
element-resize-detector@1.2.4:
resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==}
emoji-regex@8.0.0: emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
...@@ -1086,6 +1137,9 @@ packages: ...@@ -1086,6 +1137,9 @@ packages:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
gm-crypt@0.0.2:
resolution: {integrity: sha512-eg3EaPQYCwWI7UNMvV4ReHD4rR1mtegDDyK80nr49FKw3PgyvVCZ44wIeqA88ITvjIVC3mT/8ZZG0qvH701LzA==}
good-listener@1.2.2: good-listener@1.2.2:
resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==}
...@@ -1157,6 +1211,9 @@ packages: ...@@ -1157,6 +1211,9 @@ packages:
htmlparser2@3.10.1: htmlparser2@3.10.1:
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
image-size@0.5.5: image-size@0.5.5:
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -1354,6 +1411,9 @@ packages: ...@@ -1354,6 +1411,9 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
js-calendar@1.2.3:
resolution: {integrity: sha512-dAA1/Zbp4+c5E+ARCVTIuKepXsNLzSYfzvOimiYD4S5eeP9QuplSHLcdhfqFSwyM1o1u6ku6RRRCyaZ0YAjiBw==}
js-cookie@3.0.5: js-cookie@3.0.5:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'} engines: {node: '>=14'}
...@@ -1361,6 +1421,9 @@ packages: ...@@ -1361,6 +1421,9 @@ packages:
js-tokens@9.0.1: js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
jsbn@1.1.0:
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
jsencrypt@3.3.2: jsencrypt@3.3.2:
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==} resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
...@@ -1409,6 +1472,9 @@ packages: ...@@ -1409,6 +1472,9 @@ packages:
lodash: '*' lodash: '*'
lodash-es: '*' lodash-es: '*'
lodash.chunk@4.2.0:
resolution: {integrity: sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==}
lodash.clonedeep@4.5.0: lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
...@@ -1416,6 +1482,9 @@ packages: ...@@ -1416,6 +1482,9 @@ packages:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
lodash@4.17.21: lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
...@@ -1525,6 +1594,9 @@ packages: ...@@ -1525,6 +1594,9 @@ packages:
nth-check@2.1.1: nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
numeral@2.0.6:
resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==}
object-assign@4.1.1: object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -1614,6 +1686,10 @@ packages: ...@@ -1614,6 +1686,10 @@ packages:
pkg-types@2.2.0: pkg-types@2.2.0:
resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==}
popper.js@1.16.1:
resolution: {integrity: sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==}
deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
posix-character-classes@0.1.1: posix-character-classes@0.1.1:
resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -1902,6 +1978,9 @@ packages: ...@@ -1902,6 +1978,9 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'} engines: {node: '>=14'}
sm-crypto@0.3.13:
resolution: {integrity: sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==}
snapdragon-node@2.1.1: snapdragon-node@2.1.1:
resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
...@@ -2050,6 +2129,9 @@ packages: ...@@ -2050,6 +2129,9 @@ packages:
tiny-emitter@2.1.0: tiny-emitter@2.1.0:
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
tinyglobby@0.2.14: tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
...@@ -2155,6 +2237,10 @@ packages: ...@@ -2155,6 +2237,10 @@ packages:
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
v-click-outside-x@3.7.1:
resolution: {integrity: sha512-WmUgmcIXr9clVpm1AYS/FgHtcDicfnfoxgQCNg4O6vfk9GVnxA0vSqO321ogUo0b7czYTidj7fQENvWFMWOkUg==}
engines: {node: '>=8.11.4', npm: 6.4.1}
varint@6.0.0: varint@6.0.0:
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
...@@ -2162,6 +2248,9 @@ packages: ...@@ -2162,6 +2248,9 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
view-ui-plus@1.3.20:
resolution: {integrity: sha512-ZQ7APuPGbs/UqxXXmGRL4CeZMb9ILVqctqih/ZzTiTfbNP18Ad0cmbxpWszqCqj1PzUsg/1kJuN5522fIvB6lg==}
vite-plugin-compression@0.5.1: vite-plugin-compression@0.5.1:
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies: peerDependencies:
...@@ -2707,6 +2796,8 @@ snapshots: ...@@ -2707,6 +2796,8 @@ snapshots:
async-function@1.0.0: {} async-function@1.0.0: {}
async-validator@3.5.2: {}
async-validator@4.2.5: {} async-validator@4.2.5: {}
asynckit@0.4.0: {} asynckit@0.4.0: {}
...@@ -2727,6 +2818,8 @@ snapshots: ...@@ -2727,6 +2818,8 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
base64-js@1.5.1: {}
base@0.11.2: base@0.11.2:
dependencies: dependencies:
cache-base: 1.0.1 cache-base: 1.0.1
...@@ -2737,6 +2830,8 @@ snapshots: ...@@ -2737,6 +2830,8 @@ snapshots:
mixin-deep: 1.3.2 mixin-deep: 1.3.2
pascalcase: 0.1.1 pascalcase: 0.1.1
batch-processor@1.0.0: {}
big.js@5.2.2: {} big.js@5.2.2: {}
birpc@2.5.0: {} birpc@2.5.0: {}
...@@ -2770,6 +2865,11 @@ snapshots: ...@@ -2770,6 +2865,11 @@ snapshots:
buffer-builder@0.2.0: {} buffer-builder@0.2.0: {}
buffer@6.0.3:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
cache-base@1.0.1: cache-base@1.0.1:
dependencies: dependencies:
collection-visit: 1.0.0 collection-visit: 1.0.0
...@@ -2870,12 +2970,16 @@ snapshots: ...@@ -2870,12 +2970,16 @@ snapshots:
object-assign: 4.1.1 object-assign: 4.1.1
vary: 1.1.2 vary: 1.1.2
countup.js@1.9.3: {}
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
crypto-js@4.2.0: {}
css-select@4.3.0: css-select@4.3.0:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
...@@ -2936,6 +3040,8 @@ snapshots: ...@@ -2936,6 +3040,8 @@ snapshots:
object-keys: 1.1.1 object-keys: 1.1.1
regexp.prototype.flags: 1.5.4 regexp.prototype.flags: 1.5.4
deepmerge@2.2.1: {}
define-data-property@1.1.4: define-data-property@1.1.4:
dependencies: dependencies:
es-define-property: 1.0.1 es-define-property: 1.0.1
...@@ -3040,6 +3146,10 @@ snapshots: ...@@ -3040,6 +3146,10 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@vue/composition-api' - '@vue/composition-api'
element-resize-detector@1.2.4:
dependencies:
batch-processor: 1.0.0
emoji-regex@8.0.0: {} emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {} emoji-regex@9.2.2: {}
...@@ -3339,6 +3449,10 @@ snapshots: ...@@ -3339,6 +3449,10 @@ snapshots:
define-properties: 1.2.1 define-properties: 1.2.1
gopd: 1.2.0 gopd: 1.2.0
gm-crypt@0.0.2:
dependencies:
base64-js: 1.5.1
good-listener@1.2.2: good-listener@1.2.2:
dependencies: dependencies:
delegate: 3.2.0 delegate: 3.2.0
...@@ -3407,6 +3521,8 @@ snapshots: ...@@ -3407,6 +3521,8 @@ snapshots:
inherits: 2.0.4 inherits: 2.0.4
readable-stream: 3.6.2 readable-stream: 3.6.2
ieee754@1.2.1: {}
image-size@0.5.5: {} image-size@0.5.5: {}
immutable@5.1.3: {} immutable@5.1.3: {}
...@@ -3598,10 +3714,14 @@ snapshots: ...@@ -3598,10 +3714,14 @@ snapshots:
glob: 10.4.5 glob: 10.4.5
nopt: 7.2.1 nopt: 7.2.1
js-calendar@1.2.3: {}
js-cookie@3.0.5: {} js-cookie@3.0.5: {}
js-tokens@9.0.1: {} js-tokens@9.0.1: {}
jsbn@1.1.0: {}
jsencrypt@3.3.2: {} jsencrypt@3.3.2: {}
json5@1.0.2: json5@1.0.2:
...@@ -3651,10 +3771,14 @@ snapshots: ...@@ -3651,10 +3771,14 @@ snapshots:
lodash: 4.17.21 lodash: 4.17.21
lodash-es: 4.17.21 lodash-es: 4.17.21
lodash.chunk@4.2.0: {}
lodash.clonedeep@4.5.0: {} lodash.clonedeep@4.5.0: {}
lodash.isequal@4.5.0: {} lodash.isequal@4.5.0: {}
lodash.throttle@4.1.1: {}
lodash@4.17.21: {} lodash@4.17.21: {}
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
...@@ -3774,6 +3898,8 @@ snapshots: ...@@ -3774,6 +3898,8 @@ snapshots:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
numeral@2.0.6: {}
object-assign@4.1.1: {} object-assign@4.1.1: {}
object-copy@0.1.0: object-copy@0.1.0:
...@@ -3856,6 +3982,8 @@ snapshots: ...@@ -3856,6 +3982,8 @@ snapshots:
exsolve: 1.0.7 exsolve: 1.0.7
pathe: 2.0.3 pathe: 2.0.3
popper.js@1.16.1: {}
posix-character-classes@0.1.1: {} posix-character-classes@0.1.1: {}
possible-typed-array-names@1.1.0: {} possible-typed-array-names@1.1.0: {}
...@@ -4183,6 +4311,10 @@ snapshots: ...@@ -4183,6 +4311,10 @@ snapshots:
signal-exit@4.1.0: {} signal-exit@4.1.0: {}
sm-crypto@0.3.13:
dependencies:
jsbn: 1.1.0
snapdragon-node@2.1.1: snapdragon-node@2.1.1:
dependencies: dependencies:
define-property: 1.0.0 define-property: 1.0.0
...@@ -4361,6 +4493,8 @@ snapshots: ...@@ -4361,6 +4493,8 @@ snapshots:
tiny-emitter@2.1.0: {} tiny-emitter@2.1.0: {}
tinycolor2@1.6.0: {}
tinyglobby@0.2.14: tinyglobby@0.2.14:
dependencies: dependencies:
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
...@@ -4516,10 +4650,28 @@ snapshots: ...@@ -4516,10 +4650,28 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
v-click-outside-x@3.7.1: {}
varint@6.0.0: {} varint@6.0.0: {}
vary@1.1.2: {} vary@1.1.2: {}
view-ui-plus@1.3.20:
dependencies:
async-validator: 3.5.2
countup.js: 1.9.3
dayjs: 1.11.13
deepmerge: 2.2.1
element-resize-detector: 1.2.4
js-calendar: 1.2.3
lodash.chunk: 4.2.0
lodash.throttle: 4.1.1
numeral: 2.0.6
popper.js: 1.16.1
select: 1.1.2
tinycolor2: 1.6.0
v-click-outside-x: 3.7.1
vite-plugin-compression@0.5.1(vite@6.3.5(@types/node@24.3.0)(sass-embedded@1.89.1)): vite-plugin-compression@0.5.1(vite@6.3.5(@types/node@24.3.0)(sass-embedded@1.89.1)):
dependencies: dependencies:
chalk: 4.1.2 chalk: 4.1.2
......
import request from '@/utils/request' import request from '@/utils/request'
// 登录方法 // 登录方法
export function login(username, password, code, uuid) { export function login(username, password) {
const data = { const data = {
username, username,
password, password
code,
uuid
} }
return request({ return request({
url: '/login', url: '/doLogin',
headers: { headers: {
isToken: false, isToken: false,
repeatSubmit: false repeatSubmit: false
......
<script setup lang="ts" name="ExpressionEditor">
import { ref, onMounted, toRefs } from "vue";
import ModalPop from "./ModalPop.vue"
const props = defineProps<{
modelValue: boolean;
data?: Object;
}>();
const emit = defineEmits(["update:modelValue", "confirm", "cancel"]);
const editorValue = ref("");
const infoText = ref('')
const listData = ref([
{
name: 'convert_base1()'
},
{
name: 'convert_base2()'
}
])
// 确认
const confirm = () => {
emit("confirm", editorValue.value);
};
// 测试
const test = () => {
console.log("test");
};
const cancel = () => {
emit("cancel");
}
// 划过事件
const hoverFunc = (item) => {
infoText.value = item;
}
const change = (val) => {
if(!val) return;
console.log(props.data)
editorValue.value = props.data.name;
}
</script>
<template>
<ModalPop v-model="props.modelValue" title="编辑器" @cancel="cancel" @change="change">
<template #content>
<div class="title">算法名称 :</div>
<div class="content">
<div class="content_left">
<div class="content_left_tap">函数</div>
<div class="content_left_list">
<el-scrollbar height="362px">
<div class="function__item" @mouseover="hoverFunc(item)" v-for="(item,index) in listData" :key="index">{{ item.name }}</div>
</el-scrollbar>
</div>
</div>
<div class="content_right">
<div class="content_right_info">
<div class="content_right_info_title">说明</div>
<div class="content_right_info_content">定义:{{ infoText }}</div>
</div>
<div class="content_right_editor">
<el-input
type="textarea"
placeholder="请输入内容"
v-model="editorValue"
/>
</div>
</div>
</div>
</template>
<template #footer>
<el-button type="primary" style="width: 150px;" @click="test">测试</el-button>
<el-button type="info" style="width: 150px;" @click="cancel">取消</el-button>
<el-button type="primary" style="width: 150px;" @click="confirm">确认</el-button>
</template>
</ModalPop>
</template>
<style lang="scss" scoped>
.title{
height: 32px; line-height: 32px;
}
.content{
display: flex;
height: 400px;
width: 100%;
&_left{
height: 100%;
width: 322px;
border-width: 1px;
border-style: solid;
border-color: rgb(220, 229, 235);
border-image: initial;
&_tap{
height: 36px;
line-height: 36px;
font-size: 14px;
font-weight: 700;
border-bottom: 1px solid rgb(220, 229, 235);
padding-left: 20px;
color: rgb(44, 158, 247);
}
&_list{
height: 100%;
.function__item{
padding-left: 20px;
cursor: pointer;
color: #7A8596;
}
.function__item:hover{
background: rgb(243, 245, 250);
}
}
}
&_right{
margin-left: 10px;
height: 100%;
flex: 1;
&_info{
height: 146px;
border-style: solid;
border-color: rgb(220, 229, 235);
border-image: initial;
border-width: 1px 1px 0px;
padding: 0px 20px;
&_title{
height: 42px;
line-height: 42px;
color: rgb(122, 132, 149);
font-size: 14px;
font-weight: 700;
}
&_content{
margin-top: -4px;
color: rgb(122, 132, 149);
font-size: 12px;
word-break: break-all;
}
}
&_editor{
width: 100%;
:deep(.el-textarea__inner){
box-sizing: border-box !important;
height: 254px !important;
min-height: 254px !important;
max-height: 254px !important;
border-radius: 0px !important;
padding: 12px 20px !important;
background: rgb(243, 245, 250) !important;
}
}
}
}
</style>
\ No newline at end of file
<script setup lang="ts" name="ModalPop">
import { ref, toRefs } from "vue";
import { Modal } from "view-ui-plus";
const props = defineProps<{
modelValue: boolean;
title: string;
}>();
const emit = defineEmits(["update:modelValue", "cancel", "change"]);
// 关闭
const cancel = () => {
emit("cancel");
};
const change = (visible: boolean) => {
emit("change", visible);
};
</script>
<template>
<Modal class="ModalPop" v-model="props.modelValue" width="1000" draggable scrollable sticky @on-cancel="cancel" @on-visible-change="change">
<template #header>
<span style="font-size: 16px; font-weight: bold;color: #7A8495;">{{ props.title }}</span>
</template>
<div class="slot-warpper">
<slot name="content"></slot>
</div>
<template #footer>
<div style="display: flex; justify-content: center; padding-top: 20px;">
<slot name="footer"></slot>
</div>
</template>
</Modal>
</template>
<style lang="scss">
.ModalPop {
.ivu-modal-header,
.ivu-modal-footer {
border: none;
}
.ivu-modal-content {
background: #f3f5fa;
}
.ivu-modal-body {
background: rgb(243, 245, 250);
border-radius: 4px;
padding: 0px 8px 8px !important;
}
.slot-warpper {
border-width: 1px;
border-style: solid;
border-color: rgb(220, 229, 235);
border-image: initial;
background: rgb(255, 255, 255);
padding: 30px;
border-radius: 4px;
max-height: 500px;
}
}
</style>
\ No newline at end of file
...@@ -37,7 +37,7 @@ const { proxy } = getCurrentInstance() ...@@ -37,7 +37,7 @@ const { proxy } = getCurrentInstance()
const quillEditorRef = ref() const quillEditorRef = ref()
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload") // 上传的图片服务器地址 const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload") // 上传的图片服务器地址
const headers = ref({ const headers = ref({
Authorization: "Bearer " + getToken() Token: getToken()
}) })
const props = defineProps({ const props = defineProps({
...@@ -189,7 +189,7 @@ function handlePasteCapture(e) { ...@@ -189,7 +189,7 @@ function handlePasteCapture(e) {
function insertImage(file) { function insertImage(file) {
const formData = new FormData() const formData = new FormData()
formData.append("file", file) formData.append("file", file)
axios.post(uploadUrl.value, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: headers.value.Authorization } }).then(res => { axios.post(uploadUrl.value, formData, { headers: { "Content-Type": "multipart/form-data", Token: headers.value.Token } }).then(res => {
handleUploadSuccess(res.data) handleUploadSuccess(res.data)
}) })
} }
......
...@@ -93,7 +93,7 @@ const number = ref(0) ...@@ -93,7 +93,7 @@ const number = ref(0)
const uploadList = ref([]) const uploadList = ref([])
const baseUrl = import.meta.env.VITE_APP_BASE_API const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // 上传文件服务器地址 const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // 上传文件服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() }) const headers = ref({ Token: getToken() })
const fileList = ref([]) const fileList = ref([])
const showTip = computed( const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize) () => props.isShowTip && (props.fileType || props.fileSize)
......
...@@ -103,7 +103,7 @@ const dialogImageUrl = ref("") ...@@ -103,7 +103,7 @@ const dialogImageUrl = ref("")
const dialogVisible = ref(false) const dialogVisible = ref(false)
const baseUrl = import.meta.env.VITE_APP_BASE_API const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // 上传的图片服务器地址 const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + props.action) // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() }) const headers = ref({ Token: getToken() })
const fileList = ref([]) const fileList = ref([])
const showTip = computed( const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize) () => props.isShowTip && (props.fileType || props.fileSize)
......
<script setup lang="ts" name="collapseView">
import { ref, computed } from 'vue'
import { Collapse, Panel } from 'view-ui-plus';
const emit = defineEmits(["add", "view", "mainDeletion", "default", "childDelete", "change"]);
const props = defineProps<{
list: Array<any>;
}>();
const listData = computed(() => props.list)
// 新增
const addClick = (item) => {
emit("add",item);
}
// 查看
const viewClick = (item) => {
emit("view",item);
}
// 主删除
const mainDeletion = (item) => {
emit("mainDeletion",item);
}
// 子级监听
const itemClick = (item) => {
emit("change",item);
}
// 默认项
const defaultClick = (item) => {
emit("default",item);
}
// 子删除
const childDelete = (item) => {
emit("childDelete",item);
}
</script>
<template>
<Collapse simple>
<Panel :name="item.name" v-for="(item, index) in listData" :key="index">
{{ item.name }}
<span class="collapse-item__btns--box">
<el-icon color="rgb(253, 84, 81)" :size="16" v-if="item.isAdd" @click.stop="addClick(item)">
<circle-plus-filled />
</el-icon>
<el-icon color="#2c9ef7" :size="16" v-if="item.isView" @click.stop="viewClick(item)" style="margin-left: 8px;">
<View />
</el-icon>
<el-icon color="rgb(13, 215, 141)" :size="16" v-if="item.isDelete" @click.stop="mainDeletion(item)" style="margin-left: 8px;">
<delete />
</el-icon>
</span>
<template #content>
<div>
<div class="rule__item" v-for="(itemTwo, i) in item.list" :key="i" @click="itemClick(itemTwo)">
<span>{{ itemTwo.name }}</span>
<div class="default"></div>
<div class="rule__item__btns">
<el-icon color="#2c9ef7" :size="15" v-if="itemTwo.isCheck" @click.stop="defaultClick(itemTwo)" style="margin-right: 8px;" >
<circle-check />
</el-icon>
<el-icon color="rgb(13, 215, 141)" :size="15" v-if="itemTwo.isDelete" @click.stop="childDelete(itemTwo)">
<delete />
</el-icon>
</div>
</div>
</div>
</template>
</Panel>
</Collapse>
</template>
<style lang="scss" scoped>
:deep(.ivu-collapse-content) {
padding: 0 0 0 14px;
}
:deep(.ivu-collapse-content-box) {
padding-bottom: 0;
}
.ivu-collapse-header {
padding-left: 0;
}
.ivu-collapse-simple {
border: none !important;
.ivu-collapse-item {
position: relative;
border: none !important;
}
.ivu-collapse-item:before {
content: " ";
width: calc(100% - 14px);
height: 1px;
background: #f3f5fa;
position: absolute;
top: 0;
left: 14px;
}
.ivu-collapse-item:first-child:before {
height: 0;
}
}
.collapse-item__btns--box {
position: absolute;
right: 4px;
}
.rule__item {
position: relative;
padding-left: 20px;
cursor: pointer;
border-bottom: 1px solid #f3f5fa;
height: 30px;
line-height: 30px;
display: flex;
align-items: center;
justify-content: space-between;
&__btns {
padding-top: 7px;
padding-right: 28px;
display: none;
line-height: 30px;
}
.default {
position: absolute;
top: 0;
right: 0;
width: 28px;
height: 30px;
background: url("@/assets/images/assetLibrary/default.png") no-repeat
center center;
background-size: 100% 100%;
pointer-events: none;
}
}
.rule__item:hover {
color: #21333f;
background: #f3f5fa;
.rule__item__btns {
display: block;
}
}
</style>
\ No newline at end of file
...@@ -95,7 +95,17 @@ function logout() { ...@@ -95,7 +95,17 @@ function logout() {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
userStore.logOut().then(() => { userStore.logOut().then(() => {
location.href = '/index' // location.href = '/index'
appStore.signOut('logout')
appStore.setNavStatus({type: 'manage'})
appStore.setQueryData({
projectId: ''
})
window.location.replace(`${import.meta.env.BASE_URL}`)
}) })
}).catch(() => { }) }).catch(() => { })
} }
......
...@@ -5,6 +5,7 @@ import Cookies from 'js-cookie' ...@@ -5,6 +5,7 @@ import Cookies from 'js-cookie'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css' import 'element-plus/theme-chalk/dark/css-vars.css'
import 'view-ui-plus/dist/styles/viewuiplus.css';
import locale from 'element-plus/es/locale/lang/zh-cn' import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css import '@/assets/styles/index.scss' // global css
......
...@@ -11,7 +11,7 @@ import usePermissionStore from '@/store/modules/permission' ...@@ -11,7 +11,7 @@ import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register', '/assetLibrary'] const whiteList = ['/login', '/register', '/assetLibrary', '/projectHome', '/projectManage','/classification']
const isWhiteList = (path) => { const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path)) return whiteList.some(pattern => isPathMatch(pattern, path))
...@@ -19,48 +19,56 @@ const isWhiteList = (path) => { ...@@ -19,48 +19,56 @@ const isWhiteList = (path) => {
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()
if (getToken()) { // if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title) // to.meta.title && useSettingsStore().setTitle(to.meta.title)
/* has token*/ // /* has token*/
if (to.path === '/login') { // if (to.path === '/login') {
next({ path: '/' }) // next({ path: '/' })
NProgress.done() // NProgress.done()
} else if (isWhiteList(to.path)) { // } else if (isWhiteList(to.path)) {
next() // next()
} else { // } else {
if (useUserStore().roles.length === 0) { // if (useUserStore().roles.length === 0) {
isRelogin.show = true // isRelogin.show = true
// 判断当前用户是否已拉取完user_info信息 // // 判断当前用户是否已拉取完user_info信息
useUserStore().getInfo().then(() => { // useUserStore().getInfo().then(() => {
isRelogin.show = false // isRelogin.show = false
usePermissionStore().generateRoutes().then(accessRoutes => { // usePermissionStore().generateRoutes().then(accessRoutes => {
// 根据roles权限生成可访问的路由表 // // 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => { // accessRoutes.forEach(route => {
if (!isHttp(route.path)) { // if (!isHttp(route.path)) {
router.addRoute(route) // 动态添加可访问路由表 // router.addRoute(route) // 动态添加可访问路由表
} // }
}) // })
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 // next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
}) // })
}).catch(err => { // }).catch(err => {
useUserStore().logOut().then(() => { // useUserStore().logOut().then(() => {
ElMessage.error(err) // ElMessage.error(err)
next({ path: '/' }) // next({ path: '/' })
}) // })
}) // })
} else { // } else {
next() // next()
} // }
} // }
} else { // } else {
// 没有token // // 没有token
if (isWhiteList(to.path)) { // if (isWhiteList(to.path)) {
// 在免登录白名单,直接进入 // // 在免登录白名单,直接进入
next() // next()
} else { // } else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 // next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
NProgress.done() // NProgress.done()
} // }
// }
if (sessionStorage.getItem('__token') || isWhiteList(to.path)){
next()
}else{
next(`/login?redirect=${to.fullPath}`)
NProgress.done()
} }
}) })
......
...@@ -15,7 +15,7 @@ export default { ...@@ -15,7 +15,7 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: { 'Token': getToken() }
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data) const isBlob = blobValidate(res.data)
if (isBlob) { if (isBlob) {
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: { 'Token': getToken() }
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data) const isBlob = blobValidate(res.data)
if (isBlob) { if (isBlob) {
...@@ -50,7 +50,7 @@ export default { ...@@ -50,7 +50,7 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: { 'Token': getToken() }
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data) const isBlob = blobValidate(res.data)
if (isBlob) { if (isBlob) {
......
...@@ -63,16 +63,30 @@ export const constantRoutes = [ ...@@ -63,16 +63,30 @@ export const constantRoutes = [
hidden: true hidden: true
}, },
{ {
// 项目首页
path: '/projectManage', path: '/projectManage',
component: () => import('@/views/projectManage/index'), component: () => import('@/views/projectManage/index'),
hidden: true hidden: true
}, },
{ {
// 项目首页
path: '/projectHome', path: '/projectHome',
component: () => import('@/views/projectHome/index'), component: () => import('@/views/projectHome/index'),
hidden: true hidden: true
}, },
{ {
// 加密设置
path: '/classification',
component: () => import('@/views/Classification/index'),
hidden: true
},
{
// 加密管理
path: '/encryptionManagement',
component: () => import('@/views/EncryptionManagement/index'),
hidden: true
},
{
path: '', path: '',
component: Layout, component: Layout,
redirect: '/index', redirect: '/index',
......
// import { defineStore } from 'pinia'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { useRouter } from 'vue-router'
const router = useRouter()
const useAppStore = defineStore('app', {
state: () => ({
// 新版基础状态
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false,
hide: false
},
device: 'desktop',
size: Cookies.get('size') || 'default',
// 旧版迁移状态
localUserName: sessionStorage.getItem('localUserName') ? JSON.parse(sessionStorage.getItem('localUserName')) : '',
bindDataSourceInfo: sessionStorage.getItem('bindDataSourceInfo') ? JSON.parse(sessionStorage.getItem('bindDataSourceInfo')) : {},
navList: sessionStorage.getItem('navList') ? JSON.parse(sessionStorage.getItem('navList')) : [],
navStatus: sessionStorage.getItem('navStatus') ? JSON.parse(sessionStorage.getItem('navStatus')) : { type: 'manage' },
leftNavActiveId: '',
queryData: sessionStorage.getItem('queryData') ? JSON.parse(sessionStorage.getItem('queryData')) : {},
userInfo: sessionStorage.getItem('userInfo') ? JSON.parse(sessionStorage.getItem('userInfo')) : {},
system: sessionStorage.getItem('system') ? JSON.parse(sessionStorage.getItem('system')) : {},
editSourcePageBackPath: sessionStorage.getItem('editSourcePageBackPath') || '',
systemList: sessionStorage.getItem('systemList') ? JSON.parse(sessionStorage.getItem('systemList')) : [],
navOpen: false,
// 图标配置
tableButtonIcons: {
getInfo: {
icon: '&#xe7d2;',
color: "rgb(83,144,213)",
label: "查看",
},
discover: {
icon: "&#xe6e9;",
color: "rgb(83,190,213)",
label: "发现",
},
log: {
icon: "&#xe617;",
color: "rgb(83,190,213)",
label: "日志",
},
carding: {
icon: "&#xe661;",
color: "rgb(83,190,213)",
label: "梳理",
},
edit: {
icon: "&#xe658;",
color: "#0f7241",
label: "编辑"
},
dele: {
icon: "&#xe600;",
color: "rgb(250,114,86)",
label: "删除",
},
getChildrenInfo: {
icon: "&#xe601;",
color: "rgb(255,189,91)",
label: "管理子任务",
},
showStartMaskingTaskWindow: {
icon: "&#xe654;",
color: "rgb(83,190,213)",
label: "执行",
},
monitor: {
icon: "&#xe622;",
color: "rgb(79,142,212)",
label: "监控",
},
statistics: {
icon: "&#xe633;",
color: "rgb(151,80,173)",
label: "统计",
},
stopTask: {
icon: "&#xe792;",
color: "rgb(250,114,86)",
label: "停止",
},
pauseTask: {
icon: "&#xe6b2;",
color: "rgb(156,89,177)",
label: "暂停",
},
recoverTask: {
icon: "&#xe69c;",
color: "rgb(255,189,91)",
label: "恢复",
},
alterTask: {
icon: "&#xe69c;",
color: "rgb(255,189,91)",
label: "异常",
},
downloadTaskFile: {
icon: "&#xe606;",
color: "#5390d5",
label: "下载",
},
setDate: {
label: "", // 日期
icon: "&#xe61d;",
color: "rgb(83,144,213)",
},
openRefuseWindow: {
icon: "&#xe645;",
color: "rgb(250,114,86)",
label: "拒绝",
},
openPassWindow: {
icon: "&#xe7ad;",
color: "rgb(83,144,213)",
label: "通过",
},
getRowInfo: {
icon: "&#xe6fa;",
label: "查看列",
},
getFileInfo: {
icon: "&#xe6fa;",
label: "查看文件",
},
test: {
icon: "&#xe60b;",
color: "rgb(83, 190, 213)",
label: "测试",
},
preview: {
icon: "&#xe66c;",
color: "#17b0a3",
label: "预览",
},
AIDiscover: {
icon: "&#xe6a0;",
color: "#eb8787",
label: "智能发现",
},
history: {
icon: "&#xe69a;",
color: "rgb(156,89,177)",
label: "查看历史",
},
result: {
icon: "&#xe69d;",
color: "rgb(15, 114, 65)",
label: "查看结果",
}
},
// 数据库规则类型
DBruleTypeList: [
{
label: '访问规则',
value: 1
},
{
label: 'SQL阻断',
value: 2
},
{
label: 'SQL替换',
value: 3
},
{
label: '表替换',
value: 4
},
{
label: '脱敏',
value: 5
},
{
label: '字段规则',
value: 7
},
{
label: '审计规则',
value: 8
}
],
// 编辑映射
EDTION_MAP: {
equal: 0,
notEqual: 1,
contain: 2,
notContain: 3
},
// 数据库图标
DATABASE_ICONS: {
MYSQL: {
text: '&#xe6b3;',
color: 'blue',
},
ORACLE: {
text: '&#xe6f4;',
color: 'red',
},
DB2: {
text: '&#xe6a8;',
color: 'red',
},
MSSQLSERVER: {
text: '&#xe6b5;',
color: 'red',
},
GREENPLUM: {
text: '&#xe857;',
color: 'red',
},
REDIS: {
text: '&#xe8b2;',
color: 'rgb(0, 193, 222)',
},
MONGODB: {
text: '&#xe6b7;',
color: 'rgb(255, 106, 0)',
},
DATABASE: {
text: '&#xe7e7;',
color: '#E6A23C'
},
TABLE: {
text: '&#xe87d;',
color: '#008fcf'
},
queryTables: {
text: '&#xe6e1;',
color: '#f0840e'
},
queryViews: {
text: '&#xe6e2;',
color: '#f0840e'
},
querySynonyms: {
text: '&#xe6e4;',
color: '#f0840e'
},
DM: {
text: '&#xe6bf;',
color: '#f0840e'
},
KINGBASE: {
text: '&#xe794;',
color: '#2c9ef7'
},
GAUSS: {
text: '&#xe795;',
color: '#008fcf'
},
OCEANBASE: {
text: '&#xe795;',
color: '#008fcf'
},
ES: {
text: '&#xe791;',
color: ''
}
},
// 数据库类型
DATABASE_TYPE: ['MYSQL', 'MARIADB', 'INFORMIX', 'SYBASE', 'SYBASEIQ', 'GBASE', 'KINGBASE', 'DM', 'OSCAR', 'UXDB', 'GREENPLUM', 'TERADATA', 'HIGHGO', 'CACHE', 'OCEANBASE'],
}),
const useAppStore = defineStore( actions: {
'app', // 新版基础动作
{ toggleSideBar(withoutAnimation) {
state: () => ({ if (this.sidebar.hide) return
sidebar: { this.sidebar.opened = !this.sidebar.opened
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, this.sidebar.withoutAnimation = withoutAnimation
withoutAnimation: false, Cookies.set('sidebarStatus', this.sidebar.opened ? '1' : '0')
hide: false },
},
device: 'desktop', closeSideBar({ withoutAnimation }) {
size: Cookies.get('size') || 'default' Cookies.set('sidebarStatus', '0')
}), this.sidebar.opened = false
actions: { this.sidebar.withoutAnimation = withoutAnimation
toggleSideBar(withoutAnimation) { },
if (this.sidebar.hide) {
return false toggleDevice(device) {
} this.device = device
this.sidebar.opened = !this.sidebar.opened },
this.sidebar.withoutAnimation = withoutAnimation
if (this.sidebar.opened) { setSize(size) {
Cookies.set('sidebarStatus', 1) this.size = size
} else { Cookies.set('size', size)
Cookies.set('sidebarStatus', 0) },
}
}, toggleSideBarHide(status) {
closeSideBar({ withoutAnimation }) { this.sidebar.hide = status
Cookies.set('sidebarStatus', 0) },
this.sidebar.opened = false
this.sidebar.withoutAnimation = withoutAnimation // 旧版迁移动作
}, setBindDataSourceInfo(data) {
toggleDevice(device) { this.bindDataSourceInfo = data
this.device = device sessionStorage.setItem('bindDataSourceInfo', JSON.stringify(data))
}, },
setSize(size) {
this.size = size setUserName(data) {
Cookies.set('size', size) this.localUserName = data
}, sessionStorage.setItem('localUserName', JSON.stringify(data))
toggleSideBarHide(status) { },
this.sidebar.hide = status
setNavStatus(data) {
this.navStatus = data
sessionStorage.setItem('navStatus', JSON.stringify(data))
},
setQueryData(data) {
if (Object.prototype.toString.call(data) === '[object Object]') {
this.queryData = data
sessionStorage.setItem('queryData', JSON.stringify(data))
} else {
this.queryData = {}
throw new Error('查询数据格式错误')
}
},
setTableButtonIconStyle() {
this.tableButtonIcons.getInfo.color = 'rgb(83,144,213)'
this.tableButtonIcons.edit.color = '#0f7241'
},
setNav(data) {
this.navList = data
sessionStorage.setItem('navList', JSON.stringify(data))
},
setNavOpen(data) {
this.navOpen = data
},
setSystem(data) {
this.system = data
sessionStorage.setItem('system', JSON.stringify(data))
},
setPath(data) {
this.editSourcePageBackPath = data
sessionStorage.setItem('editSourcePageBackPath', data)
},
setLeftNavActiveId(data) {
this.leftNavActiveId = data
},
setSystemList(data) {
this.systemList = data
sessionStorage.setItem('systemList', JSON.stringify(data))
},
setUserInfo(data) {
this.userInfo = data
sessionStorage.setItem('userInfo', JSON.stringify(data))
},
async signOut(status) {
sessionStorage.clear()
this.system = {}
if (status !== 'login') {
await router.push({
path: '/login'
})
} }
} }
}) }
})
export default useAppStore export default useAppStore
\ No newline at end of file
...@@ -4,7 +4,10 @@ import { login, logout, getInfo } from '@/api/login' ...@@ -4,7 +4,10 @@ import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from '@/utils/auth'
import { isHttp, isEmpty } from "@/utils/validate" import { isHttp, isEmpty } from "@/utils/validate"
import defAva from '@/assets/images/profile.jpg' import defAva from '@/assets/images/profile.jpg'
import { sm4 as SM4 } from 'gm-crypt'
// import useAppStore from './app'
// const appStore = useAppStore()
const useUserStore = defineStore( const useUserStore = defineStore(
'user', 'user',
{ {
...@@ -21,19 +24,70 @@ const useUserStore = defineStore( ...@@ -21,19 +24,70 @@ const useUserStore = defineStore(
// 登录 // 登录
login(userInfo) { login(userInfo) {
const username = userInfo.username.trim() const username = userInfo.username.trim()
const password = userInfo.password // const password = userInfo.password
const code = userInfo.code console.log('userInfo.password',userInfo.password)
const uuid = userInfo.uuid const password = this.encryptPassword(userInfo.password)
// const code = userInfo.code
// const uuid = userInfo.uuid
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password).then(res => {
setToken(res.token) console.log(res)
this.token = res.token if (res.code == "POP_00014"){
resolve()
resolve(res.data)
}else{
reject(error)
}
// return
// setToken(res.token)
// this.token = res.token
reject(error)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
}) })
// login(username, password, code, uuid).then(res => {
// setToken(res.token)
// this.token = res.token
// resolve()
// }).catch(error => {
// reject(error)
// })
}) })
}, },
// 加密方法
encryptPassword(plainPassword) {
const sm4Config = {
key: "GJstSK_YBD=gSOFT",
mode: 'ecb',
cipherType: 'base64'
}
const sm4 = new SM4(sm4Config)
try {
return sm4.encrypt(plainPassword)
} catch (error) {
console.error('加密失败:', error)
throw new Error('密码加密处理失败')
}
},
// 十六进制转Base64工具方法
hexToBase64(hexString) {
// 将十六进制字符串转换为字节数组
const byteArray = new Uint8Array(
hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))
);
// 将字节数组转换为Base64
const base64String = btoa(
String.fromCharCode.apply(null, byteArray)
);
return base64String;
},
// 获取用户信息 // 获取用户信息
getInfo() { getInfo() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
......
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token' const TokenKey = '__token'
export function getToken() { export function getToken() {
return Cookies.get(TokenKey) return sessionStorage.getItem(TokenKey) || Cookies.get(TokenKey)
} }
export function setToken(token) { export function setToken(token) {
return Cookies.set(TokenKey, token) return Cookies.set(TokenKey, token)
} }
export function removeToken() { export function removeToken() {
......
...@@ -27,7 +27,7 @@ service.interceptors.request.use(config => { ...@@ -27,7 +27,7 @@ service.interceptors.request.use(config => {
// 是否需要防止数据重复提交 // 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) { if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers['Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
} }
// get请求映射params参数 // get请求映射params参数
if (config.method === 'get' && config.params) { if (config.method === 'get' && config.params) {
...@@ -74,7 +74,7 @@ service.interceptors.request.use(config => { ...@@ -74,7 +74,7 @@ service.interceptors.request.use(config => {
// 响应拦截器 // 响应拦截器
service.interceptors.response.use(res => { service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态 // 未设置状态码则默认成功状态
const code = res.data.code || 200 const code = res.data.code || 'POP_00014'
// 获取错误信息 // 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default'] const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回 // 二进制数据则直接返回
...@@ -100,7 +100,7 @@ service.interceptors.response.use(res => { ...@@ -100,7 +100,7 @@ service.interceptors.response.use(res => {
} else if (code === 601) { } else if (code === 601) {
ElMessage({ message: msg, type: 'warning' }) ElMessage({ message: msg, type: 'warning' })
return Promise.reject(new Error(msg)) return Promise.reject(new Error(msg))
} else if (code !== 200) { } else if (code !== 'POP_00014') {
ElNotification.error({ title: msg }) ElNotification.error({ title: msg })
return Promise.reject('error') return Promise.reject('error')
} else { } else {
......
<script setup name="Classification">
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted } from 'vue'
import TreeFilter from './modules/TreeFilter.vue'
import BasicInfoTab from './modules/BasicInfoTab.vue'
import TableInfoTab from './modules/TableInfoTab.vue'
import StructureTab from './modules/StructureTab.vue'
import EncryptionTab from './modules/EncryptionTab.vue'
import { useDict } from '@/utils/dict'
import { useRouter } from 'vue-router'
const router = useRouter()
const { proxy } = getCurrentInstance()
const projectId = ref('')
onMounted(()=>{
projectId.value =proxy.$route.query.projectId
console.log('projectId',projectId.value)
})
// const props = defineProps({
// projectId: String, // 主键
// })
// 树形数据
const treeData = ref([
{
id: 'system',
label: '若依配测系统',
type: 'system',
children: [
{
id: 'database',
label: 'ry',
type: 'database',
children: [
{
id: 'tables',
label: '表',
type: 'category',
children: [
{ id: 'gen_table', label: 'gen_table', type: 'table' },
{ id: 'gen_table_column', label: 'gen_table_column', type: 'table' },
{ id: 'sys_config', label: 'sys_config', type: 'table' },
{ id: 'sys_dept', label: 'sys_dept', type: 'table' },
{ id: 'sys_dict_data', label: 'sys_dict_data', type: 'table' },
{ id: 'sys_dict_type', label: 'sys_dict_type', type: 'table' },
{ id: 'sys_job', label: 'sys_job', type: 'table' },
{ id: 'sys_job_log', label: 'sys_job_log', type: 'table' },
{ id: 'sys_logininfor', label: 'sys_logininfor', type: 'table' },
{ id: 'sys_menu', label: 'sys_menu', type: 'table' },
{ id: 'sys_notice', label: 'sys_notice', type: 'table' },
{ id: 'sys_oper_log', label: 'sys_oper_log', type: 'table' },
{ id: 'sys_post', label: 'sys_post', type: 'table' },
{ id: 'sys_role', label: 'sys_role', type: 'table' },
{ id: 'sys_role_dept', label: 'sys_role_dept', type: 'table' },
{ id: 'sys_role_menu', label: 'sys_role_menu', type: 'table' },
{ id: 'sys_user', label: 'sys_user', type: 'table' },
{ id: 'sys_user_online', label: 'sys_user_online', type: 'table' },
{ id: 'sys_user_post', label: 'sys_user_post', type: 'table' },
{ id: 'sys_user_role', label: 'sys_user_role', type: 'table' }
]
}
]
}
]
}
])
// 当前选中的节点数据
const currentNodeData = ref(null)
const currentNodeLevel = computed(() => {
if (!currentNodeData.value) return 0
if (currentNodeData.value.type === 'system') return 1
if (currentNodeData.value.type === 'database') return 2
if (currentNodeData.value.type === 'category') return 3
if (currentNodeData.value.type === 'table') return 4
return 0
})
// 是否启用解密插件
const enableDecryptionPlugin = ref(false)
// 当前激活的Tab
const activeTab = ref('basic')
// 当前表结构数据 (匹配图片中的gen_table结构)
const currentTableStructure = ref([
{ pk: '', fieldName: 'business_name', comment: '生成业务名', fieldType: 'VARCHAR', length: '30', precision: '', algorithm: '' },
{ pk: '', fieldName: 'business_name_...', comment: '', fieldType: 'TEXT', length: '65535', precision: '', algorithm: '' },
{ pk: '', fieldName: 'class_name', comment: '实体类名称', fieldType: 'VARCHAR', length: '100', precision: '', algorithm: '' },
{ pk: '', fieldName: 'create_by', comment: '创建者', fieldType: 'VARCHAR', length: '64', precision: '', algorithm: '' },
{ pk: '', fieldName: 'create_time', comment: '创建时间', fieldType: 'DATETIME', length: '19', precision: '', algorithm: '' },
{ pk: '', fieldName: 'function_author', comment: '生成功能作者', fieldType: 'VARCHAR', length: '50', precision: '', algorithm: '' },
{ pk: '', fieldName: 'function_name', comment: '生成功能名', fieldType: 'VARCHAR', length: '50', precision: '', algorithm: '' },
{ pk: '', fieldName: 'gen_path', comment: '生成路径(不填...', fieldType: 'VARCHAR', length: '200', precision: '', algorithm: '' },
{ pk: '', fieldName: 'gen_type', comment: '生成代码方式(0...', fieldType: 'CHAR', length: '1', precision: '', algorithm: '' },
{ pk: '', fieldName: 'module_name', comment: '生成模块名', fieldType: 'VARCHAR', length: '30', precision: '', algorithm: '' }
])
// 树节点点击处理
const handleNodeClick = (data) => {
currentNodeData.value = data
activeTab.value = 'basic'
}
// 批量加密
const handleBatchEncrypt = () => {
console.log('批量加密', currentNodeData.value)
}
// 批量解密
const handleBatchDecrypt = () => {
console.log('批量解密', currentNodeData.value)
}
// 删除多余列
const handleDeleteColumns = () => {
console.log('删除多余列', currentNodeData.value)
}
// 编辑字段
const handleEditField = (field) => {
console.log('编辑字段', field)
}
const openDecrypt = ref(false)
function pageProjectManage() {
router.push({
path: '/projectManage'
})
}
defineExpose({
// handleRedInk,
// handleVoid
})
</script>
<template>
<div class="app-container scroller">
<PageTitle :back="true" @back="pageProjectManage" >
<template #title>
返回项目管理
</template>
</PageTitle>
<div class="app-container__body">
<div class="flex-container content-container">
<div class="left">
<el-card class="image-card tree-container">
<TreeFilter :tree-data="treeData" @node-click="handleNodeClick"/>
</el-card>
</div>
<div class="right flex1">
<el-card class="image-card">
<div class="header-section">
<div class="breadcrumb flex-container justify-between align-center">
<el-breadcrumb separator="/">
<el-breadcrumb-item>若依配测系统</el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 2">ry</el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 3"></el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 4">{{ currentNodeData?.label }}</el-breadcrumb-item>
</el-breadcrumb>
<el-checkbox v-model="openDecrypt">是否启用解密插件</el-checkbox>
</div>
<div class="radio-group" v-if="currentNodeLevel === 4">
<el-radio-group v-model="enableDecryptionPlugin">
<el-radio :label="true">启用解密插件</el-radio>
<el-radio :label="false">不启用解密插件</el-radio>
</el-radio-group>
</div>
</div>
<!-- Tab区域 -->
<div class="tab-section">
<el-tabs v-model="activeTab">
<!-- 基本信息Tab -->
<el-tab-pane label="基本信息" name="basic">
<BasicInfoTab
:node-data="currentNodeData"
v-if="activeTab === 'basic' && currentNodeLevel === 1"
/>
<TableInfoTab
:node-data="currentNodeData"
v-if="activeTab === 'basic' && currentNodeLevel === 4"
/>
</el-tab-pane>
<!-- 数据结构Tab (仅4级节点显示) -->
<el-tab-pane label="数据结构" name="structure" v-if="currentNodeLevel === 4">
<StructureTab
:table-data="currentTableStructure"
v-if="activeTab === 'structure'"
/>
</el-tab-pane>
<!-- 字段加密配置Tab (仅4级节点显示) -->
<el-tab-pane label="字段加密配置" name="encryption" v-if="currentNodeLevel === 4">
<EncryptionTab
:table-data="currentTableStructure"
@batch-encrypt="handleBatchEncrypt"
@batch-decrypt="handleBatchDecrypt"
@delete-columns="handleDeleteColumns"
@edit-field="handleEditField"
v-if="activeTab === 'encryption'"
/>
</el-tab-pane>
</el-tabs>
</div>
</el-card>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.flex-container {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.flex1 {
flex: 1;
}
.content-container {
.left {
.tree-container {
width: 300px;
}
}
.right {
margin-left: var(--container-pd);
overflow: hidden;
}
}
</style>
<template>
<div class="basic-info-tab">
<el-descriptions
title="系统基本信息"
border
:column="1"
size="medium"
>
<el-descriptions-item label="项目">若依配测系统</el-descriptions-item>
<el-descriptions-item label="数据源">若依配测系统</el-descriptions-item>
<el-descriptions-item label="数据源类型">MYSQL</el-descriptions-item>
<el-descriptions-item label="IP">172.19.1.166</el-descriptions-item>
<el-descriptions-item label="管理的SCHEMA">ry</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
// 可以留空,因为数据是静态的
</script>
<style scoped>
.basic-info-tab {
padding: 20px;
background-color: white;
}
:deep(.el-descriptions__title) {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
}
:deep(.el-descriptions__header) {
margin-bottom: 16px;
}
:deep(.el-descriptions__label) {
width: 180px;
background-color: #f5f7fa;
font-weight: bold;
color: #333;
}
:deep(.el-descriptions__content) {
background-color: white;
}
</style>
\ No newline at end of file
<template>
<el-dialog
title="设置加密规则"
v-model="dialogVisible"
width="800px"
:before-close="handleClose"
>
<div class="encryption-rule-dialog">
<!-- 上部:规则和密钥选择 -->
<div class="selection-section">
<!-- 左侧加密规则选择 -->
<div class="rule-selection">
<div class="section-title">选择加密规则</div>
<el-radio-group v-model="selectedRule" class="rule-radio-group">
<el-radio
v-for="rule in encryptionRules"
:key="rule.id"
:label="rule.id"
class="rule-radio"
>
{{ rule.name }}
</el-radio>
</el-radio-group>
</div>
<!-- 分割线 -->
<div class="divider"></div>
<!-- 右侧加密密钥选择 -->
<div class="key-selection">
<div class="section-title">选择加密密钥</div>
<el-radio-group v-model="selectedKey" class="key-radio-group">
<el-radio
v-for="key in currentKeys"
:key="key.id"
:label="key.id"
class="key-radio"
>
{{ key.name }}
</el-radio>
</el-radio-group>
</div>
</div>
<!-- 下部:配置区域 -->
<div class="config-section">
<div class="config-row">
<!-- 加密位置 -->
<div class="config-item">
<span class="required-label">*加密位置:</span>
<el-select v-model="ruleConfig.positionType" style="width: 120px">
<el-option label="保留前" value="prefix" />
<el-option label="保留后" value="suffix" />
</el-select>
<el-input-number
v-model="ruleConfig.position"
:min="0"
:max="100"
controls-position="right"
style="width: 100px; margin-left: 10px;"
/>
<span class="unit"></span>
</div>
</div>
<div class="config-row">
<!-- 源长度 -->
<div class="config-item">
<span class="label">源长度:</span>
<el-input-number
v-model="ruleConfig.sourceLength"
:min="0"
:max="1000"
controls-position="right"
style="width: 100px;"
/>
<el-button
type="primary"
size="small"
style="margin-left: 10px;"
@click="calculateLength"
>
计算
</el-button>
</div>
<!-- 加密后长度 -->
<div class="config-item">
<span class="label">加密后长度:</span>
<span class="value">{{ encryptedLength || '--' }}</span>
</div>
</div>
<div class="action-row">
<el-checkbox v-model="supportFuzzy">支持模糊</el-checkbox>
<div class="action-buttons">
<el-button @click="resetRules">重置规则</el-button>
<el-button type="primary" @click="confirmRules">确定规则</el-button>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
fieldData: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['update:visible', 'confirm'])
// 控制弹窗显示
const dialogVisible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
})
// 加密规则数据
const encryptionRules = ref([
{ id: 'name', name: '姓名加密规则' },
{ id: 'gender', name: '性别加密规则' }
])
// 加密密钥数据
const encryptionKeys = ref({
name: [
{ id: 'name_key1', name: '姓名加密密钥1' },
{ id: 'name_key2', name: '姓名加密密钥2' }
],
gender: [
{ id: 'gender_key1', name: '性别加密密钥1' },
{ id: 'gender_key2', name: '性别加密密钥2' }
]
})
// 当前选中的规则
const selectedRule = ref('name')
// 当前选中的密钥
const selectedKey = ref('')
// 当前显示的密钥列表
const currentKeys = computed(() => {
return encryptionKeys.value[selectedRule.value] || []
})
// 加密配置
const ruleConfig = ref({
positionType: 'prefix',
position: 0,
sourceLength: 100
})
// 加密后长度
const encryptedLength = ref('')
// 是否支持模糊
const supportFuzzy = ref(false)
// 监听规则变化,自动选择第一个密钥
watch(selectedRule, (newVal) => {
if (currentKeys.value.length > 0) {
selectedKey.value = currentKeys.value[0].id
}
}, { immediate: true })
// 计算加密后长度
const calculateLength = () => {
// 这里应该是实际的加密长度计算逻辑
encryptedLength.value = Math.floor(ruleConfig.value.sourceLength * 0.8)
}
// 重置规则
const resetRules = () => {
selectedRule.value = 'name'
ruleConfig.value = {
positionType: 'prefix',
position: 0,
sourceLength: 100
}
encryptedLength.value = ''
supportFuzzy.value = false
}
// 确认规则
const confirmRules = () => {
emit('confirm', {
rule: selectedRule.value,
key: selectedKey.value,
config: ruleConfig.value,
supportFuzzy: supportFuzzy.value,
encryptedLength: encryptedLength.value
})
dialogVisible.value = false
}
// 关闭弹窗前处理
const handleClose = (done) => {
done()
}
</script>
<style scoped>
.encryption-rule-dialog {
padding: 10px;
}
.selection-section {
display: flex;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.rule-selection, .key-selection {
flex: 1;
padding: 0 15px;
}
/* 新增的分割线样式 */
.divider {
width: 1px;
background-color: #ebeef5;
margin: 0 10px;
}
.section-title {
margin-bottom: 15px;
font-size: 14px;
font-weight: bold;
color: #333;
}
.rule-radio-group, .key-radio-group {
display: flex;
flex-direction: column;
}
.rule-radio, .key-radio {
margin: 5px 0;
}
.config-section {
padding: 0 15px;
}
.config-row {
display: flex;
align-items: center;
margin-bottom: 15px;
flex-wrap: wrap;
}
.config-item {
display: flex;
align-items: center;
margin-right: 20px;
}
.required-label {
width: 80px;
text-align: right;
margin-right: 10px;
font-size: 14px;
color: #f56c6c;
}
.label {
text-align: right;
margin-right: 10px;
font-size: 14px;
color: #666;
}
.unit {
margin-left: 5px;
font-size: 14px;
color: #666;
}
.value {
font-size: 14px;
color: #333;
font-weight: bold;
}
.action-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
}
.action-buttons {
display: flex;
gap: 10px;
}
</style>
\ No newline at end of file
<template>
<div class="encryption-tab">
<!-- 搜索区域 -->
<div class="filter-section">
<el-form :inline="true" :model="filterForm" class="filter-form">
<el-form-item label="字段名过滤:">
<el-input
v-model="filterForm.fieldName"
placeholder="字段名模糊搜索"
clearable
style="width: 200px;"
/>
</el-form-item>
<el-form-item label="状态:">
<el-select style="width: 200px;" v-model="filterForm.status" placeholder="全部" clearable>
<el-option label="已加密" value="encrypted" />
<el-option label="未加密" value="unencrypted" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form>
</div>
<!-- 表格区域 -->
<el-table
:data="filteredTableData"
border
style="width: 100%; margin-top: 15px;"
:row-class-name="tableRowClassName"
>
<!-- 左浮动列 -->
<el-table-column prop="pk" label="主键" width="60" align="left" fixed />
<el-table-column prop="fieldName" label="字段名" width="150" align="left" fixed/>
<el-table-column prop="fieldType" label="字段类型" width="120" align="center" />
<el-table-column prop="length" label="长度" width="80" align="center" />
<el-table-column prop="algorithm" label="加密算法" width="120" align="center" />
<el-table-column label="密钥" width="120" align="center">
<template #default="{ row }">
<el-button type="text" @click="openEncryptionDialog(row)">设置</el-button>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag v-if="row.status === 'encrypted'" type="success" size="small">已加密</el-tag>
<el-tag v-else type="info" size="small">未加密</el-tag>
</template>
</el-table-column>
<!-- 右浮动列 -->
<el-table-column prop="comment" label="注释" align="left" min-width="200" />
<el-table-column label="描述信息" align="left" fixed="right">
<template #default="{ row }">
<el-input
v-model="row.description"
size="small"
:disabled="!isEditing"
@change="handleDescriptionChange(row)"
/>
</template>
</el-table-column>
<el-table-column prop="plaintextProcess" label="明文处理" align="left" fixed="right"/>
</el-table>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<el-button type="primary" @click="handleBatchEncrypt">批量加密</el-button>
<el-button type="primary" @click="handleBatchDecrypt">批量解密</el-button>
<el-button type="primary" @click="handleDeleteColumns">删除多余列</el-button>
<el-button
type="primary"
@click="toggleEditMode"
>
{{ isEditing ? '保存' : '编辑' }}
</el-button>
</div>
<EncryptionRuleDialog
v-model:visible="showEncryptionDialog"
:field-data="currentField"
@confirm="handleRuleConfirm"
/>
</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue'
import EncryptionRuleDialog from './EncryptionRuleDialog.vue'
const props = defineProps({
tableData: {
type: Array,
required: true,
default: () => [
{
pk: 'PK',
fieldName: 'table_id',
fieldType: 'BIGINT',
length: '19',
algorithm: '',
status: 'unencrypted',
comment: '编号',
description: '主键ID',
plaintextProcess: ''
},
// 其他数据行...
]
}
})
const emit = defineEmits(['batch-encrypt', 'batch-decrypt', 'delete-columns', 'edit-field', 'update-field'])
// 搜索表单
const filterForm = reactive({
fieldName: '',
status: ''
})
// 编辑模式
const isEditing = ref(false)
// 表格行样式
const tableRowClassName = ({ row, rowIndex }) => {
return row.status === 'encrypted' ? 'encrypted-row' : ''
}
// 处理搜索
const handleSearch = () => {
// 搜索逻辑已在计算属性中实现
}
// 切换编辑模式
const toggleEditMode = () => {
isEditing.value = !isEditing.value
}
// 处理描述信息变更
const handleDescriptionChange = (row) => {
emit('update-field', row)
}
// 批量加密
const handleBatchEncrypt = () => {
emit('batch-encrypt')
}
// 批量解密
const handleBatchDecrypt = () => {
emit('batch-decrypt')
}
// 删除多余列
const handleDeleteColumns = () => {
emit('delete-columns')
}
// 过滤表格数据
const filteredTableData = computed(() => {
return props.tableData.filter(item => {
const matchesName = filterForm.fieldName
? item.fieldName.includes(filterForm.fieldName)
: true
const matchesStatus = filterForm.status
? item.status === filterForm.status
: true
return matchesName && matchesStatus
})
})
const showEncryptionDialog = ref(false)
const currentField = ref({})
// 处理设置密钥
const openEncryptionDialog = (row) => {
if(!isEditing.value) return
currentField.value = row
showEncryptionDialog.value = true
}
const handleRuleConfirm = (ruleData) => {
console.log('确认加密规则:', ruleData)
// 更新表格数据或调用API
}
</script>
<style scoped>
.encryption-tab {
padding: 15px;
background-color: white;
}
.filter-section {
margin-bottom: 15px;
}
.filter-form {
display: flex;
align-items: center;
}
.action-buttons {
margin-top: 20px;
text-align: center;
}
:deep(.el-table .encrypted-row) {
background-color: #f0f9eb;
}
:deep(.el-table td) {
padding: 8px 0;
}
:deep(.el-table th) {
background-color: #f5f7fa;
}
:deep(.el-form-item) {
margin-bottom: 0;
}
:deep(.el-form-item__label) {
color: #333;
font-weight: normal;
}
</style>
\ No newline at end of file
<template>
<div class="structure-tab">
<el-table
:data="tableData"
border
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa', color: '#333' }"
:row-style="{ height: '40px' }"
:cell-style="{ padding: '8px 0', textAlign: 'center' }"
>
<el-table-column prop="pk" label="主键" width="120" fixed/>
<el-table-column prop="fieldName" label="字段名" width="180" />
<el-table-column prop="comment" label="注释" min-width="200" />
<el-table-column prop="fieldType" label="类型" width="120" />
<el-table-column prop="length" label="长度" width="120" />
<el-table-column prop="precision" label="精度" width="120" />
</el-table>
</div>
</template>
<script setup>
const props = defineProps({
tableData: {
type: Array,
required: true,
default: () => [
{ pk: '', fieldName: 'business_name', comment: '生成业务名', fieldType: 'VARCHAR', length: '30', precision: '' },
{ pk: '', fieldName: 'business_name_...', comment: '', fieldType: 'TEXT', length: '65535', precision: '' },
{ pk: '', fieldName: 'class_name', comment: '实体类名称', fieldType: 'VARCHAR', length: '100', precision: '' },
{ pk: '', fieldName: 'create_by', comment: '创建者', fieldType: 'VARCHAR', length: '64', precision: '' },
{ pk: '', fieldName: 'create_time', comment: '创建时间', fieldType: 'DATETIME', length: '19', precision: '' },
{ pk: '', fieldName: 'function_author', comment: '生成功能作者', fieldType: 'VARCHAR', length: '50', precision: '' },
{ pk: '', fieldName: 'function_name', comment: '生成功能名', fieldType: 'VARCHAR', length: '50', precision: '' },
{ pk: '', fieldName: 'gen_path', comment: '生成路径(不填...', fieldType: 'VARCHAR', length: '200', precision: '' },
{ pk: '', fieldName: 'gen_type', comment: '生成代码方式(0...', fieldType: 'CHAR', length: '1', precision: '' },
{ pk: '', fieldName: 'module_name', comment: '生成模块名', fieldType: 'VARCHAR', length: '30', precision: '' }
]
}
})
</script>
<style scoped>
.structure-tab {
padding: 10px;
background-color: white;
}
:deep(.el-table) {
font-size: 14px;
}
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td) {
background-color: #fafafa;
}
</style>
\ No newline at end of file
<template>
<div class="table-info-tab">
<el-descriptions
title="表基本信息"
border
:column="1"
size="medium"
>
<el-descriptions-item label="字段数">224</el-descriptions-item>
<el-descriptions-item label="加密表数量">0</el-descriptions-item>
<el-descriptions-item label="加密字段数量">0</el-descriptions-item>
<el-descriptions-item label="未加密表数量">20</el-descriptions-item>
<el-descriptions-item label="未加密字段数量">224</el-descriptions-item>
<el-descriptions-item label="操作人">admin</el-descriptions-item>
<el-descriptions-item label="操作时间">2023-05-15 14:30:22</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
// 可以留空,因为数据是静态的
</script>
<style scoped>
.table-info-tab {
padding: 20px;
background-color: white;
}
:deep(.el-descriptions__title) {
font-size: 16px;
font-weight: bold;
margin-bottom: 16px;
}
:deep(.el-descriptions__header) {
margin-bottom: 16px;
}
:deep(.el-descriptions__label) {
width: 180px;
background-color: #f5f7fa;
font-weight: bold;
color: #333;
}
:deep(.el-descriptions__content) {
background-color: white;
}
</style>
\ No newline at end of file
<template>
<div class="tree-filter-container">
<!-- 搜索框 -->
<div class="search-box">
<el-input
v-model="filterText"
placeholder="输入关键字过滤"
clearable
prefix-icon="el-icon-search"
/>
</div>
<!-- 树形结构 -->
<el-tree
ref="treeRef"
class="filter-tree"
:data="treeData"
:props="defaultProps"
:filter-node-method="filterNode"
:expand-on-click-node="false"
node-key="id"
highlight-current
default-expand-all
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<i :class="getNodeIcon(data.type)" class="node-icon"></i>
<span>{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
const emit = defineEmits(['node-click'])
const props = defineProps({
treeData: {
type: Array,
default: () => [
{
id: 'system',
label: '若依配测系统',
type: 'system',
children: [
{
id: 'database',
label: 'ry',
type: 'database',
children: [
{
id: 'tables',
label: '表',
type: 'category',
children: [
{ id: 'gen_table', label: 'gen_table', type: 'table' },
{ id: 'gen_table_column', label: 'gen_table_column', type: 'table' },
{ id: 'sys_config', label: 'sys_config', type: 'table' },
{ id: 'sys_dept', label: 'sys_dept', type: 'table' },
{ id: 'sys_dict_data', label: 'sys_dict_data', type: 'table' },
{ id: 'sys_dict_type', label: 'sys_dict_type', type: 'table' },
{ id: 'sys_job', label: 'sys_job', type: 'table' },
{ id: 'sys_job_log', label: 'sys_job_log', type: 'table' },
{ id: 'sys_logininfor', label: 'sys_logininfor', type: 'table' },
{ id: 'sys_menu', label: 'sys_menu', type: 'table' },
{ id: 'sys_notice', label: 'sys_notice', type: 'table' },
{ id: 'sys_oper_log', label: 'sys_oper_log', type: 'table' },
{ id: 'sys_post', label: 'sys_post', type: 'table' },
{ id: 'sys_role', label: 'sys_role', type: 'table' },
{ id: 'sys_role_dept', label: 'sys_role_dept', type: 'table' },
{ id: 'sys_role_menu', label: 'sys_role_menu', type: 'table' },
{ id: 'sys_user', label: 'sys_user', type: 'table' },
{ id: 'sys_user_online', label: 'sys_user_online', type: 'table' },
{ id: 'sys_user_post', label: 'sys_user_post', type: 'table' },
{ id: 'sys_user_role', label: 'sys_user_role', type: 'table' }
]
}
]
}
]
}
]
}
})
const filterText = ref('')
const treeRef = ref(null)
const defaultProps = {
children: 'children',
label: 'label'
}
// 根据节点类型获取图标
const getNodeIcon = (type) => {
const iconMap = {
system: 'el-icon-s-platform',
database: 'el-icon-s-data',
category: 'el-icon-folder-opened',
table: 'el-icon-s-grid'
}
return iconMap[type] || 'el-icon-document'
}
// 过滤树节点
const filterNode = (value, data) => {
if (!value) return true
return data.label.toLowerCase().includes(value.toLowerCase())
}
// 监听过滤文本变化
watch(filterText, (val) => {
treeRef.value.filter(val)
})
// 节点点击事件
const handleNodeClick = (data) => {
emit('node-click', data)
}
</script>
<style scoped>
.tree-filter-container {
width: 100%;
height: 100%;
background-color: #f5f5f5;
padding: 10px;
border-right: 1px solid #e6e6e6;
}
.search-box {
margin-bottom: 10px;
}
.filter-tree {
background-color: transparent;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
font-size: 14px;
}
.node-icon {
margin-right: 6px;
color: #606266;
}
:deep(.el-tree-node__content) {
height: 36px;
}
</style>
\ No newline at end of file
<script setup lang="ts" name="QueryForm">
import { computed,ref,watch } from 'vue'
import type { FormInstance } from 'element-plus'
import PageWrapperSearch from '@/components/search/PageWrapperSearch.vue'
// import { useDict } from '@/utils/dict'
// import { listDept } from '@/api/system/dept'// 部门
// const { approve_status, invoice_status} = useDict('approve_status', 'invoice_status')
const emit = defineEmits(['update:modelValue', 'query', 'reset'])
const invoice_status_filter = ref([])
const employeesList = ref([])
const props = defineProps<{
modelValue: any
}>()
const queryForm = computed({
get() {
return props.modelValue
},
set(val: any) {
console.log('query computed', val)
emit('update:modelValue', val)
}
})
// 搜索
function onSearch() {
emit('query')
}
// 重置
function onReset(formRef: FormInstance) {
queryForm.value.datasource = ''
queryForm.value.schema = ''
queryForm.value.tableName = ''
queryForm.value.fieldName = ''
queryForm.value.status = ''
emit('reset', formRef)
}
</script>
<template>
<!-- el-form -->
<page-wrapper-search
:model="queryForm"
@search="onSearch"
@reset="onReset">
<el-form-item label="数据源名称" prop="datasource">
<el-input
v-model="queryForm.datasource"
placeholder="请输入数据源名称"
clearable
/>
</el-form-item>
<el-form-item label="SCHEMA" prop="schema">
<el-input
v-model="queryForm.schema"
placeholder="请输入SCHEMA"
clearable
/>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryForm.tableName"
placeholder="请输入表名称"
clearable
/>
</el-form-item>
<el-form-item label="字段名称" prop="fieldName">
<el-input
v-model="queryForm.fieldName"
placeholder="请输入字段名称"
clearable
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryForm.status"
placeholder="请选择状态"
clearable
>
<el-option label="启用" value="active" />
<el-option label="禁用" value="inactive" />
</el-select>
</el-form-item>
</page-wrapper-search>
</template>
<style scoped>
</style>
<script setup lang="ts" name="projectManageIndex">
import { ref } from 'vue'
import list from './list.vue'
const widget = {
list: list
}
const page = ref('list')
const params = ref({})
function onChangePage(val: string, param?: any) {
page.value = val
params.value = param ?? {}
}
</script>
<template>
<component :is="widget[page]" v-bind="params" @page="onChangePage" />
</template>
<script setup name="ProjectManageList">
import { getCurrentInstance, reactive, ref, toRefs } from 'vue'
import { ElMessage } from 'element-plus'
import QueryForm from './QueryForm.vue'
// import ProjectEditDialog from './ProjectEditDialog.vue'
// import DownloadPluginDialog from './DownloadPluginDialog.vue'
// import ExportDialog from './ExportDialog.vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const emit = defineEmits(['page'])
const { proxy } = getCurrentInstance()
function onReset(formQuery) {
console.log('onReset')
formQuery.resetFields()
handleQuery()
}
function onQuery() {
handleQuery()
}
// 搜索按钮操作
function handleQuery() {
console.log('queryParams',queryParams.value)
queryParams.value.pageNum = 1
getList()
}
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 8
}
})
// 表格数据
const { queryParams } = toRefs(data)
const total = ref(3)
const loading = ref(false)
// 查询列表
function getList() {
loading.value = true
setTimeout(() => {
loading.value = false
}, 3000);
}
function pageProjectManage() {
router.push({
path: '/projectManage'
})
}
/**
* 删除多余列
*/
function deleteUnnecessaryColumns(){
console.log('删除多余列')
}
/**
* 批量加密
*/
function bulkEncryption(){
console.log('批量加密')
}
/**
* 批量解密
*/
function batchDecryption() {
console.log('批量解密')
}
</script>
<template>
<div class="app-container scroller">
<PageTitle :back="true" @back="pageProjectManage">
<template #title>
返回项目管理
</template>
<template #buttons>
<el-button
type="primary"
@click="deleteUnnecessaryColumns"
>
删除多余列
</el-button>
<el-button
type="primary"
@click="bulkEncryption"
>
批量加密
</el-button>
<el-button
type="primary"
@click="batchDecryption"
>
批量解密
</el-button>
</template>
</PageTitle>
<div class="app-container__body">
<div>
<query-form
ref="QueryFormRef"
v-model="queryParams"
@query="onQuery"
@reset="onReset"/>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.table-item {
margin-top: var(--container-pd);
margin-bottom: 20px;
}
.item-content {
margin: 8px 0;
.label {
width: 80px;
color: #888;
}
}
.flex-container {
display: flex;
}
.align-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.flex1 {
flex: 1;
}
</style>
\ No newline at end of file
...@@ -67,10 +67,7 @@ const onConfirm = () => { ...@@ -67,10 +67,7 @@ const onConfirm = () => {
<div class="app-container scroller"> <div class="app-container scroller">
<PageTitle> <PageTitle>
<template #title> <template #title>
<span id="badDebt" class="title-icon"> 资产库
资产库
<PageTour tourType="badDebt" />
</span>
</template> </template>
<template #buttons> <template #buttons>
<el-button type="primary" icon="Plus" @click="handleAdd">新增数据源</el-button> <el-button type="primary" icon="Plus" @click="handleAdd">新增数据源</el-button>
......
++ "b/src/views/assetLibrary/\350\265\204\344\272\247\345\272\223"
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="code" v-if="captchaEnabled"> <!-- <el-form-item prop="code" v-if="captchaEnabled">
<el-input <el-input
v-model="loginForm.code" v-model="loginForm.code"
size="large" size="large"
...@@ -39,8 +39,8 @@ ...@@ -39,8 +39,8 @@
<div class="login-code"> <div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/> <img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div> </div>
</el-form-item> </el-form-item> -->
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> <!-- <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox> -->
<el-form-item style="width:100%;"> <el-form-item style="width:100%;">
<el-button <el-button
:loading="loading" :loading="loading"
...@@ -67,13 +67,17 @@ ...@@ -67,13 +67,17 @@
<script setup> <script setup>
import { getCodeImg } from "@/api/login" import { getCodeImg } from "@/api/login"
import Cookies from "js-cookie" import Cookies from "js-cookie"
import { sm4 as SM4 } from 'gm-crypt'
import { encrypt, decrypt } from "@/utils/jsencrypt" import { encrypt, decrypt } from "@/utils/jsencrypt"
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import useAppStore from '@/store/modules/app'
const title = import.meta.env.VITE_APP_TITLE import { useRoute, useRouter } from 'vue-router'
const userStore = useUserStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const title = import.meta.env.VITE_APP_TITLE
const userStore = useUserStore()
const appStore = useAppStore()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const loginForm = ref({ const loginForm = ref({
...@@ -106,38 +110,123 @@ function handleLogin() { ...@@ -106,38 +110,123 @@ function handleLogin() {
proxy.$refs.loginRef.validate(valid => { proxy.$refs.loginRef.validate(valid => {
if (valid) { if (valid) {
loading.value = true loading.value = true
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 // // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) { // if (loginForm.value.rememberMe) {
Cookies.set("username", loginForm.value.username, { expires: 30 }) // Cookies.set("username", loginForm.value.username, { expires: 30 })
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 }) // Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 }) // Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 })
} else { // } else {
// 否则移除 // // 否则移除
Cookies.remove("username") // Cookies.remove("username")
Cookies.remove("password") // Cookies.remove("password")
Cookies.remove("rememberMe") // Cookies.remove("rememberMe")
} // }
// 调用action的登录方法 // 调用action的登录方法
userStore.login(loginForm.value).then(() => { userStore.login(loginForm.value).then(async (res) => {
const query = route.query console.log('res123',res)
const otherQueryParams = Object.keys(query).reduce((acc, cur) => { let data = res
if (cur !== "redirect") {
acc[cur] = query[cur] let menus = data.menus.map(item => {
item.children = item.submenu.map(child => {
return {
children: [],
iconCls: child.icon,
id: child.id,
keepAlive: false,
name: child.menuname,
path: child.url,
requireAuth: false
}
})
return {
children: item.children,
name: item.menuname,
id: item.id,
path: item.url,
type: item.type,
iconCls: item.icon
}
})
// 用户数据整理
let user = data.tsysUser;
let loginBlankMenus = false
if(data.menus.length === 0) {
loginBlankMenus = true
} }
return acc try {
}, {}) await appStore.signOut('login')
router.push({ path: redirect.value || "/", query: otherQueryParams })
// 设置导航菜单
appStore.setNav({ menus: data.menus })
// 设置用户信息
appStore.setUserInfo({user, licenseRst: data.licenseRst, loginBlankMenus})
// 存储token和登录信息
window.sessionStorage.setItem('__token', data.token)
const loginStr = JSON.stringify({
username: loginForm.value.username,
password: encryptPassword(loginForm.value.password)
})
window.sessionStorage.setItem('login', loginStr)
const query = route.query
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== "redirect") {
acc[cur] = query[cur]
}
return acc
}, {})
console.log('路由配置:', router.getRoutes())
router.push({ path:"/index", query: otherQueryParams })
// router.push({ path: redirect.value || "/index", query: otherQueryParams })
// if(redirect.value){
// console.log('redirect',redirect.value)
// router.push({ path: redirect.value, query: otherQueryParams })
// router.push({ path: redirect.value, query: otherQueryParams })
// console.log(2134)
// }else{
// router.push({ path: "/", query: otherQueryParams })
// }
// console.log('redirect',redirect.value)
// 跳转页面或其他操作
// router.push('/dashboard')
} catch (error) {
console.error('登录处理失败:', error)
}
}).catch(() => { }).catch(() => {
loading.value = false loading.value = false
// 重新获取验证码 // 重新获取验证码
if (captchaEnabled.value) { if (captchaEnabled.value) {
getCode() // getCode()
} }
}) })
} }
}) })
} }
function encryptPassword(plainPassword) {
const sm4Config = {
key: "GJstSK_YBD=gSOFT",
mode: 'ecb',
cipherType: 'base64'
}
const sm4 = new SM4(sm4Config)
try {
return sm4.encrypt(plainPassword)
} catch (error) {
console.error('加密失败:', error)
throw new Error('密码加密处理失败')
}
}
function getCode() { function getCode() {
getCodeImg().then(res => { getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
...@@ -159,8 +248,8 @@ function getCookie() { ...@@ -159,8 +248,8 @@ function getCookie() {
} }
} }
getCode() // getCode()
getCookie() // getCookie()
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
......
...@@ -117,7 +117,7 @@ const handleEnterProject = (project) => { ...@@ -117,7 +117,7 @@ const handleEnterProject = (project) => {
console.log('进入项目:', project) console.log('进入项目:', project)
// // ElMessage.success(`进入项目 ${project.projectName}`) // // ElMessage.success(`进入项目 ${project.projectName}`)
// emit('page', 'detail', { projectId: project.id}) // emit('page', 'detail', { projectId: project.id})
router.push({ path:'/project',query: { projectId: project.id } }) router.push({ path:'/projectHome',query: { projectId: project.id } })
} }
......
<script setup name="Algorithm">
import { onMounted, ref, toRefs } from 'vue'
import { Split } from 'view-ui-plus';
import CollapseView from '@/components/CollapseView/index.vue'
import formModule from './modules/formModule.vue'
import ModalPop from "@/components/EditPop/ModalPop.vue"
const splitNum = ref(0.31) // 左右分割比例
const collapseList = ref([])
const data = reactive({
formEdit: {
name: "",
},
formAdd: {
name: "",
}
});
const { formEdit, formAdd } = toRefs(data);
const modalData = reactive({
show: false,
text: '',
icon: 'error',
cancel: true
})
const modalPopShow = ref(false)
// 获取数据
const getCollapse = () => {
const data = [
{
name: '测试数据域',
list: [
{
name: 'aaaaa'
},
{
name: 'bbbbb'
}
]
},
{
name: '通用规则',
list: [
{
name: 'aaaaa'
},
{
name: 'bbbbb'
}
]
},
{
name: '解密数据',
list: []
}
]
collapseList.value = data.map(item => {
const list = item.list.map(itemTwo => {
return {
...itemTwo,
isCheck: false,
isDelete: true,
}
})
return {
...item,
list: list,
isAdd: true,
isView: false,
isDelete: false,
}
})
}
// 新增算法关闭
const modalPopCancel = () => {
modalPopShow.value = false
}
// 新增算法
const collapseAdd = (item) => {
console.log('添加事件', item)
formAdd.value = {}
modalPopShow.value = true
}
// 删除事件
const collapseDelete = (item) => {
console.log('删除事件', item)
modalData.show = true
modalData.icon = 'error'
modalData.text = '删除后无法恢复,是否确认删除[' + item.name + ']?'
}
// 删除回调
const modalConfirm = () => {
modalData.show = false
}
// 点击监听
const collapseChange = (item) => {
formEdit.value = item
}
// 算法确认
const formModuleConfirm = (item) => {
console.log('新增算法', item)
modalPopShow.value = false
}
onMounted(() => {
getCollapse()
})
</script>
<template>
<div class="app-container scroller">
<PageTitle>
<template #title>
脱敏算法
</template>
</PageTitle>
<div class="app-container__body">
<Split v-model="splitNum">
<template #left>
<div class="demo-split-pane" style="padding: 0 38px 10px 0;width: 100%;overflow: auto;height: 100%;">
<el-input class="mb20" placeholder="脱敏规则搜索">
<template #suffix>
<el-icon style="vertical-align: middle;">
<search />
</el-icon>
</template>
</el-input>
<CollapseView :list="collapseList" @add="collapseAdd" @childDelete="collapseDelete" @change="collapseChange" />
</div>
</template>
<template #right>
<div class="demo-split-pane">
<div class="right">
<div class="right-title">
<el-icon>
<info-filled />
</el-icon>
<span style="margin-left: 5px;">脱敏规则</span>
</div>
<div class="right-content">
<formModule v-model="formEdit" type="edit" />
</div>
</div>
</div>
</template>
</Split>
</div>
<!-- 提示框 -->
<Modal v-model="modalData.show" :icon="modalData.icon" :cancel="modalData.cancel" :text="modalData.text"
@confirm="modalConfirm"></Modal>
<!-- 新增算法 -->
<ModalPop v-model="modalPopShow" title="编辑器" @cancel="modalPopCancel">
<template #content>
<formModule v-model="formAdd" type="add" @cancel="modalPopCancel" @confirm="formModuleConfirm" />
</template>
</ModalPop>
</div>
</template>
<style lang="scss" scoped>
.app-container__body {
height: calc(
100vh - var(--navbar-height) - var(--container-pd) - var(--container-pd)
) !important;
.right {
padding: 6px 10px 10px;
height: 100%;
&-title {
padding: 0px 0px 10px 10px;
display: flex;
align-items: center;
font-weight: 700;
color: #515a6e;
}
&-content {
padding: 10px 0px;
width: 80%;
margin: 20px auto;
.openEditor {
position: absolute;
bottom: 0;
right: 0;
}
}
&-btn {
padding: 20px 20px 20px 100px;
display: flex;
justify-content: center;
}
}
}
</style>
\ No newline at end of file
<script setup lang="ts" name="Form">
import { onMounted, reactive, ref, toRefs, watch } from "vue";
import { Switch } from "view-ui-plus";
import ExpressionEditor from '@/components/EditPop/ExpressionEditor.vue'
const props = defineProps<{
modelValue: boolean;
type: string;
}>();
const emit = defineEmits(["update:modelValue", 'cancel','confirm']);
const data = reactive({
rules: {},
});
const { rules } = toRefs(data);
const editorShow = ref(false);
const readOnly = ref(true);
const editor = ref({});
watch(
() => props.type,
(newVal) => {
readOnly.value = props.type === 'edit' ? true : false;
},
{ deep: true, immediate: true }
);
// 打开编辑器
const openEditor = () => {
editorShow.value = true
editor.value = props.modelValue
}
// 取消
const cancel = () => {
if (props.type === 'edit') {
readOnly.value = true
}else if (props.type === 'add') {
emit('cancel')
}
}
const confirm = () => {
if (props.type === 'edit') {
readOnly.value = true
}
emit('confirm')
}
// 编辑器确认
const formConfirm = (val) => {
editorShow.value = false
props.modelValue.name = val
}
</script>
<template>
<div>
<el-form ref="formRef" :model="modelValue" label-width="100px" :disabled="readOnly">
<el-form-item label="算法名称" required>
<el-input v-model="modelValue.name"></el-input>
</el-form-item>
<el-form-item label="表达式" required>
<el-input type="textarea" rows="8" v-model="modelValue.name"></el-input>
<el-button class="openEditor" type="primary" @click="openEditor">打开编辑器</el-button>
</el-form-item>
<el-form-item label="默认规则">
<Switch :disabled="readOnly">
<template #open>
<span></span>
</template>
<template #close>
<span></span>
</template>
</Switch>
</el-form-item>
</el-form>
<div class="btn">
<el-button type="primary" style="width: 150px;" @click="readOnly = false" v-if="readOnly">编辑</el-button>
<el-button type="info" style="width: 150px;" @click="cancel" v-if="!readOnly">取消</el-button>
<el-button type="primary" style="width: 150px;" @click="confirm" v-if="!readOnly">确认</el-button>
</div>
<ExpressionEditor v-model="editorShow" :data="editor" @cancel=" editorShow = false" @confirm="formConfirm" />
</div>
</template>
<style lang="scss" scoped>
.openEditor {
position: absolute;
bottom: 0;
right: 0;
}
.btn {
padding: 20px 20px 20px 100px;
display: flex;
justify-content: center;
}
</style>
\ No newline at end of file
++ "b/src/views/ruleConfig/Algorithm/\350\204\261\346\225\217\347\256\227\346\263\225.md"
<script setup name="DiscoveryRule">
import { onMounted, ref, toRefs } from 'vue'
</script>
<template>
<div class="app-container scroller">
<PageTitle>
<template #title>
发现规则
</template>
</PageTitle>
<div class="app-container__body"></div>
</div>
</template>
<style lang="scss" scoped>
.app-container__body {
height: calc(
100vh - var(--navbar-height) - var(--container-pd) - var(--container-pd)
) !important;
}
</style>
\ No newline at end of file
++ "b/src/views/ruleConfig/discoveryRule/\345\217\221\347\216\260\350\247\204\345\210\231.md"
...@@ -252,7 +252,7 @@ const upload = reactive({ ...@@ -252,7 +252,7 @@ const upload = reactive({
// 是否更新已经存在的用户数据 // 是否更新已经存在的用户数据
updateSupport: 0, updateSupport: 0,
// 设置上传的请求头部 // 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() }, headers: { Token: getToken() },
// 上传的地址 // 上传的地址
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData" url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
}) })
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论