round-report.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <div class="app-container">
  3. <el-card>
  4. <template #header>
  5. <div class="fx-row fx-bet-cen">
  6. <div class="fx-row">
  7. <round-settings v-if="isFrontMaster" class="mr10"></round-settings>
  8. <round-history></round-history>
  9. </div>
  10. <span>选科管理</span>
  11. </div>
  12. </template>
  13. <mx-condition :query-params="queryParams" :require-fields="requireFields" @query="handleQuery"
  14. @invalid="handleInvalidQuery"></mx-condition>
  15. <el-card v-if="summary" shadow="hover" class="mt20">
  16. <div class="fx-row fx-bet-cen">
  17. <span class="fx-1">总人数:{{ summary.total }}</span>
  18. <span class="fx-1">已选人数:{{ summary.selected }}</span>
  19. <span>未选人数:{{ summary.total - summary.selected }}</span>
  20. <el-button type="primary" plain @click="handleMessageSend" icon="el-icon-s-promotion"
  21. size="small" class="ml40">发送选科消息
  22. </el-button>
  23. </div>
  24. </el-card>
  25. <el-card v-if="summary" shadow="hover" class="mt20">
  26. <template #header>
  27. <div class="text-right">科目组合人数统计</div>
  28. </template>
  29. <el-row>
  30. <el-col :span="16">
  31. <mx-chart :options="groupChartData" height="400px"></mx-chart>
  32. </el-col>
  33. <el-col :span="8">
  34. <mx-table :prop-defines="groupTableData.propDefines" :rows="groupTableData.dataList">
  35. <template #detail="{row}">
  36. <el-button type="text" icon="el-icon-view" @click="handleViewDetail(row)">查看</el-button>
  37. </template>
  38. </mx-table>
  39. </el-col>
  40. </el-row>
  41. </el-card>
  42. <el-card v-if="summary" shadow="hover" class="mt20">
  43. <template #header>
  44. <div class="text-right">单科人数统计</div>
  45. </template>
  46. <el-row>
  47. <el-col :span="16">
  48. <mx-chart :options="subjectChartData" height="400px"></mx-chart>
  49. </el-col>
  50. <el-col :span="8">
  51. <mx-table-dynamic :local-data="subjectTableData"></mx-table-dynamic>
  52. </el-col>
  53. </el-row>
  54. </el-card>
  55. </el-card>
  56. <el-dialog :visible.sync="detailDialogVisible" title="选科详情">
  57. <mx-table-dynamic :local-data="detailTable"></mx-table-dynamic>
  58. </el-dialog>
  59. </div>
  60. </template>
  61. <script>
  62. import RoundSettings from '@/views/permission/components/round-settings'
  63. import RoundHistory from '@/views/system/user/profile/components/round-history'
  64. import MxCondition from '@/components/MxCondition/mx-condition'
  65. import { mapGetters } from 'vuex'
  66. import { getSelectDetail, getSelectReport, sendSelectedNotice } from '@/api/webApi/selection'
  67. import MxChart from '@/components/MxChart/index'
  68. import MxTableDynamic from '@/components/MxTableDynamic/index'
  69. export default {
  70. name: 'round-select-manage',
  71. components: { MxTableDynamic, MxChart, MxCondition, RoundHistory, RoundSettings },
  72. data() {
  73. return {
  74. requireFields: ['year', 'roundId'],
  75. queryParams: {
  76. year: '',
  77. roundId: ''
  78. },
  79. reportData: {},
  80. detailDialogVisible: false,
  81. detailTable: {}
  82. }
  83. },
  84. computed: {
  85. ...mapGetters(['isFrontMaster']),
  86. summary() {
  87. return this.reportData?.group?.options
  88. },
  89. subjectChartData() {
  90. if (!this.reportData?.subject?.columns?.length) return null
  91. const subjectTable = this.reportData.subject
  92. const { columns, rows } = this.dynamicTableExchangeRowColumn(subjectTable)
  93. const option = {
  94. title: {
  95. text: '选科统计',
  96. subtext: '单科/学生数量',
  97. left: 'center'
  98. },
  99. xAxis: {
  100. type: 'category',
  101. data: columns.slice(1)
  102. },
  103. yAxis: {
  104. type: 'value'
  105. },
  106. series: [{
  107. data: rows.first().slice(1),
  108. type: 'bar',
  109. emphasis: {
  110. itemStyle: {
  111. shadowBlur: 10,
  112. shadowOffsetX: 0,
  113. shadowColor: 'rgba(0, 0, 0, 0.5)'
  114. }
  115. }
  116. }]
  117. }
  118. return option
  119. },
  120. subjectTableData() {
  121. return this.reportData?.subject || {}
  122. },
  123. groupChartData() {
  124. if (!this.reportData?.group?.columns?.length) return null
  125. const groupTable = this.reportData.group
  126. const data = groupTable.rows.map(r => ({
  127. name: r[0],
  128. value: r[1]
  129. }))
  130. const option = {
  131. title: {
  132. text: '选科统计',
  133. subtext: '组合/学生数量',
  134. left: 'center'
  135. },
  136. tooltip: {
  137. trigger: 'item'
  138. },
  139. legend: {
  140. orient: 'vertical',
  141. left: 'left'
  142. },
  143. series: [
  144. {
  145. name: groupTable.columns.first(),
  146. type: 'pie',
  147. radius: '50%',
  148. data: data,
  149. emphasis: {
  150. itemStyle: {
  151. shadowBlur: 10,
  152. shadowOffsetX: 0,
  153. shadowColor: 'rgba(0, 0, 0, 0.5)'
  154. }
  155. }
  156. }
  157. ]
  158. }
  159. return option
  160. },
  161. groupTableData() {
  162. if (!this.reportData?.group) return {}
  163. const groupTable = this.reportData.group
  164. const dataList = this.reverseDynamicTableToObjects(groupTable)
  165. const propDefines = {}
  166. propDefines[groupTable.columns.first()] = {
  167. label: groupTable.columns.first() // 组合
  168. }
  169. propDefines[groupTable.columns[1]] = {
  170. label: groupTable.columns[1] // 人数
  171. }
  172. propDefines['detail'] = {
  173. label: '详情', // 详情
  174. slot: 'detail'
  175. }
  176. return {
  177. dataList,
  178. propDefines
  179. }
  180. }
  181. },
  182. beforeMount() {
  183. if (this.isFrontMaster) {
  184. this.queryParams = {
  185. ...this.queryParams,
  186. classGradeId: '',
  187. classId: ''
  188. }
  189. }
  190. },
  191. methods: {
  192. handleQuery(model) {
  193. getSelectReport({
  194. year: model.year,
  195. roundId: model.roundId,
  196. gradeIds: model.classGradeId,
  197. classIds: model.classId
  198. }).then(res => this.reportData = res.data)
  199. },
  200. handleInvalidQuery() {
  201. this.reportData = {}
  202. },
  203. handleMessageSend() {
  204. if (!this.queryParams.roundId) {
  205. this.msgError('请选择次数')
  206. return
  207. }
  208. if (this.summary.total && this.summary.total == this.summary.selected) {
  209. this.msgError('所有学生均已完成选科')
  210. return
  211. }
  212. sendSelectedNotice({
  213. year: this.queryParams.year,
  214. roundId: this.queryParams.roundId
  215. }).then(res => {
  216. this.msgSuccess('发送成功')
  217. })
  218. },
  219. handleViewDetail(row) {
  220. getSelectDetail({
  221. year: this.queryParams.year,
  222. gradeIds: this.queryParams.classGradeId,
  223. classIds: this.queryParams.classId,
  224. roundId: row.roundId,
  225. groupId: row.groupId
  226. }).then(res => {
  227. this.detailTable = res.data
  228. this.detailDialogVisible = true
  229. })
  230. }
  231. }
  232. }
  233. </script>
  234. <style scoped>
  235. .fat-button {
  236. }
  237. </style>