index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <script setup lang="ts">
  2. import {watch} from "vue";
  3. import {useUserStore} from "@/store/modules/user";
  4. import {GradeList} from "@/api/grade/types";
  5. import {TrainingItem, TrainingParams} from "@/api/training/types";
  6. import {getGradeSelect} from "@/api/grade";
  7. import {getTrainingLists} from "@/api/training";
  8. import {trimInput} from "@/utils";
  9. const userStore = useUserStore();
  10. defineOptions({
  11. name: "TrainingIndex",
  12. inheritAttrs: false,
  13. });
  14. const pageParams: TrainingParams = reactive({
  15. school_id: userStore.schoolId,
  16. is_formal: 1, // 1正式,2非正式
  17. grade_id: 0,
  18. page_no: 1,
  19. page_size: 10,
  20. // 学生名称/手机号
  21. search: "",
  22. });
  23. /**
  24. * 班级数据
  25. */
  26. const gradeData = ref<GradeList[]>();
  27. async function getGradeData(schoolId: number) {
  28. getGradeSelect(schoolId)
  29. .then(({data}) => {
  30. gradeData.value = data;
  31. gradeData.value?.unshift({id: 0, name: "全部班级"});
  32. })
  33. .catch((error) => {
  34. gradeData.value = [];
  35. gradeData.value?.unshift({id: 0, name: "全部班级"});
  36. console.log(error);
  37. });
  38. }
  39. const dataMessage = ref("加载中...");
  40. const trainingData = ref<TrainingItem[]>();
  41. const trainingCount = ref(0);
  42. async function getTrainingData(schoolId: number) {
  43. pageParams.school_id = schoolId;
  44. getTrainingLists(pageParams)
  45. .then(({data}) => {
  46. const {count, lists} = data;
  47. trainingData.value = lists;
  48. trainingCount.value = count;
  49. if (!(count && count > 0 && lists.length > 0)) {
  50. dataMessage.value = "没有符合搜索条件的记录!";
  51. if (pageParams.grade_id == 0 && pageParams.is_formal == 0 && pageParams.search == "") {
  52. dataMessage.value = "还没有任何学生训练记录!";
  53. }
  54. }
  55. })
  56. .catch((error) => {
  57. dataMessage.value = error.message;
  58. console.log(error);
  59. });
  60. }
  61. function getTrainingSearch() {
  62. getTrainingData(userStore.schoolId);
  63. }
  64. function alertError() {
  65. ElMessage.error("本次训练采集的数据不足,无法分析并生成有效报告!");
  66. }
  67. onMounted(() => {
  68. getGradeData(userStore.schoolId);
  69. getTrainingData(userStore.schoolId);
  70. });
  71. watch(
  72. () => userStore.schoolId,
  73. (newValue) => {
  74. // 学校切换后重新获取
  75. getGradeData(newValue);
  76. getTrainingData(newValue);
  77. }
  78. );
  79. </script>
  80. <template>
  81. <div class="training-container">
  82. <!-- 学生查找 -->
  83. <div class="training-search">
  84. <el-select v-model="pageParams.is_formal" placeholder="正式学生/体验用户" size="large">
  85. <el-option key="1" :value="Number(1)" label="正式学生"></el-option>
  86. <el-option key="2" :value="Number(2)" label="体验用户"></el-option>
  87. </el-select>
  88. <el-select v-model="pageParams.grade_id" placeholder="请选择班级" size="large">
  89. <el-option v-for="item in gradeData" :key="item.id" :label="item.name" :value="item.id" />
  90. </el-select>
  91. <el-input
  92. v-model="pageParams.search"
  93. placeholder="请输入学生名称或手机号码"
  94. size="large"
  95. @input="(value:string) => (pageParams.search = trimInput(value))" />
  96. <el-button size="large" type="primary" @click="getTrainingSearch()">查找</el-button>
  97. </div>
  98. <!-- 学生数据 -->
  99. <div class="list-table">
  100. <el-table :data="trainingData" style="width: 100%">
  101. <el-table-column align="center" label="序号" max-width="120" type="index" />
  102. <el-table-column prop="name" label="学生名称" align="center" />
  103. <el-table-column prop="phone" label="手机号码" align="center" />
  104. <el-table-column prop="device_name" label="训练方式" align="center" />
  105. <el-table-column prop="create_time" label="训练时间" align="center" />
  106. <el-table-column prop="play_time" label="训练时长" align="center" />
  107. <el-table-column prop="grade_name" label="所在班级" align="center" />
  108. <el-table-column label="操作" align="center" min-width="120">
  109. <template #default="scope">
  110. <template v-if="scope.row.report_status == 1">
  111. <router-link
  112. :to="
  113. '/training/result?id=' +
  114. scope.row.game_record_id +
  115. '&type=' +
  116. scope.row.device_id +
  117. '&formal=' +
  118. pageParams.is_formal
  119. "
  120. class="table-btn"
  121. >报告详情</router-link
  122. >
  123. </template>
  124. <button v-else class="table-btn disabled" @click="alertError()">训练效果分析</button>
  125. </template>
  126. </el-table-column>
  127. <!-- 无数据插槽 -->
  128. <template #empty>
  129. <div class="empty">
  130. <img src="../../assets/empty.png" alt="数据为空" />
  131. <p>{{ dataMessage }}</p>
  132. </div>
  133. </template>
  134. </el-table>
  135. </div>
  136. <pagination
  137. v-if="trainingCount > 0"
  138. v-model:total="trainingCount"
  139. v-model:page="pageParams.page_no"
  140. v-model:limit="pageParams.page_size"
  141. @pagination="getTrainingSearch()" />
  142. </div>
  143. </template>
  144. <style lang="scss" scoped>
  145. .training-container {
  146. position: relative;
  147. padding: 20px 30px;
  148. }
  149. .training-search {
  150. margin-bottom: 20px;
  151. font-size: 16px;
  152. .el-select {
  153. width: 200px;
  154. margin: 0 20px 0 0;
  155. }
  156. .el-input {
  157. width: 250px;
  158. margin: 0;
  159. }
  160. :deep(.el-input__inner) {
  161. font-size: 16px;
  162. }
  163. .el-button {
  164. padding: 0 26px;
  165. margin: 0 20px;
  166. font-size: 16px;
  167. background: #4284f2;
  168. border-radius: 10px;
  169. }
  170. }
  171. :deep(.el-input__wrapper) {
  172. background: #fff;
  173. border-radius: 12px;
  174. box-shadow: none !important;
  175. }
  176. :deep(.el-select) {
  177. --el-select-input-focus-border-color: none !important;
  178. }
  179. :deep(.el-select .el-input__wrapper.is-focus) {
  180. box-shadow: none !important;
  181. }
  182. :deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
  183. box-shadow: none !important;
  184. }
  185. :deep(.el-table .el-table__header .el-table__cell .cell) {
  186. overflow: visible;
  187. white-space: nowrap;
  188. }
  189. :deep(.el-table th.el-table__cell) {
  190. background: #e9ebee;
  191. }
  192. .list-table {
  193. overflow: hidden;
  194. background: #fff;
  195. border-radius: 25px;
  196. .table-btn {
  197. display: inline-block;
  198. height: 38px;
  199. padding: 0 15px;
  200. line-height: 38px;
  201. color: #fff;
  202. background: #4284f2;
  203. border-radius: 10px;
  204. &.disabled {
  205. background: #bfbfbf;
  206. }
  207. }
  208. }
  209. .empty {
  210. padding: 200px 0;
  211. }
  212. </style>