双击详情完成

This commit is contained in:
2024-12-30 09:50:38 +08:00
parent 2bd0de8c17
commit 0ad404d3e8
29 changed files with 1469 additions and 1076 deletions

263
cdTMP/package-lock.json generated
View File

@@ -28,7 +28,7 @@
"vue": "^3.5.13",
"vue-clipboard3": "^2.0.0",
"vue-color-kit": "^1.0.6",
"vue-data-ui": "^2.4.50",
"vue-data-ui": "^2.4.58",
"vue-router": "^4.5.0",
"vuedraggable": "^2.24.3"
},
@@ -48,10 +48,10 @@
"less-loader": "^12.2.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"rollup-plugin-visualizer": "^5.12.0",
"rollup-plugin-visualizer": "^5.13.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"vite": "^6.0.5"
"vite": "^6.0.6"
}
},
"node_modules/@alloc/quick-lru": {
@@ -487,9 +487,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
"integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
"cpu": [
"ppc64"
],
@@ -504,9 +504,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.0.tgz",
"integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
"cpu": [
"arm"
],
@@ -521,9 +521,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz",
"integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
"cpu": [
"arm64"
],
@@ -538,9 +538,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.0.tgz",
"integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
"cpu": [
"x64"
],
@@ -555,9 +555,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz",
"integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
"cpu": [
"arm64"
],
@@ -572,9 +572,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz",
"integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
"cpu": [
"x64"
],
@@ -589,9 +589,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz",
"integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
"cpu": [
"arm64"
],
@@ -606,9 +606,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz",
"integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
"cpu": [
"x64"
],
@@ -623,9 +623,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz",
"integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
"cpu": [
"arm"
],
@@ -640,9 +640,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz",
"integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
"cpu": [
"arm64"
],
@@ -657,9 +657,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz",
"integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
"cpu": [
"ia32"
],
@@ -674,9 +674,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz",
"integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
"cpu": [
"loong64"
],
@@ -691,9 +691,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz",
"integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
"cpu": [
"mips64el"
],
@@ -708,9 +708,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz",
"integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
"cpu": [
"ppc64"
],
@@ -725,9 +725,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz",
"integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
"cpu": [
"riscv64"
],
@@ -742,9 +742,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz",
"integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
"cpu": [
"s390x"
],
@@ -759,9 +759,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
"integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
"cpu": [
"x64"
],
@@ -775,10 +775,27 @@
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz",
"integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
"cpu": [
"x64"
],
@@ -793,9 +810,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz",
"integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
"cpu": [
"arm64"
],
@@ -810,9 +827,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz",
"integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
"cpu": [
"x64"
],
@@ -827,9 +844,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz",
"integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
"cpu": [
"x64"
],
@@ -844,9 +861,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz",
"integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
"cpu": [
"arm64"
],
@@ -861,9 +878,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz",
"integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
"cpu": [
"ia32"
],
@@ -878,9 +895,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz",
"integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
"cpu": [
"x64"
],
@@ -2903,9 +2920,9 @@
"peer": true
},
"node_modules/esbuild": {
"version": "0.24.0",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.0.tgz",
"integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz",
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2916,30 +2933,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.24.0",
"@esbuild/android-arm": "0.24.0",
"@esbuild/android-arm64": "0.24.0",
"@esbuild/android-x64": "0.24.0",
"@esbuild/darwin-arm64": "0.24.0",
"@esbuild/darwin-x64": "0.24.0",
"@esbuild/freebsd-arm64": "0.24.0",
"@esbuild/freebsd-x64": "0.24.0",
"@esbuild/linux-arm": "0.24.0",
"@esbuild/linux-arm64": "0.24.0",
"@esbuild/linux-ia32": "0.24.0",
"@esbuild/linux-loong64": "0.24.0",
"@esbuild/linux-mips64el": "0.24.0",
"@esbuild/linux-ppc64": "0.24.0",
"@esbuild/linux-riscv64": "0.24.0",
"@esbuild/linux-s390x": "0.24.0",
"@esbuild/linux-x64": "0.24.0",
"@esbuild/netbsd-x64": "0.24.0",
"@esbuild/openbsd-arm64": "0.24.0",
"@esbuild/openbsd-x64": "0.24.0",
"@esbuild/sunos-x64": "0.24.0",
"@esbuild/win32-arm64": "0.24.0",
"@esbuild/win32-ia32": "0.24.0",
"@esbuild/win32-x64": "0.24.0"
"@esbuild/aix-ppc64": "0.24.2",
"@esbuild/android-arm": "0.24.2",
"@esbuild/android-arm64": "0.24.2",
"@esbuild/android-x64": "0.24.2",
"@esbuild/darwin-arm64": "0.24.2",
"@esbuild/darwin-x64": "0.24.2",
"@esbuild/freebsd-arm64": "0.24.2",
"@esbuild/freebsd-x64": "0.24.2",
"@esbuild/linux-arm": "0.24.2",
"@esbuild/linux-arm64": "0.24.2",
"@esbuild/linux-ia32": "0.24.2",
"@esbuild/linux-loong64": "0.24.2",
"@esbuild/linux-mips64el": "0.24.2",
"@esbuild/linux-ppc64": "0.24.2",
"@esbuild/linux-riscv64": "0.24.2",
"@esbuild/linux-s390x": "0.24.2",
"@esbuild/linux-x64": "0.24.2",
"@esbuild/netbsd-arm64": "0.24.2",
"@esbuild/netbsd-x64": "0.24.2",
"@esbuild/openbsd-arm64": "0.24.2",
"@esbuild/openbsd-x64": "0.24.2",
"@esbuild/sunos-x64": "0.24.2",
"@esbuild/win32-arm64": "0.24.2",
"@esbuild/win32-ia32": "0.24.2",
"@esbuild/win32-x64": "0.24.2"
}
},
"node_modules/escalade": {
@@ -5105,14 +5123,14 @@
}
},
"node_modules/rollup-plugin-visualizer": {
"version": "5.12.0",
"resolved": "https://registry.npmmirror.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz",
"integrity": "sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==",
"version": "5.13.1",
"resolved": "https://registry.npmmirror.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.13.1.tgz",
"integrity": "sha512-vMg8i6BprL8aFm9DKvL2c8AwS8324EgymYQo9o6E26wgVvwMhsJxS37aNL6ZsU7X9iAcMYwdME7gItLfG5fwJg==",
"dev": true,
"license": "MIT",
"dependencies": {
"open": "^8.4.0",
"picomatch": "^2.3.1",
"picomatch": "^4.0.2",
"source-map": "^0.7.4",
"yargs": "^17.5.1"
},
@@ -5120,17 +5138,34 @@
"rollup-plugin-visualizer": "dist/bin/cli.js"
},
"engines": {
"node": ">=14"
"node": ">=18"
},
"peerDependencies": {
"rolldown": "1.x",
"rollup": "2.x || 3.x || 4.x"
},
"peerDependenciesMeta": {
"rolldown": {
"optional": true
},
"rollup": {
"optional": true
}
}
},
"node_modules/rollup-plugin-visualizer/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/rollup-plugin-visualizer/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.7.4.tgz",
@@ -5745,13 +5780,13 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vite": {
"version": "6.0.5",
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.0.5.tgz",
"integrity": "sha512-akD5IAH/ID5imgue2DYhzsEwCi0/4VKY31uhMLEYJwPP4TiUp8pL5PIK+Wo7H8qT8JY9i+pVfPydcFPYD1EL7g==",
"version": "6.0.6",
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.0.6.tgz",
"integrity": "sha512-NSjmUuckPmDU18bHz7QZ+bTYhRR0iA72cs2QAxCqDpafJ0S6qetco0LB3WW2OxlMHS0JmAv+yZ/R3uPmMyGTjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "0.24.0",
"esbuild": "^0.24.2",
"postcss": "^8.4.49",
"rollup": "^4.23.0"
},
@@ -5855,9 +5890,9 @@
}
},
"node_modules/vue-data-ui": {
"version": "2.4.50",
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.4.50.tgz",
"integrity": "sha512-6QMApKXfLIaaYCAsWIcWrfdoHb8yv12iEEzpeNmcN8+puXEL3MzFvBzwdkItdImCJ6b1sdlR6UDGUwmmwza9Pw==",
"version": "2.4.58",
"resolved": "https://registry.npmmirror.com/vue-data-ui/-/vue-data-ui-2.4.58.tgz",
"integrity": "sha512-D3GXumRbllzqCqfJtN7DlZs04utnfL585jkHFmv0nLd8fcRzYRQ7k9D+H/lsdOsNGUWemqmuPmZuJrgXFVAUGQ==",
"license": "MIT"
},
"node_modules/vue-eslint-parser": {

View File

@@ -31,7 +31,7 @@
"vue": "^3.5.13",
"vue-clipboard3": "^2.0.0",
"vue-color-kit": "^1.0.6",
"vue-data-ui": "^2.4.50",
"vue-data-ui": "^2.4.58",
"vue-router": "^4.5.0",
"vuedraggable": "^2.24.3"
},
@@ -51,9 +51,9 @@
"less-loader": "^12.2.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"rollup-plugin-visualizer": "^5.12.0",
"rollup-plugin-visualizer": "^5.13.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"vite": "^6.0.5"
"vite": "^6.0.6"
}
}

