evaluationRecords.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from '../index.module.less';
  3. import {
  4. NButton,
  5. NDataTable,
  6. NForm,
  7. NFormItem,
  8. NInput,
  9. NInputNumber,
  10. NModal,
  11. NSpace,
  12. NTag
  13. } from 'naive-ui';
  14. // import { useECharts } from '@/hooks/web/useECharts';
  15. import Pagination from '/src/components/pagination';
  16. import { getPracticeRecordList } from '../api';
  17. import {
  18. getNowDateAndMonday,
  19. getNowDateAndSunday,
  20. getTimes
  21. } from '/src/utils/dateFormat';
  22. import { vaildMusicScoreUrl } from '@/utils/urlUtils';
  23. import CDatePicker from '/src/components/CDatePicker';
  24. import { useUserStore } from '/src/store/modules/users';
  25. import TheEmpty from '/src/components/TheEmpty';
  26. import { initCache, setCache } from '/src/hooks/use-async';
  27. import { iframeDislableKeyboard } from '/src/utils';
  28. import { modalClickMask } from '/src/state';
  29. // import SearchInput from '/src/components/searchInput';
  30. import CSelect from '/src/components/CSelect';
  31. import { evaluateDifficultArray } from '/src/utils/searchArray';
  32. export default defineComponent({
  33. name: 'student-practiceData',
  34. props: {
  35. studentId: {
  36. type: String,
  37. default: ''
  38. },
  39. classGroupId: {
  40. type: String,
  41. default: ''
  42. }
  43. },
  44. setup(props) {
  45. const userStore = useUserStore();
  46. const chartRef = ref<HTMLDivElement | null>(null);
  47. // const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  48. // const practiceFlag = ref(true);
  49. const payForm = reactive({
  50. height: '360px',
  51. width: '100%',
  52. practiceDurationAvg: 0,
  53. practiceDays: 0,
  54. practiceDurationTotal: 0,
  55. dateList: [],
  56. timeList: [],
  57. detailVisiable: false
  58. });
  59. const reportSrc = ref('');
  60. const state = reactive({
  61. loading: false,
  62. pagination: {
  63. page: 1,
  64. rows: 10,
  65. pageTotal: 4
  66. },
  67. searchForm: {
  68. musicSheetName: '',
  69. heardLevel: null, //
  70. userMusicFlag: null, // 是否生成作品
  71. minScore: null,
  72. maxScore: null,
  73. musicStartTime: []
  74. },
  75. tableList: [] as any,
  76. goCourseVisiable: false
  77. });
  78. const timer = ref<[number, number]>([
  79. getNowDateAndMonday(new Date().getTime()),
  80. getNowDateAndSunday(new Date().getTime())
  81. ]);
  82. const columns = () => {
  83. return [
  84. {
  85. title: '时间',
  86. key: 'createTime'
  87. },
  88. {
  89. title: '评测曲目',
  90. key: 'musicSheetName',
  91. render(row: any) {
  92. return <span>{row.musicSheetName}</span>;
  93. }
  94. },
  95. // 入门:BEGINNER/进阶:ADVANCED/大师:PERFORMER"
  96. {
  97. title: '评测难度',
  98. key: 'heardLevel',
  99. render(row: any) {
  100. return (
  101. <>
  102. {row.heardLevel == null ? <span>--</span> : null}
  103. {row.heardLevel == 'BEGINNER' ? (
  104. <NTag type="info">入门级</NTag>
  105. ) : null}
  106. {row.heardLevel == 'ADVANCED' ? (
  107. <NTag type="warning">进阶级</NTag>
  108. ) : null}
  109. {row.heardLevel == 'PERFORMER' ? (
  110. <NTag type="error">大师级</NTag>
  111. ) : null}
  112. </>
  113. );
  114. }
  115. },
  116. {
  117. title: '评测分数',
  118. key: 'score',
  119. render(row: any) {
  120. return <span>{row.score}</span>;
  121. }
  122. },
  123. {
  124. title: '音准',
  125. key: 'intonation',
  126. render(row: any) {
  127. return <span>{row.intonation}</span>;
  128. }
  129. },
  130. {
  131. title: '节奏',
  132. key: 'cadence',
  133. render(row: any) {
  134. return <span>{row.cadence}</span>;
  135. }
  136. },
  137. {
  138. title: '完整度',
  139. key: 'integrity',
  140. render(row: any) {
  141. return <span>{row.integrity}</span>;
  142. }
  143. },
  144. {
  145. title: '生成作品',
  146. key: 'integrity',
  147. render(row: any) {
  148. return <span>{row.userMusicFlag ? '是' : '否'}</span>;
  149. }
  150. },
  151. {
  152. title: '生成时间',
  153. key: 'userMusicTime',
  154. render(row: any) {
  155. return <span>{row.userMusicTime || '--'}</span>;
  156. }
  157. },
  158. {
  159. title: '操作',
  160. key: 'id',
  161. render(row: any) {
  162. return (
  163. <NButton
  164. text
  165. type="primary"
  166. onClick={() => {
  167. gotoRecode(row);
  168. }}>
  169. 评测报告
  170. </NButton>
  171. );
  172. }
  173. }
  174. ];
  175. };
  176. const getList = async () => {
  177. const { musicStartTime, ...temp } = state.searchForm;
  178. const res = await getPracticeRecordList({
  179. userId: props.studentId,
  180. ...state.pagination,
  181. ...temp,
  182. ...getTimes(
  183. musicStartTime,
  184. ['userMusicStartTime', 'userMusicEndTime'],
  185. 'YYYY-MM-DD'
  186. ),
  187. classGroupId: props.classGroupId,
  188. feature: 'EVALUATION',
  189. ...getTimes(timer.value, ['startTime', 'endTime'], 'YYYY-MM-DD')
  190. });
  191. state.tableList = res.data.rows;
  192. state.pagination.pageTotal = res.data.total;
  193. };
  194. const gotoRecode = (row: any) => {
  195. const token = userStore.getToken;
  196. reportSrc.value =
  197. vaildMusicScoreUrl() +
  198. `/instrument/?v=${+new Date()}#/evaluat-report?v=${+new Date()}&id=${
  199. row.id
  200. }&platform=webTeacher&Authorization=${token}`;
  201. payForm.detailVisiable = true;
  202. };
  203. const search = () => {
  204. state.pagination.page = 1;
  205. getList();
  206. setCache({
  207. current: { timer: timer.value },
  208. saveKey: 'classStudentRecordEvaluationRecords'
  209. });
  210. };
  211. const onReset = () => {
  212. timer.value = [
  213. getNowDateAndMonday(new Date().getTime()),
  214. getNowDateAndSunday(new Date().getTime())
  215. ];
  216. state.searchForm = {
  217. musicSheetName: '',
  218. heardLevel: null, //
  219. userMusicFlag: null, // 是否生成作品
  220. minScore: null,
  221. maxScore: null,
  222. musicStartTime: []
  223. };
  224. search();
  225. setCache({
  226. current: { timer: timer.value },
  227. saveKey: 'classStudentRecordEvaluationRecords'
  228. });
  229. };
  230. initCache({
  231. current: { timer: timer.value },
  232. saveKey: 'classStudentRecordEvaluationRecords',
  233. callBack: (active: any) => {
  234. timer.value = active.timer;
  235. }
  236. });
  237. const iframeRef = ref();
  238. onMounted(() => {
  239. getList();
  240. });
  241. return () => (
  242. <>
  243. <NForm label-placement="left" inline style="flex-wrap: wrap;">
  244. <NFormItem>
  245. <CDatePicker
  246. v-model:value={timer.value}
  247. separator={'至'}
  248. type="daterange"
  249. class={styles.datePicker}
  250. startPlaceholder="评测开始时间"
  251. endPlaceholder="评测结束时间"
  252. timerValue={timer.value}></CDatePicker>
  253. </NFormItem>
  254. <NFormItem>
  255. <NInput
  256. placeholder="请输入曲目名称"
  257. v-model:value={state.searchForm.musicSheetName}
  258. />
  259. {/* v-model:value={state.searchForm.keyword} */}
  260. {/* <SearchInput
  261. {...{ placeholder: '请输入曲目名称' }}
  262. class={styles.searchInput}
  263. style={{ width: '160px' }}
  264. // searchWord={state.searchForm.keyword}
  265. // onChangeValue={(val: string) =>
  266. // (state.searchForm.keyword = val)
  267. // }
  268. ></SearchInput> */}
  269. </NFormItem>
  270. <NFormItem>
  271. <CSelect
  272. {...({
  273. options: evaluateDifficultArray,
  274. placeholder: '请输入评测难度',
  275. clearable: true,
  276. inline: true
  277. } as any)}
  278. v-model:value={state.searchForm.heardLevel}></CSelect>
  279. </NFormItem>
  280. <NFormItem>
  281. <div class={styles.inputRangeSection}>
  282. <NInputNumber
  283. placeholder="最小分值"
  284. min={0}
  285. max={state.searchForm.maxScore || 100}
  286. showButton={false}
  287. v-model:value={state.searchForm.minScore}></NInputNumber>
  288. <span class={styles.pair}>-</span>
  289. <NInputNumber
  290. placeholder="最大分值"
  291. min={state.searchForm.minScore || 0}
  292. max={100}
  293. showButton={false}
  294. v-model:value={state.searchForm.maxScore}></NInputNumber>
  295. </div>
  296. </NFormItem>
  297. <NFormItem>
  298. <CSelect
  299. {...({
  300. options: [
  301. { label: '是', value: true },
  302. { label: '否', value: false }
  303. ],
  304. placeholder: '请选择是否生成作品',
  305. clearable: true,
  306. inline: true
  307. } as any)}
  308. v-model:value={state.searchForm.userMusicFlag}></CSelect>
  309. </NFormItem>
  310. <NFormItem>
  311. <CDatePicker
  312. v-model:value={state.searchForm.musicStartTime}
  313. separator={'至'}
  314. class={styles.datePicker}
  315. type="daterange"
  316. startPlaceholder="生成开始时间"
  317. endPlaceholder="生成结束时间"
  318. timerValue={state.searchForm.musicStartTime}></CDatePicker>
  319. </NFormItem>
  320. <NFormItem>
  321. <NSpace justify="end">
  322. <NButton type="primary" class="searchBtn" onClick={search}>
  323. 搜索
  324. </NButton>
  325. <NButton type="primary" ghost class="resetBtn" onClick={onReset}>
  326. 重置
  327. </NButton>
  328. </NSpace>
  329. </NFormItem>
  330. </NForm>
  331. <div class={styles.tableWrap}>
  332. <NDataTable
  333. v-slots={{
  334. empty: () => <TheEmpty></TheEmpty>
  335. }}
  336. class={styles.classTable}
  337. loading={state.loading}
  338. columns={columns()}
  339. data={state.tableList}></NDataTable>
  340. <Pagination
  341. v-model:page={state.pagination.page}
  342. v-model:pageSize={state.pagination.rows}
  343. v-model:pageTotal={state.pagination.pageTotal}
  344. onList={getList}
  345. sync
  346. />
  347. </div>
  348. <NModal
  349. maskClosable={modalClickMask}
  350. v-model:show={payForm.detailVisiable}
  351. preset="card"
  352. class={['modalTitle background', styles.reportModel]}
  353. title={'评测报告'}>
  354. <div class={styles.reportContainer} style={{ lineHeight: 0 }}>
  355. <iframe
  356. width={'100%'}
  357. ref={iframeRef}
  358. frameborder="0"
  359. onLoad={(val: any) => {
  360. iframeDislableKeyboard(val.target);
  361. }}
  362. src={reportSrc.value}></iframe>
  363. </div>
  364. </NModal>
  365. </>
  366. );
  367. }
  368. });