index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <template>
  2. <div class="reportList">
  3. <div class="title">{{ dic.project[parameter.project] || "" }}测试记录</div>
  4. <div class="searchBox">
  5. <!-- <el-select class="select" v-model="optionForm.grade" :popper-append-to-body="false" placeholder="年级" @change="changeGrade" clearable>
  6. <el-option v-for="item in gradeLists" :key="item.value" :label="item.label" :value="item.value" />
  7. </el-select>
  8. <el-select
  9. class="select"
  10. v-model="optionForm.class"
  11. :popper-append-to-body="false"
  12. placeholder="班级"
  13. @change="getSearchStudent"
  14. @clear="getSearchStudent"
  15. clearable
  16. >
  17. <el-option v-for="item in classData" :key="item.value" :label="item.name" :value="item.id" />
  18. </el-select> -->
  19. <el-input class="input" v-model="optionForm.student_name" placeholder="姓名" clearable @clear="getSearchStudent" />
  20. <el-button class="button" type="primary" @click="getSearchStudent">搜索</el-button>
  21. </div>
  22. <ul :ref="reportScrollRef" @scroll="getScroll($event)">
  23. <li v-for="(item, index) in reportList" :key="index" @click="openReport(item)">
  24. <div class="left">
  25. <div class="pic">
  26. <img v-if="item.face_pic || item.logo_url || item.student_icon_url" :src="item.face_pic || item.logo_url || item.student_icon_url" />
  27. <img v-else src="@/assets/images/common/noImg.png" />
  28. </div>
  29. <div class="txt">
  30. <div>
  31. <div class="name">{{ item.student_name }}</div>
  32. <div class="className">{{ item.class_name }}</div>
  33. </div>
  34. </div>
  35. </div>
  36. <div class="center">
  37. {{ proxy?.$utils.timestampFormat(item.finish_time,'MM-DD HH:mm:ss') }}
  38. </div>
  39. <div class="right" v-if="timeProjectList.includes(parameter.project)">
  40. <div class="score">{{ proxy?.$utils.runTime(item.result, true, false) }}</div>
  41. </div>
  42. <div class="right" v-else>
  43. <div class="score">{{ item.result }}</div>
  44. <div class="unit">{{ unit }}</div>
  45. </div>
  46. </li>
  47. </ul>
  48. </div>
  49. </template>
  50. <script setup lang="ts">
  51. import { clearInterval, clearTimeout, setInterval, setTimeout } from 'worker-timers';
  52. import dataDictionary from '@/utils/dataDictionary';
  53. import useAppStore from '@/store/modules/app';
  54. const router = useRouter();
  55. const route = useRoute();
  56. const dic: any = dataDictionary;
  57. const { proxy } = getCurrentInstance() as any;
  58. const timeProjectList = ['basketballv1', 'run50', 'run60', 'run70', 'run100', 'run200', 'run400', 'run800', 'run1000', 'runa800', 'runa1000', 'runwb800', 'runwb1000'];
  59. const reportScrollRef = ref();
  60. //筛选班别
  61. const classData = computed(() => {
  62. optionForm.value.class = '';
  63. let list = classList.value.filter((item: any) => {
  64. return item.grade == optionForm.value.grade;
  65. });
  66. return list;
  67. });
  68. //年级
  69. const gradeLists = computed(() => {
  70. let myInfo: any = localStorage.getItem('userInfo');
  71. let userInfo = JSON.parse(myInfo);
  72. let obj = dataDictionary.gradeLists.find((item) => {
  73. return userInfo.category == item.value;
  74. });
  75. return obj != undefined ? obj.child : [];
  76. });
  77. const data = reactive<any>({
  78. parameter: {},
  79. optionForm: {},
  80. classList: [],
  81. reportList: [], //测试列表
  82. studentPage: {
  83. current: 1,
  84. size: 20,
  85. pages: 1
  86. }, //学生分页
  87. debounceTime: '', //加载状态
  88. unit: '' //单位
  89. });
  90. const { parameter, optionForm, classList, reportList, studentPage, debounceTime, unit } = toRefs(data);
  91. /**
  92. * 成绩列表
  93. */
  94. const getReportList = () => {
  95. let type = parameter.value.project;
  96. let school = parameter.value.school;
  97. let params: any = {
  98. exam_name: type,
  99. school_id: school,
  100. page: studentPage.value.current,
  101. per_page: studentPage.value.size,
  102. ...optionForm.value
  103. };
  104. proxy?.$http.analysis.reportList(params).then((res: any) => {
  105. if (res.data.length > 0) {
  106. let list = res.data.map((item: any) => {
  107. if (type == 'solidball' || type == 'shotball') {
  108. item.result = item.result / 100;
  109. }
  110. let result = null;
  111. if (item.result.toString().indexOf('.') != -1) {
  112. if (
  113. [
  114. 'jump',
  115. 'longjump',
  116. 'run50',
  117. 'run60',
  118. 'run70',
  119. 'run100',
  120. 'run200',
  121. 'run400',
  122. 'run800',
  123. 'run1000',
  124. 'run15x4',
  125. 'run50x8',
  126. 'run10x4',
  127. 'basketballv1',
  128. 'basketballv1'
  129. ].includes(type)
  130. ) {
  131. result = item.result.toFixed(2);
  132. } else {
  133. result = item.result.toFixed(1);
  134. }
  135. } else {
  136. result = item.result;
  137. }
  138. item.result = result;
  139. return item;
  140. });
  141. studentPage.value.current == 1 ? (reportList.value = list) : reportList.value.push(...list);
  142. studentPage.value.pages = res.total;
  143. getPages(res.total);
  144. }
  145. });
  146. };
  147. /**
  148. * 计算页码
  149. */
  150. const getPages = (data: any) => {
  151. studentPage.value.pages = Math.ceil(data / studentPage.value.size);
  152. };
  153. /**
  154. * 查看详情
  155. */
  156. const openReport = (data: any) => {
  157. let params = {
  158. exam_name: data.exam_name,
  159. student_id: data.student_id,
  160. result_ids: data.result_id
  161. };
  162. router.push({
  163. path: '/analysis/detail',
  164. query: params
  165. });
  166. };
  167. /**
  168. * 成绩翻页
  169. */
  170. const getScroll = (event?: any) => {
  171. if (studentPage.value.current == studentPage.value.pages) {
  172. return false;
  173. }
  174. let obj = event.target;
  175. let scrollHeight = obj.scrollHeight;
  176. let scrollTop = obj.scrollTop;
  177. let clientHeight = obj.clientHeight;
  178. //提前高度加载数据
  179. if (scrollTop + clientHeight + 150 >= scrollHeight) {
  180. // console.log('到底了!');
  181. //继续加载下一页
  182. if (debounceTime.value) {
  183. clearTimeout(debounceTime.value);
  184. }
  185. debounceTime.value = setTimeout(() => {
  186. studentPage.value.current++;
  187. getReportList();
  188. }, 500);
  189. } else {
  190. // console.log('没到底');
  191. }
  192. };
  193. /**
  194. * 初始化列表
  195. */
  196. const getIniReportList = () => {
  197. studentPage.value.current = 1;
  198. getReportList();
  199. };
  200. //变更年级
  201. const changeGrade = () => {
  202. optionForm.value.class = '';
  203. getIniReportList();
  204. };
  205. //搜索
  206. const getSearchStudent = () => {
  207. getIniReportList();
  208. };
  209. //获取班级列表
  210. const getClass = () => {
  211. const list: any = useAppStore().getClass();
  212. if (list.length) {
  213. classList.value = list;
  214. console.log('classList.value', classList.value);
  215. } else {
  216. let params = {
  217. per_page: 1000,
  218. page: 1
  219. };
  220. proxy?.$http.common.classList(params).then((res: any) => {
  221. if (res.data.length > 0) {
  222. let myList: any = res.data;
  223. classList.value = myList;
  224. useAppStore().setClass(myList);
  225. }
  226. });
  227. }
  228. };
  229. onBeforeMount(() => {
  230. parameter.value = route.query;
  231. let project = parameter.value.project;
  232. unit.value = dic.unit[project];
  233. });
  234. onMounted(() => {
  235. getIniReportList();
  236. //getClass();
  237. });
  238. </script>
  239. <style lang="scss">
  240. @media screen and (max-width: 1280px) {
  241. :root {
  242. font-size: calc(1280px / 106);
  243. }
  244. }
  245. .reportList {
  246. display: flex;
  247. flex-direction: column;
  248. height: 100%;
  249. .title {
  250. height: 7.05vh;
  251. line-height: 7.05vh;
  252. width: 100%;
  253. text-align: center;
  254. color: #1a293a;
  255. font-size: 3.5vh;
  256. background: radial-gradient(120% 126% at 5% 93%, #8effa9 0%, #07ffe7 100%);
  257. }
  258. .searchBox {
  259. padding: 10px 10px;
  260. display: flex;
  261. justify-content: space-between;
  262. .select,
  263. .input {
  264. // width: 27%;
  265. width: 100%;
  266. }
  267. .el-select__wrapper {
  268. // border-radius: 15px;
  269. color: #1a293a;
  270. background: radial-gradient(30% 126% at 97% 6%, #35ffc6 0%, #00ffe8 100%) !important;
  271. }
  272. .el-input__wrapper {
  273. width: 25%;
  274. background: #ffffff;
  275. // border-radius: 15px;
  276. }
  277. .button {
  278. color: #1a293a;
  279. background: radial-gradient(141% 126% at 5% 93%, #8effa9 0%, #07ffe7 100%);
  280. box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.3);
  281. border: none;
  282. }
  283. }
  284. ul {
  285. height: 100%;
  286. overflow-y: scroll;
  287. li {
  288. border-bottom: 1px solid #48677e;
  289. padding: 8px 25px;
  290. display: flex;
  291. justify-content: space-between;
  292. align-items: center;
  293. cursor: pointer;
  294. transition: all 0.2s;
  295. &:hover {
  296. background: rgba(255, 255, 255, 0.4);
  297. }
  298. .left {
  299. display: flex;
  300. .pic {
  301. width: 7.5vh;
  302. height: 7.5vh;
  303. border-radius: 50%;
  304. display: flex;
  305. justify-content: center;
  306. align-items: center;
  307. overflow: hidden;
  308. box-sizing: border-box;
  309. border: 1px solid rgba(255, 255, 255, 0.5);
  310. margin-right: 13px;
  311. flex-shrink: 0;
  312. img {
  313. width: 100%;
  314. }
  315. }
  316. .txt {
  317. display: flex;
  318. align-items: center;
  319. .name {
  320. color: #f9f9f9;
  321. font-size: 1.38rem;
  322. }
  323. .className {
  324. color: #13ed84;
  325. font-size: 1.1rem;
  326. }
  327. }
  328. }
  329. .center {
  330. color: #ffffff;
  331. }
  332. .right {
  333. display: flex;
  334. font-weight: bold;
  335. align-items: center;
  336. .score {
  337. color: #ffffff;
  338. font-size: 1.1rem;
  339. font-family: 'Saira-ExtraBold';
  340. }
  341. .unit {
  342. color: #ffffff;
  343. font-size: 0.8rem;
  344. margin-left: 2px;
  345. }
  346. }
  347. }
  348. &::-webkit-scrollbar {
  349. width: 0px;
  350. }
  351. &::-webkit-scrollbar-thumb {
  352. border-width: 2px;
  353. border-radius: 4px;
  354. border-style: dashed;
  355. border-color: transparent;
  356. background-color: rgba(216, 216, 216, 0.8);
  357. background-clip: padding-box;
  358. }
  359. &::-webkit-scrollbar-button:hover {
  360. border-radius: 6px;
  361. background: rgba(216, 216, 216, 0.8);
  362. }
  363. }
  364. }
  365. </style>