需求解析功能进一步完善
This commit is contained in:
20
cdTMP/components.json
Normal file
20
cdTMP/components.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://shadcn-vue.com/schema.json",
|
||||||
|
"style": "new-york",
|
||||||
|
"typescript": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.js",
|
||||||
|
"css": "src/style/index.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"composables": "@/composables",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib"
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide"
|
||||||
|
}
|
||||||
160
cdTMP/package-lock.json
generated
160
cdTMP/package-lock.json
generated
@@ -10,41 +10,46 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arco-design/color": "^0.4.0",
|
"@arco-design/color": "^0.4.0",
|
||||||
"@arco-design/web-vue": "^2.57.0",
|
"@arco-design/web-vue": "^2.57.0",
|
||||||
"@tanstack/vue-query": "^5.74.5",
|
"@tanstack/vue-query": "^5.74.9",
|
||||||
"@tinymce/tinymce-vue": "^6.1.0",
|
"@tinymce/tinymce-vue": "^6.1.0",
|
||||||
"@vueuse/core": "^13.1.0",
|
"@vueuse/core": "^13.1.0",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.9.0",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"file2md5": "^1.3.0",
|
"file2md5": "^1.3.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lucide-vue-next": "^0.503.0",
|
||||||
"mammoth": "^1.9.0",
|
"mammoth": "^1.9.0",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.2",
|
||||||
"pinyin-match": "^1.2.6",
|
"pinyin-match": "^1.2.7",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"qs": "^6.14.0",
|
"qs": "^6.14.0",
|
||||||
|
"tailwind-merge": "^3.2.0",
|
||||||
"tinymce": "^7.8.0",
|
"tinymce": "^7.8.0",
|
||||||
|
"tw-animate-css": "^1.2.8",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-color-kit": "^1.0.6",
|
"vue-color-kit": "^1.0.6",
|
||||||
"vue-data-ui": "^2.6.40",
|
"vue-data-ui": "^2.6.41",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.1",
|
||||||
"vuedraggable": "^2.24.3"
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.4",
|
"@tailwindcss/postcss": "^4.1.4",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.15.3",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.9.18",
|
"@types/qs": "^6.9.18",
|
||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||||
"@vue/babel-plugin-jsx": "^1.4.0",
|
"@vue/babel-plugin-jsx": "^1.4.0",
|
||||||
"browserslist": "^4.24.4",
|
"browserslist": "^4.24.4",
|
||||||
"eslint": "^9.25.0",
|
"eslint": "^9.25.1",
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
"eslint-plugin-vue": "^10.0.1",
|
||||||
"less": "^4.3.0",
|
"less": "^4.3.0",
|
||||||
"less-loader": "^12.2.0",
|
"less-loader": "^12.2.0",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
@@ -52,7 +57,7 @@
|
|||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"rollup-plugin-visualizer": "^5.14.0",
|
||||||
"tailwindcss": "^4.1.4",
|
"tailwindcss": "^4.1.4",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.2",
|
"vite": "^6.3.3",
|
||||||
"vue-eslint-parser": "^10.1.3"
|
"vue-eslint-parser": "^10.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1019,9 +1024,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.25.0",
|
"version": "9.25.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.25.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.25.1.tgz",
|
||||||
"integrity": "sha512-iWhsUS8Wgxz9AXNfvfOPFSW4VfMXdVhp1hjkZVhXCrpgh/aLcc45rX6MPu+tIVUWDw0HfNwth7O28M1xDxNf9w==",
|
"integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1753,9 +1758,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.74.4",
|
"version": "5.74.9",
|
||||||
"resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.74.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.74.9.tgz",
|
||||||
"integrity": "sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A==",
|
"integrity": "sha512-qmjXpWyigDw4SfqdSBy24FzRvpBPXlaSbl92N77lcrL+yvVQLQkf0T6bQNbTxl9IEB/SvVFhhVZoIlQvFnNuuw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1763,13 +1768,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/vue-query": {
|
"node_modules/@tanstack/vue-query": {
|
||||||
"version": "5.74.5",
|
"version": "5.74.9",
|
||||||
"resolved": "https://registry.npmmirror.com/@tanstack/vue-query/-/vue-query-5.74.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@tanstack/vue-query/-/vue-query-5.74.9.tgz",
|
||||||
"integrity": "sha512-1IvuUASQ3h5jbM+90AR4vIDDLxYyGA9Iefvzx9uQMDA4c5Gpd9ETKHZgSUvFM3sXw6k0tY3uHtllBf875OqOcQ==",
|
"integrity": "sha512-iMZxrKfIiDdX9uNH8WusBZXq87lBL8v2UXhifYiBNH+BUPCaezP7gNv4TN7WAlHVSfAx0fsnMKLB5+D3GAspbA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/match-sorter-utils": "^8.19.4",
|
"@tanstack/match-sorter-utils": "^8.19.4",
|
||||||
"@tanstack/query-core": "5.74.4",
|
"@tanstack/query-core": "5.74.9",
|
||||||
"@vue/devtools-api": "^6.6.3",
|
"@vue/devtools-api": "^6.6.3",
|
||||||
"vue-demi": "^0.14.10"
|
"vue-demi": "^0.14.10"
|
||||||
},
|
},
|
||||||
@@ -1884,9 +1889,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.14.1",
|
"version": "22.15.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.14.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.3.tgz",
|
||||||
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2481,9 +2486,9 @@
|
|||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.8.4",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.8.4.tgz",
|
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.9.0.tgz",
|
||||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
@@ -2657,6 +2662,18 @@
|
|||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/class-variance-authority": {
|
||||||
|
"version": "0.7.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||||
|
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://polar.sh/cva"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clipboard": {
|
"node_modules/clipboard": {
|
||||||
"version": "2.0.11",
|
"version": "2.0.11",
|
||||||
"resolved": "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz",
|
"resolved": "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz",
|
||||||
@@ -2682,6 +2699,15 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clsx": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color": {
|
"node_modules/color": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||||
@@ -3023,9 +3049,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.25.0",
|
"version": "9.25.1",
|
||||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.25.0.tgz",
|
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.25.1.tgz",
|
||||||
"integrity": "sha512-MsBdObhM4cEwkzCiraDv7A6txFXEqtNXOb877TsSp2FCkBNl8JfVQrmiuDqC1IkejT6JLPzYBXx/xAiYhyzgGA==",
|
"integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3035,7 +3061,7 @@
|
|||||||
"@eslint/config-helpers": "^0.2.1",
|
"@eslint/config-helpers": "^0.2.1",
|
||||||
"@eslint/core": "^0.13.0",
|
"@eslint/core": "^0.13.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.25.0",
|
"@eslint/js": "9.25.1",
|
||||||
"@eslint/plugin-kit": "^0.2.8",
|
"@eslint/plugin-kit": "^0.2.8",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -3084,9 +3110,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-vue": {
|
"node_modules/eslint-plugin-vue": {
|
||||||
"version": "10.0.0",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.0.1.tgz",
|
||||||
"integrity": "sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==",
|
"integrity": "sha512-A5dRYc3eQ5i2rJFBW8J6F69ur/H7YfYg+5SCg6v829FU0BhM4fUTrRVR2d4MdZgzw0ioJEk6otYHEAnoGFqO4A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3314,9 +3340,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/fdir": {
|
"node_modules/fdir": {
|
||||||
"version": "6.4.3",
|
"version": "6.4.4",
|
||||||
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz",
|
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.4.tgz",
|
||||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -4275,6 +4301,15 @@
|
|||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lucide-vue-next": {
|
||||||
|
"version": "0.503.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/lucide-vue-next/-/lucide-vue-next-0.503.0.tgz",
|
||||||
|
"integrity": "sha512-3MrtHIBdh4dPCUZDLxQnvmQ17UzUnBYgezUSIo87Laais8hOz6qIPllp0iG/uS/UIzk7bJxyZRzoZTW/gLSr4A==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": ">=3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.11",
|
"version": "0.30.11",
|
||||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.11.tgz",
|
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.11.tgz",
|
||||||
@@ -4702,9 +4737,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pinyin-match": {
|
"node_modules/pinyin-match": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmmirror.com/pinyin-match/-/pinyin-match-1.2.6.tgz",
|
"resolved": "https://registry.npmmirror.com/pinyin-match/-/pinyin-match-1.2.7.tgz",
|
||||||
"integrity": "sha512-d9fMSwZujH7UlMu+FO8MGXrgUYv0CwJtzpf3fQ8xgLJy1qfXlzOZsnQuL7Ej7msAiEtt37U7bE4dkVmyWaFfwA==",
|
"integrity": "sha512-RnypoF7OKgSKL8L4IayHmmHj9cHeked45TFAOffddcvpIIDrLcTSEJNruprE5otXCegBBqWm4YEi8JwMqToeig==",
|
||||||
"license": "SATA"
|
"license": "SATA"
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
@@ -5346,6 +5381,16 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tailwind-merge": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/dcastil"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.1.4",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.1.4.tgz",
|
||||||
@@ -5428,13 +5473,13 @@
|
|||||||
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.12",
|
"version": "0.2.13",
|
||||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
||||||
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
|
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fdir": "^6.4.3",
|
"fdir": "^6.4.4",
|
||||||
"picomatch": "^4.0.2"
|
"picomatch": "^4.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -5456,6 +5501,15 @@
|
|||||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tw-animate-css": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tw-animate-css/-/tw-animate-css-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-AxSnYRvyFnAiZCUndS3zQZhNfV/B77ZhJ+O7d3K6wfg/jKJY+yv6ahuyXwnyaYA9UdLqnpCwhTRv9pPTBnPR2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/Wombosvideo"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
||||||
@@ -5541,18 +5595,18 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.3.2",
|
"version": "6.3.3",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.3.2.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.3.3.tgz",
|
||||||
"integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==",
|
"integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.3",
|
"fdir": "^6.4.4",
|
||||||
"picomatch": "^4.0.2",
|
"picomatch": "^4.0.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"rollup": "^4.34.9",
|
"rollup": "^4.34.9",
|
||||||
"tinyglobby": "^0.2.12"
|
"tinyglobby": "^0.2.13"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -5654,9 +5708,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-data-ui": {
|
"node_modules/vue-data-ui": {
|
||||||
"version": "2.6.40",
|
"version": "2.6.41",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.6.40.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.6.41.tgz",
|
||||||
"integrity": "sha512-vd9Zy1WawOQAeqtpP7LE+nuqgaZ8RVc9ij+DxdsP6m7McKgG+cbse9Irk7nOQrQ0om6gZvZciCOyKKw4TKUzaw==",
|
"integrity": "sha512-Sfy3TypoDvB14WpXk3UmlWCtXjUQjqNfxzy6gl+RJ2oGYqNY6LA2Xxun8428oxQ2CS3NaGTCinvddR+TDDd9pw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": ">=3.3.0"
|
"vue": ">=3.3.0"
|
||||||
@@ -5714,9 +5768,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
|
||||||
"integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
|
"integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-api": "^6.6.4"
|
"@vue/devtools-api": "^6.6.4"
|
||||||
|
|||||||
@@ -13,41 +13,46 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@arco-design/color": "^0.4.0",
|
"@arco-design/color": "^0.4.0",
|
||||||
"@arco-design/web-vue": "^2.57.0",
|
"@arco-design/web-vue": "^2.57.0",
|
||||||
"@tanstack/vue-query": "^5.74.5",
|
"@tanstack/vue-query": "^5.74.9",
|
||||||
"@tinymce/tinymce-vue": "^6.1.0",
|
"@tinymce/tinymce-vue": "^6.1.0",
|
||||||
"@vueuse/core": "^13.1.0",
|
"@vueuse/core": "^13.1.0",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.9.0",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"file2md5": "^1.3.0",
|
"file2md5": "^1.3.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lucide-vue-next": "^0.503.0",
|
||||||
"mammoth": "^1.9.0",
|
"mammoth": "^1.9.0",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.2",
|
||||||
"pinyin-match": "^1.2.6",
|
"pinyin-match": "^1.2.7",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"qs": "^6.14.0",
|
"qs": "^6.14.0",
|
||||||
|
"tailwind-merge": "^3.2.0",
|
||||||
"tinymce": "^7.8.0",
|
"tinymce": "^7.8.0",
|
||||||
|
"tw-animate-css": "^1.2.8",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-color-kit": "^1.0.6",
|
"vue-color-kit": "^1.0.6",
|
||||||
"vue-data-ui": "^2.6.40",
|
"vue-data-ui": "^2.6.41",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.1",
|
||||||
"vuedraggable": "^2.24.3"
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.4",
|
"@tailwindcss/postcss": "^4.1.4",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.15.3",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qs": "^6.9.18",
|
"@types/qs": "^6.9.18",
|
||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||||
"@vue/babel-plugin-jsx": "^1.4.0",
|
"@vue/babel-plugin-jsx": "^1.4.0",
|
||||||
"browserslist": "^4.24.4",
|
"browserslist": "^4.24.4",
|
||||||
"eslint": "^9.25.0",
|
"eslint": "^9.25.1",
|
||||||
"eslint-plugin-vue": "^10.0.0",
|
"eslint-plugin-vue": "^10.0.1",
|
||||||
"less": "^4.3.0",
|
"less": "^4.3.0",
|
||||||
"less-loader": "^12.2.0",
|
"less-loader": "^12.2.0",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
@@ -55,7 +60,7 @@
|
|||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"rollup-plugin-visualizer": "^5.14.0",
|
||||||
"tailwindcss": "^4.1.4",
|
"tailwindcss": "^4.1.4",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.2",
|
"vite": "^6.3.3",
|
||||||
"vue-eslint-parser": "^10.1.3"
|
"vue-eslint-parser": "^10.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,28 @@ export default {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 生成-软件问题统计-2025年4月27日新增
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
createProblemStatistics(params = {}) {
|
||||||
|
return request({
|
||||||
|
url: `/generateBG/create/problem_statistics`,
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 生成摸底清单-依据测试项
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
createBgModiList(params = {}) {
|
||||||
|
return request({
|
||||||
|
url: `/generateBG/create/modi_list`,
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 删除output/bg中所有文件,防止之前数据干扰
|
* 删除output/bg中所有文件,防止之前数据干扰
|
||||||
* @returns
|
* @returns
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ export default {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns 顶层技术依据文件
|
||||||
|
*/
|
||||||
|
createTopFile(params = {}) {
|
||||||
|
return request({
|
||||||
|
url: `/generate/create/top_file`,
|
||||||
|
method: "get",
|
||||||
|
params
|
||||||
|
})
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns 生成联系方式
|
* @returns 生成联系方式
|
||||||
@@ -55,17 +66,6 @@ export default {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns 生成测评大纲-被测软件功能
|
|
||||||
*/
|
|
||||||
createFuncList(params = {}) {
|
|
||||||
return request({
|
|
||||||
url: `/generate/create/funcList`,
|
|
||||||
method: "get",
|
|
||||||
params
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns 生成测评大纲-测评对象的软件组成描述
|
* @returns 生成测评大纲-测评对象的软件组成描述
|
||||||
@@ -88,17 +88,6 @@ export default {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns 生成测评大纲-被测软件性能
|
|
||||||
*/
|
|
||||||
createPerformance(params = {}) {
|
|
||||||
return request({
|
|
||||||
url: `/generate/create/performance`,
|
|
||||||
method: "get",
|
|
||||||
params
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns 生成测评大纲-被测软件基本信息
|
* @returns 生成测评大纲-被测软件基本信息
|
||||||
@@ -318,5 +307,5 @@ export default {
|
|||||||
method: "get",
|
method: "get",
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { request } from "@/api/request"
|
import { request } from "@/api/request"
|
||||||
|
import { head } from "lodash-es"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 666 KiB |
42
cdTMP/src/components/UploadInput/index.vue
Normal file
42
cdTMP/src/components/UploadInput/index.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="upload-input-container">
|
||||||
|
<a-upload
|
||||||
|
accept=".zip"
|
||||||
|
tip="只支持C/C++,不支持FPGA代码,上传后会自行录入圈复杂度等信息"
|
||||||
|
:limit="1"
|
||||||
|
:action="`/api/dut_upload/upload_file?dut_id=${form.id}`"
|
||||||
|
@success="uploadSuccessHandle"
|
||||||
|
@error="handleError"
|
||||||
|
></a-upload>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Message } from "@arco-design/web-vue"
|
||||||
|
import { inject } from "vue"
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form: any = inject("formModel")
|
||||||
|
// 组件props
|
||||||
|
const props = defineProps({
|
||||||
|
component: Object, // 组件配置信息
|
||||||
|
customField: { type: String, default: undefined } // 自定义字段名称,用于子表单
|
||||||
|
})
|
||||||
|
// 上传成功后回调-即时给前端反馈
|
||||||
|
const uploadSuccessHandle = (FileItem: any) => {
|
||||||
|
form.value.comment_lines = FileItem.response.data.comment_lines
|
||||||
|
form.value.effective_lines = FileItem.response.data.effective_lines
|
||||||
|
form.value.total_lines = FileItem.response.data.total_lines
|
||||||
|
Message.success("解析代码成功,圈复杂度、模块大小等均已录入")
|
||||||
|
}
|
||||||
|
// 上传失败
|
||||||
|
const handleError = () => {
|
||||||
|
Message.error("处理失败,请检查是否是C/C++代码,且zip文件")
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "UploadInput"
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
@@ -57,7 +57,7 @@ const props = defineProps({
|
|||||||
type: [String, Array],
|
type: [String, Array],
|
||||||
// 如果要取消粘贴只粘贴文本,需要用户加格式请加上pastetext
|
// 如果要取消粘贴只粘贴文本,需要用户加格式请加上pastetext
|
||||||
default:
|
default:
|
||||||
"undo redo aligncenter alignleft indent styleselect formatselect fontselect fontsizeselect removeformat"
|
"code undo redo aligncenter alignleft indent styleselect formatselect fontselect fontsizeselect removeformat"
|
||||||
|
|
||||||
// 下面是备份配置:
|
// 下面是备份配置:
|
||||||
// default:"code undo redo restoredraft | paste | bold | aligncenter alignleft alignjustify indent | \
|
// default:"code undo redo restoredraft | paste | bold | aligncenter alignleft alignjustify indent | \
|
||||||
|
|||||||
@@ -10,20 +10,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, provide } from 'vue'
|
import { ref, watch, provide } from "vue"
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from "@arco-design/web-vue"
|
||||||
|
|
||||||
import uploadConfig from '@/config/upload'
|
import uploadConfig from "@/config/upload"
|
||||||
import MaImageUpload from './components/image-upload.vue'
|
import MaImageUpload from "./components/image-upload.vue"
|
||||||
import MaFileUpload from './components/file-upload.vue'
|
import MaFileUpload from "./components/file-upload.vue"
|
||||||
import MaChunkUpload from './components/chunk-upload.vue'
|
import MaChunkUpload from "./components/chunk-upload.vue"
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(["update:modelValue"])
|
||||||
const file = ref()
|
const file = ref()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { type: [String, Number, Array], default: () => {} },
|
modelValue: { type: [String, Number, Array], default: () => {} },
|
||||||
title: { type: String, default: 'buttonText', },
|
title: { type: String, default: "buttonText" },
|
||||||
icon: { type: String, default: 'icon-plus'},
|
icon: { type: String, default: "icon-plus" },
|
||||||
rounded: { type: Boolean, default: false },
|
rounded: { type: Boolean, default: false },
|
||||||
multiple: { type: Boolean, default: false },
|
multiple: { type: Boolean, default: false },
|
||||||
disabled: { type: Boolean, default: false },
|
disabled: { type: Boolean, default: false },
|
||||||
@@ -33,30 +33,35 @@ const props = defineProps({
|
|||||||
chunkSize: { type: Number, default: 1 * 1024 * 1024 },
|
chunkSize: { type: Number, default: 1 * 1024 * 1024 },
|
||||||
limit: { type: Number, default: 0 },
|
limit: { type: Number, default: 0 },
|
||||||
tip: { type: String, default: undefined },
|
tip: { type: String, default: undefined },
|
||||||
type: { type: String, default: 'image' },
|
type: { type: String, default: "image" },
|
||||||
accept: { type: String, default: '*' },
|
accept: { type: String, default: "*" },
|
||||||
returnType: { type: String, default: 'hash' },
|
returnType: { type: String, default: "hash" },
|
||||||
fileType: { type: String, default: 'button' },
|
fileType: { type: String, default: "button" },
|
||||||
showList: { type: Boolean, default: true },
|
showList: { type: Boolean, default: true },
|
||||||
requestData: { type: Object, default: {} },
|
requestData: { type: Object, default: {} }
|
||||||
})
|
})
|
||||||
|
|
||||||
if (! ['id', 'url', 'hash'].includes(props.returnType)) {
|
if (!["id", "url", "hash"].includes(props.returnType)) {
|
||||||
Message.error('MaUpload组件props的returnType只能为:id, url, hash 其中一个')
|
Message.error("MaUpload组件props的returnType只能为:id, url, hash 其中一个")
|
||||||
console.error('MaUpload组件props的returnType只能为:id, url, hash 其中一个')
|
console.error("MaUpload组件props的returnType只能为:id, url, hash 其中一个")
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.modelValue, (val) => {
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
file.value = val
|
file.value = val
|
||||||
}, {
|
},
|
||||||
deep: true, immediate: true
|
{
|
||||||
})
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
provide('storageMode', uploadConfig.storageMode)
|
provide("storageMode", uploadConfig.storageMode)
|
||||||
provide('config', props)
|
provide("config", props)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => file.value,
|
() => file.value,
|
||||||
vl => emit('update:modelValue', vl)
|
(vl) => emit("update:modelValue", vl)
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
250
cdTMP/src/components/ui/particles-bg/ParticlesBg.vue
Normal file
250
cdTMP/src/components/ui/particles-bg/ParticlesBg.vue
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="canvasContainerRef"
|
||||||
|
:class="$props.class"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<canvas ref="canvasRef"></canvas>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useMouse, useDevicePixelRatio } from '@vueuse/core';
|
||||||
|
import { ref, onMounted, onBeforeUnmount, watch, computed, reactive } from 'vue';
|
||||||
|
|
||||||
|
type Circle = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
translateX: number;
|
||||||
|
translateY: number;
|
||||||
|
size: number;
|
||||||
|
alpha: number;
|
||||||
|
targetAlpha: number;
|
||||||
|
dx: number;
|
||||||
|
dy: number;
|
||||||
|
magnetism: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
color?: string;
|
||||||
|
quantity?: number;
|
||||||
|
staticity?: number;
|
||||||
|
ease?: number;
|
||||||
|
class?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
color: '#FFF',
|
||||||
|
quantity: 100,
|
||||||
|
staticity: 50,
|
||||||
|
ease: 50,
|
||||||
|
class: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
||||||
|
const canvasContainerRef = ref<HTMLDivElement | null>(null);
|
||||||
|
const context = ref<CanvasRenderingContext2D | null>(null);
|
||||||
|
const circles = ref<Circle[]>([]);
|
||||||
|
const mouse = reactive<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||||
|
const canvasSize = reactive<{ w: number; h: number }>({ w: 0, h: 0 });
|
||||||
|
const { x: mouseX, y: mouseY } = useMouse();
|
||||||
|
const { pixelRatio } = useDevicePixelRatio();
|
||||||
|
|
||||||
|
const color = computed(() => {
|
||||||
|
// Remove the leading '#' if it's present
|
||||||
|
let hex = props.color.replace(/^#/, '');
|
||||||
|
|
||||||
|
// If the hex code is 3 characters, expand it to 6 characters
|
||||||
|
if (hex.length === 3) {
|
||||||
|
hex = hex
|
||||||
|
.split('')
|
||||||
|
.map((char) => char + char)
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the r, g, b values from the hex string
|
||||||
|
const bigint = parseInt(hex, 16);
|
||||||
|
const r = (bigint >> 16) & 255; // Extract the red component
|
||||||
|
const g = (bigint >> 8) & 255; // Extract the green component
|
||||||
|
const b = bigint & 255; // Extract the blue component
|
||||||
|
|
||||||
|
// Return the RGB values as a string separated by spaces
|
||||||
|
return `${r} ${g} ${b}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (canvasRef.value) {
|
||||||
|
context.value = canvasRef.value.getContext('2d');
|
||||||
|
}
|
||||||
|
|
||||||
|
initCanvas();
|
||||||
|
animate();
|
||||||
|
window.addEventListener('resize', initCanvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', initCanvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch([mouseX, mouseY], () => {
|
||||||
|
onMouseMove();
|
||||||
|
});
|
||||||
|
|
||||||
|
function initCanvas() {
|
||||||
|
resizeCanvas();
|
||||||
|
drawParticles();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseMove() {
|
||||||
|
if (canvasRef.value) {
|
||||||
|
const rect = canvasRef.value.getBoundingClientRect();
|
||||||
|
const { w, h } = canvasSize;
|
||||||
|
const x = mouseX.value - rect.left - w / 2;
|
||||||
|
const y = mouseY.value - rect.top - h / 2;
|
||||||
|
|
||||||
|
const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;
|
||||||
|
if (inside) {
|
||||||
|
mouse.x = x;
|
||||||
|
mouse.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
if (canvasContainerRef.value && canvasRef.value && context.value) {
|
||||||
|
circles.value.length = 0;
|
||||||
|
canvasSize.w = canvasContainerRef.value.offsetWidth;
|
||||||
|
canvasSize.h = canvasContainerRef.value.offsetHeight;
|
||||||
|
canvasRef.value.width = canvasSize.w * pixelRatio.value;
|
||||||
|
canvasRef.value.height = canvasSize.h * pixelRatio.value;
|
||||||
|
canvasRef.value.style.width = canvasSize.w + 'px';
|
||||||
|
canvasRef.value.style.height = canvasSize.h + 'px';
|
||||||
|
context.value.scale(pixelRatio.value, pixelRatio.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function circleParams(): Circle {
|
||||||
|
const x = Math.floor(Math.random() * canvasSize.w);
|
||||||
|
const y = Math.floor(Math.random() * canvasSize.h);
|
||||||
|
const translateX = 0;
|
||||||
|
const translateY = 0;
|
||||||
|
const size = Math.floor(Math.random() * 2) + 1;
|
||||||
|
const alpha = 0;
|
||||||
|
const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));
|
||||||
|
const dx = (Math.random() - 0.5) * 0.2;
|
||||||
|
const dy = (Math.random() - 0.5) * 0.2;
|
||||||
|
const magnetism = 0.1 + Math.random() * 4;
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
translateX,
|
||||||
|
translateY,
|
||||||
|
size,
|
||||||
|
alpha,
|
||||||
|
targetAlpha,
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
magnetism,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCircle(circle: Circle, update = false) {
|
||||||
|
if (context.value) {
|
||||||
|
const { x, y, translateX, translateY, size, alpha } = circle;
|
||||||
|
context.value.translate(translateX, translateY);
|
||||||
|
context.value.beginPath();
|
||||||
|
context.value.arc(x, y, size, 0, 2 * Math.PI);
|
||||||
|
context.value.fillStyle = `rgba(${color.value.split(' ').join(', ')}, ${alpha})`;
|
||||||
|
context.value.fill();
|
||||||
|
context.value.setTransform(pixelRatio.value, 0, 0, pixelRatio.value, 0, 0);
|
||||||
|
|
||||||
|
if (!update) {
|
||||||
|
circles.value.push(circle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearContext() {
|
||||||
|
if (context.value) {
|
||||||
|
context.value.clearRect(0, 0, canvasSize.w, canvasSize.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawParticles() {
|
||||||
|
clearContext();
|
||||||
|
const particleCount = props.quantity;
|
||||||
|
for (let i = 0; i < particleCount; i++) {
|
||||||
|
const circle = circleParams();
|
||||||
|
drawCircle(circle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function remapValue(
|
||||||
|
value: number,
|
||||||
|
start1: number,
|
||||||
|
end1: number,
|
||||||
|
start2: number,
|
||||||
|
end2: number,
|
||||||
|
): number {
|
||||||
|
const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
|
||||||
|
return remapped > 0 ? remapped : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
clearContext();
|
||||||
|
circles.value.forEach((circle, i) => {
|
||||||
|
// Handle the alpha value
|
||||||
|
const edge = [
|
||||||
|
circle.x + circle.translateX - circle.size, // distance from left edge
|
||||||
|
canvasSize.w - circle.x - circle.translateX - circle.size, // distance from right edge
|
||||||
|
circle.y + circle.translateY - circle.size, // distance from top edge
|
||||||
|
canvasSize.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
|
||||||
|
];
|
||||||
|
|
||||||
|
const closestEdge = edge.reduce((a, b) => Math.min(a, b));
|
||||||
|
const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2));
|
||||||
|
|
||||||
|
if (remapClosestEdge > 1) {
|
||||||
|
circle.alpha += 0.02;
|
||||||
|
if (circle.alpha > circle.targetAlpha) circle.alpha = circle.targetAlpha;
|
||||||
|
} else {
|
||||||
|
circle.alpha = circle.targetAlpha * remapClosestEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
circle.x += circle.dx;
|
||||||
|
circle.y += circle.dy;
|
||||||
|
circle.translateX +=
|
||||||
|
(mouse.x / (props.staticity / circle.magnetism) - circle.translateX) / props.ease;
|
||||||
|
circle.translateY +=
|
||||||
|
(mouse.y / (props.staticity / circle.magnetism) - circle.translateY) / props.ease;
|
||||||
|
|
||||||
|
// circle gets out of the canvas
|
||||||
|
if (
|
||||||
|
circle.x < -circle.size ||
|
||||||
|
circle.x > canvasSize.w + circle.size ||
|
||||||
|
circle.y < -circle.size ||
|
||||||
|
circle.y > canvasSize.h + circle.size
|
||||||
|
) {
|
||||||
|
// remove the circle from the array
|
||||||
|
circles.value.splice(i, 1);
|
||||||
|
// create a new circle
|
||||||
|
const newCircle = circleParams();
|
||||||
|
drawCircle(newCircle);
|
||||||
|
// update the circle position
|
||||||
|
} else {
|
||||||
|
drawCircle(
|
||||||
|
{
|
||||||
|
...circle,
|
||||||
|
x: circle.x,
|
||||||
|
y: circle.y,
|
||||||
|
translateX: circle.translateX,
|
||||||
|
translateY: circle.translateY,
|
||||||
|
alpha: circle.alpha,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
1
cdTMP/src/components/ui/particles-bg/index.ts
Normal file
1
cdTMP/src/components/ui/particles-bg/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { default as ParticlesBg } from './ParticlesBg.vue';
|
||||||
@@ -39,31 +39,24 @@ const soDutColumn = ref([
|
|||||||
rules: [{ required: true, message: "单位必选" }]
|
rules: [{ required: true, message: "单位必选" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "空行",
|
title: "总行数",
|
||||||
dataIndex: "black_line",
|
dataIndex: "total_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
rules: [{ required: true, message: "空行数必填" }],
|
rules: [{ required: true, message: "总行数必填" }],
|
||||||
min: 0
|
min: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "纯注释",
|
title: "有效行数",
|
||||||
dataIndex: "comment_line",
|
dataIndex: "effective_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
rules: [{ required: true, message: "纯注释数必填" }],
|
rules: [{ required: true, message: "有效行数必填" }],
|
||||||
min: 0
|
min: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "混合行",
|
title: "注释行数",
|
||||||
dataIndex: "mix_line",
|
dataIndex: "comment_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
rules: [{ required: true, message: "混合行必填" }],
|
rules: [{ required: true, message: "注释行数必填" }],
|
||||||
min: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "纯代码",
|
|
||||||
dataIndex: "code_line",
|
|
||||||
formType: "input-number",
|
|
||||||
rules: [{ required: true, message: "纯代码行必填" }],
|
|
||||||
min: 0
|
min: 0
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ export function useRightClick(projectId, routeViewRef) {
|
|||||||
*/
|
*/
|
||||||
const displayRightMenu = (e) => {
|
const displayRightMenu = (e) => {
|
||||||
if (e.target) {
|
if (e.target) {
|
||||||
const { nodekey, level, title, isLeaf } = getContextNodeInfo(e.target)
|
const context = getContextNodeInfo(e.target)
|
||||||
|
if (!context) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { nodekey = undefined, level, title, isLeaf } = context
|
||||||
// 如果是测试项则弹出【1.根据测试项步骤生成当前测试项用例 2.复制测试项到设计需求】
|
// 如果是测试项则弹出【1.根据测试项步骤生成当前测试项用例 2.复制测试项到设计需求】
|
||||||
if (+level === 3) {
|
if (+level === 3) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
6
cdTMP/src/lib/utils.ts
Normal file
6
cdTMP/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from 'clsx'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
@import "tw-animate-css";
|
||||||
|
/*
|
||||||
|
---break---
|
||||||
|
*/
|
||||||
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@config '../../tailwind.config.js';
|
@config '../../tailwind.config.js';
|
||||||
|
|
||||||
@@ -20,3 +25,130 @@
|
|||||||
border-color: var(--color-gray-200, currentColor);
|
border-color: var(--color-gray-200, currentColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
---break---
|
||||||
|
*/
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--color-card: var(--card);
|
||||||
|
--color-card-foreground: var(--card-foreground);
|
||||||
|
--color-popover: var(--popover);
|
||||||
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
|
--color-primary: var(--primary);
|
||||||
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
|
--color-secondary: var(--secondary);
|
||||||
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
|
--color-muted: var(--muted);
|
||||||
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
--color-accent: var(--accent);
|
||||||
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
--color-destructive: var(--destructive);
|
||||||
|
--color-destructive-foreground: var(--destructive-foreground);
|
||||||
|
--color-border: var(--border);
|
||||||
|
--color-input: var(--input);
|
||||||
|
--color-ring: var(--ring);
|
||||||
|
--color-chart-1: var(--chart-1);
|
||||||
|
--color-chart-2: var(--chart-2);
|
||||||
|
--color-chart-3: var(--chart-3);
|
||||||
|
--color-chart-4: var(--chart-4);
|
||||||
|
--color-chart-5: var(--chart-5);
|
||||||
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
--radius-lg: var(--radius);
|
||||||
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
|
--color-sidebar: var(--sidebar);
|
||||||
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||||
|
--color-sidebar-primary: var(--sidebar-primary);
|
||||||
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||||
|
--color-sidebar-accent: var(--sidebar-accent);
|
||||||
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||||
|
--color-sidebar-border: var(--sidebar-border);
|
||||||
|
--color-sidebar-ring: var(--sidebar-ring);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
---break---
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--background: oklch(1 0 0);
|
||||||
|
--foreground: oklch(0.145 0 0);
|
||||||
|
--card: oklch(1 0 0);
|
||||||
|
--card-foreground: oklch(0.145 0 0);
|
||||||
|
--popover: oklch(1 0 0);
|
||||||
|
--popover-foreground: oklch(0.145 0 0);
|
||||||
|
--primary: oklch(0.205 0 0);
|
||||||
|
--primary-foreground: oklch(0.985 0 0);
|
||||||
|
--secondary: oklch(0.97 0 0);
|
||||||
|
--secondary-foreground: oklch(0.205 0 0);
|
||||||
|
--muted: oklch(0.97 0 0);
|
||||||
|
--muted-foreground: oklch(0.556 0 0);
|
||||||
|
--accent: oklch(0.97 0 0);
|
||||||
|
--accent-foreground: oklch(0.205 0 0);
|
||||||
|
--destructive: oklch(0.577 0.245 27.325);
|
||||||
|
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||||
|
--border: oklch(0.922 0 0);
|
||||||
|
--input: oklch(0.922 0 0);
|
||||||
|
--ring: oklch(0.708 0 0);
|
||||||
|
--chart-1: oklch(0.646 0.222 41.116);
|
||||||
|
--chart-2: oklch(0.6 0.118 184.704);
|
||||||
|
--chart-3: oklch(0.398 0.07 227.392);
|
||||||
|
--chart-4: oklch(0.828 0.189 84.429);
|
||||||
|
--chart-5: oklch(0.769 0.188 70.08);
|
||||||
|
--radius: 0.625rem;
|
||||||
|
--sidebar: oklch(0.985 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.145 0 0);
|
||||||
|
--sidebar-primary: oklch(0.205 0 0);
|
||||||
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-accent: oklch(0.97 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||||
|
--sidebar-border: oklch(0.922 0 0);
|
||||||
|
--sidebar-ring: oklch(0.708 0 0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
---break---
|
||||||
|
*/
|
||||||
|
.dark {
|
||||||
|
--background: oklch(0.145 0 0);
|
||||||
|
--foreground: oklch(0.985 0 0);
|
||||||
|
--card: oklch(0.145 0 0);
|
||||||
|
--card-foreground: oklch(0.985 0 0);
|
||||||
|
--popover: oklch(0.145 0 0);
|
||||||
|
--popover-foreground: oklch(0.985 0 0);
|
||||||
|
--primary: oklch(0.985 0 0);
|
||||||
|
--primary-foreground: oklch(0.205 0 0);
|
||||||
|
--secondary: oklch(0.269 0 0);
|
||||||
|
--secondary-foreground: oklch(0.985 0 0);
|
||||||
|
--muted: oklch(0.269 0 0);
|
||||||
|
--muted-foreground: oklch(0.708 0 0);
|
||||||
|
--accent: oklch(0.269 0 0);
|
||||||
|
--accent-foreground: oklch(0.985 0 0);
|
||||||
|
--destructive: oklch(0.396 0.141 25.723);
|
||||||
|
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||||
|
--border: oklch(0.269 0 0);
|
||||||
|
--input: oklch(0.269 0 0);
|
||||||
|
--ring: oklch(0.439 0 0);
|
||||||
|
--chart-1: oklch(0.488 0.243 264.376);
|
||||||
|
--chart-2: oklch(0.696 0.17 162.48);
|
||||||
|
--chart-3: oklch(0.769 0.188 70.08);
|
||||||
|
--chart-4: oklch(0.627 0.265 303.9);
|
||||||
|
--chart-5: oklch(0.645 0.246 16.439);
|
||||||
|
--sidebar: oklch(0.205 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||||
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-accent: oklch(0.269 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-border: oklch(0.269 0 0);
|
||||||
|
--sidebar-ring: oklch(0.439 0 0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
---break---
|
||||||
|
*/
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border outline-ring/50;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="background" class="fixed"></div>
|
<div id="background" class="fixed"></div>
|
||||||
<div class="bg-backdrop-layout"></div>
|
<div class="bg-backdrop-layout">
|
||||||
|
<ParticlesBg class="h-full" :quantity="200" :ease="100" :color="'#000'" :staticity="10" refresh></ParticlesBg>
|
||||||
|
</div>
|
||||||
<div class="login-container">
|
<div class="login-container">
|
||||||
<div class="login-width md:w-10/12 mx-auto flex justify-between h-full items-center">
|
<div class="login-width md:w-10/12 mx-auto flex justify-between h-full items-center">
|
||||||
<div class="w-6/12 mx-auto left-panel rounded-l pl-5 pr-5 hidden md:block">
|
<div class="w-6/12 mx-auto left-panel rounded-l pl-5 pr-5 hidden md:block">
|
||||||
@@ -107,6 +109,8 @@ import verifyCode from "@cps/ma-verifyCode/index.vue"
|
|||||||
import { useUserStore } from "@/store"
|
import { useUserStore } from "@/store"
|
||||||
import { useRouter, useRoute } from "vue-router"
|
import { useRouter, useRoute } from "vue-router"
|
||||||
import userApi from "@/api/system/user"
|
import userApi from "@/api/system/user"
|
||||||
|
// 导入背景ui组件
|
||||||
|
import ParticlesBg from "@/components/ui/particles-bg/ParticlesBg.vue"
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
// 绑定登录form的数据
|
// 绑定登录form的数据
|
||||||
@@ -157,7 +161,6 @@ const handleSubmit = async ({ values, errors }) => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-image: url("@/assets/BingWallpaper.jpg");
|
|
||||||
}
|
}
|
||||||
.bg-backdrop-layout {
|
.bg-backdrop-layout {
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -176,13 +179,14 @@ const handleSubmit = async ({ values, errors }) => {
|
|||||||
z-index: 3;
|
z-index: 3;
|
||||||
.login-width {
|
.login-width {
|
||||||
max-width: 950px;
|
max-width: 950px;
|
||||||
background: #fff;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
margin-top: -255px;
|
margin-top: -255px;
|
||||||
border-radius: var(--border-radius-small);
|
border-radius: var(--border-radius-small);
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.25) 0px 14px 28px, rgba(0, 0, 0, 0.22) 0px 10px 10px;
|
||||||
|
backdrop-filter: blur(3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-panel {
|
.left-panel {
|
||||||
|
|||||||
@@ -10,7 +10,44 @@ export default function useOptions(formRef: any) {
|
|||||||
})
|
})
|
||||||
const crudColumns = useColumn(formRef)
|
const crudColumns = useColumn(formRef)
|
||||||
const columnOptions = computed(() => {
|
const columnOptions = computed(() => {
|
||||||
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
|
const transformColumns = tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
|
||||||
|
// 针对测试项的布局优化
|
||||||
|
// 取出所有字段
|
||||||
|
const identColumn = transformColumns.find((item: any) => item.dataIndex === "ident")
|
||||||
|
const nameColumn = transformColumns.find((item: any) => item.dataIndex === "name")
|
||||||
|
const priorityColumn = transformColumns.find((item: any) => item.dataIndex === "priority")
|
||||||
|
const testTypeColumn = transformColumns.find((item: any) => item.dataIndex === "testType")
|
||||||
|
const testMethodColumn = transformColumns.find((item: any) => item.dataIndex === "testMethod")
|
||||||
|
// 组装表单布局
|
||||||
|
const identAndNameColumn = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [
|
||||||
|
{ span: 12, formList: [identColumn] },
|
||||||
|
{ span: 12, formList: [nameColumn] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const priorityColumnNew = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [{ span: 24, formList: [priorityColumn] }]
|
||||||
|
}
|
||||||
|
const testTypeAndMethodColumn = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [
|
||||||
|
{ span: 12, formList: [testTypeColumn] },
|
||||||
|
{ span: 12, formList: [testMethodColumn] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
// 取除原数组里面的内容
|
||||||
|
const newColumnsArray = transformColumns.filter(
|
||||||
|
(it: any) =>
|
||||||
|
it.dataIndex !== "ident" &&
|
||||||
|
it.dataIndex !== "name" &&
|
||||||
|
it.dataIndex !== "priority" &&
|
||||||
|
it.dataIndex !== "testType" &&
|
||||||
|
it.dataIndex !== "testMethod"
|
||||||
|
)
|
||||||
|
newColumnsArray.unshift(identAndNameColumn, priorityColumnNew, testTypeAndMethodColumn)
|
||||||
|
return newColumnsArray
|
||||||
})
|
})
|
||||||
return { options, columnOptions }
|
return { options, columnOptions }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export default function (crudOrFormRef: any) {
|
|||||||
{
|
{
|
||||||
title: "名称",
|
title: "名称",
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
width: 120,
|
width: 150,
|
||||||
align: "center",
|
align: "center",
|
||||||
search: true,
|
search: true,
|
||||||
commonRules: [{ required: true, message: "名称是必填" }],
|
commonRules: [{ required: true, message: "名称是必填" }],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="modalVisible"
|
v-model:visible="modalVisible"
|
||||||
width="80%"
|
width="80%"
|
||||||
title="设计需求批量写入"
|
title="批量导入设计需求"
|
||||||
:unmount-on-close="true"
|
:unmount-on-close="true"
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
ok-text="录入"
|
ok-text="录入"
|
||||||
@@ -11,20 +11,30 @@
|
|||||||
:on-before-ok="handleModalSubmit"
|
:on-before-ok="handleModalSubmit"
|
||||||
>
|
>
|
||||||
<div class="uploadContainer">
|
<div class="uploadContainer">
|
||||||
<span :style="{ marginBottom: '10px', flex: '0 1 160px' }">上传设计需求.docx:</span>
|
<span :style="{ marginBottom: '10px', flex: '0 1 150px' }">上传需求.docx:</span>
|
||||||
<a-upload
|
<a-upload
|
||||||
:style="{ marginBottom: '10px' }"
|
:style="{ marginBottom: '10px' }"
|
||||||
:custom-request="handleRquest"
|
|
||||||
:limit="1"
|
:limit="1"
|
||||||
accept=".docx"
|
accept=".docx"
|
||||||
|
:action="`/api/dut_upload/upload_xq_docx/?parseChapter=${parseChapter}`"
|
||||||
@change="handleUploadChange"
|
@change="handleUploadChange"
|
||||||
|
@success="handleUploadSuccess"
|
||||||
|
@error="handleUploadError"
|
||||||
|
:disabled="parseChapter.trim() === ''"
|
||||||
></a-upload>
|
></a-upload>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="w-[350px]">要解析的章节名称:</span>
|
||||||
|
<a-input placeholder="输入要解析的章节名称" v-model="parseChapter"></a-input>
|
||||||
|
<span class="w-[350px]">选择需求录入类型:</span>
|
||||||
|
<a-select allow-search v-model="selectValue">
|
||||||
|
<a-option v-for="item in demandType" :key="item.key" :value="item.key">{{ item.title }}</a-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
<a-alert :style="{ margin: '10px 0' }" type="warning">
|
<a-alert :style="{ margin: '10px 0' }" type="warning">
|
||||||
请去除需求规格说明文件中不必要的部分再来此处解析,注意:本系统不支持word中emf格式图片,如果使用了visio等图片请<span
|
只能上传.docx,<span class="important-text">如果有visio图请替换为普通图片上传</span
|
||||||
class="important-text"
|
>,请在需求规格说明文档中操作 ->
|
||||||
>在word变为普通图片上传</span
|
<span class="important-text">引用 -> 目录 -> 自定义目录 -> 显示级别改为6</span>以上保存后上传
|
||||||
>
|
|
||||||
</a-alert>
|
</a-alert>
|
||||||
<div class="operation-container">
|
<div class="operation-container">
|
||||||
<span :style="{ marginRight: '10px', fontWeight: 700 }">操作按钮:</span>
|
<span :style="{ marginRight: '10px', fontWeight: 700 }">操作按钮:</span>
|
||||||
@@ -109,104 +119,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, nextTick, watch } from "vue"
|
import { ref, watch } from "vue"
|
||||||
import mammoth from "mammoth"
|
|
||||||
import dictApi from "@/api/system/dict"
|
import dictApi from "@/api/system/dict"
|
||||||
import demandApi from "@/api/project/designDemand"
|
import demandApi from "@/api/project/designDemand"
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute } from "vue-router"
|
||||||
import { parseHtmlStringByDemandDut } from "@/views/project/dut/tools/parseHtmlString"
|
|
||||||
import { HtmlParser } from "@/views/project/dut/tools/parser"
|
|
||||||
import { useTreeDataStore } from "@/store"
|
import { useTreeDataStore } from "@/store"
|
||||||
// 其他初始化数据
|
|
||||||
const route = useRoute()
|
|
||||||
const router = useRouter()
|
|
||||||
const treeDataStore = useTreeDataStore()
|
|
||||||
// ~导入editor组件~tinymce
|
|
||||||
import MaEditor from "@/components/ma-editor/index.vue"
|
import MaEditor from "@/components/ma-editor/index.vue"
|
||||||
import { Message } from "@arco-design/web-vue"
|
import { Message } from "@arco-design/web-vue"
|
||||||
// 单个设计需求录入模版
|
import useUpload from "./useUpload"
|
||||||
const templateDemandObj = {
|
import useListOperaton from "./useListOperation"
|
||||||
chapter: "",
|
// 定义录入完毕的事件,给父组件刷新表格
|
||||||
title: "",
|
const emit = defineEmits(["enterFinish"])
|
||||||
ident: "",
|
// 其他初始化数据
|
||||||
demandType: "",
|
const route = useRoute()
|
||||||
content: ""
|
const treeDataStore = useTreeDataStore()
|
||||||
}
|
// ~~~刚开始就加载字典数据,给选择框使用~~~
|
||||||
// 先请求设计需求的dict,然后给demandType选项
|
|
||||||
let demandType = []
|
let demandType = []
|
||||||
const getDictDemandType = async function () {
|
const getDictDemandType = async function () {
|
||||||
const res = await dictApi.getDictByCode({ code: "demandType" })
|
const res = await dictApi.getDictByCode({ code: "demandType" })
|
||||||
demandType = res.data
|
demandType = res.data
|
||||||
}
|
}
|
||||||
getDictDemandType()
|
getDictDemandType()
|
||||||
// 弹窗显示
|
// 弹窗显示ref
|
||||||
const modalVisible = ref(false)
|
const modalVisible = ref(false)
|
||||||
// 全部html数据-循环创建折叠项
|
// 全部html数据-给a-list展示
|
||||||
const htmlData = ref([])
|
const htmlData = ref([])
|
||||||
// 数据变化spin显示
|
|
||||||
const loading = ref(false)
|
// ~~~~1.list~~~~
|
||||||
// 当upload组件发生变化时候
|
const { loading, handleCreateAtLatest, handleResetData, handledownCreate, handlePageChange, handleDelete } =
|
||||||
const handleUploadChange = (files) => {
|
useListOperaton(htmlData)
|
||||||
files.length ? (files.length = 1) : (htmlData.value = [])
|
|
||||||
}
|
// ~~~~2.upload~~~~
|
||||||
// 上传行为函数
|
const { handleUploadSuccess, handleUploadError, parseChapter, selectValue } = useUpload(htmlData)
|
||||||
const handleRquest = function (options) {
|
|
||||||
const { onProgress, onError, onSuccess, fileItem } = options
|
|
||||||
onProgress(0.1)
|
|
||||||
// 让spin组件先转圈
|
|
||||||
loading.value = true
|
|
||||||
// 让Empty组件不显示
|
|
||||||
htmlData.value.push(templateDemandObj)
|
|
||||||
// 获取文件
|
|
||||||
let reader = new FileReader()
|
|
||||||
reader.readAsArrayBuffer(fileItem.file)
|
|
||||||
reader.onload = function (loadEvent) {
|
|
||||||
let arrayBuffer = loadEvent.target.result
|
|
||||||
mammoth
|
|
||||||
.convertToHtml({ arrayBuffer: arrayBuffer })
|
|
||||||
.then((res) => {
|
|
||||||
// 已经上传到浏览器了,需要解析为列表
|
|
||||||
onSuccess(1)
|
|
||||||
const rawHtml = res.value
|
|
||||||
const parser = new HtmlParser(rawHtml)
|
|
||||||
const finalData = parser.parseToArray()
|
|
||||||
htmlData.value = finalData
|
|
||||||
// ~~~~使用nextTick:等待DOM更新完成~~~~
|
|
||||||
nextTick(() => {
|
|
||||||
loading.value = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
console.log("处理错误导致失败,请检查前端代码")
|
|
||||||
console.log("错误如下:", error)
|
|
||||||
onError(error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 上方按钮:直接在最下新增一条
|
|
||||||
const handleCreateAtLatest = () => {
|
|
||||||
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
|
|
||||||
htmlData.value.push(newDemand)
|
|
||||||
}
|
|
||||||
// 上方按钮:重置数据,点击页面不卡段
|
|
||||||
const handleResetData = () => {
|
|
||||||
htmlData.value = []
|
|
||||||
}
|
|
||||||
// 点击单条右侧按钮:下方新增 - 深拷贝,并插入到下方
|
|
||||||
const handledownCreate = (index) => {
|
|
||||||
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
|
|
||||||
htmlData.value.splice(index + 1, 0, newDemand)
|
|
||||||
}
|
|
||||||
// 因为a-list限制必须知道当前页码和页容量
|
|
||||||
const currentPage = ref(1)
|
|
||||||
const handlePageChange = (page) => {
|
|
||||||
currentPage.value = page
|
|
||||||
}
|
|
||||||
// 点击单条右侧按钮:删除 - 需要根据currentPage动态觉得因为a-list每页都是这样计算的
|
|
||||||
const handleDelete = (index) => {
|
|
||||||
const currentIndex = index + (currentPage.value - 1) * 15
|
|
||||||
htmlData.value.splice(currentIndex, 1)
|
|
||||||
}
|
|
||||||
// 打开弹窗并初始化form数据
|
// 打开弹窗并初始化form数据
|
||||||
const open = function () {
|
const open = function () {
|
||||||
// 打开时候传入对象可初始化from
|
// 打开时候传入对象可初始化from
|
||||||
@@ -234,11 +179,19 @@ const handleModalSubmit = async () => {
|
|||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
treeDataStore.updateDesignDemandTreeData(res.data, route.query.id)
|
treeDataStore.updateDesignDemandTreeData(res.data, route.query.id)
|
||||||
|
// 给父元素说明我已经完成了
|
||||||
|
emit("enterFinish")
|
||||||
Message.success("批量新增设计需求成功...")
|
Message.success("批量新增设计需求成功...")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当upload组件发生变化时候-性能配置
|
||||||
|
const handleUploadChange = (files) => {
|
||||||
|
files.length ? (files.length = 1) : (htmlData.value = [])
|
||||||
|
}
|
||||||
|
|
||||||
// 暴露该组件ref的方法
|
// 暴露该组件ref的方法
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { ref } from "vue"
|
||||||
|
|
||||||
|
const templateDemandObj = {
|
||||||
|
chapter: "",
|
||||||
|
title: "",
|
||||||
|
ident: "",
|
||||||
|
demandType: "",
|
||||||
|
content: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useListOperaton(htmlData: any) {
|
||||||
|
// 数据变化spin显示
|
||||||
|
const loading = ref(false)
|
||||||
|
// 上方按钮:直接在最下新增一条
|
||||||
|
const handleCreateAtLatest = () => {
|
||||||
|
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
|
||||||
|
htmlData.value.push(newDemand)
|
||||||
|
}
|
||||||
|
// 上方按钮:重置数据,点击页面不卡段
|
||||||
|
const handleResetData = () => {
|
||||||
|
htmlData.value = []
|
||||||
|
}
|
||||||
|
// 点击单条右侧按钮:下方新增 - 深拷贝,并插入到下方
|
||||||
|
const handledownCreate = (index: number) => {
|
||||||
|
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
|
||||||
|
htmlData.value.splice(index + 1, 0, newDemand)
|
||||||
|
}
|
||||||
|
// 因为a-list限制必须知道当前页码和页容量
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const handlePageChange = (page) => {
|
||||||
|
currentPage.value = page
|
||||||
|
}
|
||||||
|
// 点击单条右侧按钮:删除 - 需要根据currentPage动态觉得因为a-list每页都是这样计算的
|
||||||
|
const handleDelete = (index: number) => {
|
||||||
|
const currentIndex = index + (currentPage.value - 1) * 15
|
||||||
|
htmlData.value.splice(currentIndex, 1)
|
||||||
|
}
|
||||||
|
return { loading, handleCreateAtLatest, handleResetData, handledownCreate, handlePageChange, handleDelete }
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import { ref } from "vue"
|
||||||
|
import { Message, Notification } from "@arco-design/web-vue"
|
||||||
|
|
||||||
|
const templateDemandObj = {
|
||||||
|
chapter: "",
|
||||||
|
title: "",
|
||||||
|
ident: "",
|
||||||
|
demandType: "",
|
||||||
|
content: ""
|
||||||
|
}
|
||||||
|
// 判断是否为{"__type__": "image","format": "base64","data": "base64数据"}
|
||||||
|
function isImageObject(obj: any) {
|
||||||
|
return (
|
||||||
|
obj !== null &&
|
||||||
|
typeof obj === "object" &&
|
||||||
|
!Array.isArray(obj) &&
|
||||||
|
Object.hasOwn(obj, "__type__") &&
|
||||||
|
Object.hasOwn(obj, "format") &&
|
||||||
|
Object.hasOwn(obj, "data")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useUpload(htmlData: any) {
|
||||||
|
const parseChapter = ref("") // 定义用户想解析的章节名称
|
||||||
|
const selectValue = ref("1") // 定义选择框
|
||||||
|
const handleUploadSuccess = (fileItem: any) => {
|
||||||
|
const data = fileItem.response.data
|
||||||
|
if (!data.children) {
|
||||||
|
Notification.error({
|
||||||
|
content: "解析失败:请确认上传文件目录级别包含6以上;章节名称正确",
|
||||||
|
duration: 3000,
|
||||||
|
closable: true
|
||||||
|
})
|
||||||
|
parseChapter.value = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 这里就是解析出东西了
|
||||||
|
const parsedData = getObjFromChapter(data)
|
||||||
|
if (parsedData) {
|
||||||
|
enterDemand(parsedData)
|
||||||
|
}
|
||||||
|
// 上传成功后清空解析章节名称
|
||||||
|
parseChapter.value = ""
|
||||||
|
}
|
||||||
|
const handleUploadError = (fileItem: any) => {
|
||||||
|
console.log(fileItem.response)
|
||||||
|
}
|
||||||
|
const getObjFromChapter = (parseObj: any) => {
|
||||||
|
if (parseObj.title === parseChapter.value) return parseObj
|
||||||
|
if (Array.isArray(parseObj.children) && parseObj.children.length > 0) {
|
||||||
|
for (const child of parseObj.children) {
|
||||||
|
const found = getObjFromChapter(child)
|
||||||
|
if (found) return found // 递归返回obj或null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null // 如果都没找到返回null
|
||||||
|
}
|
||||||
|
// 辅助函数:(递归)将parseObj转为templateDemandObj录入,递归录入
|
||||||
|
const enterDemand = (parseObj: any) => {
|
||||||
|
// 下面是录入
|
||||||
|
const demandObj = JSON.parse(JSON.stringify(templateDemandObj))
|
||||||
|
demandObj.chapter = parseObj.number
|
||||||
|
demandObj.title = parseObj.title
|
||||||
|
demandObj.ident = parseObj.ordinal ? parseObj.ordinal : "" // 设计需求标识如果没有则为空
|
||||||
|
demandObj.demandType = selectValue.value
|
||||||
|
// 解析数组,然后添加到内容中
|
||||||
|
const content = formatContentForTinyMCE(JSON.parse(parseObj.content))
|
||||||
|
demandObj.content = content
|
||||||
|
htmlData.value.push(demandObj)
|
||||||
|
// 如果有子对象,则再运行一次即可
|
||||||
|
if (Array.isArray(parseObj.children) && parseObj.children.length > 0) {
|
||||||
|
for (const childObj of parseObj.children) {
|
||||||
|
enterDemand(childObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 上面函数的辅助函数:将数组变为HTML给tinymce使用
|
||||||
|
function formatContentForTinyMCE(data: any) {
|
||||||
|
let htmlContent = ""
|
||||||
|
// 处理普通文本行
|
||||||
|
for (const item of data) {
|
||||||
|
// 如果是普通文本
|
||||||
|
if (typeof item === "string") {
|
||||||
|
// 处理表头标记
|
||||||
|
if (item.includes("见表") || item.includes("如表") || item.includes("如下表")) {
|
||||||
|
htmlContent += `<p>${item.replace(/见表\d+/, "见下表").replace(/见图\d+/, "见下图")}</p>`
|
||||||
|
} else if (item.includes("见图") || item.includes("如图") || item.includes("如下图")) {
|
||||||
|
htmlContent += `<p>${item.replace(/见图\d+/, "见下图").replace(/见表\d+/, "见下表")}</p>`
|
||||||
|
} else if (/表\d+/.test(item)) {
|
||||||
|
htmlContent += ``
|
||||||
|
} else if (/图\d+/.test(item)) {
|
||||||
|
htmlContent += `${item.replace(/图\d+/, "下图")}`
|
||||||
|
} else {
|
||||||
|
htmlContent += `<p>${item}</p>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是对象(根据后端逻辑是图片)
|
||||||
|
else if (isImageObject(item)) {
|
||||||
|
// item现在是对象,其data是base64字符串
|
||||||
|
htmlContent += `<p><img src="data:image/png;base64,${item.data}" style="max-width:100%; height:auto; margin: 0 auto; display: block;"></img></p>`
|
||||||
|
}
|
||||||
|
// 处理表格数据
|
||||||
|
else if (Array.isArray(item)) {
|
||||||
|
htmlContent += '<table border="1" style="margin: 0 auto;max-width:70%; border-collapse:collapse;">'
|
||||||
|
// 处理表头
|
||||||
|
const headers = item[0].split("\t")
|
||||||
|
htmlContent += "<thead><tr>"
|
||||||
|
for (const header of headers) {
|
||||||
|
htmlContent += `<th style="padding:8px; border:1px solid #ddd;">${header}</th>`
|
||||||
|
}
|
||||||
|
htmlContent += "</tr></thead>"
|
||||||
|
// 处理表格内容
|
||||||
|
htmlContent += "<tbody>"
|
||||||
|
for (let i = 1; i < item.length; i++) {
|
||||||
|
const cells = item[i].split("\t")
|
||||||
|
htmlContent += "<tr>"
|
||||||
|
for (const cell of cells) {
|
||||||
|
// 处理单元格内的换行符
|
||||||
|
const formattedCell = cell.replace(/\n/g, "<br>")
|
||||||
|
htmlContent += `<td style="padding:8px; border:1px solid #ddd;">${formattedCell}</td>`
|
||||||
|
}
|
||||||
|
htmlContent += "</tr>"
|
||||||
|
}
|
||||||
|
htmlContent += "</tbody></table>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return htmlContent
|
||||||
|
}
|
||||||
|
return { handleUploadSuccess, handleUploadError, parseChapter, selectValue }
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<template #inputPrepend-ident> SJ-XX- </template>
|
<template #inputPrepend-ident> SJ-XX- </template>
|
||||||
</ma-crud>
|
</ma-crud>
|
||||||
</div>
|
</div>
|
||||||
<file-input-modal ref="fileInputRef"></file-input-modal>
|
<file-input-modal ref="fileInputRef" @enterFinish="crudRef.refresh()"></file-input-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,148 +0,0 @@
|
|||||||
/**
|
|
||||||
* 辅助函数,给每个h2增加个自定义属性,用来储存章节号,返回功能/接口h2节点对象【非DOM,有dom属性表示DOM】
|
|
||||||
*/
|
|
||||||
function getNeedH2NodeList(h1h2Node) {
|
|
||||||
const h2ObjList = []
|
|
||||||
// 首先将h1和h2节点都组成一个数组
|
|
||||||
let h1Index = 0,
|
|
||||||
h2Index = 0
|
|
||||||
h1h2Node.forEach((hDom) => {
|
|
||||||
if (hDom.tagName === "H1") {
|
|
||||||
// 找到h1,那么其index+1
|
|
||||||
h1Index += 1
|
|
||||||
h2Index = 0
|
|
||||||
} else if (hDom.tagName === "H2") {
|
|
||||||
// 按顺序找到h2了,
|
|
||||||
h2Index += 1
|
|
||||||
let h2Obj = {
|
|
||||||
chapter: h1Index + "." + h2Index,
|
|
||||||
dom: hDom,
|
|
||||||
text: hDom.innerText
|
|
||||||
}
|
|
||||||
h2ObjList.push(h2Obj)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 1.~~~~TODO:可以从这里修改识别范围~~~~
|
|
||||||
return h2ObjList.filter(
|
|
||||||
(item) =>
|
|
||||||
item.text.includes("CSCI功能需求") ||
|
|
||||||
item.text.includes("CSCI外部接口需求") ||
|
|
||||||
item.text.includes("CSCI能力需求")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 思路:因为mammoth解析后变为html字符串,使用new DOMParser()转换为DOM进行解析
|
|
||||||
* 作用:创建DOMParser()对象,然后解析需求规格说明的html字符串,目前仅支持功能和接口需求
|
|
||||||
* 返回:Array[Object[String,String]]
|
|
||||||
*/
|
|
||||||
export function parseHtmlStringByDemandDut(htmlString) {
|
|
||||||
const parser = new DOMParser()
|
|
||||||
const doc = parser.parseFromString(htmlString, "text/html")
|
|
||||||
const h1h2NodeList = doc.querySelectorAll("h1,h2")
|
|
||||||
// 这一步得到功能需求、接口需求的h2对象,里面有dom、text、chapter
|
|
||||||
const h2ObjArray = getNeedH2NodeList(h1h2NodeList)
|
|
||||||
// 这里开始就要获取全部有用信息:
|
|
||||||
// 2.遍历全部DOM
|
|
||||||
const allArray = Array.from(doc.body.children)
|
|
||||||
const demandArray = []
|
|
||||||
let h2Index = 0
|
|
||||||
let locker = false
|
|
||||||
// 3.将H3和H4的索引增加
|
|
||||||
let currentH3ele = {
|
|
||||||
initChapter: "",
|
|
||||||
index: 0,
|
|
||||||
title: "",
|
|
||||||
ident: "",
|
|
||||||
isIn: false
|
|
||||||
}
|
|
||||||
let currentH4ele = {
|
|
||||||
initChapter: "",
|
|
||||||
index: 0,
|
|
||||||
title: "",
|
|
||||||
ident: ""
|
|
||||||
}
|
|
||||||
let adpterIndex = 0
|
|
||||||
|
|
||||||
allArray.forEach((element) => {
|
|
||||||
// 2.1.找到h2ObjArray的位置
|
|
||||||
if (h2ObjArray[h2Index] && element === h2ObjArray[h2Index].dom) {
|
|
||||||
h2Index += 1
|
|
||||||
currentH3ele.index = 0
|
|
||||||
locker = true
|
|
||||||
} else if (element.tagName === "H1" || element.tagName === "H2") {
|
|
||||||
locker = false
|
|
||||||
} else if (locker && element.tagName !== "H2") {
|
|
||||||
// 就是从H3开始需求的
|
|
||||||
if (element.tagName === "H3") {
|
|
||||||
// 按顺序解析到H3
|
|
||||||
currentH3ele.index += 1
|
|
||||||
currentH4ele.index = 0
|
|
||||||
const splitString = element.innerText.split(/[(())]/)
|
|
||||||
currentH3ele.title = splitString[0]
|
|
||||||
currentH3ele.ident = splitString[1] ? splitString[1] : ""
|
|
||||||
currentH3ele.initChapter = h2ObjArray[h2Index - 1].chapter + "." + currentH3ele.index
|
|
||||||
// 将isIn变为true,说明当前解析在这里面
|
|
||||||
currentH3ele.isIn = true
|
|
||||||
// 段落索引设置0
|
|
||||||
adpterIndex = 0
|
|
||||||
} else if (element.tagName === "H4") {
|
|
||||||
// 按顺序解析到H4
|
|
||||||
currentH4ele.index += 1
|
|
||||||
const splitString = element.innerText.split(/[(())]/)
|
|
||||||
currentH4ele.title = splitString[0]
|
|
||||||
currentH4ele.ident = splitString[1] ? splitString[1] : ""
|
|
||||||
// 将H3的isIn变为false,说明在H4里面不在H3了
|
|
||||||
currentH3ele.isIn = false
|
|
||||||
// chapter
|
|
||||||
currentH4ele.initChapter = currentH3ele.initChapter + "." + currentH4ele.index
|
|
||||||
// 段落索引
|
|
||||||
adpterIndex = 0
|
|
||||||
} else {
|
|
||||||
// 当currentH3ele的title有值的时候开始解析
|
|
||||||
if (currentH3ele.title) {
|
|
||||||
const demandObj = {
|
|
||||||
chapter: "",
|
|
||||||
title: "",
|
|
||||||
ident: "",
|
|
||||||
demandType: "",
|
|
||||||
content: ""
|
|
||||||
}
|
|
||||||
if (currentH3ele.isIn) {
|
|
||||||
demandObj.chapter = currentH3ele.initChapter
|
|
||||||
demandObj.title = currentH3ele.title
|
|
||||||
demandObj.ident = currentH3ele.ident
|
|
||||||
demandObj.demandType = demandObj.title.includes("接口") ? "3" : "1"
|
|
||||||
} else {
|
|
||||||
demandObj.chapter = currentH4ele.initChapter
|
|
||||||
demandObj.title = currentH4ele.title
|
|
||||||
demandObj.ident = currentH4ele.ident
|
|
||||||
demandObj.demandType = demandObj.title.includes("接口") ? "3" : "1"
|
|
||||||
}
|
|
||||||
// 1.解析table元素
|
|
||||||
if (element.tagName === "TABLE") {
|
|
||||||
demandObj.content = element.outerHTML
|
|
||||||
adpterIndex += 1
|
|
||||||
demandObj.ident = demandObj.ident + `-t${adpterIndex}`
|
|
||||||
demandArray.push(demandObj)
|
|
||||||
}
|
|
||||||
// 2.解析p元素-注意排除图片元素
|
|
||||||
if (element.tagName === "P" && !element.querySelector("img")) {
|
|
||||||
demandObj.content = element.innerText
|
|
||||||
adpterIndex += 1
|
|
||||||
demandObj.ident = demandObj.ident + `-p${adpterIndex}`
|
|
||||||
demandArray.push(demandObj)
|
|
||||||
}
|
|
||||||
// 3.解析ol和ul元素
|
|
||||||
if (element.tagName === "OL" || element.tagName === "UL") {
|
|
||||||
demandObj.content = element.innerHTML
|
|
||||||
adpterIndex += 1
|
|
||||||
demandObj.ident = demandObj.ident + `-u${adpterIndex}`
|
|
||||||
demandArray.push(demandObj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return demandArray
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
// 根据后端定义,不能更改的枚举
|
|
||||||
enum DemandType {
|
|
||||||
gn = "1",
|
|
||||||
xn = "2",
|
|
||||||
jk = "3",
|
|
||||||
kkx = "4",
|
|
||||||
aqx = "5",
|
|
||||||
other = "6"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数据每一项的结构
|
|
||||||
interface DemandObj {
|
|
||||||
chapter: string
|
|
||||||
title: string
|
|
||||||
ident?: string // 如果其标题有()则放入
|
|
||||||
demandType: DemandType
|
|
||||||
content: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义h元素对象接口
|
|
||||||
interface IHobj {
|
|
||||||
level: number // h1 -> 1
|
|
||||||
title: string // 标题文字
|
|
||||||
ident?: string // 如果有()则放入
|
|
||||||
index: number // 该标题的索引,先map的时候不设置后续再排列
|
|
||||||
demandType: DemandType
|
|
||||||
}
|
|
||||||
|
|
||||||
// h元素对象带计算出的章节号的对象
|
|
||||||
interface IHobjWithChapter extends IHobj {
|
|
||||||
chapter: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HtmlParser {
|
|
||||||
domArray: Element[] // 初始化得到一个元素的集合
|
|
||||||
hWithChapter: IHobjWithChapter[]
|
|
||||||
constructor(htmlText: string) {
|
|
||||||
const parser = new DOMParser()
|
|
||||||
const doc = parser.parseFromString(htmlText, "text/html")
|
|
||||||
this.domArray = Array.from(doc.body.children)
|
|
||||||
// 解析domArray将h元素加入
|
|
||||||
const HDomArray = this.domArray.filter((domItem) => domItem.tagName.startsWith("H"))
|
|
||||||
const storeArray: IHobj[] = []
|
|
||||||
HDomArray.forEach((it, i) => {
|
|
||||||
!it.textContent && (it.textContent = "")
|
|
||||||
// 这里判断是什么类型的设计需求 -> 后续可以添加
|
|
||||||
let type: DemandType = DemandType.gn
|
|
||||||
if (it.textContent.includes("接口")) {
|
|
||||||
type = DemandType.jk
|
|
||||||
} else if (it.textContent.includes("性能")) {
|
|
||||||
type = DemandType.xn
|
|
||||||
} else if (it.textContent.includes("可靠")) {
|
|
||||||
type = DemandType.kkx
|
|
||||||
} else if (it.textContent.includes("安全")) {
|
|
||||||
type = DemandType.aqx
|
|
||||||
}
|
|
||||||
// 获取章节号
|
|
||||||
const level = +it.tagName.slice(1)
|
|
||||||
// 1.判断当前的章节级别的前一个级别的level是否一样/小于/大于
|
|
||||||
let index = 0
|
|
||||||
if (i > 0) {
|
|
||||||
// 找上一个标题对象的level
|
|
||||||
if (level === storeArray[i - 1].level) {
|
|
||||||
index = storeArray[i - 1].index + 1
|
|
||||||
} else if (level < storeArray[i - 1].level) {
|
|
||||||
// 如果等级小于上一个标题对象,找storeArray里面level一样的长度
|
|
||||||
for (let j = storeArray.length - 1; j >= 0; j--) {
|
|
||||||
if (storeArray[j].level === level) {
|
|
||||||
index = storeArray[j].index + 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
storeArray.push({
|
|
||||||
level: level,
|
|
||||||
title: it.textContent,
|
|
||||||
ident: it.textContent.match(/[\((](.*?)[\))]/)?.[1],
|
|
||||||
index: index,
|
|
||||||
demandType: type
|
|
||||||
})
|
|
||||||
})
|
|
||||||
// 直接将storeArray计算出章节号
|
|
||||||
const chapterArray: any[] = storeArray.map((it, indx) => {
|
|
||||||
let str = it.index + 1 + ""
|
|
||||||
for (let i = it.level - 1; i > 0; i--) {
|
|
||||||
for (let j = indx - 1; j >= 0; j--) {
|
|
||||||
if (storeArray[j].level === i) {
|
|
||||||
str = storeArray[j].index + 1 + "." + str
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...it,
|
|
||||||
chapter: str
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.hWithChapter = chapterArray
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 将所有Element元素遍历,输出列表格式
|
|
||||||
*/
|
|
||||||
parseToArray(): DemandObj[] {
|
|
||||||
const resArr: DemandObj[] = []
|
|
||||||
let index = 0
|
|
||||||
let currentHElement: IHobjWithChapter = this.hWithChapter[index]
|
|
||||||
let adapterIndex: number = 1
|
|
||||||
this.domArray.forEach((item) => {
|
|
||||||
// 1.如果循环到H元素,将其存入
|
|
||||||
if (item.tagName.startsWith("H")) {
|
|
||||||
const text = item.textContent
|
|
||||||
if (text !== currentHElement.title) {
|
|
||||||
currentHElement = this.hWithChapter[index + 1]
|
|
||||||
index++
|
|
||||||
adapterIndex = 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 2.构造每一项放入 - chapter和content计算
|
|
||||||
let content = ""
|
|
||||||
let ident = currentHElement.ident
|
|
||||||
if (!ident) {
|
|
||||||
ident = ""
|
|
||||||
}
|
|
||||||
// 这里对图片进行处理
|
|
||||||
if (item.querySelector("img")) {
|
|
||||||
const img = item.querySelector("img")
|
|
||||||
if (img) {
|
|
||||||
const strblob = img.src + ""
|
|
||||||
const blob = strblob.split(",")[1]
|
|
||||||
content = `<img src="data:image/png;base64,${blob}" />`
|
|
||||||
}
|
|
||||||
ident += `-g${adapterIndex}`
|
|
||||||
adapterIndex++
|
|
||||||
resArr.push({
|
|
||||||
chapter: currentHElement.chapter,
|
|
||||||
title: currentHElement.title,
|
|
||||||
ident: ident,
|
|
||||||
demandType: currentHElement.demandType,
|
|
||||||
content
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 如果不是图片进行判断
|
|
||||||
if (item.textContent) {
|
|
||||||
if (item.tagName === "TABLE") {
|
|
||||||
content = item.outerHTML
|
|
||||||
ident += `-t${adapterIndex}`
|
|
||||||
adapterIndex++
|
|
||||||
}
|
|
||||||
if (item.tagName === "P" && !item.querySelector("img")) {
|
|
||||||
content = item.innerHTML.trim()
|
|
||||||
ident += `-p${adapterIndex}`
|
|
||||||
adapterIndex++
|
|
||||||
}
|
|
||||||
if (item.tagName === "OL" || item.tagName === "UL") {
|
|
||||||
content = item.innerHTML.trim()
|
|
||||||
ident += `-u${adapterIndex}`
|
|
||||||
adapterIndex++
|
|
||||||
}
|
|
||||||
// title要将括号去除
|
|
||||||
resArr.push({
|
|
||||||
chapter: currentHElement.chapter,
|
|
||||||
title: currentHElement.title,
|
|
||||||
ident: ident,
|
|
||||||
demandType: currentHElement.demandType,
|
|
||||||
content
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return resArr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ const beiceType: BeiceTypeT[] = [
|
|||||||
{ label: "设计说明", value: "SJ" },
|
{ label: "设计说明", value: "SJ" },
|
||||||
{ label: "需求文档", value: "XQ" },
|
{ label: "需求文档", value: "XQ" },
|
||||||
{ label: "通信协议", value: "XY" },
|
{ label: "通信协议", value: "XY" },
|
||||||
{ label: "研制总要求", value: "YZ" }
|
{ label: "研制总要求/技术协议等", value: "YZ" }
|
||||||
]
|
]
|
||||||
|
|
||||||
export default beiceType
|
export default beiceType
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { ref } from "vue"
|
import { ref, shallowRef } from "vue"
|
||||||
import { useRoute } from "vue-router"
|
import { useRoute } from "vue-router"
|
||||||
import beiceType from "@/views/project/round/beiceType"
|
import beiceType from "@/views/project/round/beiceType"
|
||||||
|
// 导入自定义组件
|
||||||
|
import UploadInput from "@/components/UploadInput/index.vue"
|
||||||
|
|
||||||
export default function (crudOrFormRef: any) {
|
export default function (crudOrFormRef: any) {
|
||||||
// global
|
// global
|
||||||
@@ -8,10 +10,8 @@ export default function (crudOrFormRef: any) {
|
|||||||
// 计算注释率计算crud/form的数据,判断
|
// 计算注释率计算crud/form的数据,判断
|
||||||
const calcPercent = () => {
|
const calcPercent = () => {
|
||||||
const formData = crudOrFormRef.value.getFormData()
|
const formData = crudOrFormRef.value.getFormData()
|
||||||
const { code_line, comment_line, mix_line, black_line } = formData
|
const { total_lines, comment_lines } = formData
|
||||||
const total_line = +black_line + +code_line + +comment_line + +mix_line
|
formData.comment_percent = `${(comment_lines / total_lines).toFixed(2).toString()}%`
|
||||||
const comment_total = +comment_line + +mix_line
|
|
||||||
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
|
|
||||||
}
|
}
|
||||||
const crudColumns = ref([
|
const crudColumns = ref([
|
||||||
{
|
{
|
||||||
@@ -51,28 +51,24 @@ export default function (crudOrFormRef: any) {
|
|||||||
translation: true,
|
translation: true,
|
||||||
tagColors: { XQ: "blue", SO: "green", SJ: "orangered", XY: "pinkpurple", YZ: "red" }
|
tagColors: { XQ: "blue", SO: "green", SJ: "orangered", XY: "pinkpurple", YZ: "red" }
|
||||||
},
|
},
|
||||||
onControl: (value) => {
|
onControl: (value: string) => {
|
||||||
if (value === "SO") {
|
if (value === "SO") {
|
||||||
return {
|
return {
|
||||||
black_line: { display: true },
|
total_lines: { display: true },
|
||||||
code_line: { display: true },
|
effective_lines: { display: true },
|
||||||
mix_line: { display: true },
|
comment_lines: { display: true },
|
||||||
comment_line: { display: true },
|
|
||||||
total_code_line: { display: true },
|
|
||||||
total_line: { display: true },
|
|
||||||
comment_percent: { display: true },
|
comment_percent: { display: true },
|
||||||
|
upload: { display: true },
|
||||||
release_date: { display: false }
|
release_date: { display: false }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 其他数据清除
|
// 其他数据清除
|
||||||
return {
|
return {
|
||||||
black_line: { display: false },
|
total_lines: { display: false },
|
||||||
code_line: { display: false },
|
effective_lines: { display: false },
|
||||||
mix_line: { display: false },
|
comment_lines: { display: false },
|
||||||
comment_line: { display: false },
|
|
||||||
total_code_line: { display: false },
|
|
||||||
total_line: { display: false },
|
|
||||||
comment_percent: { display: false },
|
comment_percent: { display: false },
|
||||||
|
upload: { display: false },
|
||||||
release_date: { display: true }
|
release_date: { display: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,49 +119,36 @@ export default function (crudOrFormRef: any) {
|
|||||||
formType: "date"
|
formType: "date"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "空行",
|
title: "总行数",
|
||||||
hide: true,
|
hide: true,
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "black_line",
|
dataIndex: "total_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
commonRules: [{ required: true, message: "空行数必填" }],
|
commonRules: [{ required: true, message: "总行数必填" }],
|
||||||
min: 0,
|
min: 0,
|
||||||
onControl: () => {
|
onControl: () => {
|
||||||
calcPercent()
|
calcPercent()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "纯代码行",
|
title: "有效行数",
|
||||||
hide: true,
|
hide: true,
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "code_line",
|
dataIndex: "effective_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
commonRules: [{ required: true, message: "纯代码行数必填" }],
|
commonRules: [{ required: true, message: "有效行数必填" }],
|
||||||
min: 0,
|
min: 0,
|
||||||
onControl: () => {
|
onControl: () => {
|
||||||
calcPercent()
|
calcPercent()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "纯注释行",
|
title: "注释行数",
|
||||||
hide: true,
|
hide: true,
|
||||||
align: "center",
|
align: "center",
|
||||||
dataIndex: "comment_line",
|
dataIndex: "comment_lines",
|
||||||
formType: "input-number",
|
formType: "input-number",
|
||||||
commonRules: [{ required: true, message: "纯注释行数必填" }],
|
commonRules: [{ required: true, message: "注释行数必填" }],
|
||||||
min: 0,
|
|
||||||
onControl: () => {
|
|
||||||
calcPercent()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "混合行",
|
|
||||||
hide: true,
|
|
||||||
align: "center",
|
|
||||||
dataIndex: "mix_line",
|
|
||||||
formType: "input-number",
|
|
||||||
help: "混合行是指:代码中一行即包含代码也包含注释",
|
|
||||||
commonRules: [{ required: true, message: "混合行数必填" }],
|
|
||||||
min: 0,
|
min: 0,
|
||||||
onControl: () => {
|
onControl: () => {
|
||||||
calcPercent()
|
calcPercent()
|
||||||
@@ -180,6 +163,15 @@ export default function (crudOrFormRef: any) {
|
|||||||
addDisabled: true,
|
addDisabled: true,
|
||||||
editDisabled: true,
|
editDisabled: true,
|
||||||
disabled: true
|
disabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "上传源代码",
|
||||||
|
align: "center",
|
||||||
|
dataIndex: "upload",
|
||||||
|
placeholder: "上传源代码",
|
||||||
|
hide: true,
|
||||||
|
formType: "component",
|
||||||
|
component: shallowRef(UploadInput)
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
return crudColumns
|
return crudColumns
|
||||||
|
|||||||
@@ -10,7 +10,78 @@ export default function useOptions(formRef: any) {
|
|||||||
})
|
})
|
||||||
const crudColumns = useColumn(formRef)
|
const crudColumns = useColumn(formRef)
|
||||||
const columnOptions = computed(() => {
|
const columnOptions = computed(() => {
|
||||||
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
|
// 处理表单布局
|
||||||
|
const transformColumns = tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
|
||||||
|
// 取出字段column对象
|
||||||
|
const identColumn = transformColumns.find((item: any) => item.dataIndex === "ident")
|
||||||
|
const nameColumn = transformColumns.find((item: any) => item.dataIndex === "name")
|
||||||
|
const designPersonColumn = transformColumns.find((item: any) => item.dataIndex === "designPerson")
|
||||||
|
const testPersonColumn = transformColumns.find((item: any) => item.dataIndex === "testPerson")
|
||||||
|
const monitorPersonColumn = transformColumns.find((item: any) => item.dataIndex === "monitorPerson")
|
||||||
|
const summarizeColumn = transformColumns.find((item: any) => item.dataIndex === "summarize")
|
||||||
|
const initializationColumn = transformColumns.find((item: any) => item.dataIndex === "initialization")
|
||||||
|
const premiseColumn = transformColumns.find((item: any) => item.dataIndex === "premise")
|
||||||
|
const exe_timeColumn = transformColumns.find((item: any) => item.dataIndex === "exe_time")
|
||||||
|
// 组装表单布局
|
||||||
|
const identAndNameColumn = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [
|
||||||
|
{ span: 12, formList: [identColumn] },
|
||||||
|
{ span: 12, formList: [nameColumn] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const cardColumn = {
|
||||||
|
formType: "card",
|
||||||
|
customClass: ["ml-5", "mb-3", "py-0", "px-0"],
|
||||||
|
title: "人员信息",
|
||||||
|
formList: [
|
||||||
|
{
|
||||||
|
formType: "grid",
|
||||||
|
cols: [
|
||||||
|
{ span: 8, formList: [designPersonColumn] },
|
||||||
|
{ span: 8, formList: [testPersonColumn] },
|
||||||
|
{ span: 8, formList: [monitorPersonColumn] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const summarizeColumnNew = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [{ span: 24, formList: [summarizeColumn] }]
|
||||||
|
}
|
||||||
|
const initializationColumnNew = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [{ span: 24, formList: [initializationColumn] }]
|
||||||
|
}
|
||||||
|
const premiseAndExeColumn = {
|
||||||
|
formType: "grid",
|
||||||
|
cols: [
|
||||||
|
{ span: 12, formList: [premiseColumn] },
|
||||||
|
{ span: 12, formList: [exe_timeColumn] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
// 取除原数组里面的内容
|
||||||
|
const newColumnsArray = transformColumns.filter(
|
||||||
|
(it: any) =>
|
||||||
|
it.dataIndex !== "ident" &&
|
||||||
|
it.dataIndex !== "name" &&
|
||||||
|
it.dataIndex !== "designPerson" &&
|
||||||
|
it.dataIndex !== "testPerson" &&
|
||||||
|
it.dataIndex !== "monitorPerson" &&
|
||||||
|
it.dataIndex !== "summarize" &&
|
||||||
|
it.dataIndex !== "initialization" &&
|
||||||
|
it.dataIndex !== "premise" &&
|
||||||
|
it.dataIndex !== "exe_time"
|
||||||
|
)
|
||||||
|
newColumnsArray.unshift(
|
||||||
|
identAndNameColumn,
|
||||||
|
cardColumn,
|
||||||
|
summarizeColumnNew,
|
||||||
|
initializationColumnNew,
|
||||||
|
premiseAndExeColumn
|
||||||
|
)
|
||||||
|
return newColumnsArray
|
||||||
})
|
})
|
||||||
|
|
||||||
return { options, columnOptions }
|
return { options, columnOptions }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,9 +140,20 @@ export default function (crudOrFormRef: any, problemFormRef?: any) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "执行时间",
|
title: "执行时间",
|
||||||
|
align: "center",
|
||||||
dataIndex: "exe_time",
|
dataIndex: "exe_time",
|
||||||
|
formType: "date",
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
// 如果不存在exe_time则显示为“没有设置”
|
||||||
|
return record.exe_time ? record.exe_time : <a-tag color="red">未填写</a-tag>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "时序图(cpu不填写此字段)",
|
||||||
hide: true,
|
hide: true,
|
||||||
formType: "date"
|
dataIndex: "timing_diagram",
|
||||||
|
addDefaultValue: "",
|
||||||
|
formType: "editor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "测试步骤",
|
title: "测试步骤",
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
formType: "card",
|
formType: "card",
|
||||||
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
|
customClass: ["ml-5", "mb-3", "py-0", "px-0"],
|
||||||
title: "人员信息",
|
title: "人员信息",
|
||||||
formList: [
|
formList: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,14 +32,12 @@ const useGenerateSecond = function () {
|
|||||||
dgGenerateApi.createTechYiju({ id }), // 技术依据文件
|
dgGenerateApi.createTechYiju({ id }), // 技术依据文件
|
||||||
dgGenerateApi.createContact({ id }), // 生成联系人和方式
|
dgGenerateApi.createContact({ id }), // 生成联系人和方式
|
||||||
dgGenerateApi.createTimeaddress({ id }), // 生成测评时间和地点
|
dgGenerateApi.createTimeaddress({ id }), // 生成测评时间和地点
|
||||||
dgGenerateApi.createFuncList({ id }), // 生成被测软件功能列表
|
|
||||||
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象-软件组成
|
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象-软件组成
|
||||||
dgGenerateApi.createAdequacyEffectiveness({ id }), // 生成测试充分性(adequancy)和有效性(effectiveness)说明
|
dgGenerateApi.createAdequacyEffectiveness({ id }), // 生成测试充分性(adequancy)和有效性(effectiveness)说明
|
||||||
dgGenerateApi.createGroup({ id }), // 生成测评组织及分工
|
dgGenerateApi.createGroup({ id }), // 生成测评组织及分工
|
||||||
dgGenerateApi.createGuarantee({ id }), // 生成测评保障
|
dgGenerateApi.createGuarantee({ id }), // 生成测评保障
|
||||||
dgGenerateApi.createAbbreviation({ id }), // 生成缩略语
|
dgGenerateApi.createAbbreviation({ id }), // 生成缩略语
|
||||||
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口
|
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口
|
||||||
dgGenerateApi.createPerformance({ id }), // 生成-被测软件性能
|
|
||||||
dgGenerateApi.createBaseInformation({ id }), // 生成-被测软件基本信息
|
dgGenerateApi.createBaseInformation({ id }), // 生成-被测软件基本信息
|
||||||
dgGenerateApi.createLevelAndType({ id }), // 生成-测试级别和测试类型 -【修改】
|
dgGenerateApi.createLevelAndType({ id }), // 生成-测试级别和测试类型 -【修改】
|
||||||
dgGenerateApi.createStrategy({ id }), // 生成-测试策略 -【新增】
|
dgGenerateApi.createStrategy({ id }), // 生成-测试策略 -【新增】
|
||||||
@@ -47,6 +45,8 @@ const useGenerateSecond = function () {
|
|||||||
dgGenerateApi.createXqComparison({ id }), // 生成-需求规格说明-测试项对照表
|
dgGenerateApi.createXqComparison({ id }), // 生成-需求规格说明-测试项对照表
|
||||||
dgGenerateApi.createFanXqComparison({ id }), // 生成-反向测试项-需求规格说明对照表
|
dgGenerateApi.createFanXqComparison({ id }), // 生成-反向测试项-需求规格说明对照表
|
||||||
dgGenerateApi.createCodeQuality({ id }), // 生成-代码质量度量分析表
|
dgGenerateApi.createCodeQuality({ id }), // 生成-代码质量度量分析表
|
||||||
|
// 2025年4月29日新增 - 顶层技术文件
|
||||||
|
dgGenerateApi.createTopFile({ id }), // 生成顶层技术文件
|
||||||
// 新增拆分接口
|
// 新增拆分接口
|
||||||
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
||||||
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
||||||
@@ -69,9 +69,7 @@ const useGenerateSecond = function () {
|
|||||||
isSmLoading.value = true
|
isSmLoading.value = true
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象 - 和大纲一样
|
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象 - 和大纲一样
|
||||||
dgGenerateApi.createFuncList({ id }), // 生成被测软件功能 - 和大纲重复
|
|
||||||
dgGenerateApi.createInterface({ id }), // 生成被测软件接口 - 和大纲重复 - 可能会删除
|
dgGenerateApi.createInterface({ id }), // 生成被测软件接口 - 和大纲重复 - 可能会删除
|
||||||
dgGenerateApi.createPerformance({ id }), // 生成被测软件性能 - 和大纲重复 - 可能会删除
|
|
||||||
dgGenerateApi.createBaseInformation({ id }), // 生成被测软件基本信息 - 和大纲重复 - 可能会删除
|
dgGenerateApi.createBaseInformation({ id }), // 生成被测软件基本信息 - 和大纲重复 - 可能会删除
|
||||||
dgGenerateApi.createYiju({ id }), // 生成标准类引用文档 - 和大纲重复 - 可能会删除
|
dgGenerateApi.createYiju({ id }), // 生成标准类引用文档 - 和大纲重复 - 可能会删除
|
||||||
smGenerateApi.createSMTechyiju({ id }), // 生成技术类引用文档列表 -> 在大纲基础上添加《测评大纲》
|
smGenerateApi.createSMTechyiju({ id }), // 生成技术类引用文档列表 -> 在大纲基础上添加《测评大纲》
|
||||||
@@ -97,7 +95,12 @@ const useGenerateSecond = function () {
|
|||||||
const createJLItem = async (id: number) => {
|
const createJLItem = async (id: number) => {
|
||||||
isGenerating.value = true
|
isGenerating.value = true
|
||||||
isJlloading.value = true
|
isJlloading.value = true
|
||||||
await jlGenerateApi.createJLcaserecord({ id }).finally(() => {
|
await Promise.all([
|
||||||
|
// 生成-被测软件基本信息 - 和大纲一样
|
||||||
|
dgGenerateApi.createBaseInformation({ id }),
|
||||||
|
// 记录相关片段
|
||||||
|
jlGenerateApi.createJLcaserecord({ id })
|
||||||
|
]).finally(() => {
|
||||||
isGenerating.value = false
|
isGenerating.value = false
|
||||||
isJlloading.value = false
|
isJlloading.value = false
|
||||||
})
|
})
|
||||||
@@ -116,7 +119,10 @@ const useGenerateSecond = function () {
|
|||||||
hsmGenerateApi.createCaseListDesc({ id }),
|
hsmGenerateApi.createCaseListDesc({ id }),
|
||||||
hsmGenerateApi.createCaseList({ id }),
|
hsmGenerateApi.createCaseList({ id }),
|
||||||
hsmGenerateApi.createTrack({ id }),
|
hsmGenerateApi.createTrack({ id }),
|
||||||
// 拆分大纲软硬件环境
|
// 拆分大纲软硬件环境-大纲内容
|
||||||
|
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象-软件组成
|
||||||
|
dgGenerateApi.createYiju({ id }), // 生成依据文件
|
||||||
|
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口 - 和大纲一样
|
||||||
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
||||||
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
||||||
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
||||||
@@ -171,7 +177,15 @@ const useGenerateSecond = function () {
|
|||||||
bgGenerateApi.createBgEntire({ id }),
|
bgGenerateApi.createBgEntire({ id }),
|
||||||
bgGenerateApi.createBgYzxqTrack({ id }),
|
bgGenerateApi.createBgYzxqTrack({ id }),
|
||||||
bgGenerateApi.createBgProblemsSummary({ id }),
|
bgGenerateApi.createBgProblemsSummary({ id }),
|
||||||
// 拆分软硬件环境
|
// 2025年4月27日新增:软件问题统计
|
||||||
|
bgGenerateApi.createProblemStatistics({ id }), // 生成软件问题统计
|
||||||
|
// 2025年4月28日新增:摸底清单
|
||||||
|
bgGenerateApi.createBgModiList({ id }), // 生成摸底清单
|
||||||
|
// 拆分软硬件环境-大纲内容
|
||||||
|
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象 - 大纲内容
|
||||||
|
dgGenerateApi.createYiju({ id }), // 生成依据文件
|
||||||
|
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口 - 大纲内容
|
||||||
|
dgGenerateApi.createAbbreviation({ id }), // 生成缩略语 - 大纲内容
|
||||||
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
||||||
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
||||||
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
||||||
@@ -179,7 +193,9 @@ const useGenerateSecond = function () {
|
|||||||
dgGenerateApi.createDynamicSoft({ id }), // 生成-动态软件项
|
dgGenerateApi.createDynamicSoft({ id }), // 生成-动态软件项
|
||||||
dgGenerateApi.createDynamicHard({ id }), // 生成-动态硬件和固件项
|
dgGenerateApi.createDynamicHard({ id }), // 生成-动态硬件和固件项
|
||||||
dgGenerateApi.createTestData({ id }), // 生成-测评数据
|
dgGenerateApi.createTestData({ id }), // 生成-测评数据
|
||||||
dgGenerateApi.createEnvDiff({ id }) // 生成-环境差异性分析
|
dgGenerateApi.createEnvDiff({ id }), // 生成-环境差异性分析
|
||||||
|
// 2025年4月29日新增 - 顶层技术文件
|
||||||
|
dgGenerateApi.createTopFile({ id }) // 生成顶层技术文件
|
||||||
]).finally(() => {
|
]).finally(() => {
|
||||||
isGenerating.value = false
|
isGenerating.value = false
|
||||||
isBgLoading.value = false
|
isBgLoading.value = false
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user