View File

@@ -11,6 +11,18 @@ export default {
params
})
},
/**
* 请求单个case信息
* @params 传入case完整的key
* @params 项目id
*/
getCaseOne(params = {}) {
return request({
url: "/project/getCaseOne",
method: "get",
params
})
},
/**
* 添加测试用例
* @returns
@@ -76,17 +88,5 @@ export default {
method: "get",
params
})
},
/**
* 请求单个case信息
* @params 传入case完整的key
* @params 项目id
*/
getCaseOne(params = {}) {
return request({
url: "/project/getCaseOne",
method: "get",
params
})
}
}

View File

@@ -12,6 +12,17 @@ export default {
params
})
},
/**
* 查询单个设计需求
* @returns 单个设计需求数据
*/
getDesignDemandOne(params = {}) {
return request({
url: `project/getDesignOne`,
method: "get",
params
})
},
/**
* 编辑设计需求
* @returns 成功编辑或失败
@@ -51,7 +62,7 @@ export default {
*/
update(id, data = {}) {
return request({
url: "/project/designDemand/update/" + id,
url: `project/editDesignDemand/` + id,
method: "put",
data
})

View File

@@ -11,6 +11,17 @@ export default {
params
})
},
/**
* 获取单个测试项信息
* @returns 单个测试项信息
*/
getTestDemandOne(params = {}) {
return request({
url: `project/getTestDemandOne`,
method: "get",
params
})
},
/**
* 添加被测件
* @returns

View File

@@ -232,7 +232,10 @@
<!-- w2:轮次的问题单ma-crud这里要传参2个首先是请求另外一个接口然后取消是否关联字段 -->
<problem-choose ref="problemRoundRef" hasRelated="roundProblem" :title="problemTitle"></problem-choose>
<!-- 下面都是对应被测件设计需求测试项测试用例问题单的SubForm -->
<DutSubForm ref="dutSubFormRef"></DutSubForm>
<DutSubForm ref="dutSubFormRef" />
<DesignSubForm ref="designSubFormRef" />
<TestDemandSubForm ref="testDemandSubFormRef" />
<CaseSubForm ref="caseSubFormRef" />
</template>
<script setup>
@@ -250,6 +253,9 @@ import { storeToRefs } from "pinia"
import Progress from "@/views/testmanage/projmanage/cpns/progress.vue"
// 导入单独节点类型单独对应的Modal组件
import DutSubForm from "@/views/project/round/DutSubForm"
import DesignSubForm from "@/views/project/dut/DesignSubForm"
import TestDemandSubForm from "@/views/project/design-demand/DemandSubForm"
import CaseSubForm from "@/views/project/testDemand/CaseSubForm"
// hooks模块化
import useTreeDrag from "@/layout/treeHooks/treeDrag.js"
import { useRightClick } from "./treeHooks/rightClick"
@@ -296,7 +302,8 @@ const {
const { expandedKeys, toggleExpanded } = useNodeExpand()
//~~~~~~大功能:单击/双击节点逻辑~~~~~~
const { selectedKeys, pointNode, dutSubFormRef } = useNodeClick(expandedKeys)
const { selectedKeys, pointNode, dutSubFormRef, designSubFormRef, testDemandSubFormRef, caseSubFormRef } =
useNodeClick(expandedKeys)
//~~~~~~大功能动态加载a-tree节点函数~~~~~~
const { loadMore } = useLoadTreeNode()

View File

@@ -6,6 +6,9 @@ import { storeToRefs } from "pinia"
import { useRouter } from "vue-router"
// 导入组件用于类型
import type { DutSubFormInstance } from "@/views/project/round/DutSubForm"
import type { DesignSubFormInstance } from "@/views/project/dut/DesignSubForm"
import type { DemandSubFormInstance } from "@/views/project/design-demand/DemandSubForm"
import type { CaseSubFormInstance } from "@/views/project/testDemand/CaseSubForm"
export default function useNodeClick(expandedKeys: Ref<string[]>) {
// global
const route = useRoute()
@@ -21,6 +24,9 @@ export default function useNodeClick(expandedKeys: Ref<string[]>) {
const previousKey = ref<any>() // 上一次点击
// SubFormRefs
const dutSubFormRef = ref<DutSubFormInstance | null>(null)
const designSubFormRef = ref<DesignSubFormInstance | null>(null)
const testDemandSubFormRef = ref<DemandSubFormInstance | null>(null)
const caseSubFormRef = ref<CaseSubFormInstance | null>(null)
// 点击节点事件
const pointNode = (value: any, data: any) => {
// 获取处理单击不选中,双击选中的变量
@@ -47,8 +53,13 @@ export default function useNodeClick(expandedKeys: Ref<string[]>) {
dutSubFormRef.value!.open(data.node)
}
if (data.node.level == "2") {
designSubFormRef.value!.open(data.node)
}
if (data.node.level == "3") {
testDemandSubFormRef.value!.open(data.node)
}
if (data.node.level == "4") {
caseSubFormRef.value!.open(data.node)
}
count = 0
if (timerId) clearTimeout(timerId)
@@ -87,6 +98,9 @@ export default function useNodeClick(expandedKeys: Ref<string[]>) {
return {
selectedKeys,
pointNode,
dutSubFormRef
dutSubFormRef,
designSubFormRef,
testDemandSubFormRef,
caseSubFormRef
}
}

View File

@@ -0,0 +1,70 @@
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import testDemandAPI from "@/api/project/testDemand"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const DemandSubForm = defineComponent({
name: "DemandSubFormForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
testDemandAPI.update,
treeDataStore.updateTestDemandTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
const res = await testDemandAPI.getTestDemandOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
formData.value.designDemand = key.split("-")[2]
visible.value = true
} catch (e) {
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
>
{{
"inputPrepend-ident": () => <span>XQ_XX_</span>
}}
</ma-form>
)
}}
</a-modal>
)
}
})
export default DemandSubForm
// 组件类型导出
type DemandSubFormOrigin = InstanceType<typeof DemandSubForm>
export interface DemandSubFormInstance extends DemandSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumns"
// demand在这里设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,145 @@
import { ref } from "vue"
import PinYinMatch from "pinyin-match"
export default function (crudOrFormRef: any) {
const crudColumns = ref([
{
title: "ID",
align: "center",
hide: true,
dataIndex: "id",
display: false
},
{
title: "测项标识",
width: 150,
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
align: "center",
search: true,
validateTrigger: "blur",
placeholder: "请填写测试项的标识,注意标识不能重复",
commonRules: [{ required: true, message: "测试项标识必填" }],
openPrepend: true
},
{
title: "名称",
dataIndex: "name",
width: 120,
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "优先级",
dataIndex: "priority",
search: true,
formType: "radio",
align: "center",
addDefaultValue: "1",
dict: {
name: "priority",
props: { label: "title", value: "key" },
translation: true,
tagColors: { 1: "red", 2: "blue", 3: "green" }
}
},
{
title: "测试类型",
dataIndex: "testType",
search: true,
align: "center",
formType: "select",
sortable: { sortDirections: ["ascend", "descend"] },
addDefaultValue: "4",
maxLength: 200,
commonRules: [{ required: true, message: "测试类型必选" }],
dict: { name: "testType", translation: true, props: { label: "title", value: "key" } },
extra: "支持拼音搜索例如gn可以搜索出功能测试",
// 这是arco的属性所以在ma-crud和ma-form可以直接使用arco属性和事件事件+onXXX
filterOption: function (inputValue, selectedOption) {
if (inputValue) {
let matchRes = PinYinMatch.match(selectedOption.label, inputValue)
if (matchRes) {
return true
}
}
}
},
{
title: "测试手段",
align: "center",
dataIndex: "testMethod",
formType: "select",
multiple: true,
dict: { name: "testMethod", props: { label: "title", value: "key" }, translation: true }
},
{
title: "充分性要求",
hide: true,
dataIndex: "adequacy",
formType: "textarea",
maxLength: 256,
commonRules: [{ required: true, message: "充分性描述必填" }],
addDefaultValue:
"测试用例覆盖XX子项名称1、XX子项名称2、XX子项名称3子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。"
},
{
title: "测试子项",
hide: true,
dataIndex: "testContent",
commonRules: [{ required: true, message: "测试方法是必填的" }],
formType: "children-form",
formList: [
{
title: "子项名称",
dataIndex: "subName",
placeholder: "对应测试项描述标题,和测试方法的标题",
rules: [{ required: true, message: "测试子项名称必填" }],
onChange: (ev) => {
// 取出子项的对象数组
const subItemFormData = crudOrFormRef.value.getFormData().testContent
// 取出充分性条件字段字符串
const mapRes = subItemFormData.map((subItem) => subItem.subName)
crudOrFormRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join(
"、"
)}子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。`
}
},
{
title: "子项描述",
dataIndex: "subDesc",
formType: "textarea",
placeholder: "对应大纲测试项表格的测试项描述",
rules: [{ required: true, message: "测试子项描述必填" }]
},
{
title: "条件",
dataIndex: "condition",
formType: "textarea",
placeholder: "在什么环境和前置条件下"
},
{
title: "操作",
dataIndex: "operation",
formType: "textarea",
placeholder: "通过xxx操作"
},
{
title: "观察",
dataIndex: "observe",
formType: "textarea",
placeholder: "查看xxx内容"
},
{
title: "期望",
dataIndex: "expect",
formType: "textarea",
placeholder: "xxx结果正确"
}
]
}
])
return crudColumns
}

View File

@@ -0,0 +1,131 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref, getCurrentInstance } from "vue"
import testDemandApi from "@/api/project/testDemand"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
import { cloneDeep, isEqual } from "lodash-es"
// types
interface ITestContent {
subName: string
subDesc: string
}
/**
* 测试项表格的Crud-options
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// global
const treeDataStore = useTreeDataStore()
const route = useRoute() as any
// variable
const roundNumber = (route.query.key as string)!.split("-")[0]
const dutNumber = (route.query.key as string)!.split("-")[1]
const designDemandNumber = (route.query.key as string)!.split("-")[2]
// refs
const projectId = ref(route.query.id)
// 处理弹窗关闭事件:处理用户数据是否保留
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormContent: ITestContent[] | undefined = undefined
const handleBeforeCancel = () => {
if (!beforeFormContent) {
return
}
const iuEqualValue = isEqual(crudRef.value.getFormData().testContent, beforeFormContent)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
const crudOptions = ref({
api: testDemandApi.getTestDemandList,
add: { show: true, api: testDemandApi.save, text: "新增测试项" },
edit: { show: true, api: testDemandApi.update, text: "修改测试项" },
delete: { show: true, api: testDemandApi.delete },
showTools: false,
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormContent = undefined
// 2.设置标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} > 测试项-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormContent = cloneDeep(record.testContent)
// 2.处理标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} >测试项[${record.name}]-`
return true
},
afterAdd: (res: any) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterEdit: (res: any) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterDelete: (_: any, record: any) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateTestDemandTreeData(record, id)
// 清空选择
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "priority" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "testType" }] },
{ span: 12, formList: [{ dataIndex: "testMethod" }] }
]
}
]
}
})
return { projectId, crudOptions, handleBeforeCancel }
}

View File

@@ -1,280 +0,0 @@
import { ref, getCurrentInstance } from "vue"
import PinYinMatch from "pinyin-match"
import { useTreeDataStore } from "@/store"
import { useRoute } from "vue-router"
import testDemandApi from "@/api/project/testDemand"
import { isEqual, cloneDeep } from "lodash-es"
interface ITestContent {
subName: string
subDesc: string
}
/**
* 1.配置crud以及全组件使用变量
* 2.另外包含一个测试项是否保留数据的功能含一个ref以及一个事件处理函数
*/
export default function useCrudRef() {
// global
const treeDataStore = useTreeDataStore()
const route = useRoute()
// variable
const roundNumber = (route.query.key as string)!.split("-")[0]
const dutNumber = (route.query.key as string)!.split("-")[1]
const designDemandNumber = (route.query.key as string)!.split("-")[2]
// refs
const projectId = ref(route.query.id)
const crudRef = ref()
// 处理弹窗关闭事件:处理用户数据是否保留
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormContent: ITestContent[] | undefined = undefined
const handleBeforeCancel = () => {
if (!beforeFormContent) {
return
}
const iuEqualValue = isEqual(crudRef.value.getFormData().testContent, beforeFormContent)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
// 配置
// crud组件
const crudOptions = ref({
api: testDemandApi.getTestDemandList,
add: { show: true, api: testDemandApi.save, text: "新增测试项" },
edit: { show: true, api: testDemandApi.update, text: "修改测试项" },
delete: { show: true, api: testDemandApi.delete },
showTools: false,
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormContent = undefined
// 2.设置标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} > 测试项-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormContent = cloneDeep(record.testContent)
// 2.处理标识
let key_split = (route.query.key as string)!.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > ${td[round_key].children[dut_key].children[design_key].title} >测试项[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateTestDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateTestDemandTreeData(record, id)
// 清空选择
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "priority" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "testType" }] },
{ span: 12, formList: [{ dataIndex: "testMethod" }] }
]
}
]
}
})
const crudColumns = ref([
{
title: "ID",
align: "center",
hide: true,
dataIndex: "id"
},
{
title: "测项标识",
width: 150,
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
align: "center",
search: true,
validateTrigger: "blur",
placeholder: "请填写测试项的标识,注意标识不能重复",
commonRules: [{ required: true, message: "测试项标识必填" }],
openPrepend: true
},
{
title: "名称",
dataIndex: "name",
width: 120,
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "优先级",
dataIndex: "priority",
search: true,
formType: "radio",
align: "center",
addDefaultValue: "1",
dict: {
name: "priority",
props: { label: "title", value: "key" },
translation: true,
tagColors: { 1: "red", 2: "blue", 3: "green" }
}
},
{
title: "测试类型",
dataIndex: "testType",
search: true,
align: "center",
formType: "select",
sortable: { sortDirections: ["ascend", "descend"] },
addDefaultValue: "4",
maxLength: 200,
commonRules: [{ required: true, message: "测试类型必选" }],
dict: { name: "testType", translation: true, props: { label: "title", value: "key" } },
extra: "支持拼音搜索例如gn可以搜索出功能测试",
// 这是arco的属性所以在ma-crud和ma-form可以直接使用arco属性和事件事件+onXXX
filterOption: function (inputValue, selectedOption) {
if (inputValue) {
let matchRes = PinYinMatch.match(selectedOption.label, inputValue)
if (matchRes) {
return true
}
}
}
},
{
title: "测试手段",
align: "center",
dataIndex: "testMethod",
formType: "select",
multiple: true,
dict: { name: "testMethod", props: { label: "title", value: "key" }, translation: true }
},
{
title: "充分性要求",
hide: true,
dataIndex: "adequacy",
formType: "textarea",
maxLength: 256,
commonRules: [{ required: true, message: "充分性描述必填" }],
addDefaultValue:
"测试用例覆盖XX子项名称1、XX子项名称2、XX子项名称3子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。"
},
{
title: "测试子项",
hide: true,
dataIndex: "testContent",
commonRules: [{ required: true, message: "测试方法是必填的" }],
formType: "children-form",
formList: [
{
title: "子项名称",
dataIndex: "subName",
placeholder: "对应测试项描述标题,和测试方法的标题",
rules: [{ required: true, message: "测试子项名称必填" }],
onChange: (ev) => {
// 取出子项的对象数组
const subItemFormData = crudRef.value.getFormData().testContent
// 取出充分性条件字段字符串
const mapRes = subItemFormData.map((subItem) => subItem.subName)
crudRef.value.getFormData().adequacy = `测试用例覆盖${mapRes.join(
"、"
)}子项要求的全部内容。\n所有用例执行完毕对于未执行的用例说明未执行原因。`
}
},
{
title: "子项描述",
dataIndex: "subDesc",
formType: "textarea",
placeholder: "对应大纲测试项表格的测试项描述",
rules: [{ required: true, message: "测试子项描述必填" }]
},
{
title: "条件",
dataIndex: "condition",
formType: "textarea",
placeholder: "在什么环境和前置条件下"
},
{
title: "操作",
dataIndex: "operation",
formType: "textarea",
placeholder: "通过xxx操作"
},
{
title: "观察",
dataIndex: "observe",
formType: "textarea",
placeholder: "查看xxx内容"
},
{
title: "期望",
dataIndex: "expect",
formType: "textarea",
placeholder: "xxx结果正确"
}
]
}
])
return {
projectId,
crudRef,
crudOptions,
crudColumns,
handleBeforeCancel
}
}

