trainDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <template>
  2. <div class="trainDetail">
  3. <van-sticky>
  4. <m-header v-if="headerStatus" :isFixed="false" />
  5. </van-sticky>
  6. <div class="evaluation">
  7. <van-cell style="padding: 16px 12px; background-color: transparent" :center="true">
  8. <template #title>
  9. <div class="teacher_info">
  10. <img class="logo" v-if="avatar" :src="avatar" alt="" />
  11. <img class="logo" v-else src="../../assets/images/icon_student.png" alt="" />
  12. <div class="teacher_content">
  13. <p style="color: #1a1a1a; font-size: 0.18rem">{{ username }}</p>
  14. <p style="font-size: 14px; color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 2.4rem">{{ musicGroupName }}</p>
  15. </div>
  16. </div>
  17. </template>
  18. <!-- <p style="font-size: 14px; color: #808080;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">{{ musicGroupName }}</p> -->
  19. </van-cell>
  20. </div>
  21. <van-row class="dataSearch" type="flex" v-if="!visitFlag">
  22. <van-col span="9" offset="1">
  23. <van-cell @click="onChangeDate('showStart')" is-link>
  24. <template #right-icon>
  25. <van-icon :name="arrowIcon" class="search-icon" size="10" />
  26. </template>
  27. <template v-if="searchList.startTime">{{ searchList.startTime }}</template>
  28. <span v-else style="color: #adadad">开始日期</span>
  29. </van-cell>
  30. </van-col>
  31. <van-col span="1" class="flexCenter">-</van-col>
  32. <van-col span="9">
  33. <van-cell @click="onChangeDate('showEnd')">
  34. <template #right-icon>
  35. <van-icon :name="arrowIcon" class="search-icon" size="10" />
  36. </template>
  37. <template v-if="searchList.endTime">{{ searchList.endTime }}</template>
  38. <span v-else style="color: #adadad">结束日期</span>
  39. </van-cell>
  40. </van-col>
  41. <van-col span="4" class="flexCenter">
  42. <span class="btn-search" @click="onSearch">搜索</span>
  43. </van-col>
  44. </van-row>
  45. <van-popup v-model="dataForm.status" position="bottom" round :style="{ height: '40%' }">
  46. <van-datetime-picker v-model="dataForm.currentDate" :min-date="dataForm.minDate" :max-date="dataForm.maxDate" :formatter="formatter" @cancel="dataForm.status = false" type="date" @confirm="chioseDate" />
  47. </van-popup>
  48. <div class="specialList" :class="{ bottomHeight: visitFlag }">
  49. <van-list v-model="loading" v-if="show" key="trainDetail" :finished="finished" finished-text="- 没有更多内容 -" :immediate-check="false" @load="getList()">
  50. <van-cell-group class="data-content" :border="false" v-for="(item, index) in dataList" :key="index" @click="showDetail(item)">
  51. <van-cell style="padding: 16px 12px" :center="true" title-style="flex-basis: 45%;">
  52. <template #title>
  53. <span style="font-size: 0.17rem; color: #333333; font-weight: 500; padding-right: 0.05rem; padding-bottom: 0.05rem">{{ item.sysMusicScoreName }}</span>
  54. <p style="font-size: 14px; color: #808080">{{ item.createTime }}</p>
  55. </template>
  56. <p>
  57. <img v-if="getLevelByScore(item.score) == 1" class="scoreImg" src="./images/1.png" alt="" />
  58. <img v-if="getLevelByScore(item.score) == 2" class="scoreImg" src="./images/2.png" alt="" />
  59. <img v-if="getLevelByScore(item.score) == 3" class="scoreImg" src="./images/3.png" alt="" />
  60. </p>
  61. </van-cell>
  62. <van-cell is-link :clickable="false" center style="padding: 12px 12px 16px">
  63. <template #title>
  64. <van-grid :border="false" column-num="4" :clickable="true">
  65. <van-grid-item text="综合得分" class="van-hairline--right">
  66. <template #icon>{{ item.score }}分</template>
  67. </van-grid-item>
  68. <van-grid-item text="音准" class="van-hairline--right">
  69. <template #icon>
  70. <span style="color: #01c1b5" v-if="item.isPercussion">--</span>
  71. <span style="color: #01c1b5" v-else>{{ item.intonation }}分</span>
  72. </template>
  73. </van-grid-item>
  74. <van-grid-item text="节奏" class="van-hairline--right">
  75. <template #icon>
  76. <span style="color: #ff802c">{{ item.cadence }}分</span>
  77. </template>
  78. </van-grid-item>
  79. <van-grid-item text="完成度">
  80. <template #icon>
  81. <span style="color: #f79c00" v-if="item.isPercussion">--</span>
  82. <span style="color: #f79c00" v-else>{{ item.integrity }}分</span>
  83. </template>
  84. </van-grid-item>
  85. </van-grid>
  86. </template>
  87. </van-cell>
  88. </van-cell-group>
  89. </van-list>
  90. <m-empty v-else key="trainDetail" msg="暂无训练详情" />
  91. <!-- 是否需要回访 -->
  92. <div class="button-group" v-if="visitFlag">
  93. <van-button type="primary" size="large" round @click="addVisited">添加回访</van-button>
  94. <div class="placeholder-btn"></div>
  95. </div>
  96. </div>
  97. </div>
  98. </template>
  99. <script>
  100. import MHeader from "@/components/MHeader";
  101. import MEmpty from "@/components/MEmpty";
  102. import { postMessage } from "@/helpers/native-message";
  103. import dayjs from "dayjs";
  104. import { browser } from "@/common/common";
  105. import { queryMusicCompareRecord } from "./api.js";
  106. export default {
  107. components: { MHeader, MEmpty },
  108. data() {
  109. const query = this.$route.query;
  110. return {
  111. arrowIcon: require("./images/arrow_down.png"),
  112. headerStatus: true,
  113. show: true,
  114. avatar: query.avatar,
  115. username: query.username,
  116. musicGroupName: query.musicGroupName,
  117. visitFlag: Number(query.visitFlag) || 0,
  118. searchList: {
  119. startTime: null,
  120. endTime: null,
  121. userId: query.userId,
  122. page: 1,
  123. rows: 20,
  124. },
  125. dataForm: {
  126. // 时间下拉框
  127. type: null,
  128. status: false,
  129. minDate: new Date(2000, 0, 1),
  130. maxDate: new Date(2030, 11, 31),
  131. currentDate: new Date(),
  132. },
  133. dataList: [],
  134. loading: false,
  135. finished: false,
  136. };
  137. },
  138. mounted() {
  139. if (browser().android || browser().iPhone) {
  140. this.headerStatus = false;
  141. }
  142. document.title = "评测详情";
  143. this.getList();
  144. },
  145. methods: {
  146. addVisited() {
  147. this.$router.push({
  148. path: "/addVisit",
  149. query: {
  150. ...this.$route.query,
  151. type: "train",
  152. name: "新增回访记录",
  153. },
  154. });
  155. },
  156. showDetail(item) {
  157. if (item.notesDataIndex > 0) {
  158. const route = location.hostname.indexOf("dayaedu.com") ? "/accompany/" : "/accompany-teacher/";
  159. postMessage({
  160. api: "openWebView",
  161. content: {
  162. url: location.origin + route + `#/report/${item.id}`,
  163. orientation: 0,
  164. isHideTitle: true,
  165. statusBarTextColor: false,
  166. isOpenLight: true,
  167. },
  168. });
  169. } else {
  170. this.$toast("本次评测未生成报告");
  171. }
  172. },
  173. isRhythmicExercises(examSongName) {
  174. return examSongName.indexOf("节奏练习") > -1;
  175. },
  176. async getList() {
  177. try {
  178. let res = await queryMusicCompareRecord(this.searchList);
  179. let result = res.data;
  180. this.loading = false;
  181. // 重点这句,判断是不是重复请求了
  182. if (this.dataList.length > 0 && result.pageNo == 1) {
  183. return;
  184. }
  185. let rows = result.rows || [];
  186. this.dataList = this.dataList.concat(rows).map((item) => {
  187. item.isPercussion = [23, 113, 121].includes(item.subjectId) || this.isRhythmicExercises(item.sysMusicScoreName);
  188. return item;
  189. });
  190. if (this.searchList.page >= result.totalPage) {
  191. this.finished = true;
  192. }
  193. this.searchList.page++;
  194. if (this.dataList.length <= 0) {
  195. this.show = false;
  196. }
  197. } catch {
  198. this.show = false;
  199. this.finished = true;
  200. }
  201. },
  202. onSearch() {
  203. this.dataList = []; // 重置数据
  204. this.show = true;
  205. this.loading = true;
  206. this.finished = false;
  207. this.searchList.page = 1;
  208. this.getList();
  209. },
  210. onChangeDate(type) {
  211. let dataForm = this.dataForm;
  212. if (type == "showEnd" && this.searchList.startTime) {
  213. dataForm.minDate = new Date(dayjs(this.searchList.startTime));
  214. dataForm.maxDate = new Date(2030, 11, 31);
  215. setTimeout(() => {
  216. dataForm.currentDate = this.searchList.endTime ? new Date(dayjs(this.searchList.endTime)) : new Date();
  217. }, 500);
  218. } else if (type == "showStart" && this.searchList.endTime) {
  219. dataForm.minDate = new Date(2000, 0, 1);
  220. dataForm.maxDate = new Date(dayjs(this.searchList.endTime));
  221. setTimeout(() => {
  222. dataForm.currentDate = this.searchList.startTime ? new Date(dayjs(this.searchList.startTime)) : new Date();
  223. }, 500);
  224. }
  225. dataForm.status = true;
  226. dataForm.type = type;
  227. },
  228. chioseDate(value) {
  229. let dataForm = this.dataForm;
  230. if (dataForm.type == "showStart") {
  231. this.searchList.startTime = dayjs(value).format("YYYY-MM-DD");
  232. } else if (dataForm.type == "showEnd") {
  233. this.searchList.endTime = dayjs(value).format("YYYY-MM-DD");
  234. }
  235. dataForm.status = false;
  236. },
  237. formatter(type, val) {
  238. if (type === "year") {
  239. return `${val}年`;
  240. } else if (type === "month") {
  241. return `${val}月`;
  242. } else if (type == "day") {
  243. return `${val}日`;
  244. }
  245. return val;
  246. },
  247. getLevelByScore(score) {
  248. let level = 3;
  249. if (score > 60 && score <= 80) {
  250. level = 2;
  251. } else if (score > 80) {
  252. level = 1;
  253. }
  254. return level;
  255. },
  256. },
  257. };
  258. </script>
  259. <style lang="less" scoped>
  260. .trainDetail {
  261. background: #f5f5f5;
  262. min-height: 100vh;
  263. overflow: hidden;
  264. }
  265. .evaluation {
  266. display: flex;
  267. align-items: center;
  268. margin: 0.12rem 0.12rem 0;
  269. height: 1.05rem;
  270. border-radius: 0.1rem;
  271. background: url("./images/user_bg.png") no-repeat center #fff;
  272. background-size: contain;
  273. .teacher_info {
  274. display: flex;
  275. align-items: center;
  276. img {
  277. margin-right: 0.15rem;
  278. width: 0.6rem;
  279. height: 0.6rem;
  280. border-radius: 50%;
  281. }
  282. }
  283. }
  284. .search-icon {
  285. display: flex;
  286. align-items: center;
  287. }
  288. .scoreImg {
  289. width: 66px;
  290. height: 25px;
  291. }
  292. .data-content {
  293. margin: 0.15rem 0.15rem 0;
  294. border-radius: 0.1rem;
  295. overflow: hidden;
  296. &:first-child {
  297. margin-top: 0;
  298. }
  299. .van-row-item {
  300. display: flex;
  301. align-items: center;
  302. }
  303. /deep/.van-grid-item__content {
  304. padding: 0.03rem;
  305. }
  306. /deep/.van-grid-item__content {
  307. background-color: transparent;
  308. }
  309. /deep/.van-grid-item__icon-wrapper {
  310. font-size: 0.15rem;
  311. font-weight: 500;
  312. color: #000;
  313. }
  314. /deep/.van-grid-item__text {
  315. padding-top: 0.03rem;
  316. font-size: 0.12rem;
  317. color: #808080;
  318. }
  319. .teacher_info {
  320. display: flex;
  321. align-items: center;
  322. img {
  323. margin-right: 0.1rem;
  324. width: 0.4rem;
  325. height: 0.4rem;
  326. border-radius: 50%;
  327. }
  328. }
  329. }
  330. .specialList {
  331. padding-top: 0.1rem;
  332. // padding-bottom: calc(env(safe-area-inset-bottom) / 2);
  333. &.bottomHeight {
  334. padding-bottom: 65px;
  335. }
  336. }
  337. .dataSearch {
  338. padding: 0.12rem 0.12rem 0.05rem;
  339. background-color: #f5f5f5;
  340. /deep/.van-cell {
  341. background: #fff;
  342. padding: 0rem 0.16rem;
  343. border-radius: 1rem;
  344. overflow: hidden;
  345. height: 0.27rem;
  346. line-height: 0.27rem;
  347. }
  348. /deep/.van-cell__value--alone {
  349. text-align: center;
  350. }
  351. .flexCenter {
  352. display: flex;
  353. align-items: center;
  354. justify-content: center;
  355. }
  356. .btn-search {
  357. background: #01c1b5;
  358. font-size: 14px;
  359. color: #fff;
  360. padding: 3px 9px;
  361. border-radius: 15px;
  362. }
  363. }
  364. .button-group {
  365. overflow: hidden;
  366. position: fixed;
  367. bottom: 0;
  368. width: calc(100% - 0.24rem);
  369. z-index: 9;
  370. margin: 0 0.12rem 12px;
  371. .van-button--primary {
  372. background: #01c1b5;
  373. border: 1px solid #01c1b5;
  374. font-size: 0.16rem;
  375. float: right;
  376. // padding-bottom: calc(env(safe-area-inset-bottom) / 2);
  377. height: auto;
  378. line-height: 48px;
  379. }
  380. }
  381. </style>