Michael Wang %!s(int64=3) %!d(string=hai) anos
pai
achega
3e09ef5856

+ 1 - 12
components.d.ts

@@ -5,31 +5,19 @@
 declare module 'vue' {
   export interface GlobalComponents {
     AButton: typeof import('ant-design-vue/es')['Button']
-    ACollapse: typeof import('ant-design-vue/es')['Collapse']
-    ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
     AForm: typeof import('ant-design-vue/es')['Form']
     AFormItem: typeof import('ant-design-vue/es')['FormItem']
     AInput: typeof import('ant-design-vue/es')['Input']
-    AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
     AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
     AMenu: typeof import('ant-design-vue/es')['Menu']
     AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
     AModal: typeof import('ant-design-vue/es')['Modal']
-    APopover: typeof import('ant-design-vue/es')['Popover']
-    ARadio: typeof import('ant-design-vue/es')['Radio']
-    ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
-    ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
     ASelect: typeof import('ant-design-vue/es')['Select']
     ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
     ASpin: typeof import('ant-design-vue/es')['Spin']
     ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
-    ASwitch: typeof import('ant-design-vue/es')['Switch']
     ATable: typeof import('ant-design-vue/es')['Table']
-    ATabPane: typeof import('ant-design-vue/es')['TabPane']
-    ATabs: typeof import('ant-design-vue/es')['Tabs']
     ATextarea: typeof import('ant-design-vue/es')['Textarea']
-    ATimeline: typeof import('ant-design-vue/es')['Timeline']
-    ATimelineItem: typeof import('ant-design-vue/es')['TimelineItem']
     CommonRangeConfig: typeof import('./src/components/CommonRangeConfig.vue')['default']
     CourseSelect: typeof import('./src/components/CourseSelect.vue')['default']
     CourseTypeSelect: typeof import('./src/components/CourseTypeSelect.vue')['default']
@@ -39,6 +27,7 @@ declare module 'vue' {
     PaperTypeSelect: typeof import('./src/components/PaperTypeSelect.vue')['default']
     ProjectCourseSelect: typeof import('./src/components/ProjectCourseSelect.vue')['default']
     ProjectSelect: typeof import('./src/components/ProjectSelect.vue')['default']
+    ProjectsSelect: typeof import('./src/components/ProjectsSelect.vue')['default']
     ProjectStatusSelect: typeof import('./src/components/ProjectStatusSelect.vue')['default']
     QmButton: typeof import('./src/components/QmButton.vue')['default']
     RoleSelect: typeof import('./src/components/RoleSelect.vue')['default']

+ 6 - 6
package.json

@@ -13,8 +13,8 @@
     "format": "prettier .  --write"
   },
   "dependencies": {
-    "@vueuse/core": "^7.4.0",
-    "@vueuse/router": "^7.3.0",
+    "@vueuse/core": "^7.4.1",
+    "@vueuse/router": "^7.4.1",
     "ant-design-vue": "^2.2.8",
     "axios": "^0.24.0",
     "axios-progress-bar": "^1.2.0",
@@ -39,7 +39,7 @@
     "@types/js-cookie": "^3.0.0",
     "@types/js-md5": "^0.4.3",
     "@types/lodash-es": "^4.17.5",
-    "@types/node": "^17.0.2",
+    "@types/node": "^17.0.4",
     "@types/qs": "^6.9.7",
     "@types/ua-parser-js": "^0.7.36",
     "@typescript-eslint/eslint-plugin": "^5.8.0",
@@ -53,9 +53,9 @@
     "eslint-plugin-vue": "^8.2.0",
     "postcss": "^8.4.5",
     "typescript": "^4.5.4",
-    "unplugin-vue-components": "^0.17.9",
-    "vite": "^2.7.5",
+    "unplugin-vue-components": "^0.17.10",
+    "vite": "^2.7.6",
     "vue-eslint-parser": "^8.0.1",
-    "vue-tsc": "^0.29.8"
+    "vue-tsc": "^0.30.0"
   }
 }

+ 74 - 89
pnpm-lock.yaml

@@ -5,7 +5,7 @@ specifiers:
   '@types/js-cookie': ^3.0.0
   '@types/js-md5': ^0.4.3
   '@types/lodash-es': ^4.17.5
-  '@types/node': ^17.0.2
+  '@types/node': ^17.0.4
   '@types/qs': ^6.9.7
   '@types/ua-parser-js': ^0.7.36
   '@typescript-eslint/eslint-plugin': ^5.8.0
@@ -13,8 +13,8 @@ specifiers:
   '@vitejs/plugin-vue': ^2.0.1
   '@vue/compiler-sfc': ^3.2.26
   '@vue/runtime-core': ^3.2.26
-  '@vueuse/core': ^7.4.0
-  '@vueuse/router': ^7.3.0
+  '@vueuse/core': ^7.4.1
+  '@vueuse/router': ^7.4.1
   ant-design-vue: ^2.2.8
   autoprefixer: ^10.4.0
   axios: ^0.24.0
@@ -36,17 +36,17 @@ specifiers:
   tailwindcss: ^3.0.7
   typescript: ^4.5.4
   ua-parser-js: ^1.0.2
-  unplugin-vue-components: ^0.17.9
-  vite: ^2.7.5
+  unplugin-vue-components: ^0.17.10
+  vite: ^2.7.6
   vue: ^3.2.26
   vue-echarts: ^6.0.0
   vue-eslint-parser: ^8.0.1
   vue-router: 4.0.10
-  vue-tsc: ^0.29.8
+  vue-tsc: ^0.30.0
 
 dependencies:
-  '@vueuse/core': 7.4.0_vue@3.2.26
-  '@vueuse/router': 7.3.0_vue-router@4.0.10+vue@3.2.26
+  '@vueuse/core': 7.4.1_vue@3.2.26
+  '@vueuse/router': 7.4.1_vue-router@4.0.10+vue@3.2.26
   ant-design-vue: 2.2.8_ae87cbba5ec93a01f3fe1197df446ca3
   axios: 0.24.0
   axios-progress-bar: 1.2.0_axios@0.24.0
@@ -71,12 +71,12 @@ devDependencies:
   '@types/js-cookie': 3.0.1
   '@types/js-md5': 0.4.3
   '@types/lodash-es': 4.17.5
-  '@types/node': 17.0.2
+  '@types/node': 17.0.4
   '@types/qs': 6.9.7
   '@types/ua-parser-js': 0.7.36
   '@typescript-eslint/eslint-plugin': 5.8.0_836011a006f4f5d67178564baf2b6d34
   '@typescript-eslint/parser': 5.8.0_eslint@8.5.0+typescript@4.5.4
-  '@vitejs/plugin-vue': 2.0.1_vite@2.7.5+vue@3.2.26
+  '@vitejs/plugin-vue': 2.0.1_vite@2.7.6+vue@3.2.26
   '@vue/compiler-sfc': 3.2.26
   '@vue/runtime-core': 3.2.26
   autoprefixer: 10.4.0_postcss@8.4.5
@@ -85,10 +85,10 @@ devDependencies:
   eslint-plugin-vue: 8.2.0_eslint@8.5.0
   postcss: 8.4.5
   typescript: 4.5.4
-  unplugin-vue-components: 0.17.9_vite@2.7.5+vue@3.2.26
-  vite: 2.7.5
+  unplugin-vue-components: 0.17.10_vite@2.7.6+vue@3.2.26
+  vite: 2.7.6
   vue-eslint-parser: 8.0.1_eslint@8.5.0
-  vue-tsc: 0.29.8_typescript@4.5.4
+  vue-tsc: 0.30.0_typescript@4.5.4
 
 packages:
 
@@ -271,8 +271,8 @@ packages:
   /@types/lodash/4.14.178:
     resolution: {integrity: sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==, tarball: '@types/lodash/download/@types/lodash-4.14.178.tgz'}
 
-  /@types/node/17.0.2:
-    resolution: {integrity: sha512-JepeIUPFDARgIs0zD/SKPgFsJEAF0X5/qO80llx59gOxFTboS9Amv3S+QfB7lqBId5sFXJ99BN0J6zFRvL9dDA==, tarball: '@types/node/download/@types/node-17.0.2.tgz'}
+  /@types/node/17.0.4:
+    resolution: {integrity: sha512-6xwbrW4JJiJLgF+zNypN5wr2ykM9/jHcL7rQ8fZe2vuftggjzZeRSM4OwRc6Xk8qWjwJ99qVHo/JgOGmomWRog==, tarball: '@types/node/download/@types/node-17.0.4.tgz'}
     dev: true
 
   /@types/parse-json/4.0.0:
@@ -397,26 +397,26 @@ packages:
       eslint-visitor-keys: 3.1.0
     dev: true
 
-  /@vitejs/plugin-vue/2.0.1_vite@2.7.5+vue@3.2.26:
+  /@vitejs/plugin-vue/2.0.1_vite@2.7.6+vue@3.2.26:
     resolution: {integrity: sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg==, tarball: '@vitejs/plugin-vue/download/@vitejs/plugin-vue-2.0.1.tgz'}
     engines: {node: '>=12.0.0'}
     peerDependencies:
       vite: ^2.5.10
       vue: ^3.2.25
     dependencies:
-      vite: 2.7.5
+      vite: 2.7.6
       vue: 3.2.26
     dev: true
 
-  /@volar/code-gen/0.29.8:
-    resolution: {integrity: sha512-eohLLUqPChHRPDFT5gXn4V6pr/CeTri7Ou5GI26lUvBRRAbP8p+oYfQRcbMPGeKmVkYjfVj0chsxQGx6T8PQ4Q==, tarball: '@volar/code-gen/download/@volar/code-gen-0.29.8.tgz'}
+  /@volar/code-gen/0.30.0:
+    resolution: {integrity: sha512-5Wl32LebqeGe1a30TGX8DDB28lUyBJ/jX1GazInkj6O605FomWXu/ju/0WTJH2L+wjD09ZND79iuFmTna2UXMw==, tarball: '@volar/code-gen/download/@volar/code-gen-0.30.0.tgz'}
     dependencies:
-      '@volar/shared': 0.29.8
-      '@volar/source-map': 0.29.8
+      '@volar/shared': 0.30.0
+      '@volar/source-map': 0.30.0
     dev: true
 
-  /@volar/html2pug/0.29.8:
-    resolution: {integrity: sha512-bhSNXg8A2aD3w0B+CwmHjqCAaKtj5rORbE5C/q/UdGqptJbC6STCmi30KuRTdfPhR++Xb18Hauf3s/WCmtNAPA==, tarball: '@volar/html2pug/download/@volar/html2pug-0.29.8.tgz'}
+  /@volar/html2pug/0.30.0:
+    resolution: {integrity: sha512-MchpYvwqv5V6P6l1c0fPIFhZ8ahLXCR6lWTb4ZRtvUdMFjJH0yXzkrb6U8UghzdV7Yok/nJuf2Unf4DmU+sTjw==, tarball: '@volar/html2pug/download/@volar/html2pug-0.30.0.tgz'}
     dependencies:
       domelementtype: 2.2.0
       domhandler: 4.3.0
@@ -424,33 +424,33 @@ packages:
       pug: 3.0.2
     dev: true
 
-  /@volar/shared/0.29.8:
-    resolution: {integrity: sha512-Y1NN6irkIukD+T0wf4p/dHWYL90sacN2e2lYoDXxRlvoYxwANnHgw0J0Rcp+yw58ElWRScdG7/YntEIuZWeJsw==, tarball: '@volar/shared/download/@volar/shared-0.29.8.tgz'}
+  /@volar/shared/0.30.0:
+    resolution: {integrity: sha512-zfQMIQWAbRd/u8iqKFUd/24EGEDKwr6QuKwEoXe1/UAhA8TIWBljnfm/pgMdyUzWPqnNFKeFLRHMlt8NUoDHJQ==, tarball: '@volar/shared/download/@volar/shared-0.30.0.tgz'}
     dependencies:
       upath: 2.0.1
       vscode-jsonrpc: 8.0.0-next.4
       vscode-uri: 3.0.2
     dev: true
 
-  /@volar/source-map/0.29.8:
-    resolution: {integrity: sha512-7w+UoYtnc6UQu30CgMVvx0YN4dzDgP4TIsSmUaW62AGmxU9Lxwp3Kkn/4N8efi91z8ma5Z78v/HddyJPwAC3LA==, tarball: '@volar/source-map/download/@volar/source-map-0.29.8.tgz'}
+  /@volar/source-map/0.30.0:
+    resolution: {integrity: sha512-uS/+4+pyGhcUPjKZLcUfccyqGD2iUoGRRljCW9qJKUJ+PGQh2HvjYzMzX2tBSqZ6LaRZZw8kIVidzSQdFfpK/g==, tarball: '@volar/source-map/download/@volar/source-map-0.30.0.tgz'}
     dependencies:
-      '@volar/shared': 0.29.8
+      '@volar/shared': 0.30.0
     dev: true
 
-  /@volar/transforms/0.29.8:
-    resolution: {integrity: sha512-o2hRa8CoDwYTO1Mu5KA47+1elUnYUjDaVhCvbyKlRfd8qpHea2llotArq7B6OORSL2M9DVs1IRJ5NGURBFeZ3Q==, tarball: '@volar/transforms/download/@volar/transforms-0.29.8.tgz'}
+  /@volar/transforms/0.30.0:
+    resolution: {integrity: sha512-Jnbh/lYt91bzbq7pJMkApG8laWe4+gAqMhsgi+Ulitu98fvdZKlc+qseSa2kezfUN+565pQpuMk5FPT2c1tFCQ==, tarball: '@volar/transforms/download/@volar/transforms-0.30.0.tgz'}
     dependencies:
-      '@volar/shared': 0.29.8
+      '@volar/shared': 0.30.0
       vscode-languageserver: 8.0.0-next.5
     dev: true
 
-  /@volar/vue-code-gen/0.29.8:
-    resolution: {integrity: sha512-E1e7P2oktNC/DzgDBditfla4s8+HlUlluZ+BtcLvEdbkl3QEjujkB0x1wxguWzXmpWgLIDPtrS3Jzll5cCOkTg==, tarball: '@volar/vue-code-gen/download/@volar/vue-code-gen-0.29.8.tgz'}
+  /@volar/vue-code-gen/0.30.0:
+    resolution: {integrity: sha512-PK4wMPrxzJMVrkVUYoZQvGAVLaXrmRdaeFqa02nMeGrdjjrg6XX8vAmgQ34/ZNUMV/oMWm7soQ0n7BN0Vab/iA==, tarball: '@volar/vue-code-gen/download/@volar/vue-code-gen-0.30.0.tgz'}
     dependencies:
-      '@volar/code-gen': 0.29.8
-      '@volar/shared': 0.29.8
-      '@volar/source-map': 0.29.8
+      '@volar/code-gen': 0.30.0
+      '@volar/shared': 0.30.0
+      '@volar/source-map': 0.30.0
       '@vue/compiler-core': 3.2.26
       '@vue/compiler-dom': 3.2.26
       '@vue/shared': 3.2.26
@@ -551,8 +551,8 @@ packages:
   /@vue/shared/3.2.26:
     resolution: {integrity: sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA==, tarball: '@vue/shared/download/@vue/shared-3.2.26.tgz'}
 
-  /@vueuse/core/7.4.0_vue@3.2.26:
-    resolution: {integrity: sha512-CgYouxjXOE63gMn3l9cOsgzPTEAk3yoncsSmJUxXAi/to25rCPVWB/39jXTPhWZboR43EDDMWoEhHaSoMzaldg==, tarball: '@vueuse/core/download/@vueuse/core-7.4.0.tgz'}
+  /@vueuse/core/7.4.1_vue@3.2.26:
+    resolution: {integrity: sha512-8UeLPCAieeQLXFHF1/28SIEK6ILLPb/4hp03hR+xkXF00gB/YUp0CEVcRAL9uQ8HTZa3S2T/jTISMc1ZjilM0A==, tarball: '@vueuse/core/download/@vueuse/core-7.4.1.tgz'}
     peerDependencies:
       '@vue/composition-api': ^1.1.0
       vue: ^2.6.0 || ^3.2.0
@@ -562,17 +562,17 @@ packages:
       vue:
         optional: true
     dependencies:
-      '@vueuse/shared': 7.4.0_vue@3.2.26
+      '@vueuse/shared': 7.4.1_vue@3.2.26
       vue: 3.2.26
       vue-demi: 0.12.1_vue@3.2.26
     dev: false
 
-  /@vueuse/router/7.3.0_vue-router@4.0.10+vue@3.2.26:
-    resolution: {integrity: sha512-MRGaZPVV21MZOZ759LMRWTlSaRvcKh+kGw2tGCLhxkihObcrNNLl0h3N5QtBy/+eR84tf7MO7JHCL+0PJspzQg==, tarball: '@vueuse/router/download/@vueuse/router-7.3.0.tgz'}
+  /@vueuse/router/7.4.1_vue-router@4.0.10+vue@3.2.26:
+    resolution: {integrity: sha512-XPMMSz/7r1gogZovrJbpHghIxgwLIoAV8k+sPbjr/cPoPzt3lNlxbqSBLZQucS8VsppGV6YyD3rC24Kpq48XLA==, tarball: '@vueuse/router/download/@vueuse/router-7.4.1.tgz'}
     peerDependencies:
       vue-router: '>=4.0.0-rc.1'
     dependencies:
-      '@vueuse/shared': 7.3.0_vue@3.2.26
+      '@vueuse/shared': 7.4.1_vue@3.2.26
       vue-demi: 0.12.1_vue@3.2.26
       vue-router: 4.0.10_vue@3.2.26
     transitivePeerDependencies:
@@ -580,23 +580,8 @@ packages:
       - vue
     dev: false
 
-  /@vueuse/shared/7.3.0_vue@3.2.26:
-    resolution: {integrity: sha512-vOAeI84tIXKVkzm8s/Mxbrzhj0QN6NyVc/sC6LrW0AjVNdvpD8sB1dZiDn9yh8T77WJmloCEt4zZVIppeq7I+w==, tarball: '@vueuse/shared/download/@vueuse/shared-7.3.0.tgz'}
-    peerDependencies:
-      '@vue/composition-api': ^1.1.0
-      vue: ^2.6.0 || ^3.2.0
-    peerDependenciesMeta:
-      '@vue/composition-api':
-        optional: true
-      vue:
-        optional: true
-    dependencies:
-      vue: 3.2.26
-      vue-demi: 0.12.1_vue@3.2.26
-    dev: false
-
-  /@vueuse/shared/7.4.0_vue@3.2.26:
-    resolution: {integrity: sha512-x5Jn6jUB8gS1mGnVCoNWFEpAoDkm2QwtacZTUgKMn0Ow8tlUBKIfGVOt4vn9qZB10froED/ARHEj79WKLXRieA==, tarball: '@vueuse/shared/download/@vueuse/shared-7.4.0.tgz'}
+  /@vueuse/shared/7.4.1_vue@3.2.26:
+    resolution: {integrity: sha512-Pzb7XoHIcgPwwBJ5Ow9lZb0HTDyaLDV3pgxKauPGTMN9qvEylG06kUG+VTjJXkPsRtiGu46di8XyFeMw2dongA==, tarball: '@vueuse/shared/download/@vueuse/shared-7.4.1.tgz'}
     peerDependencies:
       '@vue/composition-api': ^1.1.0
       vue: ^2.6.0 || ^3.2.0
@@ -2371,8 +2356,8 @@ packages:
     resolution: {integrity: sha1-4pdsNNv7MLFdLDALKlPqyHxXp3U=, tarball: ua-parser-js/download/ua-parser-js-1.0.2.tgz}
     dev: false
 
-  /unplugin-vue-components/0.17.9_vite@2.7.5+vue@3.2.26:
-    resolution: {integrity: sha512-SZrK3T/uEoP2g2bH+8DwBznoqlS0dI7kQvCmHmL8HmTXdM78kh5P/9SN5IwuNpfbmXoGXWJPB8Pr8Ke8zsgpmA==, tarball: unplugin-vue-components/download/unplugin-vue-components-0.17.9.tgz}
+  /unplugin-vue-components/0.17.10_vite@2.7.6+vue@3.2.26:
+    resolution: {integrity: sha512-7FXgLcDl+ZOFqezlSVPs+t4vP7hV3FhR+nOJs6IpkX7zBWHKNy1YeHSBn+By1p8vBbLLDRYDxL11KQqjrwPK3Q==, tarball: unplugin-vue-components/download/unplugin-vue-components-0.17.10.tgz}
     engines: {node: '>=14'}
     peerDependencies:
       '@babel/parser': ^7.15.8
@@ -2393,7 +2378,7 @@ packages:
       magic-string: 0.25.7
       minimatch: 3.0.4
       resolve: 1.20.0
-      unplugin: 0.2.21_vite@2.7.5
+      unplugin: 0.2.21_vite@2.7.6
       vue: 3.2.26
     transitivePeerDependencies:
       - rollup
@@ -2402,7 +2387,7 @@ packages:
       - webpack
     dev: true
 
-  /unplugin/0.2.21_vite@2.7.5:
+  /unplugin/0.2.21_vite@2.7.6:
     resolution: {integrity: sha512-IJ15/L5XbhnV7J09Zjk0FT5HEkBjkXucWAXQWRsmEtUxmmxwh23yavrmDbCF6ZPxWiVB28+wnKIHePTRRpQPbQ==, tarball: unplugin/download/unplugin-0.2.21.tgz}
     peerDependencies:
       rollup: ^2.50.0
@@ -2416,7 +2401,7 @@ packages:
       webpack:
         optional: true
     dependencies:
-      vite: 2.7.5
+      vite: 2.7.6
       webpack-virtual-modules: 0.4.3
     dev: true
 
@@ -2439,8 +2424,8 @@ packages:
     resolution: {integrity: sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=, tarball: v8-compile-cache/download/v8-compile-cache-2.3.0.tgz}
     dev: true
 
-  /vite/2.7.5:
-    resolution: {integrity: sha512-Bx8Iph9IJn6pWcErPkHKnyPABGMwK/vcdA0+V4TRC8TJFA7Zf6Xd1lRoUzsHHWUM8J+iUKKEuuNqqQUoxY3XvQ==, tarball: vite/download/vite-2.7.5.tgz}
+  /vite/2.7.6:
+    resolution: {integrity: sha512-PBNoc87rDYLtkpFU9dbVeGdbcyKzz6c34oScqivE3FEa3BhVa4ASupCzcz0eDIiSECovfLcQnLUJt9vhiEU08g==, tarball: vite/download/vite-2.7.6.tgz}
     engines: {node: '>=12.2.0'}
     hasBin: true
     peerDependencies:
@@ -2531,22 +2516,22 @@ packages:
     resolution: {integrity: sha1-mfDaC9nqfNpE5WWnTFSx8rwleEA=, tarball: vscode-nls/download/vscode-nls-5.0.0.tgz}
     dev: true
 
-  /vscode-pug-languageservice/0.29.8:
-    resolution: {integrity: sha512-QHYAzDSJLg7GOLxCZ12qsM0dAM0dPeMSS1t4kKfzLsfpErmZpFzkAIXbidVrNMdMffGZMtTuIlcpEyWHbx96Iw==, tarball: vscode-pug-languageservice/download/vscode-pug-languageservice-0.29.8.tgz}
+  /vscode-pug-languageservice/0.30.0:
+    resolution: {integrity: sha512-vSBf4ZXIUDK/COxAMkIe5wDKWNQUcdjndir/r3MoknEuC0LLE8GEH80x25yAGMXnMDhXUwL+ekCOzgb4RH6upA==, tarball: vscode-pug-languageservice/download/vscode-pug-languageservice-0.30.0.tgz}
     dependencies:
-      '@volar/code-gen': 0.29.8
-      '@volar/shared': 0.29.8
-      '@volar/source-map': 0.29.8
-      '@volar/transforms': 0.29.8
+      '@volar/code-gen': 0.30.0
+      '@volar/shared': 0.30.0
+      '@volar/source-map': 0.30.0
+      '@volar/transforms': 0.30.0
       pug-lexer: 5.0.1
       pug-parser: 6.0.0
       vscode-languageserver: 8.0.0-next.5
     dev: true
 
-  /vscode-typescript-languageservice/0.29.8:
-    resolution: {integrity: sha512-eecDqHk4WjEvy6VHQ6teHczppQ9yJO2wExCy7yu7WiFj35qbw0h4G6Erv46MvP3ClL8FggFzD7s1qM6vdqJUfw==, tarball: vscode-typescript-languageservice/download/vscode-typescript-languageservice-0.29.8.tgz}
+  /vscode-typescript-languageservice/0.30.0:
+    resolution: {integrity: sha512-Os+1yxz7+xZLeUNPS/cpiUsOxrSFIC6s79ir56W3QWd9jV/jcL1rt69Wsz8AilmQ7zSA9Cri5wqOb4VHj8IICQ==, tarball: vscode-typescript-languageservice/download/vscode-typescript-languageservice-0.30.0.tgz}
     dependencies:
-      '@volar/shared': 0.29.8
+      '@volar/shared': 0.30.0
       semver: 7.3.5
       upath: 2.0.1
       vscode-languageserver: 8.0.0-next.5
@@ -2561,15 +2546,15 @@ packages:
     resolution: {integrity: sha1-7P0dBmy470w6II3s26uajCPQVdA=, tarball: vscode-uri/download/vscode-uri-3.0.2.tgz}
     dev: true
 
-  /vscode-vue-languageservice/0.29.8:
-    resolution: {integrity: sha512-qSJdvW5ttyGUB/8uWDKgo8vnIoFnXYlBP4Z/cn54btsRn6ZMw7IJGJU1381e7p/yGvMTLeGbugD53SghbnSa6g==, tarball: vscode-vue-languageservice/download/vscode-vue-languageservice-0.29.8.tgz}
+  /vscode-vue-languageservice/0.30.0:
+    resolution: {integrity: sha512-1O7wv3nrQxRwwuFXdWcBqj+szl3Hs/FrvoP3AkUNfMuY9ZPRNvqhObekcizzOCSe1vM1bZxXPai/5NeW/6AOkA==, tarball: vscode-vue-languageservice/download/vscode-vue-languageservice-0.30.0.tgz}
     dependencies:
-      '@volar/code-gen': 0.29.8
-      '@volar/html2pug': 0.29.8
-      '@volar/shared': 0.29.8
-      '@volar/source-map': 0.29.8
-      '@volar/transforms': 0.29.8
-      '@volar/vue-code-gen': 0.29.8
+      '@volar/code-gen': 0.30.0
+      '@volar/html2pug': 0.30.0
+      '@volar/shared': 0.30.0
+      '@volar/source-map': 0.30.0
+      '@volar/transforms': 0.30.0
+      '@volar/vue-code-gen': 0.30.0
       '@vscode/emmet-helper': 2.8.2
       '@vue/reactivity': 3.2.26
       '@vue/shared': 3.2.26
@@ -2580,8 +2565,8 @@ packages:
       vscode-json-languageservice: 4.1.10
       vscode-languageserver: 8.0.0-next.5
       vscode-languageserver-textdocument: 1.0.3
-      vscode-pug-languageservice: 0.29.8
-      vscode-typescript-languageservice: 0.29.8
+      vscode-pug-languageservice: 0.30.0
+      vscode-typescript-languageservice: 0.30.0
     dev: true
 
   /vue-demi/0.11.4_vue@3.2.26:
@@ -2658,15 +2643,15 @@ packages:
       vue: 3.2.26
     dev: false
 
-  /vue-tsc/0.29.8_typescript@4.5.4:
-    resolution: {integrity: sha512-pT0wLRjvRuSmB+J4WJT6uuV9mO0KtSSXEAtaVXZQzyk5+DJdbLIQTbRce/TXSkfqt1l1WogO78RjtOJFiMCgfQ==, tarball: vue-tsc/download/vue-tsc-0.29.8.tgz}
+  /vue-tsc/0.30.0_typescript@4.5.4:
+    resolution: {integrity: sha512-gtak7jRYpoERneZIItE+UoLPjV2Ba73nTA/MUzR+Wg3JnINhP4xgke+VHesM2JVTkABmAwj3yyaiMjDP0pY9jA==, tarball: vue-tsc/download/vue-tsc-0.30.0.tgz}
     hasBin: true
     peerDependencies:
       typescript: '*'
     dependencies:
-      '@volar/shared': 0.29.8
+      '@volar/shared': 0.30.0
       typescript: 4.5.4
-      vscode-vue-languageservice: 0.29.8
+      vscode-vue-languageservice: 0.30.0
     dev: true
 
   /vue-types/3.0.2_vue@3.2.26:

+ 14 - 0
src/api/projectCompareDetailPage.ts

@@ -0,0 +1,14 @@
+import { httpApp } from "@/plugins/axiosApp";
+import { SASPaper } from "@/types";
+
+/** 试卷特征量数对比分析 */
+export function getPaperCompareList(params: {
+  contrastProjectId: number;
+  projectIds: number[];
+  courseCode: string;
+}) {
+  return httpApp.post<any, { data: SASPaper[] }>(
+    "/api/ess/contrast/paper/list",
+    params
+  );
+}

+ 7 - 1
src/components/ProjectSelect.vue

@@ -3,6 +3,7 @@
     placeholder="请选择项目"
     allowClear
     :value="valueStr"
+    :disabled="props.disabled"
     style="width: 140px"
     @change="handleChange"
   >
@@ -20,7 +21,12 @@
 import { getProjectList } from "@/api/projectManagementPage";
 import { onMounted, computed } from "vue";
 
-const props = defineProps<{ value?: null | number; projectId: number }>();
+const props =
+  defineProps<{
+    value?: null | number;
+    projectId: number;
+    disabled?: boolean;
+  }>();
 const emit = defineEmits(["update:value"]);
 
 let optionList = $ref<{ id: number; name: string }[]>([]);

+ 15 - 5
src/components/ProjectsSelect.vue

@@ -2,8 +2,10 @@
   <a-select
     placeholder="请选择项目"
     allowClear
+    :disabled="disabled"
     style="width: 140px"
     :mode="isMultiple ? 'multiple' : undefined"
+    :value="value"
     @change="handleChange"
   >
     <a-select-option
@@ -20,17 +22,25 @@
 import { getProjectList } from "@/api/projectManagementPage";
 import { onMounted, computed, onUpdated } from "vue";
 
-const props =
-  defineProps<{ value?: null | number | number[]; rootOrgId: number }>();
+// eslint-disable-next-line vue/no-setup-props-destructure
+const {
+  value = null,
+  rootOrgId = -1,
+  disabled = false,
+} = defineProps<{
+  value?: number | number[];
+  rootOrgId: number;
+  disabled?: boolean;
+}>();
 const emit = defineEmits(["update:value"]);
 
 let optionList = $ref<{ id: number; name: string }[]>([]);
 
 async function fetchData() {
-  if (!props.rootOrgId) return;
+  if (!rootOrgId) return;
   const res = await getProjectList({
     // id: props.projectId,
-    rootOrgId: props.rootOrgId,
+    rootOrgId: rootOrgId,
     pageNo: 1,
     pageSize: 100,
   });
@@ -39,7 +49,7 @@ async function fetchData() {
 onMounted(fetchData);
 onUpdated(fetchData);
 
-const isMultiple = computed(() => Array.isArray(props.value));
+const isMultiple = computed(() => Array.isArray(value));
 
 // const valueStr = computed(() => {
 //   let res: undefined | number | string = props.value ?? undefined;

+ 214 - 0
src/features/projectCompareDetail/ProjectCompareDetail.vue

@@ -0,0 +1,214 @@
+<template>
+  <div>
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl tw-mb-5">
+      <ProjectsSelect
+        v-if="rootOrgId"
+        v-model:value="projectIds"
+        disabled
+        :rootOrgId="rootOrgId"
+        placeholder="请选择分析项目"
+        style="width: 400px !important"
+      />
+      <span class="tw-mr-4"></span>
+      <ProjectsSelect
+        v-if="rootOrgId"
+        v-model:value="contrastProjectId"
+        disabled
+        :rootOrgId="rootOrgId"
+        placeholder="请选择参照项目"
+      />
+      <span class="tw-mr-4"></span>
+      <div class="tw-float-right tw-flex tw-gap-2">
+        <a-button @click="goBack">返回</a-button>
+      </div>
+    </div>
+
+    <div class="tw-bg-white tw-p-5 tw-rounded-xl">
+      <div class="tw-flex tw-flex-1 tw-gap-4 tw-pt-4">
+        <div style="flex-grow: 1; height: 300px">
+          <v-chart class="chart" :option="segementsLine" :autoresize="true" />
+        </div>
+
+        <!-- <a-button style="margin-left: -100px; margin-right: 20px"
+          >说明</a-button
+        > -->
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useMainStore } from "@/store";
+import type { SASPaper } from "@/types";
+import { message } from "ant-design-vue";
+import { onMounted, computed } from "vue";
+import { goBack } from "@/utils/utils";
+import { getPaperCompareList } from "@/api/projectCompareDetailPage";
+import type { EChartsOption } from "echarts";
+
+const store = useMainStore();
+store.currentLocation = "项目管理 / 关联分析";
+
+let rootOrgId = $ref(undefined as unknown as number);
+
+let projectIds: number[] = $ref([]);
+let contrastProjectId: number = $ref();
+
+let data = $ref<SASPaper[]>([]);
+
+async function fetchData() {
+  if (projectIds.length === 0) {
+    void message.warn("请选择对比项目");
+    return;
+  }
+  if (typeof contrastProjectId !== "number") {
+    void message.warn("请选择参照项目");
+    return;
+  }
+  const res = await getPaperCompareList({
+    projectIds,
+    contrastProjectId,
+    courseCode,
+  });
+  // console.log(res);
+  data = res.data.map((v) => {
+    v.avgScore = Math.round(v.avgScore * 100) / 100;
+    v.stdev = Math.round(v.stdev * 100) / 100;
+    v.coefficient = Math.round(v.coefficient * 100) / 100;
+    v.reliability1 = Math.round(v.reliability1 * 100) / 100;
+    v.reliability2 = Math.round(v.reliability2 * 100) / 100;
+    v.difficulty = Math.round(v.difficulty * 100) / 100;
+    return v;
+  });
+}
+
+const segementsLine = computed(() => {
+  // console.log(data, data.length);
+  if (data.length === 0) return;
+  return {
+    // color: ["#003366", "#006699"],
+    tooltip: {
+      trigger: "axis",
+      axisPointer: {
+        type: "shadow",
+      },
+    },
+    // legend: { data: [{ name: "xx" }, { name: "aa" }] },
+    // legend: {},
+    title: {
+      text: data[0].courseName + "试卷特征量数对比分析",
+      left: "50%",
+      // right: "center",
+      // right: "50%",
+      // textStyle: {
+      //   width: "100%",
+      // },
+      textAlign: "center",
+      bottom: "0px",
+    },
+    // xAxis: {
+    //   type: "category",
+    //   axisTick: {
+    //     show: false,
+    //   },
+    // },
+    // yAxis: {},
+    //     dataset: {
+    //   source: [
+    //     ["type", ...columns.map((v) => v.title)],
+    //     [data[0].projectName, ...columns.map((v) => data[0][v.dataIndex])],
+    //     [data[1].projectName, ...columns.map((v) => data[1][v.dataIndex])],
+    //   ],
+    // },
+    // series: [
+    //   {
+    //     type: "bar",
+    //     seriesLayoutBy: "row",
+    //   },
+    //   {
+    //     type: "bar",
+    //     seriesLayoutBy: "row",
+    //   },
+    // ],
+    xAxis: {
+      type: "category",
+      data: columns.map((v) => v.title),
+    },
+    yAxis: {
+      type: "value",
+    },
+    series: [
+      {
+        type: "bar",
+        stack: "x",
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+        data: columns.map((v) => data[0][v.dataIndex]),
+      },
+      {
+        type: "bar",
+        stack: "y",
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+        data: columns.map((v) => data[1][v.dataIndex]),
+      },
+      // { type: "bar", stack: "y", data: [6, 7, 8, 9, 10] },
+    ],
+  } as EChartsOption;
+});
+
+const columns = [
+  {
+    title: "满分",
+    dataIndex: "totalScore",
+  },
+  {
+    title: "最高分",
+    dataIndex: "maxScore",
+  },
+  {
+    title: "最低分",
+    dataIndex: "minScore",
+  },
+  {
+    title: "全距",
+    dataIndex: "allRange",
+  },
+  {
+    title: "平均分",
+    dataIndex: "avgScore",
+  },
+  {
+    title: "标准差",
+    dataIndex: "stdev",
+  },
+  {
+    title: "差异系数",
+    dataIndex: "coefficient",
+  },
+  {
+    title: "信度1",
+    dataIndex: "reliability1",
+  },
+  {
+    title: "信度2",
+    dataIndex: "reliability2",
+  },
+  {
+    title: "难度",
+    dataIndex: "difficulty",
+  },
+];
+
+let courseCode = $ref("");
+onMounted(() => {
+  rootOrgId = store.userInfo.rootOrgId;
+  setTimeout(() => {
+    projectIds = history.state.projectIds;
+    contrastProjectId = history.state.contrastProjectId;
+    courseCode = history.state.courseCode;
+
+    void fetchData();
+  }, 16);
+});
+</script>
+
+<style></style>

+ 21 - 21
src/features/projectCompareManagement/ProjectCompareManagement.vue

@@ -42,7 +42,7 @@
           <span>
             <a-button
               v-if="record.projectId !== contrastProjectId"
-              @click="goCompareDetail(record)"
+              @click="goCompareDetail(record.courseCode)"
               >查看详情</a-button
             >
           </span>
@@ -58,7 +58,7 @@ import router from "@/router";
 import { useMainStore } from "@/store";
 import { SASPaper } from "@/types";
 import { message } from "ant-design-vue";
-import { watch, onMounted } from "vue";
+import { watch, onMounted, toRaw } from "vue";
 
 const store = useMainStore();
 store.currentLocation = "项目管理 / 关联分析";
@@ -198,25 +198,25 @@ onMounted(() => {
 });
 
 async function goCompareDetail(courseCode: string) {
-  await router.push({
-    path: "compareDetail",
-    state: { courseCode, contrastProjectId, projectIds },
-  });
+  if (
+    !(await router.push({
+      path: "/project/projectCompareDetail",
+      // state: { courseCode, contrastProjectId, projectIds },
+    }))
+  ) {
+    history.replaceState(
+      {
+        ...history.state,
+        ...{
+          courseCode: toRaw(courseCode),
+          contrastProjectId: toRaw(contrastProjectId),
+          projectIds: toRaw(projectIds),
+        },
+      },
+      ""
+    );
+  }
 }
 </script>
 
-<style>
-.need-compute span {
-  color: red;
-  animation: 1s ease-in-out 1s infinite alternate scale_text;
-}
-
-@keyframes scale_text {
-  from {
-    transform: scale(1);
-  }
-  to {
-    transform: scale(1.1);
-  }
-}
-</style>
+<style></style>

+ 4 - 1
src/main.ts

@@ -21,18 +21,21 @@ import ECharts from "vue-echarts";
 import { use } from "echarts/core";
 
 import { CanvasRenderer } from "echarts/renderers";
-import { LineChart } from "echarts/charts";
+import { LineChart, BarChart } from "echarts/charts";
 import {
   GridComponent,
   TitleComponent,
+  TooltipComponent,
   LegendComponent,
 } from "echarts/components";
 
 use([
   CanvasRenderer,
   LineChart,
+  BarChart,
   GridComponent,
   TitleComponent,
+  TooltipComponent,
   LegendComponent,
 ]);
 

+ 7 - 0
src/router/index.ts

@@ -4,6 +4,7 @@ import Layout from "@/components/Layout.vue";
 import { getToken } from "@/auth/auth";
 import { isNil } from "lodash-es";
 import { useMainStore } from "@/store";
+// import ProjectCompareDetail from "@/features/projectCompareDetail/ProjectCompareDetail.vue";
 
 const routes = [
   { path: "/", redirect: "/login" },
@@ -85,6 +86,12 @@ const routes = [
             "@/features/projectCompareManagement/ProjectCompareManagement.vue"
           ),
       },
+      {
+        path: "projectCompareDetail",
+        component: () =>
+          import("@/features/projectCompareDetail/ProjectCompareDetail.vue"),
+        // component: ProjectCompareDetail,
+      },
     ],
     component: Layout,
   },

+ 2 - 0
src/types/index.ts

@@ -112,6 +112,7 @@ export interface Paper {
 
 // 整体分析-试卷特征量数
 export interface SASPaper {
+  [key: string]: string | number;
   allRange: number;
   avgScore: number;
   coefficient: number;
@@ -125,6 +126,7 @@ export interface SASPaper {
   paperId: number;
   paperName: string;
   paperType: string;
+  // projectName?: string;
   projectId: number;
   reliability1: number;
   reliability2: number;