View File

@@ -45,11 +45,14 @@
import { ref } from "vue"
import commonApi from "@/api/common"
// hooks
import useCrudRef from "./hooks/useCrudRef"
import useCrudOpMore from "./hooks/useCrudOpMore"
import useColumn from "./hooks/useColumns"
import useRalateDemand from "./hooks/useRalateDemand"
// refs
const crudRef = ref(null)
// 根据传参获取key分别为轮次、设计需求的key
const { projectId, crudRef, crudOptions, crudColumns, handleBeforeCancel } = useCrudRef()
const { projectId, crudOptions, handleBeforeCancel } = useCrudOpMore(crudRef)
const crudColumns = useColumn(crudRef)
// 关联弹窗、关联的事件处理
const { visible, relatedData, options, cascaderLoading, computedRelatedData, handleOpenRelationCSX, handleRelatedOk } =
useRalateDemand(projectId)

View File

@@ -0,0 +1,69 @@
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import designDemandAPI from "@/api/project/designDemand"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const DesignSubForm = defineComponent({
name: "DesignSubForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
designDemandAPI.update,
treeDataStore.updateDesignDemandTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
const res = await designDemandAPI.getDesignDemandOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
visible.value = true
} catch (e) {
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
>
{{
"inputPrepend-ident": () => <span>SJ-XX-</span>
}}
</ma-form>
)
}}
</a-modal>
)
}
})
export default DesignSubForm
// 组件类型导出
type DesignSubFormOrigin = InstanceType<typeof DesignSubForm>
export interface DesignSubFormInstance extends DesignSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumns"
// 设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,119 @@
import { ref } from "vue"
export default function (crudOrFormRef: any) {
const crudColumns = ref([
{
title: "ID",
align: "center",
width: 50,
hide: true,
dataIndex: "id",
commonRules: [{ required: true, message: "ID必填" }],
validateTrigger: "blur",
display: false
},
{
title: "设需标识",
align: "center",
sortable: { sortDirections: ["ascend"] },
width: 180,
dataIndex: "ident",
search: true,
validateTrigger: "blur",
placeholder: "请输入文档中设计需求的标识",
help: '若不知道则填"无"或不填',
openPrepend: true
},
{
title: "设需名称",
align: "center",
width: 200,
dataIndex: "name",
search: true,
commonRules: [{ required: true, message: "设计需求名称是必填" }],
validateTrigger: "blur"
},
{
title: "章节号",
align: "center",
width: 150,
dataIndex: "chapter",
search: true,
help: '若为隐含需求则填"/"'
},
{
title: "需求类型",
width: 150,
align: "center",
dataIndex: "demandType",
addDefaultValue: "1",
formType: "radio",
search: true,
dict: { name: "demandType", props: { label: "title", value: "key" }, translation: true },
commonRules: [{ required: true, message: "需求类型是必填" }],
validateTrigger: "blur",
// 主要为了添加“接口”的4个字段
onControl: (value) => {
if (value === "3") {
return {
source: { display: true },
to: { display: true },
type: { display: true },
protocal: { display: true }
}
} else {
return {
source: { display: false },
to: { display: false },
type: { display: false },
protocal: { display: false }
}
}
}
},
{
formType: "grid-tailwind",
customClass: [],
colNumber: 2,
cols: [
{
formList: [
{
title: "接口来源",
dataIndex: "source",
hide: true
},
{
title: "目的地",
dataIndex: "to",
hide: true
}
]
},
{
formList: [
{
title: "接口类型",
dataIndex: "type",
hide: true
},
{
title: "接口内容",
dataIndex: "protocal",
hide: true
}
]
}
]
},
{
title: "需求描述",
dataIndex: "description",
hide: true,
width: 300,
formType: "editor",
height: 300
}
])
return crudColumns
}

