需求解析功能进一步完善
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": {
|
||||
"@arco-design/color": "^0.4.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",
|
||||
"@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",
|
||||
"file2md5": "^1.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucide-vue-next": "^0.503.0",
|
||||
"mammoth": "^1.9.0",
|
||||
"mitt": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.2",
|
||||
"pinyin-match": "^1.2.6",
|
||||
"pinyin-match": "^1.2.7",
|
||||
"postcss-import": "^16.1.0",
|
||||
"qs": "^6.14.0",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"tinymce": "^7.8.0",
|
||||
"tw-animate-css": "^1.2.8",
|
||||
"vue": "^3.5.13",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-color-kit": "^1.0.6",
|
||||
"vue-data-ui": "^2.6.40",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-data-ui": "^2.6.41",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.4",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qs": "^6.9.18",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"@vue/babel-plugin-jsx": "^1.4.0",
|
||||
"browserslist": "^4.24.4",
|
||||
"eslint": "^9.25.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-plugin-vue": "^10.0.1",
|
||||
"less": "^4.3.0",
|
||||
"less-loader": "^12.2.0",
|
||||
"postcss": "^8.5.3",
|
||||
@@ -52,7 +57,7 @@
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.2",
|
||||
"vite": "^6.3.3",
|
||||
"vue-eslint-parser": "^10.1.3"
|
||||
}
|
||||
},
|
||||
@@ -1019,9 +1024,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.25.0",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.25.0.tgz",
|
||||
"integrity": "sha512-iWhsUS8Wgxz9AXNfvfOPFSW4VfMXdVhp1hjkZVhXCrpgh/aLcc45rX6MPu+tIVUWDw0HfNwth7O28M1xDxNf9w==",
|
||||
"version": "9.25.1",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.25.1.tgz",
|
||||
"integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1753,9 +1758,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.74.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.74.4.tgz",
|
||||
"integrity": "sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A==",
|
||||
"version": "5.74.9",
|
||||
"resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.74.9.tgz",
|
||||
"integrity": "sha512-qmjXpWyigDw4SfqdSBy24FzRvpBPXlaSbl92N77lcrL+yvVQLQkf0T6bQNbTxl9IEB/SvVFhhVZoIlQvFnNuuw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -1763,13 +1768,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/vue-query": {
|
||||
"version": "5.74.5",
|
||||
"resolved": "https://registry.npmmirror.com/@tanstack/vue-query/-/vue-query-5.74.5.tgz",
|
||||
"integrity": "sha512-1IvuUASQ3h5jbM+90AR4vIDDLxYyGA9Iefvzx9uQMDA4c5Gpd9ETKHZgSUvFM3sXw6k0tY3uHtllBf875OqOcQ==",
|
||||
"version": "5.74.9",
|
||||
"resolved": "https://registry.npmmirror.com/@tanstack/vue-query/-/vue-query-5.74.9.tgz",
|
||||
"integrity": "sha512-iMZxrKfIiDdX9uNH8WusBZXq87lBL8v2UXhifYiBNH+BUPCaezP7gNv4TN7WAlHVSfAx0fsnMKLB5+D3GAspbA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@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-demi": "^0.14.10"
|
||||
},
|
||||
@@ -1884,9 +1889,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.14.1.tgz",
|
||||
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
||||
"version": "22.15.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.3.tgz",
|
||||
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2481,9 +2486,9 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.9.0.tgz",
|
||||
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
@@ -2657,6 +2662,18 @@
|
||||
"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": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmmirror.com/clipboard/-/clipboard-2.0.11.tgz",
|
||||
@@ -2682,6 +2699,15 @@
|
||||
"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": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||
@@ -3023,9 +3049,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.25.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.25.0.tgz",
|
||||
"integrity": "sha512-MsBdObhM4cEwkzCiraDv7A6txFXEqtNXOb877TsSp2FCkBNl8JfVQrmiuDqC1IkejT6JLPzYBXx/xAiYhyzgGA==",
|
||||
"version": "9.25.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.25.1.tgz",
|
||||
"integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3035,7 +3061,7 @@
|
||||
"@eslint/config-helpers": "^0.2.1",
|
||||
"@eslint/core": "^0.13.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.25.0",
|
||||
"@eslint/js": "9.25.1",
|
||||
"@eslint/plugin-kit": "^0.2.8",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@@ -3084,9 +3110,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.0.0.tgz",
|
||||
"integrity": "sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==",
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.0.1.tgz",
|
||||
"integrity": "sha512-A5dRYc3eQ5i2rJFBW8J6F69ur/H7YfYg+5SCg6v829FU0BhM4fUTrRVR2d4MdZgzw0ioJEk6otYHEAnoGFqO4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3314,9 +3340,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.4.3",
|
||||
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.3.tgz",
|
||||
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.4.4.tgz",
|
||||
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
@@ -4275,6 +4301,15 @@
|
||||
"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": {
|
||||
"version": "0.30.11",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.11.tgz",
|
||||
@@ -4702,9 +4737,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pinyin-match": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmmirror.com/pinyin-match/-/pinyin-match-1.2.6.tgz",
|
||||
"integrity": "sha512-d9fMSwZujH7UlMu+FO8MGXrgUYv0CwJtzpf3fQ8xgLJy1qfXlzOZsnQuL7Ej7msAiEtt37U7bE4dkVmyWaFfwA==",
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/pinyin-match/-/pinyin-match-1.2.7.tgz",
|
||||
"integrity": "sha512-RnypoF7OKgSKL8L4IayHmmHj9cHeked45TFAOffddcvpIIDrLcTSEJNruprE5otXCegBBqWm4YEi8JwMqToeig==",
|
||||
"license": "SATA"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
@@ -5346,6 +5381,16 @@
|
||||
"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": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.1.4.tgz",
|
||||
@@ -5428,13 +5473,13 @@
|
||||
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.12.tgz",
|
||||
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.13.tgz",
|
||||
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.3",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5456,6 +5501,15 @@
|
||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
||||
"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": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -5541,18 +5595,18 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.3.2.tgz",
|
||||
"integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==",
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.3.3.tgz",
|
||||
"integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.3",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.12"
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -5654,9 +5708,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-data-ui": {
|
||||
"version": "2.6.40",
|
||||
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.6.40.tgz",
|
||||
"integrity": "sha512-vd9Zy1WawOQAeqtpP7LE+nuqgaZ8RVc9ij+DxdsP6m7McKgG+cbse9Irk7nOQrQ0om6gZvZciCOyKKw4TKUzaw==",
|
||||
"version": "2.6.41",
|
||||
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.6.41.tgz",
|
||||
"integrity": "sha512-Sfy3TypoDvB14WpXk3UmlWCtXjUQjqNfxzy6gl+RJ2oGYqNY6LA2Xxun8428oxQ2CS3NaGTCinvddR+TDDd9pw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vue": ">=3.3.0"
|
||||
@@ -5714,9 +5768,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz",
|
||||
"integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
|
||||
"integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.6.4"
|
||||
|
||||
@@ -13,41 +13,46 @@
|
||||
"dependencies": {
|
||||
"@arco-design/color": "^0.4.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",
|
||||
"@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",
|
||||
"file2md5": "^1.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucide-vue-next": "^0.503.0",
|
||||
"mammoth": "^1.9.0",
|
||||
"mitt": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.2",
|
||||
"pinyin-match": "^1.2.6",
|
||||
"pinyin-match": "^1.2.7",
|
||||
"postcss-import": "^16.1.0",
|
||||
"qs": "^6.14.0",
|
||||
"tailwind-merge": "^3.2.0",
|
||||
"tinymce": "^7.8.0",
|
||||
"tw-animate-css": "^1.2.8",
|
||||
"vue": "^3.5.13",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-color-kit": "^1.0.6",
|
||||
"vue-data-ui": "^2.6.40",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-data-ui": "^2.6.41",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuedraggable": "^2.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.4",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qs": "^6.9.18",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"@vue/babel-plugin-jsx": "^1.4.0",
|
||||
"browserslist": "^4.24.4",
|
||||
"eslint": "^9.25.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-plugin-vue": "^10.0.1",
|
||||
"less": "^4.3.0",
|
||||
"less-loader": "^12.2.0",
|
||||
"postcss": "^8.5.3",
|
||||
@@ -55,7 +60,7 @@
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"tailwindcss": "^4.1.4",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^6.3.2",
|
||||
"vite": "^6.3.3",
|
||||
"vue-eslint-parser": "^10.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,28 @@ export default {
|
||||
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中所有文件,防止之前数据干扰
|
||||
* @returns
|
||||
|
||||
@@ -22,6 +22,17 @@ export default {
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 顶层技术依据文件
|
||||
*/
|
||||
createTopFile(params = {}) {
|
||||
return request({
|
||||
url: `/generate/create/top_file`,
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 生成联系方式
|
||||
@@ -55,17 +66,6 @@ export default {
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 生成测评大纲-被测软件功能
|
||||
*/
|
||||
createFuncList(params = {}) {
|
||||
return request({
|
||||
url: `/generate/create/funcList`,
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 生成测评大纲-测评对象的软件组成描述
|
||||
@@ -88,17 +88,6 @@ export default {
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 生成测评大纲-被测软件性能
|
||||
*/
|
||||
createPerformance(params = {}) {
|
||||
return request({
|
||||
url: `/generate/create/performance`,
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @returns 生成测评大纲-被测软件基本信息
|
||||
@@ -318,5 +307,5 @@ export default {
|
||||
method: "get",
|
||||
params
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { request } from "@/api/request"
|
||||
import { head } from "lodash-es"
|
||||
|
||||
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],
|
||||
// 如果要取消粘贴只粘贴文本,需要用户加格式请加上pastetext
|
||||
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 | \
|
||||
|
||||
@@ -10,20 +10,20 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, watch, provide } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { ref, watch, provide } from "vue"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
|
||||
import uploadConfig from '@/config/upload'
|
||||
import MaImageUpload from './components/image-upload.vue'
|
||||
import MaFileUpload from './components/file-upload.vue'
|
||||
import MaChunkUpload from './components/chunk-upload.vue'
|
||||
import uploadConfig from "@/config/upload"
|
||||
import MaImageUpload from "./components/image-upload.vue"
|
||||
import MaFileUpload from "./components/file-upload.vue"
|
||||
import MaChunkUpload from "./components/chunk-upload.vue"
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const emit = defineEmits(["update:modelValue"])
|
||||
const file = ref()
|
||||
const props = defineProps({
|
||||
modelValue: { type: [String, Number, Array], default: () => {} },
|
||||
title: { type: String, default: 'buttonText', },
|
||||
icon: { type: String, default: 'icon-plus'},
|
||||
title: { type: String, default: "buttonText" },
|
||||
icon: { type: String, default: "icon-plus" },
|
||||
rounded: { type: Boolean, default: false },
|
||||
multiple: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
@@ -33,30 +33,35 @@ const props = defineProps({
|
||||
chunkSize: { type: Number, default: 1 * 1024 * 1024 },
|
||||
limit: { type: Number, default: 0 },
|
||||
tip: { type: String, default: undefined },
|
||||
type: { type: String, default: 'image' },
|
||||
accept: { type: String, default: '*' },
|
||||
returnType: { type: String, default: 'hash' },
|
||||
fileType: { type: String, default: 'button' },
|
||||
type: { type: String, default: "image" },
|
||||
accept: { type: String, default: "*" },
|
||||
returnType: { type: String, default: "hash" },
|
||||
fileType: { type: String, default: "button" },
|
||||
showList: { type: Boolean, default: true },
|
||||
requestData: { type: Object, default: {} },
|
||||
requestData: { type: Object, default: {} }
|
||||
})
|
||||
|
||||
if (! ['id', 'url', 'hash'].includes(props.returnType)) {
|
||||
Message.error('MaUpload组件props的returnType只能为:id, url, hash 其中一个')
|
||||
console.error('MaUpload组件props的returnType只能为:id, url, hash 其中一个')
|
||||
if (!["id", "url", "hash"].includes(props.returnType)) {
|
||||
Message.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
|
||||
}, {
|
||||
deep: true, immediate: true
|
||||
})
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
provide('storageMode', uploadConfig.storageMode)
|
||||
provide('config', props)
|
||||
provide("storageMode", uploadConfig.storageMode)
|
||||
provide("config", props)
|
||||
|
||||
watch(
|
||||
() => file.value,
|
||||
vl => emit('update:modelValue', vl)
|
||||
(vl) => emit("update:modelValue", vl)
|
||||
)
|
||||
</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: "单位必选" }]
|
||||
},
|
||||
{
|
||||
title: "空行",
|
||||
dataIndex: "black_line",
|
||||
title: "总行数",
|
||||
dataIndex: "total_lines",
|
||||
formType: "input-number",
|
||||
rules: [{ required: true, message: "空行数必填" }],
|
||||
rules: [{ required: true, message: "总行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "纯注释",
|
||||
dataIndex: "comment_line",
|
||||
title: "有效行数",
|
||||
dataIndex: "effective_lines",
|
||||
formType: "input-number",
|
||||
rules: [{ required: true, message: "纯注释数必填" }],
|
||||
rules: [{ required: true, message: "有效行数必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "混合行",
|
||||
dataIndex: "mix_line",
|
||||
title: "注释行数",
|
||||
dataIndex: "comment_lines",
|
||||
formType: "input-number",
|
||||
rules: [{ required: true, message: "混合行必填" }],
|
||||
min: 0
|
||||
},
|
||||
{
|
||||
title: "纯代码",
|
||||
dataIndex: "code_line",
|
||||
formType: "input-number",
|
||||
rules: [{ required: true, message: "纯代码行必填" }],
|
||||
rules: [{ required: true, message: "注释行数必填" }],
|
||||
min: 0
|
||||
}
|
||||
])
|
||||
|
||||
@@ -31,7 +31,11 @@ export function useRightClick(projectId, routeViewRef) {
|
||||
*/
|
||||
const displayRightMenu = (e) => {
|
||||
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.复制测试项到设计需求】
|
||||
if (+level === 3) {
|
||||
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 "tw-animate-css";
|
||||
/*
|
||||
---break---
|
||||
*/
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@config '../../tailwind.config.js';
|
||||
|
||||
@@ -20,3 +25,130 @@
|
||||
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>
|
||||
<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-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">
|
||||
@@ -107,6 +109,8 @@ import verifyCode from "@cps/ma-verifyCode/index.vue"
|
||||
import { useUserStore } from "@/store"
|
||||
import { useRouter, useRoute } from "vue-router"
|
||||
import userApi from "@/api/system/user"
|
||||
// 导入背景ui组件
|
||||
import ParticlesBg from "@/components/ui/particles-bg/ParticlesBg.vue"
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
// 绑定登录form的数据
|
||||
@@ -157,7 +161,6 @@ const handleSubmit = async ({ values, errors }) => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-image: url("@/assets/BingWallpaper.jpg");
|
||||
}
|
||||
.bg-backdrop-layout {
|
||||
top: 0;
|
||||
@@ -176,13 +179,14 @@ const handleSubmit = async ({ values, errors }) => {
|
||||
z-index: 3;
|
||||
.login-width {
|
||||
max-width: 950px;
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
height: 500px;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
margin-top: -255px;
|
||||
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 {
|
||||
|
||||
@@ -10,7 +10,44 @@ export default function useOptions(formRef: any) {
|
||||
})
|
||||
const crudColumns = useColumn(formRef)
|
||||
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 }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function (crudOrFormRef: any) {
|
||||
{
|
||||
title: "名称",
|
||||
dataIndex: "name",
|
||||
width: 120,
|
||||
width: 150,
|
||||
align: "center",
|
||||
search: true,
|
||||
commonRules: [{ required: true, message: "名称是必填" }],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<a-modal
|
||||
v-model:visible="modalVisible"
|
||||
width="80%"
|
||||
title="设计需求批量写入"
|
||||
title="批量导入设计需求"
|
||||
:unmount-on-close="true"
|
||||
:mask-closable="false"
|
||||
ok-text="录入"
|
||||
@@ -11,20 +11,30 @@
|
||||
:on-before-ok="handleModalSubmit"
|
||||
>
|
||||
<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
|
||||
:style="{ marginBottom: '10px' }"
|
||||
:custom-request="handleRquest"
|
||||
:limit="1"
|
||||
accept=".docx"
|
||||
:action="`/api/dut_upload/upload_xq_docx/?parseChapter=${parseChapter}`"
|
||||
@change="handleUploadChange"
|
||||
@success="handleUploadSuccess"
|
||||
@error="handleUploadError"
|
||||
:disabled="parseChapter.trim() === ''"
|
||||
></a-upload>
|
||||
</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">
|
||||
请去除需求规格说明文件中不必要的部分再来此处解析,注意:本系统不支持word中emf格式图片,如果使用了visio等图片请<span
|
||||
class="important-text"
|
||||
>在word变为普通图片上传</span
|
||||
>
|
||||
只能上传.docx,<span class="important-text">如果有visio图请替换为普通图片上传</span
|
||||
>,请在需求规格说明文档中操作 ->
|
||||
<span class="important-text">引用 -> 目录 -> 自定义目录 -> 显示级别改为6</span>以上保存后上传
|
||||
</a-alert>
|
||||
<div class="operation-container">
|
||||
<span :style="{ marginRight: '10px', fontWeight: 700 }">操作按钮:</span>
|
||||
@@ -109,104 +119,39 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, nextTick, watch } from "vue"
|
||||
import mammoth from "mammoth"
|
||||
import { ref, watch } from "vue"
|
||||
import dictApi from "@/api/system/dict"
|
||||
import demandApi from "@/api/project/designDemand"
|
||||
import { useRoute, useRouter } from "vue-router"
|
||||
import { parseHtmlStringByDemandDut } from "@/views/project/dut/tools/parseHtmlString"
|
||||
import { HtmlParser } from "@/views/project/dut/tools/parser"
|
||||
import { useRoute } from "vue-router"
|
||||
import { useTreeDataStore } from "@/store"
|
||||
// 其他初始化数据
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const treeDataStore = useTreeDataStore()
|
||||
// ~导入editor组件~tinymce
|
||||
import MaEditor from "@/components/ma-editor/index.vue"
|
||||
import { Message } from "@arco-design/web-vue"
|
||||
// 单个设计需求录入模版
|
||||
const templateDemandObj = {
|
||||
chapter: "",
|
||||
title: "",
|
||||
ident: "",
|
||||
demandType: "",
|
||||
content: ""
|
||||
}
|
||||
// 先请求设计需求的dict,然后给demandType选项
|
||||
import useUpload from "./useUpload"
|
||||
import useListOperaton from "./useListOperation"
|
||||
// 定义录入完毕的事件,给父组件刷新表格
|
||||
const emit = defineEmits(["enterFinish"])
|
||||
// 其他初始化数据
|
||||
const route = useRoute()
|
||||
const treeDataStore = useTreeDataStore()
|
||||
// ~~~刚开始就加载字典数据,给选择框使用~~~
|
||||
let demandType = []
|
||||
const getDictDemandType = async function () {
|
||||
const res = await dictApi.getDictByCode({ code: "demandType" })
|
||||
demandType = res.data
|
||||
}
|
||||
getDictDemandType()
|
||||
// 弹窗显示
|
||||
// 弹窗显示ref
|
||||
const modalVisible = ref(false)
|
||||
// 全部html数据-循环创建折叠项
|
||||
// 全部html数据-给a-list展示
|
||||
const htmlData = ref([])
|
||||
// 数据变化spin显示
|
||||
const loading = ref(false)
|
||||
// 当upload组件发生变化时候
|
||||
const handleUploadChange = (files) => {
|
||||
files.length ? (files.length = 1) : (htmlData.value = [])
|
||||
}
|
||||
// 上传行为函数
|
||||
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)
|
||||
}
|
||||
|
||||
// ~~~~1.list~~~~
|
||||
const { loading, handleCreateAtLatest, handleResetData, handledownCreate, handlePageChange, handleDelete } =
|
||||
useListOperaton(htmlData)
|
||||
|
||||
// ~~~~2.upload~~~~
|
||||
const { handleUploadSuccess, handleUploadError, parseChapter, selectValue } = useUpload(htmlData)
|
||||
|
||||
// 打开弹窗并初始化form数据
|
||||
const open = function () {
|
||||
// 打开时候传入对象可初始化from
|
||||
@@ -234,11 +179,19 @@ const handleModalSubmit = async () => {
|
||||
})
|
||||
if (res.code === 200) {
|
||||
treeDataStore.updateDesignDemandTreeData(res.data, route.query.id)
|
||||
// 给父元素说明我已经完成了
|
||||
emit("enterFinish")
|
||||
Message.success("批量新增设计需求成功...")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 当upload组件发生变化时候-性能配置
|
||||
const handleUploadChange = (files) => {
|
||||
files.length ? (files.length = 1) : (htmlData.value = [])
|
||||
}
|
||||
|
||||
// 暴露该组件ref的方法
|
||||
defineExpose({ open })
|
||||
</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>
|
||||
</ma-crud>
|
||||
</div>
|
||||
<file-input-modal ref="fileInputRef"></file-input-modal>
|
||||
<file-input-modal ref="fileInputRef" @enterFinish="crudRef.refresh()"></file-input-modal>
|
||||
</div>
|
||||
</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: "XQ" },
|
||||
{ label: "通信协议", value: "XY" },
|
||||
{ label: "研制总要求", value: "YZ" }
|
||||
{ label: "研制总要求/技术协议等", value: "YZ" }
|
||||
]
|
||||
|
||||
export default beiceType
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ref } from "vue"
|
||||
import { ref, shallowRef } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import beiceType from "@/views/project/round/beiceType"
|
||||
// 导入自定义组件
|
||||
import UploadInput from "@/components/UploadInput/index.vue"
|
||||
|
||||
export default function (crudOrFormRef: any) {
|
||||
// global
|
||||
@@ -8,10 +10,8 @@ export default function (crudOrFormRef: any) {
|
||||
// 计算注释率计算crud/form的数据,判断
|
||||
const calcPercent = () => {
|
||||
const formData = crudOrFormRef.value.getFormData()
|
||||
const { code_line, comment_line, mix_line, black_line } = formData
|
||||
const total_line = +black_line + +code_line + +comment_line + +mix_line
|
||||
const comment_total = +comment_line + +mix_line
|
||||
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
|
||||
const { total_lines, comment_lines } = formData
|
||||
formData.comment_percent = `${(comment_lines / total_lines).toFixed(2).toString()}%`
|
||||
}
|
||||
const crudColumns = ref([
|
||||
{
|
||||
@@ -51,28 +51,24 @@ export default function (crudOrFormRef: any) {
|
||||
translation: true,
|
||||
tagColors: { XQ: "blue", SO: "green", SJ: "orangered", XY: "pinkpurple", YZ: "red" }
|
||||
},
|
||||
onControl: (value) => {
|
||||
onControl: (value: string) => {
|
||||
if (value === "SO") {
|
||||
return {
|
||||
black_line: { display: true },
|
||||
code_line: { display: true },
|
||||
mix_line: { display: true },
|
||||
comment_line: { display: true },
|
||||
total_code_line: { display: true },
|
||||
total_line: { display: true },
|
||||
total_lines: { display: true },
|
||||
effective_lines: { display: true },
|
||||
comment_lines: { display: true },
|
||||
comment_percent: { display: true },
|
||||
upload: { display: true },
|
||||
release_date: { display: false }
|
||||
}
|
||||
} else {
|
||||
// 其他数据清除
|
||||
return {
|
||||
black_line: { display: false },
|
||||
code_line: { display: false },
|
||||
mix_line: { display: false },
|
||||
comment_line: { display: false },
|
||||
total_code_line: { display: false },
|
||||
total_line: { display: false },
|
||||
total_lines: { display: false },
|
||||
effective_lines: { display: false },
|
||||
comment_lines: { display: false },
|
||||
comment_percent: { display: false },
|
||||
upload: { display: false },
|
||||
release_date: { display: true }
|
||||
}
|
||||
}
|
||||
@@ -123,49 +119,36 @@ export default function (crudOrFormRef: any) {
|
||||
formType: "date"
|
||||
},
|
||||
{
|
||||
title: "空行",
|
||||
title: "总行数",
|
||||
hide: true,
|
||||
align: "center",
|
||||
dataIndex: "black_line",
|
||||
dataIndex: "total_lines",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "空行数必填" }],
|
||||
commonRules: [{ required: true, message: "总行数必填" }],
|
||||
min: 0,
|
||||
onControl: () => {
|
||||
calcPercent()
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "纯代码行",
|
||||
title: "有效行数",
|
||||
hide: true,
|
||||
align: "center",
|
||||
dataIndex: "code_line",
|
||||
dataIndex: "effective_lines",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "纯代码行数必填" }],
|
||||
commonRules: [{ required: true, message: "有效行数必填" }],
|
||||
min: 0,
|
||||
onControl: () => {
|
||||
calcPercent()
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "纯注释行",
|
||||
title: "注释行数",
|
||||
hide: true,
|
||||
align: "center",
|
||||
dataIndex: "comment_line",
|
||||
dataIndex: "comment_lines",
|
||||
formType: "input-number",
|
||||
commonRules: [{ required: true, message: "纯注释行数必填" }],
|
||||
min: 0,
|
||||
onControl: () => {
|
||||
calcPercent()
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "混合行",
|
||||
hide: true,
|
||||
align: "center",
|
||||
dataIndex: "mix_line",
|
||||
formType: "input-number",
|
||||
help: "混合行是指:代码中一行即包含代码也包含注释",
|
||||
commonRules: [{ required: true, message: "混合行数必填" }],
|
||||
commonRules: [{ required: true, message: "注释行数必填" }],
|
||||
min: 0,
|
||||
onControl: () => {
|
||||
calcPercent()
|
||||
@@ -180,6 +163,15 @@ export default function (crudOrFormRef: any) {
|
||||
addDisabled: true,
|
||||
editDisabled: true,
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
title: "上传源代码",
|
||||
align: "center",
|
||||
dataIndex: "upload",
|
||||
placeholder: "上传源代码",
|
||||
hide: true,
|
||||
formType: "component",
|
||||
component: shallowRef(UploadInput)
|
||||
}
|
||||
])
|
||||
return crudColumns
|
||||
|
||||
@@ -10,7 +10,78 @@ export default function useOptions(formRef: any) {
|
||||
})
|
||||
const crudColumns = useColumn(formRef)
|
||||
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 }
|
||||
}
|
||||
|
||||
@@ -140,9 +140,20 @@ export default function (crudOrFormRef: any, problemFormRef?: any) {
|
||||
},
|
||||
{
|
||||
title: "执行时间",
|
||||
align: "center",
|
||||
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,
|
||||
formType: "date"
|
||||
dataIndex: "timing_diagram",
|
||||
addDefaultValue: "",
|
||||
formType: "editor"
|
||||
},
|
||||
{
|
||||
title: "测试步骤",
|
||||
|
||||
@@ -123,7 +123,7 @@ export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
|
||||
},
|
||||
{
|
||||
formType: "card",
|
||||
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
|
||||
customClass: ["ml-5", "mb-3", "py-0", "px-0"],
|
||||
title: "人员信息",
|
||||
formList: [
|
||||
{
|
||||
|
||||
@@ -32,14 +32,12 @@ const useGenerateSecond = function () {
|
||||
dgGenerateApi.createTechYiju({ id }), // 技术依据文件
|
||||
dgGenerateApi.createContact({ id }), // 生成联系人和方式
|
||||
dgGenerateApi.createTimeaddress({ id }), // 生成测评时间和地点
|
||||
dgGenerateApi.createFuncList({ id }), // 生成被测软件功能列表
|
||||
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象-软件组成
|
||||
dgGenerateApi.createAdequacyEffectiveness({ id }), // 生成测试充分性(adequancy)和有效性(effectiveness)说明
|
||||
dgGenerateApi.createGroup({ id }), // 生成测评组织及分工
|
||||
dgGenerateApi.createGuarantee({ id }), // 生成测评保障
|
||||
dgGenerateApi.createAbbreviation({ id }), // 生成缩略语
|
||||
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口
|
||||
dgGenerateApi.createPerformance({ id }), // 生成-被测软件性能
|
||||
dgGenerateApi.createBaseInformation({ id }), // 生成-被测软件基本信息
|
||||
dgGenerateApi.createLevelAndType({ id }), // 生成-测试级别和测试类型 -【修改】
|
||||
dgGenerateApi.createStrategy({ id }), // 生成-测试策略 -【新增】
|
||||
@@ -47,6 +45,8 @@ const useGenerateSecond = function () {
|
||||
dgGenerateApi.createXqComparison({ id }), // 生成-需求规格说明-测试项对照表
|
||||
dgGenerateApi.createFanXqComparison({ id }), // 生成-反向测试项-需求规格说明对照表
|
||||
dgGenerateApi.createCodeQuality({ id }), // 生成-代码质量度量分析表
|
||||
// 2025年4月29日新增 - 顶层技术文件
|
||||
dgGenerateApi.createTopFile({ id }), // 生成顶层技术文件
|
||||
// 新增拆分接口
|
||||
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
||||
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
||||
@@ -69,9 +69,7 @@ const useGenerateSecond = function () {
|
||||
isSmLoading.value = true
|
||||
await Promise.all([
|
||||
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象 - 和大纲一样
|
||||
dgGenerateApi.createFuncList({ id }), // 生成被测软件功能 - 和大纲重复
|
||||
dgGenerateApi.createInterface({ id }), // 生成被测软件接口 - 和大纲重复 - 可能会删除
|
||||
dgGenerateApi.createPerformance({ id }), // 生成被测软件性能 - 和大纲重复 - 可能会删除
|
||||
dgGenerateApi.createBaseInformation({ id }), // 生成被测软件基本信息 - 和大纲重复 - 可能会删除
|
||||
dgGenerateApi.createYiju({ id }), // 生成标准类引用文档 - 和大纲重复 - 可能会删除
|
||||
smGenerateApi.createSMTechyiju({ id }), // 生成技术类引用文档列表 -> 在大纲基础上添加《测评大纲》
|
||||
@@ -97,7 +95,12 @@ const useGenerateSecond = function () {
|
||||
const createJLItem = async (id: number) => {
|
||||
isGenerating.value = true
|
||||
isJlloading.value = true
|
||||
await jlGenerateApi.createJLcaserecord({ id }).finally(() => {
|
||||
await Promise.all([
|
||||
// 生成-被测软件基本信息 - 和大纲一样
|
||||
dgGenerateApi.createBaseInformation({ id }),
|
||||
// 记录相关片段
|
||||
jlGenerateApi.createJLcaserecord({ id })
|
||||
]).finally(() => {
|
||||
isGenerating.value = false
|
||||
isJlloading.value = false
|
||||
})
|
||||
@@ -116,7 +119,10 @@ const useGenerateSecond = function () {
|
||||
hsmGenerateApi.createCaseListDesc({ id }),
|
||||
hsmGenerateApi.createCaseList({ id }),
|
||||
hsmGenerateApi.createTrack({ id }),
|
||||
// 拆分大纲软硬件环境
|
||||
// 拆分大纲软硬件环境-大纲内容
|
||||
dgGenerateApi.createSoftComposition({ id }), // 生成测评对象-软件组成
|
||||
dgGenerateApi.createYiju({ id }), // 生成依据文件
|
||||
dgGenerateApi.createInterface({ id }), // 生成-被测软件接口 - 和大纲一样
|
||||
dgGenerateApi.createStaticEnvironment({ id }), // 生成-静态测试环境说明
|
||||
dgGenerateApi.createStaticSoft({ id }), // 生成-静态软件项
|
||||
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
||||
@@ -171,7 +177,15 @@ const useGenerateSecond = function () {
|
||||
bgGenerateApi.createBgEntire({ id }),
|
||||
bgGenerateApi.createBgYzxqTrack({ 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.createStaticSoft({ id }), // 生成-静态软件项
|
||||
dgGenerateApi.createStaticHard({ id }), // 生成-静态硬件和固件项
|
||||
@@ -179,7 +193,9 @@ const useGenerateSecond = function () {
|
||||
dgGenerateApi.createDynamicSoft({ id }), // 生成-动态软件项
|
||||
dgGenerateApi.createDynamicHard({ id }), // 生成-动态硬件和固件项
|
||||
dgGenerateApi.createTestData({ id }), // 生成-测评数据
|
||||
dgGenerateApi.createEnvDiff({ id }) // 生成-环境差异性分析
|
||||
dgGenerateApi.createEnvDiff({ id }), // 生成-环境差异性分析
|
||||
// 2025年4月29日新增 - 顶层技术文件
|
||||
dgGenerateApi.createTopFile({ id }) // 生成顶层技术文件
|
||||
]).finally(() => {
|
||||
isGenerating.value = false
|
||||
isBgLoading.value = false
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user