diff --git a/package.json b/package.json
index fc269a2..6d4f39f 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,7 @@
"konva": "^9.3.22",
"pinia": "2.0.36",
"pinia-plugin-persistedstate": "3.2.1",
+ "uni-echarts": "^2.0.0",
"vue": "3.4.21",
"vue-draggable-plus": "^0.6.0",
"wot-design-uni": "^1.9.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 24e6572..7bd58a9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -89,6 +89,9 @@ importers:
pinia-plugin-persistedstate:
specifier: 3.2.1
version: 3.2.1(pinia@2.0.36(typescript@5.9.2)(vue@3.4.21(typescript@5.9.2)))
+ uni-echarts:
+ specifier: ^2.0.0
+ version: 2.0.0(echarts@6.0.0)(vue@3.4.21(typescript@5.9.2))
vue:
specifier: 3.4.21
version: 3.4.21(typescript@5.9.2)
@@ -1148,12 +1151,21 @@ packages:
'@emnapi/core@1.4.5':
resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==}
+ '@emnapi/core@1.5.0':
+ resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==}
+
'@emnapi/runtime@1.4.5':
resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==}
+ '@emnapi/runtime@1.5.0':
+ resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
+
'@emnapi/wasi-threads@1.0.4':
resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==}
+ '@emnapi/wasi-threads@1.1.0':
+ resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+
'@es-joy/jsdoccomment@0.50.2':
resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==}
engines: {node: '>=18'}
@@ -1979,6 +1991,9 @@ packages:
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
+ '@napi-rs/wasm-runtime@1.0.6':
+ resolution: {integrity: sha512-DXj75ewm11LIWUk198QSKUTxjyRjsBwk09MuMk5DGK+GDUtyPhhEHOGP/Xwwj3DjQXXkivoBirmOnKrLfc0+9g==}
+
'@node-rs/xxhash-android-arm-eabi@1.7.6':
resolution: {integrity: sha512-ptmfpFZ8SgTef58Us+0HsZ9BKhyX/gZYbhLkuzPt7qUoMqMSJK85NC7LEgzDgjUiG+S5GahEEQ9/tfh9BVvKhw==}
engines: {node: '>= 12'}
@@ -2082,6 +2097,104 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
+ '@oxc-parser/binding-android-arm64@0.93.0':
+ resolution: {integrity: sha512-hTxegqGaVA5py2XCNV3Ry6e0tJNl32ZlB5TNOL9YuxvzTY3y3ySJovhufaubtOr/qW/FYmA5l+UC78gbtRTLEw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-parser/binding-darwin-arm64@0.93.0':
+ resolution: {integrity: sha512-8Er+e4+0BX3hc+Ajuq/60p4qA4/dW8XGUdbE1LBEwx6z1anKv4lAc/J2GfPWLUAhJLZIaM/waGBSxhoWDrZD9A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-parser/binding-darwin-x64@0.93.0':
+ resolution: {integrity: sha512-pRLB9uEgTj/P4eNrQlKJX6Ey5pelhaQnywdF4uIFPWLVGjRoS8IEuRVE9+FxUjnikXBIJceDgtRd16/EArgAKQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-parser/binding-freebsd-x64@0.93.0':
+ resolution: {integrity: sha512-aH2kMXL+60rhBbHYWU5cICo6HufTAWs1/8Ztu0nI4rr0Facp/mK2Ft6pGeuDxCJeKGyYIC21GIxVA7BHrGk9TQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.93.0':
+ resolution: {integrity: sha512-vk1nZchv1hH2yf6hE5Nbs8DliRGEoDtAwonxpz/yBaAvUsKFZHHwx0hXdJdWr+8EfSfgbWfk4YT6rUadz9N7hQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.93.0':
+ resolution: {integrity: sha512-xDrvQ23KUGWi7hPfGrFTrGLiwSeb9W1IEVpMPsRKmlvLP+zJS9Ht+RaPaLJwwQgdlNYI9f05oE6opAH5sw7MTQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.93.0':
+ resolution: {integrity: sha512-NoB7BJmwVGrcS/J5XXn362lBsIyeTqZF70rCFij3/XwQ2kcELfGMALY9AUulFYauLTY2AG4vcmctJQxn9Lj85g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-arm64-musl@0.93.0':
+ resolution: {integrity: sha512-s+nraJJR9SuHsgsr42nbOBpAsaSAE6MhK7HGbz01svLJzDsk3Ylh9cbVUPLaS3gOlTq5WC6VjPBkQuInLo0hvQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.93.0':
+ resolution: {integrity: sha512-oNIQb/7HGxVNeVgtkoqNcDS1hjfxArLDuMI72V+Slp67yfBdxgvfmM2JSWE7kGR5gyiZQeTjRbG89VrRwPDtww==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.93.0':
+ resolution: {integrity: sha512-YyzhzAoq5WpRtAGOngpJUu+4jKagSbknORejmpeW48vu8/+XjrVZFc/1Qe4i72EsPzLorDwCxWVkU8VftpM4iA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-gnu@0.93.0':
+ resolution: {integrity: sha512-UMXsE6c0MIlvtqDe5t5K8qwC6HqNb3wmy8zKxONo42dIx0WAhVV9ydG2Xlznt1/RhD6nLLtHVaq4yWJXRjUxcg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-musl@0.93.0':
+ resolution: {integrity: sha512-0Vd0yFUq129VW+Cpcj/gJOqub4EMN5hUWnVk8UfAvUZ+lxZBFeXbYNI5483SLwzvw5umzlMmkKpYWw5OTwYFaA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-wasm32-wasi@0.93.0':
+ resolution: {integrity: sha512-EXyCyY4GJO+SNTQJPPmJJwYbPkPOzw2nxSRMmUlwG19WKO7QHzHyL6u+4hXpp5IwgIWvgQgoix2/pB9JF+EA7w==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.93.0':
+ resolution: {integrity: sha512-LiWj6Yp91YnN8QptfP/+s2nfvQrbYXuaU53w9Pkyceimx0msQboddW3Dud4fbbmp3xzvNkw13+bMkGz5BLHO1w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-parser/binding-win32-x64-msvc@0.93.0':
+ resolution: {integrity: sha512-e3XD808kQLxvTD1x4xJ4p73x9idhHtSgtgcXjgo3L4hgvoRSwT1+Mu9ddZ9BLuV4wo49tmKZpp2exfxhZx1vhQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@oxc-project/types@0.93.0':
+ resolution: {integrity: sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg==}
+
'@pkgr/core@0.1.2':
resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -2290,6 +2403,9 @@ packages:
'@tybys/wasm-util@0.10.0':
resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==}
+ '@tybys/wasm-util@0.10.1':
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -5299,6 +5415,10 @@ packages:
resolution: {integrity: sha512-Sv0OvhPiMutICiwORAUefv02DCPb62IelBmo8ZsSrRHyI3FStqIWZvjqDkvtjU+lcujo7UNir+dCwKSqlEQ/5w==}
engines: {node: '>=10', yarn: ^1.22.4}
+ oxc-parser@0.93.0:
+ resolution: {integrity: sha512-ktMzTb3AqYCAsgnGTsWOhJYEBxGhxm6F+Ja9HsRibvVYBnA/BCiALAYLQk6M47mdEyybP9B3sOj56UDT+VIkMg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
p-cancelable@2.1.1:
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
engines: {node: '>=8'}
@@ -6220,6 +6340,12 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+ uni-echarts@2.0.0:
+ resolution: {integrity: sha512-Sa+nS7WOHzfMXDZl0iEFOXIkU/pYx2pAZZVnJRrh46FkAPqdVbq438iqrQQXNkuke4WxevExqfDHPAj27axUWA==}
+ peerDependencies:
+ echarts: '>=5.3.0'
+ vue: '>=3.3.0'
+
unicode-canonical-property-names-ecmascript@2.0.1:
resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==}
engines: {node: '>=4'}
@@ -8349,16 +8475,32 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@emnapi/core@1.5.0':
+ dependencies:
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
+ optional: true
+
'@emnapi/runtime@1.4.5':
dependencies:
tslib: 2.8.1
optional: true
+ '@emnapi/runtime@1.5.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@emnapi/wasi-threads@1.0.4':
dependencies:
tslib: 2.8.1
optional: true
+ '@emnapi/wasi-threads@1.1.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@es-joy/jsdoccomment@0.50.2':
dependencies:
'@types/estree': 1.0.8
@@ -9214,6 +9356,13 @@ snapshots:
'@tybys/wasm-util': 0.10.0
optional: true
+ '@napi-rs/wasm-runtime@1.0.6':
+ dependencies:
+ '@emnapi/core': 1.5.0
+ '@emnapi/runtime': 1.5.0
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
'@node-rs/xxhash-android-arm-eabi@1.7.6':
optional: true
@@ -9287,6 +9436,55 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
+ '@oxc-parser/binding-android-arm64@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-arm64@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-x64@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-freebsd-x64@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-musl@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-gnu@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-musl@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-wasm32-wasi@0.93.0':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.0.6
+ optional: true
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.93.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-x64-msvc@0.93.0':
+ optional: true
+
+ '@oxc-project/types@0.93.0': {}
+
'@pkgr/core@0.1.2': {}
'@pkgr/core@0.2.9': {}
@@ -9438,6 +9636,11 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.28.0
@@ -13253,6 +13456,26 @@ snapshots:
dependencies:
lcid: 3.1.1
+ oxc-parser@0.93.0:
+ dependencies:
+ '@oxc-project/types': 0.93.0
+ optionalDependencies:
+ '@oxc-parser/binding-android-arm64': 0.93.0
+ '@oxc-parser/binding-darwin-arm64': 0.93.0
+ '@oxc-parser/binding-darwin-x64': 0.93.0
+ '@oxc-parser/binding-freebsd-x64': 0.93.0
+ '@oxc-parser/binding-linux-arm-gnueabihf': 0.93.0
+ '@oxc-parser/binding-linux-arm-musleabihf': 0.93.0
+ '@oxc-parser/binding-linux-arm64-gnu': 0.93.0
+ '@oxc-parser/binding-linux-arm64-musl': 0.93.0
+ '@oxc-parser/binding-linux-riscv64-gnu': 0.93.0
+ '@oxc-parser/binding-linux-s390x-gnu': 0.93.0
+ '@oxc-parser/binding-linux-x64-gnu': 0.93.0
+ '@oxc-parser/binding-linux-x64-musl': 0.93.0
+ '@oxc-parser/binding-wasm32-wasi': 0.93.0
+ '@oxc-parser/binding-win32-arm64-msvc': 0.93.0
+ '@oxc-parser/binding-win32-x64-msvc': 0.93.0
+
p-cancelable@2.1.1: {}
p-limit@2.3.0:
@@ -14153,6 +14376,12 @@ snapshots:
undici-types@6.21.0: {}
+ uni-echarts@2.0.0(echarts@6.0.0)(vue@3.4.21(typescript@5.9.2)):
+ dependencies:
+ echarts: 6.0.0
+ oxc-parser: 0.93.0
+ vue: 3.4.21(typescript@5.9.2)
+
unicode-canonical-property-names-ecmascript@2.0.1: {}
unicode-match-property-ecmascript@2.0.0:
diff --git a/src/components/class-analysis/AverageScoreChart.vue b/src/components/class-analysis/AverageScoreChart.vue
index b950f96..a7c902d 100644
--- a/src/components/class-analysis/AverageScoreChart.vue
+++ b/src/components/class-analysis/AverageScoreChart.vue
@@ -1,15 +1,15 @@
@@ -232,14 +277,17 @@ defineExpose({
-
-
+
+
+
+
-
+
暂无数据
@@ -250,10 +298,9 @@ defineExpose({
-
diff --git a/src/components/score/OverviewSettingsDialog.vue b/src/components/score/OverviewSettingsDialog.vue
new file mode 100644
index 0000000..ccc5f0d
--- /dev/null
+++ b/src/components/score/OverviewSettingsDialog.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+ 整体概况设置
+
+
+
+
+
+
+ 优秀得分率
+ ≥
+
+ %
+
+
+
+
+ 良好得分率
+ ≥
+
+ %
+
+
+
+
+ 及格得分率
+ ≥
+
+ %
+
+
+
+
+ 年级前N名
+ -
+
+ 名
+
+
+
+
+
+
+ 取消
+
+
+ 确定
+
+
+
+
+
+
+
+
diff --git a/src/components/score/RankSettingsDialog.vue b/src/components/score/RankSettingsDialog.vue
new file mode 100644
index 0000000..e28fef4
--- /dev/null
+++ b/src/components/score/RankSettingsDialog.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+ 名次分析设置
+
+
+
+
+
+
+ 前xx名(1)
+ -
+
+ 名
+
+
+
+
+ 前xx名(2)
+ -
+
+ 名
+
+
+
+
+ 前xx名(3)
+ -
+
+ 名
+
+
+
+
+
+
+ 取消
+
+
+ 确定
+
+
+
+
+
+
+
+
diff --git a/src/pages/class-analysis/index.vue b/src/pages/class-analysis/index.vue
index bf1358e..8f23be7 100644
--- a/src/pages/class-analysis/index.vue
+++ b/src/pages/class-analysis/index.vue
@@ -32,11 +32,15 @@ const showCompareClassDialog = ref(false)
// 图表组件引用
const chartRef = ref>()
-// 班级选择选项(用于对比班级选择)
-const classOptions = computed(() => homeStore.classOptions.map(cls => ({
- label: cls.label,
- value: cls.value,
-})))
+// 班级选择选项(用于对比班级选择,过滤掉当前班级)
+const classOptions = computed(() =>
+ homeStore.classOptions
+ .filter(cls => cls.value !== homeStore.selectedClassId)
+ .map(cls => ({
+ label: cls.label,
+ value: cls.value,
+ })),
+)
// 科目选项(包含全科)
const subjectTabs = computed(() => {
@@ -46,9 +50,9 @@ const subjectTabs = computed(() => {
homeStore.subjectOptions.forEach((subject) => {
tabs.push({
- name: `subject-${subject.value}`,
+ name: `subject-${subject.subjectId}`,
title: subject.label,
- subjectId: subject.value,
+ subjectId: subject.subjectId || 0,
})
})
@@ -90,18 +94,11 @@ function handleCompareClassChange(classId: number) {
showCompareClassDialog.value = false
}
-// 页面初始化
-onMounted(async () => {
- try {
- // 如果store中没有数据,先获取选项数据
- if (homeStore.classOptions.length === 0) {
- await homeStore.fetchOptions()
- }
- }
- catch (error) {
- console.error('初始化数据失败:', error)
- }
-})
+// 清除对比班级
+function clearCompareClass() {
+ compareClassId.value = null
+ showCompareClassDialog.value = false
+}
@@ -145,6 +142,7 @@ onMounted(async () => {
@@ -157,8 +155,16 @@ onMounted(async () => {
>
-
+
选择对比班级
+
+ 清除
+
@@ -166,12 +172,17 @@ onMounted(async () => {
{{ cls.label }}
+
+
+
+ 暂无其他班级
+
diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue
index 16b7c4d..92d6a7e 100644
--- a/src/pages/index/index.vue
+++ b/src/pages/index/index.vue
@@ -11,7 +11,7 @@
@@ -648,7 +503,7 @@ onMounted(async () => {
考试人数
- {{ statsData.examCount }}
+ {{ statsData?.examCount || 0 }}
@@ -656,7 +511,7 @@ onMounted(async () => {
平均分/满分
- {{ statsData.averageScore }}/{{ statsData.totalScore }}
+ {{ statsData?.averageScore || 0 }}/{{ statsData?.totalScore || 100 }}
@@ -664,7 +519,7 @@ onMounted(async () => {
最高分/最低分
- {{ statsData.highestScore }}/{{ statsData.lowestScore }}
+ {{ statsData?.highestScore || 0 }}/{{ statsData?.lowestScore || 0 }}
@@ -672,7 +527,7 @@ onMounted(async () => {
优秀率
- {{ statsData.excellentRate }}%
+ {{ statsData?.excellentRate || 0 }}%
@@ -680,7 +535,7 @@ onMounted(async () => {
良好率
- {{ statsData.goodRate }}%
+ {{ statsData?.goodRate || 0 }}%
@@ -688,7 +543,7 @@ onMounted(async () => {
及格率
- {{ statsData.passRate }}%
+ {{ statsData?.passRate || 0 }}%
@@ -754,7 +609,7 @@ onMounted(async () => {
-
+
暂无对比数据
@@ -805,7 +660,7 @@ onMounted(async () => {
-
+
暂无名次数据
@@ -874,12 +729,12 @@ onMounted(async () => {
-
+
暂无{{ keyStudentType === 'up' ? '进步' : '退步' }}学生数据
-
+
{
-
-
-
-
- 整体概况设置
-
-
-
-
-
-
- 优秀得分率
- ≥
-
- %
-
-
-
-
- 良好得分率
- ≥
-
- %
-
-
-
-
- 及格得分率
- ≥
-
- %
-
-
-
-
- 年级前N名
- -
-
- 名
-
-
-
-
-
-
- 取消
-
-
- 确定
-
-
-
-
+ :settings="scoreSettings"
+ @confirm="confirmOverviewSettings"
+ />
-
-
-
-
- 名次分析设置
-
-
-
-
-
-
- 前xx名(1)
- -
-
- 名
-
-
-
-
- 前xx名(2)
- -
-
- 名
-
-
-
-
- 前xx名(3)
- -
-
- 名
-
-
-
-
-
-
- 取消
-
-
- 确定
-
-
-
-
+ :settings="scoreSettings"
+ @confirm="confirmRankSettings"
+ />
-
+
diff --git a/src/pages/student/list.vue b/src/pages/student/list.vue
index 55ddad5..8a59dce 100644
--- a/src/pages/student/list.vue
+++ b/src/pages/student/list.vue
@@ -12,7 +12,7 @@ const searchQuery = ref('')
// 检查是否可以加载学生数据
const canLoadStudents = computed(() => {
- return homeStore.selectedClassId && homeStore.selectedExamId && homeStore.selectedSubjectId && homeStore.selectedGradeKey
+ return homeStore.selectedClassId && homeStore.selectedExamId && homeStore.selectedExamSubjectId && homeStore.selectedGradeKey
})
// 使用 TanStack Query 获取学生数据
@@ -26,7 +26,7 @@ const {
'students',
homeStore.selectedClassId,
homeStore.selectedExamId,
- homeStore.selectedSubjectId,
+ homeStore.selectedExamSubjectId,
homeStore.selectedGradeKey,
searchQuery.value,
]),
@@ -34,7 +34,7 @@ const {
const response = await teacherAnalysisStudentListUsingPost({
body: {
class_id: homeStore.selectedClassId!,
- exam_subject_id: homeStore.selectedSubjectId!,
+ exam_subject_id: homeStore.selectedExamSubjectId!,
grade_id: homeStore.selectedGradeKey!,
keyword: searchQuery.value || undefined,
},
@@ -59,16 +59,16 @@ function goToStudentDetail(student: StudentInfo) {
}
// 切换关注状态
-async function toggleAttention(student: StudentInfo) {
+async function toggleAttention(student: StudentInfo, isAttentioned: boolean) {
if (!student.student_number) {
- return uni.showToast({ title: '学生信息不完整', icon: 'error' })
+ return uni.showToast({ title: '学生信息缺少学号', icon: 'error' })
}
uni.showLoading({ title: '处理中...' })
try {
await teacherAnalysisAttentionStudentUsingPost({
- body: { student_number: student.student_number, remark: '' },
+ body: { student_number: student.student_number, is_attention: !isAttentioned },
})
uni.showToast({ title: '操作成功', icon: 'success' })
refetch()
@@ -90,7 +90,7 @@ async function handleDownload() {
const response = await teacherAnalysisExportStudentListUsingPost({
body: {
class_id: homeStore.selectedClassId!,
- exam_subject_id: homeStore.selectedSubjectId!,
+ exam_subject_id: homeStore.selectedExamSubjectId!,
grade_id: homeStore.selectedGradeKey!,
},
})
@@ -168,7 +168,7 @@ onMounted(async () => {
-
+
@@ -193,7 +193,7 @@ onMounted(async () => {
:index="index + 1"
:is-attentioned="true"
@click="goToStudentDetail"
- @toggle-attention="toggleAttention"
+ @toggle-attention="toggleAttention(student, true)"
/>
@@ -210,7 +210,7 @@ onMounted(async () => {
:index="attentionedStudents.length + index + 1"
:is-attentioned="false"
@click="goToStudentDetail"
- @toggle-attention="toggleAttention"
+ @toggle-attention="toggleAttention(student, false)"
/>
diff --git a/src/service/laoshichengjifenxi.ts b/src/service/laoshichengjifenxi.ts
index 4c8420f..00d27bd 100644
--- a/src/service/laoshichengjifenxi.ts
+++ b/src/service/laoshichengjifenxi.ts
@@ -71,6 +71,28 @@ export async function teacherAnalysisClassExamComparisonUsingPost({
});
}
+/** 获取班级考试对比(横向对比) 获取指定班级的所有考试对比数据,包括班级平均分、年级平均分、班级排名、学科名字、学科ID POST /teacher-analysis/class-exam-comparison-horizontal */
+export async function teacherAnalysisClassExamComparisonHorizontalUsingPost({
+ body,
+ options,
+}: {
+ body: API.ClassExamComparisonRequestH;
+ options?: CustomRequestOptions;
+}) {
+ return request<
+ API.Response & {
+ data?: API.ClassExamComparisonDataH;
+ }
+ >('/teacher-analysis/class-exam-comparison-horizontal', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ data: body,
+ ...(options || {}),
+ });
+}
+
/** 获取班级下所有学生成绩列表 获取指定科目、年级、班级的所有学生成绩列表 POST /teacher-analysis/class-student-score-list */
export async function teacherAnalysisClassStudentScoreListUsingPost({
body,
diff --git a/src/service/types.ts b/src/service/types.ts
index ba291ba..fe0998c 100644
--- a/src/service/types.ts
+++ b/src/service/types.ts
@@ -263,6 +263,11 @@ export type ClassExamComparisonData = {
exam_list?: ExamComparisonItem[];
};
+export type ClassExamComparisonDataH = {
+ /** 考试对比列表 */
+ exam_list?: ExamComparisonItemH[];
+};
+
export type ClassExamComparisonRequest = {
/** 班级 */
class_key: number;
@@ -272,6 +277,17 @@ export type ClassExamComparisonRequest = {
subject_id?: number;
};
+export type ClassExamComparisonRequestH = {
+ /** 考试ID */
+ exam_id: number;
+ /** 班级 */
+ class_key: number;
+ /** 年级 */
+ grade_key: number;
+ /** 科目ID */
+ subject_id?: number;
+};
+
export type ClassExportRequest = {
/** 班级字典key列表,必填 */
class_ids: string[];
@@ -446,6 +462,8 @@ export type CreateTeacherAttentionStudentRequest = {
remark?: string;
/** 学生学号 */
student_number: string;
+ /** 是否关注传入的学生 */
+ is_attention?: boolean;
};
export type CreateUploadSessionRequest = {
@@ -579,6 +597,19 @@ export type ExamComparisonItem = {
grade_top50_count?: number;
};
+export type ExamComparisonItemH = {
+ /** 科目ID */
+ subject_id?: number;
+ /** 科目名称 */
+ subject_name?: string;
+ /** 班级平均分 */
+ class_average?: number;
+ /** 年级平均分 */
+ grade_average?: number;
+ /** 班级排名 */
+ class_rank?: number;
+};
+
export type ExamMarkingTaskListResponse = {
/** 考试列表 */
list?: ExamMarkingTaskResponse[];
@@ -1239,14 +1270,18 @@ export type GetStudentMarkingQualityResponse = {
};
export type GetTrendRequest = {
+ /** 年级参数 */
+ grade_key: number;
/** 查询班级 */
class_key: number;
- /** 查询年级 */
- grade_key: number;
+ /** 对比的年级 */
+ class_key_compare: number;
/** 考试科目ID */
subject_id?: number;
/** 查看年级前N名人数 */
top_n: number;
+ /** 查询最近几次考试的成绩 */
+ exam_number?: number;
};
export type GetTrendResponse = {
@@ -1328,6 +1363,8 @@ export type KeyStudentInfo = {
student_name?: string;
/** 学生学号 */
student_number?: string;
+ /** 是否关注 */
+ is_attention?: boolean;
};
export type LearningSituationAnalysis = {
@@ -3254,17 +3291,32 @@ export type TotalScoreInfo = {
score_line?: number;
};
-export type TrendInfo = {
+export type TrendDataItem = {
+ /** 班级key */
+ class_key?: number;
+ /** 班级名称 */
+ class_name?: string;
/** 班级平均分 */
class_avg_score?: number;
+ /** 班级排名 */
+ class_rank?: number;
+ /** 班级前N名人数 */
+ class_top_count?: number;
+};
+
+export type TrendInfo = {
/** 考试日期 */
exam_date?: string;
/** 考试ID */
exam_id?: number;
/** 考试名称 */
exam_name?: string;
+ /** 班级平均分 */
+ class_avg_score?: number;
/** 年级平均分 */
grade_avg_score?: number;
+ /** 年级走势数据 */
+ trend_data?: TrendDataItem[];
};
export type UnifiedConfigData = {
diff --git a/src/store/home.ts b/src/store/home.ts
index fe040a1..47590a7 100644
--- a/src/store/home.ts
+++ b/src/store/home.ts
@@ -1,3 +1,4 @@
+import type { ModelTeacherAnalysisClassInfo, ModelTeacherAnalysisExamInfo } from '@/api/data-contracts'
import { whenever } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
@@ -6,14 +7,8 @@ import { teacherScoreAnalysisApi } from '@/api'
export interface SelectOption {
label: string
value: number
-}
-
-// 考试科目组合数据类型
-export interface ExamSubjectItem {
- examId: number
- examName: string
- examSubjectId: number
- subjectName: string
+ examSubjectId?: number
+ subjectId?: number
}
// 班级信息类型
@@ -31,7 +26,7 @@ export const useHomeStore = defineStore(
() => {
// 数据存储
const loading = ref(false)
- const examSubjectList = ref([])
+ const examDataMap = ref