View File

@@ -0,0 +1,74 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref } from "vue"
import designDemandApi from "@/api/project/designDemand"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute() as any
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
const dutNumber = (route.query.key as any).split("-")[1]
// refs
const crudOptions = ref({
api: designDemandApi.getDesignDemandList,
add: { show: true, api: designDemandApi.save, text: "新增设计需求" },
edit: { show: true, api: designDemandApi.editDesignDemand, text: "编辑设计需求" },
delete: { show: true, api: designDemandApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} > 设计需求-`
return true
},
beforeOpenEdit: function (record) {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >设计需求[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDesignDemandTreeData(record, id)
// 删除后情况行选择器
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 4,
tablePagination: false,
operationColumnWidth: 250,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200
},
showTools: false
})
return crudOptions
}

View File

@@ -25,21 +25,18 @@
<script setup lang="jsx">
import { ref } from "vue"
import useCrudOptions from "@/views/project/dut/hooks/useCrudOptions"
import useColumns from "./hooks/useColumns"
import { useRoute } from "vue-router"
import designDemandApi from "@/api/project/designDemand"
import dutApi from "@/api/project/dut"
import commonApi from "@/api/common"
import { useTreeDataStore } from "@/store"
import FileInputModal from "./components/FileInputModal/index.vue"
const treeDataStore = useTreeDataStore()
const route = useRoute()
const crudRef = ref()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const projectId = ref(route.query.id)
// 5月8日修改设计需求标识就按SJ-FT-设计需求标识来
const demandTypeDict = ref([])
!(function () {
;(function () {
commonApi.getDict("demandType").then((res) => {
demandTypeDict.value = res
})
@@ -63,175 +60,8 @@ const showType = (record) => {
}
}
// crud组件
const crudOptions = ref({
api: designDemandApi.getDesignDemandList,
add: { show: true, api: designDemandApi.save, text: "新增设计需求" },
edit: { show: true, api: designDemandApi.editDesignDemand, text: "编辑设计需求" },
delete: { show: true, api: designDemandApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} > 设计需求-`
return true
},
beforeOpenEdit: function (record) {
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} > ${td[round_key].title} > ${td[round_key].children[dut_key].title} >设计需求[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDesignDemandTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDesignDemandTreeData(record, id)
// 删除后情况行选择器
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber
},
showIndex: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 4,
tablePagination: false,
operationColumnWidth: 250,
operationColumn: true,
operationColumnAlign: "center",
formOption: {
width: 1200
},
showTools: false
})
const crudColumns = ref([
{
title: "ID",
align: "center",
width: 50,
hide: true,
dataIndex: "id",
commonRules: [{ required: true, message: "ID必填" }],
validateTrigger: "blur"
},
{
title: "设需标识",
align: "center",
sortable: { sortDirections: ["ascend"] },
width: 180,
dataIndex: "ident",
search: true,
validateTrigger: "blur",
placeholder: "请输入文档中设计需求的标识",
help: '若不知道则填"无"或不填',
openPrepend: true
},
{
title: "设需名称",
align: "center",
width: 200,
dataIndex: "name",
search: true,
commonRules: [{ required: true, message: "设计需求名称是必填" }],
validateTrigger: "blur"
},
{
title: "章节号",
align: "center",
width: 150,
dataIndex: "chapter",
search: true,
help: '若为隐含需求则填"/"'
},
{
title: "需求类型",
width: 150,
align: "center",
dataIndex: "demandType",
addDefaultValue: "1",
formType: "radio",
search: true,
dict: { name: "demandType", props: { label: "title", value: "key" }, translation: true },
commonRules: [{ required: true, message: "需求类型是必填" }],
validateTrigger: "blur",
// 主要为了添加“接口”的4个字段
onControl: (value) => {
if (value === "3") {
return {
source: { display: true },
to: { display: true },
type: { display: true },
protocal: { display: true }
}
} else {
return {
source: { display: false },
to: { display: false },
type: { display: false },
protocal: { display: false }
}
}
}
},
{
formType: "grid-tailwind",
customClass: [],
colNumber: 2,
cols: [
{
formList: [
{
title: "接口来源",
dataIndex: "source",
hide: true
},
{
title: "目的地",
dataIndex: "to",
hide: true
}
]
},
{
formList: [
{
title: "接口类型",
dataIndex: "type",
hide: true
},
{
title: "接口内容",
dataIndex: "protocal",
hide: true
}
]
}
]
},
{
title: "需求描述",
dataIndex: "description",
hide: true,
width: 300,
formType: "editor",
height: 300
}
])
const crudOptions = useCrudOptions(crudRef)
const crudColumns = useColumns(crudRef)
// ~~~大功能打开ma-form-modal~~~
const fileInputRef = ref(null)
const handleAddFileInputDemand = () => {

View File

@@ -0,0 +1,42 @@
/**
* 该hook为了各个页面双击弹窗SubForm进行公共代码提取
*/
import { ref, inject } from "vue"
import { useRoute } from "vue-router"
import MaForm from "@/components/ma-form/index.vue"
import { Message } from "@arco-design/web-vue"
export default function (updateApiFunc: Function, updateTreeFunc: Function, width = "40%") {
const route = useRoute()
const project_id = route.query.id // 只能拿ID其他是null
const rightViewRef = inject("rightViewRef")
// has returns
const visible = ref(false)
const formRef = ref<InstanceType<typeof MaForm> | null>(null)
const formData = ref<any>({})
// 标题
const title = ref("")
// 异步确认按钮点击
const handleBeforeOk = async () => {
const isValidated = await formRef.value!.validateForm()
if (isValidated) {
// 失败
return false
} else {
// 成功 **变化**
const res = await updateApiFunc(formData.value.id, { project_id, ...formData.value })
updateTreeFunc(res.data, project_id) // 刷新树节点信息
!(rightViewRef as any).value.refresh()
Message.success("修改成功")
}
}
const modalOptions = {
width,
draggable: true,
"unmount-on-close": true,
"ok-text": "保存",
"cancel-text": "关闭",
"on-before-ok": handleBeforeOk
}
return { title, formData, formRef, modalOptions, project_id, visible }
}

View File

@@ -1,28 +1,21 @@
import { defineComponent, inject, ref } from "vue"
import { defineComponent } from "vue"
import { TreeNodeData } from "@arco-design/web-vue"
import { useRoute } from "vue-router"
import { Message } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import dutAPI from "@/api/project/dut"
import useOptions from "./useOptions"
import MaForm from "@/components/ma-form/index.vue"
import subFormHooks from "../../projPublicHooks/subFormHooks"
const DutSubForm = defineComponent({
name: "DutSubForm",
setup(props, { expose }) {
// globals
const route = useRoute()
const project_id = route.query.id
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const rightViewRef = inject("rightViewRef")
// refs
const visible = ref(false)
const formRef = ref<InstanceType<typeof MaForm> | null>(null)
const formData = ref<any>({})
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
dutAPI.update,
treeDataStore.updateDutTreeData
)
// hooks
const { options, columnOptions } = useOptions(formRef)
// 标题
const title = ref("被测件详情")
const { options, columnOptions } = useOptions(formRef) // **变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
@@ -30,43 +23,22 @@ const DutSubForm = defineComponent({
const key = nodeData.key
// 设置表单名称
title.value = nodeData.title!
const res = await dutAPI.getDutOne({ project_id, key })
const res = await dutAPI.getDutOne({ project_id, key }) // **API变化**
// 更新表单
formData.value = res.data
formData.value.round = key
formData.value.round = key // **属性变化**
visible.value = true
} catch (e) {
visible.value = false
}
}
// 异步确认按钮点击
const handleBeforeOk = async () => {
const isValidated = await formRef.value!.validateForm()
if (isValidated) {
// 失败
return false
} else {
// 成功
const res = await dutAPI.update(formData.value.id, { project_id, ...formData.value })
treeDataStore.updateDutTreeData(res.data, project_id) // 刷新树节点信息
!(rightViewRef as any).value.refresh()
Message.success("修改成功")
}
}
// out use
expose({ open })
// Dom
return () => (
<a-modal
v-model:visible={visible.value}
width={"40%"}
draggable
unmount-on-close
ok-text="保存"
cancel-text="关闭"
on-before-ok={handleBeforeOk}
>
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (

View File

@@ -1,13 +1,13 @@
import { ref, computed } from "vue"
import useCrudRef from "@/views/project/round/hooks/useCrudRef"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumn"
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const { crudColumns } = useCrudRef(undefined, formRef)
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})

View File

@@ -1,91 +1,18 @@
import { ref } from "vue"
import dutApi from "@/api/project/dut"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
import beiceType from "@/views/project/round/beiceType"
/**
* Ref返回其options和columnOptions
* @param crudRef crud组件的Refundefined
* @param formRef ma-form组件Ref
* @returns
*/
export default function useCrudRef(crudRef?, formRef?) {
// globals
export default function (crudOrFormRef: any) {
// global
const route = useRoute()
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
// 计算注释率计算crud/form的数据判断
const calcPercent = () => {
if (crudRef) {
const formData = crudRef.value.getFormData()
const total_line = +formData.black_line + +formData.code_line + +formData.comment_line + +formData.mix_line
const comment_total = +formData.comment_line + +formData.mix_line
formData.comment_percent = `${(comment_total / total_line).toFixed(2).toString()}%`
} else if (formRef) {
const formData = formRef.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 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()}%`
}
// refs
const crudOptions = ref({
api: dutApi.getDutList,
add: { show: true, api: dutApi.save, text: "新增被测件" },
edit: { show: true, api: dutApi.update, text: "编辑被测件" },
delete: { show: true, api: dutApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件-`
return true
},
beforeOpenEdit: function (record) {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDutTreeData(record, id)
// 清空行选择器
crudRef.value.tableRef.selectAll(false)
},
// 新增、编辑、删除均携带下面
parameters: {
projectId: route.query.id,
round: roundNumber
},
operationWidth: 500,
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200, // 操作列宽度
operationColumn: true,
operationColumnAlign: "center",
formOption: {
viewType: "drawer",
width: 600,
mask: false
}
})
const crudColumns = ref([
{
title: "ID",
@@ -251,11 +178,9 @@ export default function useCrudRef(crudRef?, formRef?) {
placeholder: "计算注释率",
hide: true,
addDisabled: true,
editDisabled: true
editDisabled: true,
disabled: true
}
])
return {
crudOptions,
crudColumns
}
return crudColumns
}

View File

@@ -0,0 +1,71 @@
import MaCrud from "@/components/ma-crud/index.vue"
import { type Ref, ref } from "vue"
import dutApi from "@/api/project/dut"
import { useRoute } from "vue-router"
import { useTreeDataStore } from "@/store"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute()
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = (route.query.key as any).split("-")[0]
// refs
const crudOptions = {
api: dutApi.getDutList,
add: { show: true, api: dutApi.save, text: "新增被测件" },
edit: { show: true, api: dutApi.update, text: "编辑被测件" },
delete: { show: true, api: dutApi.delete },
// 处理添加后函数
beforeOpenAdd: function () {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件-`
return true
},
beforeOpenEdit: function (record) {
let round_str = parseInt(route.query.key as any) + 1
crudRef.value.crudFormRef.actionTitle = `${route.query.ident}>第${round_str}轮>被测件[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateDutTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateDutTreeData(record, id)
// 清空行选择器
crudRef.value.tableRef.selectAll(false)
},
// 新增、编辑、删除均携带下面
parameters: {
projectId: route.query.id,
round: roundNumber
},
operationWidth: 500,
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 200, // 操作列宽度
operationColumn: true,
operationColumnAlign: "center",
formOption: {
viewType: "drawer",
width: 600,
mask: false
}
}
return crudOptions
}

View File

@@ -12,10 +12,12 @@
<script setup lang="jsx">
import { ref } from "vue"
import useCrudRef from "@/views/project/round/hooks/useCrudRef"
import useCrudOptions from "@/views/project/round/hooks/useCrudOptions"
import useColumn from "@/views/project/round/hooks/useColumn"
const crudRef = ref()
// crud组件
const { crudOptions, crudColumns } = useCrudRef(crudRef)
const crudOptions = useCrudOptions(crudRef)
const crudColumns = useColumn(crudRef)
const refreshCrudTable = () => {
crudRef.value.refresh()

View File

@@ -0,0 +1,69 @@
import { defineComponent } from "vue"
import { Message, TreeNodeData } from "@arco-design/web-vue"
import { useTreeDataStore } from "@/store"
import caseApi from "@/api/project/case"
import useOptions from "./useOptions"
import subFormHooks from "@/views/project/projPublicHooks/subFormHooks"
const CaseSubForm = defineComponent({
name: "DemandSubFormForm",
setup(_, { expose }) {
// hook variable
const treeDataStore = useTreeDataStore()
const { title, formData, formRef, modalOptions, project_id, visible } = subFormHooks(
caseApi.update,
treeDataStore.updateCaseTreeData,
"80%"
)
// hooks
const { options, columnOptions } = useOptions(formRef) // **option里面变化**
// 双击打开回调
const open = async (nodeData: TreeNodeData) => {
// 请求数据
try {
const key = nodeData.key as string
// 设置表单名称
title.value = nodeData.title!
// 注意这里因为case接口原因这里需要projectId!!!!!!!!!!!!!!!
const res = await caseApi.getCaseOne({ projectId: project_id, key }) // **API变化**
// 更新表单
formData.value = res.data // **属性变化**
formData.value.round = key.split("-")[0]
formData.value.dut = key.split("-")[1]
formData.value.designDemand = key.split("-")[2]
formData.value.testDemand = key.split("-")[3]
visible.value = true
} catch (e) {
Message.error("数据未获取到,请联系开发者")
visible.value = false
}
}
// out use
expose({ open })
// Dom
return () => (
// 注意v-model:visible是不能放在对象解构的
<a-modal {...modalOptions} v-model:visible={visible.value}>
{{
title: () => <span>[]-{title.value}</span>,
default: () => (
<ma-form
ref={formRef}
v-model={formData.value}
options={options.value}
columns={columnOptions.value}
></ma-form>
)
}}
</a-modal>
)
}
})
export default CaseSubForm
// 组件类型导出
type CaseSubFormOrigin = InstanceType<typeof CaseSubForm>
export interface CaseSubFormInstance extends CaseSubFormOrigin {
open(nodeData: TreeNodeData): void
}

View File

@@ -0,0 +1,16 @@
import { ref, computed } from "vue"
import tool from "@/utils/tool"
import useColumn from "../hooks/useColumn"
// Case用例在这里设置不同ma-form选项
export default function useOptions(formRef: any) {
const options = ref({
showButtons: false,
labelAlign: "center"
})
const crudColumns = useColumn(formRef)
const columnOptions = computed(() => {
return tool.renameKeyInArray(crudColumns.value, "commonRules", "rules")
})
return { options, columnOptions }
}

View File

@@ -0,0 +1,213 @@
import { ref } from "vue"
import { useRoute } from "vue-router"
export default function (crudOrFormRef: any, problemFormRef?: any) {
const title = ref("问题单表单")
const route = useRoute()
const crudColumns = ref([
{
title: "ID",
width: 60,
align: "center",
hide: true,
dataIndex: "id",
fixed: "left",
display: false
},
{
title: "用例标识",
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
width: 180,
align: "center",
addDisabled: true,
addDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDisabled: true,
search: true,
validateTrigger: "blur"
},
{
title: "名称",
dataIndex: "name",
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "是否通过",
align: "center",
display: false,
addDisplay: false,
editDisplay: false,
customRender: ({ record }) => {
let passCount = 0
let failCount = 0
let stepCount = record.testStep.length
record.testStep.forEach((item) => {
if (item.passed === "1") {
passCount++
} else if (item.passed === "2") {
failCount++
}
})
if (failCount > 0) {
return (
<a-tag bordered color="red">
</a-tag>
)
} else {
if (passCount === stepCount) {
return (
<a-tag bordered color="green">
</a-tag>
)
} else {
return (
<a-tag bordered color="orange">
</a-tag>
)
}
}
}
},
{
title: "设计人员",
width: 80,
dataIndex: "designPerson",
align: "center",
hide: true,
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "执行人员",
dataIndex: "testPerson",
width: 120,
align: "center",
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "审核人员",
dataIndex: "monitorPerson",
width: 80,
align: "center",
hide: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "用例综述",
align: "center",
dataIndex: "summarize",
hide: true,
search: true,
addDefaultValue: ""
},
{
title: "用例初始化",
dataIndex: "initialization",
hide: true,
addDefaultValue: "软件正常启动,正常登录进软件"
},
{
title: "前提和约束",
dataIndex: "premise",
hide: true,
addDefaultValue: "软件正常启动,各界面显示工作正常"
},
{
title: "执行时间",
dataIndex: "exe_time",
hide: true,
formType: "date"
},
{
title: "测试步骤",
dataIndex: "testStep",
hide: true,
addDefaultValue: [
{
operation: "",
expect: "",
result: "",
passed: "3"
}
],
formType: "children-form",
type: "group",
formList: [
{
title: "操作",
dataIndex: "operation",
formType: "editor",
height: 180
},
{
title: "预期",
placeholder: "请输入预期结果",
dataIndex: "expect"
},
{
title: "结果",
dataIndex: "result",
formType: "editor",
height: 180
},
{
title: "是否通过",
dataIndex: "passed",
formType: "radio",
dict: { name: "passType", props: { label: "title", value: "key" } },
commonRules: [{ required: true, message: "是否通过必填" }]
}
]
},
{
title: "关联问题",
dataIndex: "problem",
width: 150,
addDisplay: false,
editDisplay: false,
align: "center",
display: false,
customRender: ({ record }) => {
if (record.problem) {
return (
<a-link
onClick={() => {
title.value = `PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`
problemFormRef.value.open(record.problem)
}}
>{`PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`}</a-link>
)
} else {
return "无问题单"
}
}
}
])
return crudColumns
}

View File

@@ -0,0 +1,159 @@
import { ref, getCurrentInstance, type Ref } from "vue"
import MaCrud from "@/components/ma-crud/index.vue"
import { useRoute } from "vue-router"
import caseApi from "@/api/project/case"
import { useTreeDataStore } from "@/store"
import { isEqual, cloneDeep } from "lodash-es"
/**
* Dut被测件的crud选项
*/
export default function (crudRef: Ref<InstanceType<typeof MaCrud>>) {
// globals
const route = useRoute() as any
const projectId = ref(route.query.id)
const treeDataStore = useTreeDataStore()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const designDemandNumber = route.query.key.split("-")[2]
const testDemandNumber = route.query.key.split("-")[3]
// 辅助
const app = getCurrentInstance()!.appContext.config.globalProperties
let beforeFormStep = undefined
// 注意只保留测试步骤!!!
const handleBeforeCancel = () => {
if (!beforeFormStep) {
return
}
crudRef.value.getFormData().testStep
const iuEqualValue = isEqual(crudRef.value.getFormData().testStep, beforeFormStep)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
// refs
const crudOptions = ref({
api: caseApi.getCaseList,
add: { show: true, api: caseApi.save, text: "新增用例" },
edit: { show: true, api: caseApi.update, text: "修改用例" },
delete: { show: true, api: caseApi.delete },
operationColumnAlign: "center",
isDbClickEdit: true, // 关闭双击编辑
// 处理新增删除后树状图显示
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormStep = undefined
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].children[test_key].title} > 用例-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormStep = cloneDeep(record.testStep)
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${(td[round_key] as any).title} > ${(td[round_key] as any).children[dut_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].title} >
${(td[round_key] as any).children[dut_key].children[design_key].children[test_key].title}
>用例[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateCaseTreeData(record, id)
// 被删除还是在选择里面
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber,
testDemand: testDemandNumber
},
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 180,
operationColumn: true,
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "card",
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
title: "人员信息",
formList: [
{
formType: "grid",
cols: [
{ span: 8, formList: [{ dataIndex: "designPerson" }] },
{ span: 8, formList: [{ dataIndex: "testPerson" }] },
{ span: 8, formList: [{ dataIndex: "monitorPerson" }] }
]
}
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "summarize" }] }]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "initialization" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "premise" }] },
{ span: 12, formList: [{ dataIndex: "exe_time" }] }
]
}
]
}
})
return { handleBeforeCancel, crudOptions }
}

