ScoreReviewStatistics.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <template>
  2. <div class="part-box">
  3. <!-- 统计图表区域 -->
  4. <div class="chart-container">
  5. <div class="chart-item">
  6. <h3>复核总进度</h3>
  7. <Chart :options="taskChartOptions" width="400px" height="300px" />
  8. </div>
  9. <div class="chart-item">
  10. <h3>科目复核进度</h3>
  11. <Chart :options="courseChartOptions" width="400px" height="300px" />
  12. </div>
  13. </div>
  14. </div>
  15. <div class="part-box is-filter">
  16. <el-form inline>
  17. <el-form-item label="科目">
  18. <select-subject v-model="searchModel.subjectId"></select-subject>
  19. </el-form-item>
  20. <el-form-item label="选做科目">
  21. <el-select
  22. v-model="searchModel.isOptional"
  23. placeholder="请选择"
  24. clearable
  25. style="width: 120px"
  26. >
  27. <el-option label="是" :value="true" />
  28. <el-option label="否" :value="false" />
  29. </el-select>
  30. </el-form-item>
  31. <el-form-item label="完成进度">
  32. <el-select
  33. v-model="searchModel.isFinished"
  34. placeholder="请选择"
  35. clearable
  36. style="width: 120px"
  37. >
  38. <el-option label="已完成" :value="true" />
  39. <el-option label="未完成" :value="false" />
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item>
  43. <el-button type="primary" @click="toPage(1)">查询</el-button>
  44. </el-form-item>
  45. </el-form>
  46. </div>
  47. <div class="part-box">
  48. <el-table
  49. class="page-table"
  50. :data="dataList"
  51. :loading="loading"
  52. @sort-change="handleSortChange"
  53. >
  54. <el-table-column property="courseName" label="科目" min-width="200" />
  55. <el-table-column label="选做科目" min-width="100" sortable>
  56. <template #default="scope">
  57. <el-tag :type="scope.row.isOptional ? 'success' : 'info'">
  58. {{ scope.row.isOptional ? '是' : '否' }}
  59. </el-tag>
  60. </template>
  61. </el-table-column>
  62. <el-table-column
  63. property="paperCount"
  64. label="试卷总量"
  65. min-width="100"
  66. sortable
  67. />
  68. <el-table-column
  69. property="taskCount"
  70. label="任务数"
  71. min-width="80"
  72. sortable
  73. />
  74. <el-table-column
  75. property="reviewedCount"
  76. label="已复核数"
  77. width="100"
  78. sortable
  79. />
  80. <el-table-column
  81. property="unReviewedCount"
  82. label="待复核数"
  83. min-width="100"
  84. sortable
  85. />
  86. <el-table-column label="完成进度" min-width="100" sortable>
  87. <template #default="scope">
  88. <el-progress
  89. :percentage="scope.row.progress"
  90. :color="scope.row.progress === 100 ? '#67c23a' : '#409eff'"
  91. />
  92. </template>
  93. </el-table-column>
  94. <el-table-column
  95. property="reviewedTimes"
  96. label="已复核次数"
  97. min-width="100"
  98. sortable
  99. />
  100. </el-table>
  101. <el-pagination
  102. v-model:current-page="pagination.pageNumber"
  103. v-model:page-size="pagination.pageSize"
  104. :layout="pagination.layout"
  105. :total="pagination.total"
  106. @size-change="pageSizeChange"
  107. @current-change="toPage"
  108. />
  109. </div>
  110. </template>
  111. <script setup lang="ts">
  112. import { reactive, ref, computed, onMounted } from 'vue';
  113. import { getReviewStatInfo, getReviewStatList } from '@/api/review';
  114. import {
  115. ReviewStatInfo,
  116. ReviewStatItem,
  117. ReviewStatListFilter,
  118. } from '@/api/types/review';
  119. import useTable from '@/hooks/table';
  120. import Chart from '@/components/chart/index.vue';
  121. defineOptions({
  122. name: 'ScoreReviewStatistics',
  123. });
  124. const searchModel = reactive<ReviewStatListFilter>({
  125. subjectId: null,
  126. isOptional: null,
  127. isFinished: null,
  128. });
  129. const {
  130. dataList,
  131. pagination,
  132. loading,
  133. toPage,
  134. pageSizeChange,
  135. handleSortChange,
  136. } = useTable<ReviewStatItem>(getReviewStatList, searchModel, false);
  137. // 统计信息
  138. const statInfo = ref<ReviewStatInfo>({
  139. taskFinishedCount: 0,
  140. taskUnfinishedCount: 0,
  141. courseFinishedCount: 0,
  142. courseUnfinishedCount: 0,
  143. });
  144. // 任务进度饼状图配置
  145. const taskChartOptions = computed(() => ({
  146. tooltip: {
  147. trigger: 'item',
  148. formatter: '{a} <br/>{b}: {c} ({d}%)',
  149. },
  150. legend: {
  151. orient: 'horizontal',
  152. bottom: '10%',
  153. data: ['任务待完成', '任务已完成'],
  154. },
  155. series: [
  156. {
  157. name: '任务进度',
  158. type: 'pie',
  159. radius: ['40%', '70%'],
  160. center: ['50%', '40%'],
  161. data: [
  162. {
  163. value: statInfo.value.taskUnfinishedCount,
  164. name: '任务待完成',
  165. itemStyle: { color: '#5470c6' },
  166. },
  167. {
  168. value: statInfo.value.taskFinishedCount,
  169. name: '任务已完成',
  170. itemStyle: { color: '#ff7875' },
  171. },
  172. ],
  173. emphasis: {
  174. itemStyle: {
  175. shadowBlur: 10,
  176. shadowOffsetX: 0,
  177. shadowColor: 'rgba(0, 0, 0, 0.5)',
  178. },
  179. },
  180. },
  181. ],
  182. }));
  183. // 科目进度饼状图配置
  184. const courseChartOptions = computed(() => ({
  185. tooltip: {
  186. trigger: 'item',
  187. formatter: '{a} <br/>{b}: {c} ({d}%)',
  188. },
  189. legend: {
  190. orient: 'horizontal',
  191. bottom: '10%',
  192. data: ['科目待完成', '科目已完成'],
  193. },
  194. series: [
  195. {
  196. name: '科目进度',
  197. type: 'pie',
  198. radius: ['40%', '70%'],
  199. center: ['50%', '40%'],
  200. data: [
  201. {
  202. value: statInfo.value.courseUnfinishedCount,
  203. name: '科目待完成',
  204. itemStyle: { color: '#5470c6' },
  205. },
  206. {
  207. value: statInfo.value.courseFinishedCount,
  208. name: '科目已完成',
  209. itemStyle: { color: '#ff7875' },
  210. },
  211. ],
  212. emphasis: {
  213. itemStyle: {
  214. shadowBlur: 10,
  215. shadowOffsetX: 0,
  216. shadowColor: 'rgba(0, 0, 0, 0.5)',
  217. },
  218. },
  219. },
  220. ],
  221. }));
  222. // 获取统计信息
  223. async function getStatInfo() {
  224. try {
  225. const data = await getReviewStatInfo();
  226. statInfo.value = data;
  227. } catch (error) {
  228. console.error('获取统计信息失败:', error);
  229. }
  230. }
  231. onMounted(() => {
  232. getStatInfo();
  233. });
  234. </script>
  235. <style scoped lang="less">
  236. .chart-container {
  237. display: flex;
  238. justify-content: space-around;
  239. align-items: center;
  240. padding: 20px;
  241. gap: 40px;
  242. .chart-item {
  243. text-align: center;
  244. h3 {
  245. margin-bottom: 20px;
  246. color: #333;
  247. font-size: 16px;
  248. font-weight: 500;
  249. }
  250. }
  251. }
  252. </style>