123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- import {
- Button,
- Cell,
- CellGroup,
- Checkbox,
- CheckboxGroup,
- Field,
- Icon,
- Image,
- List,
- Radio,
- RadioGroup,
- Tag,
- showToast
- } from 'vant';
- import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
- import styles from './detail.module.less';
- import iconTimer from '@/common/images/icon-timer.png';
- import iconTeacher from '@/common/images/icon-teacher-default.png';
- import iconEdit from '@/common/images/icon-edit.png';
- import iconFace1 from './images/icon-face-1.png';
- import iconFace2 from './images/icon-face-2.png';
- import iconFace3 from './images/icon-face-3.png';
- import iconFace4 from './images/icon-face-4.png';
- import iconUploadImg from './images/icon-upload-img.png';
- import iconUploadVideo from './images/icon-upload-video.png';
- import SkeletionDetailModal from './skeletion-detail.modal';
- import MUploader from '@/components/m-uploader';
- import MUploaderInside from '@/components/m-uploader/inside';
- import MFullRefresh from '@/components/m-full-refresh';
- import { coursesStatus, evaluateStatus, problemType } from '@/helpers/constant';
- import MEmpty from '@/components/m-empty';
- import request from '@/helpers/request';
- import dayjs from 'dayjs';
- import { useRoute } from 'vue-router';
- import MImagePreview from '@/components/m-image-preview';
- import { checkFile } from '@/helpers/toolsValidate';
- import deepClone from '@/helpers/deep-clone';
- import iconVideoDefault from '@common/images/icon-video-c.png';
- export default defineComponent({
- name: 'detail-list',
- props: {
- type: {
- type: String,
- default: ''
- },
- evaluateStatus: {
- type: String,
- default: ''
- },
- problemType: {
- type: String,
- default: ''
- },
- courseType: {
- type: String,
- default: ''
- },
- status: {
- type: String,
- default: ''
- },
- activeTab: {
- type: String,
- default: 'NotEvaluated'
- }
- },
- setup(props) {
- const route = useRoute();
- const forms = reactive({
- isClick: false,
- imageShow: false,
- startPosition: 0,
- imagePreview: [] as string[],
- listState: {
- dataShow: true, // 判断是否有数据
- loading: true,
- finished: false,
- refreshing: false
- },
- params: {
- evaluateFlag: props.type === 'Evaluated' ? true : false,
- evaluateStatus: '',
- problemType: '',
- courseType: '',
- status: '',
- startTime: route.query.date || '',
- endTime: route.query.date || '',
- page: 1,
- rows: 20
- },
- changeType: null,
- questionType: null,
- evaluateList: [] as any,
- problemTypeList: [] as any,
- list: [],
- btnLoading: false
- });
- const list = ref([] as any[]);
- const onRefresh = () => {
- forms.params.page = 1;
- forms.listState.refreshing = true;
- getList();
- };
- const getList = async () => {
- try {
- if (forms.isClick) return;
- forms.isClick = true;
- const { data } = await request.post(
- '/api-web/coursePatrolEvaluation/page',
- {
- data: forms.params
- }
- );
- const result = data || {};
- // 格式化数据
- const rows = result.rows || [];
- rows.forEach((row: any) => {
- const attachmentUrlList = row.attachmentUrl
- ? row.attachmentUrl.split(',')
- : [];
- const problemTypeList = row.problemType
- ? row.problemType.split(',')
- : [];
- row.problemTypeList = problemTypeList;
- // 级别
- row.submitEvaluateStatus = row.evaluateStatus || '';
- // 问题类型
- row.submitProblemType = problemTypeList || [];
- row.submitProblemDesc = row.problemDesc || '';
- // 图片和视屏
- row.submitVideoList = [];
- row.submitImgList = [];
- attachmentUrlList.forEach((url: any) => {
- // 判断是否是图片
- if (checkFile(url, 'image')) {
- row.submitImgList.push(url);
- } else {
- row.submitVideoList.push(url);
- }
- // 判断是否是视频
- });
- row.attachmentUrlList = attachmentUrlList || [];
- // 判断是否评价,如果有评价则直接显示评价内容
- if (!row.evaluateFlag) {
- row.isEdit = true;
- }
- });
- // 判断是否有数据
- if (forms.listState.refreshing) {
- list.value = rows || [];
- } else {
- list.value = list.value.concat(rows || []);
- }
- forms.listState.finished = result.pageNo >= result.totalPage;
- forms.params.page = result.pageNo + 1;
- } catch {
- forms.listState.finished = true;
- } finally {
- setTimeout(() => {
- forms.listState.dataShow = list.value.length > 0;
- forms.listState.refreshing = false;
- forms.listState.loading = false;
- forms.isClick = false;
- }, 300);
- }
- };
- // 提交评价
- const onSubmit = async (item: any) => {
- try {
- const url = [...item.submitImgList, ...item.submitVideoList];
- //
- if (!item.submitEvaluateStatus) {
- showToast('请选择评价');
- return;
- }
- // 当选择“不合格”的时候,问题类型、问题描述、上传附件为必填项
- if (item.submitEvaluateStatus === 'UNQUALIFIED') {
- if (
- !item.submitProblemType ||
- (item.submitProblemType && item.submitProblemType.length <= 0)
- ) {
- showToast('请选择问题类型');
- return;
- }
- if (!item.submitProblemDesc) {
- showToast('请输入问题描述');
- return;
- }
- if (item.submitProblemDesc.length < 3) {
- showToast('问题描述最少输入3个字');
- return;
- }
- // 最大支持3-50汉字
- if (
- item.submitProblemDesc.length < 3 ||
- item.submitProblemDesc.length <= 50
- )
- if (url.length <= 0) {
- showToast('请上传附件');
- return;
- }
- }
- const params = {
- id: item.id,
- evaluateStatus: item.submitEvaluateStatus,
- problemType: item.submitProblemType.join(','),
- problemDesc: item.submitProblemDesc,
- attachmentUrl: url.join(',')
- };
- forms.btnLoading = true;
- if (item.evaluateFlag) {
- // 修改
- await request.post('/api-web/coursePatrolEvaluation/update', {
- // hideLoading: false,
- data: params
- });
- } else {
- // 添加
- await request.post('/api-web/coursePatrolEvaluation/save', {
- // hideLoading: false,
- data: {
- ...params,
- courseScheduleId: item.courseScheduleId
- }
- });
- }
- forms.btnLoading = false;
- list.value = [];
- onRefresh();
- } catch {
- //
- forms.btnLoading = false;
- }
- };
- const onShowPreView = (attachmentUrlList: string[], index: number) => {
- forms.imagePreview = deepClone(attachmentUrlList);
- forms.imageShow = true;
- forms.startPosition = index;
- };
- const formatFace = (type: string) => {
- if (type === 'EXCELLENT') {
- return iconFace1;
- } else if (type === 'GOOD') {
- return iconFace2;
- } else if (type === 'QUALIFIED') {
- return iconFace3;
- } else if (type === 'UNQUALIFIED') {
- return iconFace4;
- } else {
- return iconFace1;
- }
- };
- onMounted(() => {
- for (const key in evaluateStatus) {
- if (Object.prototype.hasOwnProperty.call(evaluateStatus, key)) {
- forms.evaluateList.push({
- text: evaluateStatus[key],
- value: key
- });
- }
- }
- for (const key in problemType) {
- if (Object.prototype.hasOwnProperty.call(problemType, key)) {
- forms.problemTypeList.push({
- text: problemType[key],
- value: key
- });
- }
- }
- getList();
- });
- // 监听
- watch(
- () => [
- props.evaluateStatus,
- props.problemType,
- props.courseType,
- props.status
- ],
- () => {
- forms.params.evaluateStatus = props.evaluateStatus;
- forms.params.problemType = props.problemType;
- forms.params.courseType = props.courseType;
- forms.params.status = props.status;
- list.value = [];
- onRefresh();
- }
- );
- watch(
- () => props.activeTab,
- () => {
- if (props.type === props.activeTab) {
- forms.params.evaluateStatus = props.evaluateStatus;
- forms.params.problemType = props.problemType;
- forms.params.courseType = props.courseType;
- forms.params.status = props.status;
- list.value = [];
- onRefresh();
- }
- }
- );
- return () => (
- <div>
- <SkeletionDetailModal v-model:show={forms.listState.loading}>
- <MFullRefresh
- v-model:modelValue={forms.listState.refreshing}
- onRefresh={() => onRefresh()}
- style={{
- minHeight: `calc(100vh - var(--header-height) - var(--van-tabs-line-height))`
- }}>
- <List
- finished={forms.listState.finished}
- finishedText=" "
- style={{ overflow: 'hidden', marginBottom: '18px' }}
- onLoad={getList}
- offset={100}
- immediateCheck={false}>
- {forms.listState.dataShow ? (
- list.value.map((item: any) => {
- return (
- <CellGroup inset class={styles.cellGroup}>
- <Cell center class={styles.timerCell} border={false}>
- {{
- icon: () => (
- <Icon name={iconTimer} class={styles.iconTimer} />
- ),
- title: () => (
- <div class={styles.timer}>
- {dayjs(item.startClassTime).format(
- 'YYYY-MM-DD HH:mm'
- )}
- ~{dayjs(item.endClassTime).format('HH:mm')}
- </div>
- ),
- value: () => (
- <div
- class={styles.eStatus}
- onClick={() => {
- item.isEdit = true;
- }}>
- {/* 判断是否评价 */}
- {item.evaluateFlag ? (
- <>
- <div class={styles.evaluateResult}>
- <Icon
- name={formatFace(item.evaluateStatus)}
- class={styles.iconFace}
- />
- <span
- class={[
- styles.sLevel,
- item.evaluateStatus === 'UNQUALIFIED'
- ? styles.error
- : styles.success
- ]}>
- {evaluateStatus[item.evaluateStatus]}
- </span>
- </div>
- <Icon
- name={iconEdit}
- class={styles.iconEdit}
- />
- </>
- ) : (
- <span
- class={[
- styles.sLevel,
- item.courseStatus === 'UNDERWAY'
- ? styles.success
- : '',
- item.courseStatus == 'OVER'
- ? styles.over
- : ''
- ]}>
- {coursesStatus[item.courseStatus]}
- </span>
- )}
- </div>
- )
- }}
- </Cell>
- <Cell center class={styles.usernameCell}>
- {{
- icon: () => (
- <Image
- src={item.teacherAvatar || iconTeacher}
- class={styles.iconTeacher}
- fit="cover"
- />
- ),
- title: () => (
- <div>
- <div class={styles.classname}>
- {item.courseName}
- </div>
- <div class={styles.name}>{item.teacherName}</div>
- </div>
- ),
- value: () => (
- <div class={styles.photoList}>
- {item.attachmentUrlList.map(
- (file: string, index: number) =>
- index < 3 && (
- <div
- class={styles.photo}
- onClick={(e: MouseEvent) => {
- e.stopPropagation();
- e.preventDefault();
- onShowPreView(
- item.attachmentUrlList,
- index
- );
- }}>
- {checkFile(file, 'image') ? (
- <Image
- src={
- file + '@base@tag=imgScale&w=120'
- }
- fit="cover"
- />
- ) : (
- <video
- poster={iconVideoDefault}
- src={file + '#t=1,4'}
- controls={false}></video>
- )}
- {/* 判断是否大于三个 */}
- {item.attachmentUrlList.length > 3 &&
- index === 2 ? (
- <div class={styles.photoMore}>
- +{item.attachmentUrlList.length - 3}
- </div>
- ) : (
- ''
- )}
- </div>
- )
- )}
- </div>
- )
- }}
- </Cell>
- {/* 展示结果 */}
- {(item.submitProblemType.length > 0 ||
- item.problemDesc) &&
- !item.isEdit ? (
- <Cell center class={styles.resultCell}>
- {item.problemTypeList.length > 0 ? (
- <div class={styles.typeGroup}>
- {item.problemTypeList.map((type: string) => (
- <Tag type="primary" plain>
- {problemType[type]}
- </Tag>
- ))}
- </div>
- ) : (
- ''
- )}
- {item.problemDesc ? (
- <div class={styles.result}>{item.problemDesc}</div>
- ) : (
- ''
- )}
- </Cell>
- ) : (
- ''
- )}
- {/* 未开始的不能进行评价 */}
- {item.isEdit && item.courseStatus != 'NOT_START' ? (
- <Cell center class={styles.operationCell}>
- <RadioGroup
- class={styles.typeGroup}
- v-model={item.submitEvaluateStatus}>
- {forms.evaluateList.map((child: any) => (
- <Tag
- type={
- item.submitEvaluateStatus === child.value
- ? 'primary'
- : 'default'
- }
- plain>
- <Radio name={child.value} />
- {child.text}
- </Tag>
- ))}
- </RadioGroup>
- {/* 当选择“不合格”的时候,问题类型、问题描述、上传附件为必填项 当选择除不合格的其他选项时,问题类型、问题描述不展示,桑川附件为选填 */}
- {item.submitEvaluateStatus === 'UNQUALIFIED' ? (
- <>
- <div class={styles.operationTitle}>问题类型</div>
- <CheckboxGroup
- class={styles.typeGroup}
- v-model={item.submitProblemType}>
- {forms.problemTypeList.map((child: any) => (
- <Tag
- type={
- item.submitProblemType.includes(
- child.value
- )
- ? 'primary'
- : 'default'
- }
- plain>
- <Checkbox name={child.value} />
- {child.text}
- </Tag>
- ))}
- </CheckboxGroup>
- <div class={styles.operationTitle}>问题描述</div>
- <Field
- type="textarea"
- rows={2}
- v-model={item.submitProblemDesc}
- maxlength={50}
- class={styles.questionContent}
- placeholder="请输入问题描述..."
- border={false}
- />
- </>
- ) : (
- ''
- )}
- <div class={styles.operationTitle}>上传附件</div>
- <div class={styles.uploadGroup}>
- <MUploader
- uploadIcon={iconUploadImg}
- maxCount={5}
- native
- v-model:modelValue={item.submitImgList}>
- <MUploaderInside
- uploadIcon={iconUploadVideo}
- uploadType="VIDEO"
- accept=".mp4"
- uploadSize={50}
- native
- maxCount={3}
- v-model:modelValue={item.submitVideoList}
- />
- </MUploader>
- </div>
- <div
- class={[
- styles.btnGroup,
- !item.evaluateFlag ? styles.singleBtn : ''
- ]}>
- {/* 评价之后才能取消 */}
- {item.evaluateFlag ? (
- <Button
- type="default"
- round
- block
- onClick={() => (item.isEdit = false)}>
- 取消
- </Button>
- ) : (
- ''
- )}
- <Button
- type="primary"
- round
- block
- disabled={forms.btnLoading}
- loading={forms.btnLoading}
- onClick={() => onSubmit(item)}>
- 确认
- </Button>
- </div>
- </Cell>
- ) : (
- ''
- )}
- </CellGroup>
- );
- })
- ) : (
- <MEmpty
- style={{
- minHeight: `calc(100vh - var(--header-height))`
- }}
- description="暂无数据"
- />
- )}
- </List>
- </MFullRefresh>
- </SkeletionDetailModal>
- <MImagePreview
- teleport="body"
- v-model:show={forms.imageShow}
- images={forms.imagePreview}
- startPosition={forms.startPosition}
- />
- </div>
- );
- }
- });
|