View File

@@ -13,369 +13,22 @@
</template>
<script setup lang="jsx">
import { ref, getCurrentInstance } from "vue"
import { useRoute } from "vue-router"
import caseApi from "@/api/project/case"
import { useTreeDataStore } from "@/store"
import { ref } from "vue"
import ProblemForm from "@/views/project/case/components/ProblemForm.vue"
import { isEqual, cloneDeep } from "lodash-es"
import useCrudOpMore from "./hooks/useCrudOpMore"
import useColumn from "./hooks/useColumn"
const problemFormRef = ref(null)
const title = ref("问题单表单")
const treeDataStore = useTreeDataStore()
const route = useRoute()
const roundNumber = route.query.key.split("-")[0]
const dutNumber = route.query.key.split("-")[1]
const designDemandNumber = route.query.key.split("-")[2]
const testDemandNumber = route.query.key.split("-")[3]
const crudRef = ref()
const projectId = ref(route.query.id)
// 标识显示字段-用例比较特殊让后端返回了“FT”字样因为FT是在测试项里面标识的
// 标识重新定义
const showType = (record) => {
let key_string = parseInt(record.key.substring(record.key.lastIndexOf("-") + 1)) + 1
return "YL-" + record.testType + "-" + record.ident + "-" + key_string.toString().padStart(3, "0")
}
// crud设置以及是否保留step数据事件函数
const app = getCurrentInstance().appContext.config.globalProperties
let beforeFormStep = undefined
// 注意只保留测试步骤!!!
const handleBeforeCancel = () => {
if (!beforeFormStep) {
return
}
crudRef.value.getFormData().testStep
const iuEqualValue = isEqual(crudRef.value.getFormData().testStep, beforeFormStep)
!iuEqualValue &&
app.$modal.confirm({
title: "测试项步骤内容你已改动,是否保留您编写的测试项/测试用例步骤数据?",
content: "",
okText: "保留",
cancelText: "恢复原数据",
simple: true,
onOk: () => null,
onCancel: () => {
crudRef.value.refresh()
}
})
}
const crudOptions = ref({
api: caseApi.getCaseList,
add: { show: true, api: caseApi.save, text: "新增用例" },
edit: { show: true, api: caseApi.update, text: "修改用例" },
delete: { show: true, api: caseApi.delete },
operationColumnAlign: "center",
isDbClickEdit: true, // 关闭双击编辑
// 处理新增删除后树状图显示
beforeOpenAdd: function () {
// 1.新增则将form的content数据变为undifined以便判断
beforeFormStep = undefined
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${td[round_key].title} > ${td[round_key].children[dut_key].title} >
${td[round_key].children[dut_key].children[design_key].title} >
${td[round_key].children[dut_key].children[design_key].children[test_key].title} > 用例-`
return true
},
beforeOpenEdit: function (record) {
// 1.储存打开前form的content数据到ref中以便后续比较
beforeFormStep = cloneDeep(record.testStep)
// 2.标识处理
let key_split = route.query.key.split("-")
let round_key = key_split[0]
let dut_key = key_split[1]
let design_key = key_split[2]
let test_key = key_split[3]
let td = treeDataStore.treeData
crudRef.value.crudFormRef.actionTitle = `${route.query.ident} >
${td[round_key].title} > ${td[round_key].children[dut_key].title} >
${td[round_key].children[dut_key].children[design_key].title} >
${td[round_key].children[dut_key].children[design_key].children[test_key].title}
>用例[${record.name}]-`
return true
},
afterAdd: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterEdit: (res) => {
let id = projectId.value
treeDataStore.updateCaseTreeData(res.data, id)
},
afterDelete: (res, record) => {
let id = projectId.value
if (!record) {
record = { key: route.query.key + "-X" }
}
treeDataStore.updateCaseTreeData(record, id)
// 被删除还是在选择里面
crudRef.value.tableRef.selectAll(false)
},
parameters: {
projectId: route.query.id,
round: roundNumber,
dut: dutNumber,
designDemand: designDemandNumber,
testDemand: testDemandNumber
},
showIndex: false,
showTools: false,
rowSelection: { showCheckedAll: true },
searchColNumber: 3,
tablePagination: false,
operationColumnWidth: 180,
operationColumn: true,
formOption: {
width: 1200,
layout: [
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "ident" }] },
{ span: 12, formList: [{ dataIndex: "name" }] }
]
},
{
formType: "card",
customClass: ["ml-10", "mb-3", "py-0", "px-0"],
title: "人员信息",
formList: [
{
formType: "grid",
cols: [
{ span: 8, formList: [{ dataIndex: "designPerson" }] },
{ span: 8, formList: [{ dataIndex: "testPerson" }] },
{ span: 8, formList: [{ dataIndex: "monitorPerson" }] }
]
}
]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "summarize" }] }]
},
{
formType: "grid",
cols: [{ span: 24, formList: [{ dataIndex: "initialization" }] }]
},
{
formType: "grid",
cols: [
{ span: 12, formList: [{ dataIndex: "premise" }] },
{ span: 12, formList: [{ dataIndex: "exe_time" }] }
]
}
]
}
})
const crudColumns = ref([
{
title: "ID",
width: 60,
align: "center",
hide: true,
dataIndex: "id",
fixed: "left"
},
{
title: "用例标识",
dataIndex: "ident",
sortable: { sortDirections: ["ascend"] },
width: 180,
align: "center",
addDisabled: true,
addDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDefaultValue: "用例标识自动生成结构为YL_IO_XXXX_001",
editDisabled: true,
search: true,
validateTrigger: "blur"
},
{
title: "名称",
dataIndex: "name",
align: "center",
search: true,
commonRules: [{ required: true, message: "名称是必填" }],
validateTrigger: "blur"
},
{
title: "是否通过",
align: "center",
display: false,
addDisplay: false,
editDisplay: false,
customRender: ({ record }) => {
let passCount = 0
let failCount = 0
let stepCount = record.testStep.length
record.testStep.forEach((item) => {
if (item.passed === "1") {
passCount++
} else if (item.passed === "2") {
failCount++
}
})
if (failCount > 0) {
return (
<a-tag bordered color="red">
未通过
</a-tag>
)
} else {
if (passCount === stepCount) {
return (
<a-tag bordered color="green">
已通过
</a-tag>
)
} else {
return (
<a-tag bordered color="orange">
包含未执行
</a-tag>
)
}
}
}
},
{
title: "设计人员",
width: 80,
dataIndex: "designPerson",
align: "center",
hide: true,
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "执行人员",
dataIndex: "testPerson",
width: 120,
align: "center",
search: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "审核人员",
dataIndex: "monitorPerson",
width: 80,
align: "center",
hide: true,
formType: "select",
dict: {
url: "system/user/list",
params: { project_id: route.query.id },
translation: true,
props: { label: "name", value: "name" }
}
},
{
title: "用例综述",
align: "center",
dataIndex: "summarize",
hide: true,
search: true,
addDefaultValue: ""
},
{
title: "用例初始化",
dataIndex: "initialization",
hide: true,
addDefaultValue: "软件正常启动,正常登录进软件"
},
{
title: "前提和约束",
dataIndex: "premise",
hide: true,
addDefaultValue: "软件正常启动,各界面显示工作正常"
},
{
title: "执行时间",
dataIndex: "exe_time",
hide: true,
formType: "date"
},
{
title: "测试步骤",
dataIndex: "testStep",
hide: true,
addDefaultValue: [
{
operation: "",
expect: "",
result: "",
passed: "3"
}
],
formType: "children-form",
type: "group",
formList: [
{
title: "操作",
dataIndex: "operation",
formType: "editor",
height: 180
},
{
title: "预期",
placeholder: "请输入预期结果",
dataIndex: "expect"
},
{
title: "结果",
dataIndex: "result",
formType: "editor",
height: 180
},
{
title: "是否通过",
dataIndex: "passed",
formType: "radio",
dict: { name: "passType", props: { label: "title", value: "key" } },
commonRules: [{ required: true, message: "是否通过必填" }]
}
]
},
{
title: "关联问题",
dataIndex: "problem",
width: 150,
addDisplay: false,
editDisplay: false,
align: "center",
customRender: ({ record }) => {
if (record.problem) {
return (
<a-link
onClick={() => {
title.value = `PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`
problemFormRef.value.open(record.problem)
}}
>{`PT_${route.query.ident}_${record.problem.ident.padStart(3, 0)}`}</a-link>
)
} else {
return "无问题单"
}
}
}
])
const { handleBeforeCancel, crudOptions } = useCrudOpMore(crudRef)
const crudColumns = useColumn(crudRef, problemFormRef)
// 暴露刷新表格方法给外部
const refreshCrudTable = () => {
crudRef.value.refresh()