瀏覽代碼

Merge branch 'master' of http://git.dayaedu.com/lex/orchestra-app

skyblued 2 年之前
父節點
當前提交
8e0c392c0d

+ 6 - 0
src/components/o-upload/index.tsx

@@ -56,10 +56,15 @@ export default defineComponent({
     bucket: {
       type: String,
       default: 'daya'
+    },
+    disabled: {
+      type: Boolean,
+      default: false
     }
   },
   methods: {
     nativeUpload() {
+      if (this.disabled) return
       postMessage(
         {
           api: 'chooseFile',
@@ -218,6 +223,7 @@ export default defineComponent({
             afterRead={this.afterRead}
             beforeRead={this.beforeRead}
             beforeDelete={this.beforeDelete}
+            disabled={this.disabled}
             v-slots={{
               default: () =>
                 this.modelValue ? (

+ 3 - 1
src/helpers/request.ts

@@ -93,6 +93,7 @@ request.interceptors.response.use(
       closeToast()
     }, 100)
 
+
     if (res.status > 299 || res.status < 200) {
       clearTimeout(toast)
       const msg = '服务器错误,状态码' + res.status
@@ -100,7 +101,8 @@ request.interceptors.response.use(
       throw new Error(msg)
     }
     const data = await res.clone().json()
-    if (data.code !== 200 && data.errCode !== 0) {
+    // 999 为特殊code码
+    if (data.code !== 200 && data.errCode !== 0 && data.code !== 999) {
       let msg = data.msg || data.message || '处理失败,请重试'
       if (initRequest) {
         if (data.code === 403 || data.code === 5000) {

+ 150 - 59
src/school/companion-teacher/companion-teacher-register.tsx

@@ -18,7 +18,7 @@ import {
   Popup,
   CountDown
 } from 'vant'
-import { defineComponent, onMounted, reactive } from 'vue'
+import { defineComponent, onMounted, reactive, ref } from 'vue'
 import { useRoute } from 'vue-router'
 import styles from './companion-teacher-register.module.less'
 import ImgCode from '@/components/o-img-code'
@@ -41,10 +41,12 @@ export default defineComponent({
       showSubject: false,
       submitStatus: false,
       showEducation: false,
+      checkPhone: true,
       id: route.query.id,
       name: route.query.name,
       t: route.query.t as any, // 过期时间
-      // qrCodeStatus: false, // 二维码是否失效
+      qrCodeStatus: false, // 二维码是否失效
+      qrCodeMessage: '',
       pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
       columns: [] as any,
       pickerType: null, // 下拉类型
@@ -66,7 +68,6 @@ export default defineComponent({
         idcardBackImg: '' // 身份证反面照
       },
       btnLoading: false,
-      checkPhone: false,
       checked: true,
       columnSubject: [] as any,
       countDownStatus: true, // 是否发送验证码
@@ -77,19 +78,21 @@ export default defineComponent({
     })
 
     const onSubmit = async () => {
-      // if (state.qrCodeStatus) {
-      //   showDialog({
-      //     title: '提示',
-      //     message: '二维码已失效',
-      //     theme: 'round-button',
-      //     confirmButtonColor: '#ff8057'
-      //   })
-      //   return
-      // }
+      if (state.qrCodeStatus) {
+        showDialog({
+          title: '提示',
+          message: state.qrCodeMessage,
+          theme: 'round-button',
+          confirmButtonColor: '#ff8057'
+        })
+        return
+      }
       if (!state.checked) {
         showToast('请阅读并同意协议')
         return
       }
+      console.log(state.forms, '///222')
+      return
       state.btnLoading = true
       try {
         const forms = state.forms
@@ -198,6 +201,28 @@ export default defineComponent({
       //   return
       // }
 
+      // t: route.query.t, // 过期时间
+      try {
+        const res = await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
+          data: {
+            schoolId: state.id,
+            qrCodeEffectiveStartTime: state.t ? dayjs(state.t).format('YYYY-MM-DD HH:mm:ss') : null
+          }
+        })
+        if (res.code === 999) {
+          showDialog({
+            title: '提示',
+            message: res.message,
+            theme: 'round-button',
+            confirmButtonColor: '#ff8057'
+          })
+          state.qrCodeStatus = true
+        }
+      } catch (e: any) {
+        //
+        console.log(e)
+      }
+
       try {
         const tempareas: any = []
         areas.forEach((item) => {
@@ -241,38 +266,6 @@ export default defineComponent({
           confirmButtonColor: '#ff8057'
         })
       }
-
-      // t: route.query.t, // 过期时间
-      try {
-        await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
-          data: {
-            schoolId: state.id
-            // qrCodeEffectiveStartTime: state.t ? dayjs(state.t).format('YYYY-MM-DD HH:mm:ss') : null
-          }
-        })
-        // if (state.t) {
-        //   const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
-        //     requestType: 'form',
-        //     params: {
-        //       paramName: 'qr_code_expire_hours'
-        //     }
-        //   })
-        //   if (dayjs(Number(state.t)).add(data.paramValue, 'hour').isBefore(dayjs())) {
-        // showDialog({
-        //   title: '提示',
-        //   message: '二维码已失效',
-        //   theme: 'round-button',
-        //   confirmButtonColor: '#ff8057'
-        // })
-        //     state.qrCodeStatus = true
-        //   } else {
-        //     state.qrCodeStatus = false
-        //   }
-        // }
-      } catch (e: any) {
-        //
-        console.log(e)
-      }
     })
 
     const onPreview = () => {
@@ -282,6 +275,76 @@ export default defineComponent({
       )
     }
 
+    const formRef = ref()
+    const checkchangePhone = async () => {
+      try {
+        await formRef.value?.validate('phone')
+        state.checkPhone = false
+
+        getTeacherDetails()
+      } catch {
+        //
+      }
+    }
+
+    const getTeacherDetails = async () => {
+      try {
+        if (!state.forms.phone) return
+        const { data } = await request.post(
+          '/api-school/open/teacher/detail/' + state.forms.phone,
+          {
+            requestType: 'form',
+            data: {
+              phone: state.forms.phone
+            }
+          }
+        )
+        // 判断是否有数据
+        if (!data) return
+        const subjects = data.subjectId
+          ? data.subjectId.split(',').map((subject: any) => Number(subject))
+          : []
+        // 显示声部
+        subjects.forEach((subject: any) => {
+          const item = state.columnSubject.find((item: any) => item.value === subject)
+
+          if (item) {
+            state.selectSubjects.push(item)
+          }
+        })
+
+        let cityCodeName = ''
+        state.columns.forEach((p: any) => {
+          if (p.areas && p.areas.length > 0) {
+            p.areas.forEach((c: any) => {
+              if (c.code === Number(data.cityCode)) {
+                cityCodeName = c.name
+              }
+            })
+          }
+        })
+
+        state.forms = {
+          realName: data.realName,
+          phone: data.phone,
+          gender: data.gender,
+          idCardNo: data.idCardNo,
+          cityCode: data.cityCode,
+          cityCodeName: cityCodeName,
+          provinceCode: data.provinceCode,
+          showSubjectIds: data.subjectId,
+          subjectIds: subjects as any,
+          smsValidCode: '',
+          educationBackground: data.educationBackground || '', // 学历
+          graduateSchool: data.graduateSchool, // 毕业学校
+          idcardFrontImg: data.idcardFrontImg || '',
+          idcardBackImg: data.idcardBackImg || '' // 身份证反面照
+        }
+      } catch {
+        //
+      }
+    }
+
     return () => (
       <div class={styles.register}>
         <div class={styles.title}>
@@ -290,20 +353,10 @@ export default defineComponent({
             <span>{state.name}</span>
           </p>
         </div>
-        <Form validateFirst scrollToError onSubmit={onSubmit} ref="form" class={styles.form}>
+        <Form validateFirst scrollToError onSubmit={onSubmit} ref={formRef} class={styles.form}>
           <CellGroup inset class={styles['cell-group']}>
             <Field
               required
-              label="真实姓名"
-              v-model={state.forms.realName}
-              rules={[{ required: true, message: '请填写真实姓名' }]}
-              name="realName"
-              placeholder="请填写真实姓名"
-              maxlength="50"
-            ></Field>
-
-            <Field
-              required
               label="手机号码"
               v-model={state.forms.phone}
               rules={[
@@ -313,8 +366,19 @@ export default defineComponent({
               name="phone"
               placeholder="请输入手机号码"
               maxlength={11}
+              onBlur={checkchangePhone}
               type="tel"
             ></Field>
+            <Field
+              required
+              label="真实姓名"
+              v-model={state.forms.realName}
+              rules={[{ required: true, message: '请填写真实姓名' }]}
+              name="realName"
+              placeholder="请填写真实姓名"
+              maxlength="50"
+              disabled={state.checkPhone}
+            ></Field>
 
             <Field
               required
@@ -331,6 +395,7 @@ export default defineComponent({
               name="idCardNo"
               maxlength={18}
               placeholder="请输入身份证号码"
+              disabled={state.checkPhone}
             ></Field>
 
             <Field
@@ -345,6 +410,7 @@ export default defineComponent({
                     checked-color="#FF8057"
                     v-model={state.forms.gender}
                     direction="horizontal"
+                    disabled={state.checkPhone}
                   >
                     <Tag
                       size="large"
@@ -385,6 +451,7 @@ export default defineComponent({
                   <OUpload
                     style={{ width: '100%' }}
                     tips="上传身份证正面"
+                    disabled={state.checkPhone}
                     v-model:modelValue={state.forms.idcardFrontImg}
                   />
                 )
@@ -404,6 +471,7 @@ export default defineComponent({
                   <OUpload
                     style={{ width: '100%' }}
                     tips="上传身份证反面"
+                    disabled={state.checkPhone}
                     v-model:modelValue={state.forms.idcardBackImg}
                   />
                 )
@@ -415,8 +483,12 @@ export default defineComponent({
               label="学历"
               v-model={state.forms.educationBackground}
               readonly
+              disabled={state.checkPhone}
               name="educationBackground"
-              onClick={() => (state.showEducation = true)}
+              onClick={() => {
+                if (state.checkPhone) return
+                state.showEducation = true
+              }}
               rules={[{ required: true, message: '请选择学历', trigger: 'onChange' }]}
               placeholder="请选择学历"
             >
@@ -430,6 +502,7 @@ export default defineComponent({
             <Field
               required
               label="毕业学校"
+              disabled={state.checkPhone}
               v-model={state.forms.graduateSchool}
               rules={[{ required: true, message: '请输入毕业学校' }]}
               name="graduateSchool"
@@ -441,8 +514,12 @@ export default defineComponent({
               label="所在城市"
               v-model={state.forms.cityCodeName}
               readonly
+              disabled={state.checkPhone}
               name="cityCodeName"
-              onClick={() => (state.showPicker = true)}
+              onClick={() => {
+                if (state.checkPhone) return
+                state.showPicker = true
+              }}
               rules={[{ required: true, message: '请选择所在城市', trigger: 'onChange' }]}
               placeholder="请选择所在城市"
             >
@@ -459,7 +536,11 @@ export default defineComponent({
               v-model={state.forms.showSubjectIds}
               readonly
               name="showSubjectIds"
-              onClick={() => (state.showSubject = true)}
+              disabled={state.checkPhone}
+              onClick={() => {
+                if (state.checkPhone) return
+                state.showSubject = true
+              }}
               rules={[{ required: true, message: '请选择声部', trigger: 'onChange' }]}
               placeholder="请选择声部"
             >
@@ -504,12 +585,20 @@ export default defineComponent({
               rules={[{ required: true, message: '请输入验证码', trigger: 'onChange' }]}
               placeholder="请输入验证码"
               maxlength={6}
+              disabled={state.checkPhone}
               type="tel"
             >
               {{
                 button: () =>
                   state.countDownStatus ? (
-                    <Button type="primary" round size="small" color="#ff8057" onClick={onSendCode}>
+                    <Button
+                      type="primary"
+                      round
+                      size="small"
+                      disabled={state.checkPhone}
+                      color="#ff8057"
+                      onClick={onSendCode}
+                    >
                       发送验证码
                     </Button>
                   ) : (
@@ -559,10 +648,12 @@ export default defineComponent({
             color="#FF8057"
             loading={state.btnLoading}
             native-type="submit"
+            disabled={state.checkPhone || state.btnLoading}
           >
             完成
           </Button>
         </Form>
+        {/* 城市 */}
         <Popup v-model:show={state.showPicker} position="bottom" round>
           <Picker
             showToolbar

+ 17 - 18
src/school/manage-teacher/manage-teacher-register.tsx

@@ -127,29 +127,28 @@ export default defineComponent({
       //   return
       // }
 
+      // t: route.query.t, // 过期时间
       try {
-        if (state.t) {
-          const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
-            requestType: 'form',
-            params: {
-              paramName: 'qr_code_expire_hours'
-            }
-          })
-          if (dayjs(Number(state.t)).add(data.paramValue, 'hour').isBefore(dayjs())) {
-            showDialog({
-              title: '提示',
-              message: '二维码已失效',
-              theme: 'round-button',
-              confirmButtonColor: '#64A9FF'
-            })
-            state.qrCodeStatus = true
-          } else {
-            state.qrCodeStatus = false
+        const res = await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
+          data: {
+            schoolId: state.id,
+            qrCodeEffectiveStartTime: state.t ? dayjs(state.t).format('YYYY-MM-DD HH:mm:ss') : null
           }
+        })
+        if (res.code === 999) {
+          state.qrCodeStatus = true
+          showDialog({
+            title: '提示',
+            message: res.message,
+            theme: 'round-button',
+            confirmButtonColor: '#64A9FF'
+          })
         }
-      } catch {
+      } catch (e: any) {
         //
+        console.log(e)
       }
+
       try {
         const tempareas: any = []
         areas.forEach((item) => {

+ 1 - 1
src/school/mass-message/component/student-list/index.tsx

@@ -137,7 +137,7 @@ export default defineComponent({
           <OSearch
             inputBackground="white"
             background="#F8F8F8"
-            placeholder="老师名称/手机号"
+            placeholder="学员名称/手机号"
             onSearch={(val: any) => {
               forms.params.keyword = val
               onSearch()

+ 1 - 1
src/school/mass-message/index.tsx

@@ -122,7 +122,7 @@ export default defineComponent({
           <OSearch
             background="#f6f8f9"
             inputBackground="white"
-            placeholder="请输入群聊/学员名称"
+            placeholder="请输入群聊/学员名称/老师名称"
             onSearch={(val: string) => {
               console.log('val', val)
               state.params.keyword = val

+ 7 - 9
src/school/orchestra/compontent/information.tsx

@@ -66,7 +66,7 @@ export default defineComponent({
       params: {
         startTime: dayjs(dayjs().year() + startTime.value).format('YYYY-MM-DD HH:mm:ss'),
         endTime: dayjs(dayjs().year() + endTime.value)
-          .subtract(1, 'day')
+          .subtract(1, 'year')
           .format('YYYY-MM-DD HH:mm:ss'),
         page: 1,
         rows: 20
@@ -134,11 +134,9 @@ export default defineComponent({
 
     const getStatistics = async () => {
       try {
-        const { data } = await request.post('/api-school/classGroup/statistics', {
+        const { data } = await request.post('/api-school/school/schoolSummaryStat', {
           data: {
-            orchestraId: route.query.id,
-            startTime: state.params.startTime,
-            endTime: state.params.endTime
+            orchestraId: route.query.id
           }
         })
         state.statistics = data || {}
@@ -192,10 +190,10 @@ export default defineComponent({
       nextTick(() => {
         // 在读学生
         const statistics = state.statistics
-        new CountUp('currentStudentNum', statistics.studentNum || 0).start()
-        new CountUp('time1', statistics.attendanceRate || 0).start()
-        new CountUp('time2', statistics.homeworkRate || 0).start()
-        new CountUp('time3', statistics.homeworkQualifiedRate || 0).start()
+        new CountUp('currentStudentNum', statistics.currentStudent || 0).start()
+        new CountUp('time1', statistics.attendanceRate * 100 || 0).start()
+        new CountUp('time2', statistics.homeworkSubmissionRate * 100 || 0).start()
+        new CountUp('time3', statistics.practicePassRate * 100 || 0).start()
       })
     }
 

+ 1 - 1
src/school/orchestra/compontent/plan.tsx

@@ -44,7 +44,7 @@ export default defineComponent({
       params: {
         startTime: dayjs(dayjs().year() + startTime.value).format('YYYY-MM-DD HH:mm:ss'),
         endTime: dayjs(dayjs().year() + endTime.value)
-          .subtract(1, 'day')
+          .subtract(1, 'year')
           .format('YYYY-MM-DD HH:mm:ss'),
         page: 1,
         rows: 20

+ 26 - 2
src/school/train-planning/component/course-preview/index.tsx

@@ -1,6 +1,18 @@
 import OHeader from '@/components/o-header'
 import OSticky from '@/components/o-sticky'
-import { Button, Cell, CellGroup, Dialog, Icon, Image, showToast, Tab, Tabs, Tag } from 'vant'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Dialog,
+  Icon,
+  Image,
+  showDialog,
+  showToast,
+  Tab,
+  Tabs,
+  Tag
+} from 'vant'
 import { defineComponent, onMounted, reactive, ref, nextTick } from 'vue'
 import styles from './index.module.less'
 import iconTimer from '../../images/icon-timer.png'
@@ -157,7 +169,19 @@ export default defineComponent({
     const onSubmit = async () => {
       try {
         state.isClick = true
-        await request.post('/api-school/orchestra/trainingPlan/' + route.query.cacheId)
+        const res = await request.post('/api-school/orchestra/trainingPlan/' + route.query.cacheId)
+
+        // 判断数据是否已经过期
+        if (res.code === 999) {
+          showDialog({
+            title: '提示',
+            message: res.message,
+            confirmButtonColor: '#ff8057'
+          }).then(() => {
+            router.back()
+          })
+          return
+        }
         setTimeout(() => {
           showToast(state.type === 'change' ? '调整成功' : '排课成功')
         }, 100)

+ 5 - 11
src/views/unit-test/examination-mode/index.tsx

@@ -26,14 +26,7 @@ import PlayQuestion from '../model/play-question'
 import request from '@/helpers/request'
 import dayjs from 'dayjs'
 import ResultFinish from '../model/result-finish'
-
-export const QuestionType = {
-  RADIO: 'RADIO',
-  CHECKBOX: 'CHECKBOX',
-  LINK: 'LINK',
-  SORT: 'SORT',
-  PLAY: 'PLAY'
-}
+import { QuestionType } from '../unit'
 
 export default defineComponent({
   name: 'unit-detail',
@@ -73,7 +66,6 @@ export default defineComponent({
         temp.forEach((item: any) => {
           item.userAnswer = formatUserAnswers(item, studentAnswerJson)
         })
-        console.log(temp)
         state.questionList = temp
 
         state.examDetail = { ...res } || {}
@@ -139,7 +131,7 @@ export default defineComponent({
         })
 
         // 判断是否是最后一题
-        console.log(state.questionList.length, state.currentIndex)
+        console.log(state.questionList.length, state.currentIndex, userAnswerList, '-----')
         if (state.questionList.length === state.currentIndex + 1) {
           state.visiableSure = true
           return
@@ -283,7 +275,9 @@ export default defineComponent({
                   type="checkbox"
                 />
               )}
-              {item.questionTypeCode === QuestionType.SORT && <DragQuestion />}
+              {item.questionTypeCode === QuestionType.SORT && (
+                <DragQuestion v-model:value={item.userAnswer} data={item} index={index + 1} />
+              )}
               {item.questionTypeCode === QuestionType.LINK && (
                 <KeepLookQuestion v-model:value={item.userAnswer} data={item} index={index + 1} />
               )}

+ 3 - 0
src/views/unit-test/model/choice-question/index.module.less

@@ -27,6 +27,9 @@
   padding-top: 20px;
   padding-bottom: 10px;
   font-size: 14px;
+  img {
+    width: 100%;
+  }
 }
 .unitTitleImg {
   width: 100%;

+ 3 - 3
src/views/unit-test/model/choice-question/index.tsx

@@ -1,6 +1,6 @@
 import { Tag, Image } from 'vant'
 import { computed, defineComponent, PropType, reactive } from 'vue'
-import { labelOptions } from '../../unit'
+import { AnswerType, labelOptions } from '../../unit'
 import styles from './index.module.less'
 
 // 单选题 - 多选题
@@ -88,12 +88,12 @@ export default defineComponent({
               onClick={() => onSelect(item)}
             >
               <span class={styles.option}>{labelOptions[index + 1]}.</span>
-              {item.questionAnswerTypeCode === 'IMAGE' && (
+              {item.questionAnswerTypeCode === AnswerType.IMAGE && (
                 <div class={styles.value}>
                   <Image src={item.questionAnswer} />
                 </div>
               )}
-              {item.questionAnswerTypeCode === 'TXT' && (
+              {item.questionAnswerTypeCode === AnswerType.TXT && (
                 <div class={styles.value}>{item.questionAnswer}</div>
               )}
             </div>

+ 11 - 2
src/views/unit-test/model/drag-question/index.module.less

@@ -30,10 +30,14 @@
   border: 1px solid #d5d5d5;
   padding: 25px 5px;
 }
+.unitDetail {
+  padding-top: 20px;
+  padding-bottom: 10px;
+  font-size: 14px;
+}
 .unitTitleImg {
   width: 100%;
 }
-
 .unitAnswers {
   padding-bottom: 30px;
   :global {
@@ -66,7 +70,8 @@
     }
   }
 
-  .items {
+  .items,
+  .imgs {
     min-width: 56px;
     height: 36px;
     font-size: 16px;
@@ -77,4 +82,8 @@
     color: #f67146;
     justify-content: center;
   }
+
+  .imgs {
+    height: 56px;
+  }
 }

+ 116 - 69
src/views/unit-test/model/drag-question/index.tsx

@@ -1,6 +1,6 @@
 import { Tag, Image, Button } from 'vant'
-import { defineComponent, nextTick, onMounted, PropType, reactive } from 'vue'
-import { labelOptions } from '../../unit'
+import { computed, defineComponent, nextTick, onMounted, PropType, reactive } from 'vue'
+import { AnswerType, labelOptions } from '../../unit'
 import Draggable from 'vuedraggable'
 import styles from './index.module.less'
 import Sortable from 'sortablejs'
@@ -11,16 +11,17 @@ export default defineComponent({
   name: 'choice-question',
   props: {
     value: {
-      type: [String, Number, Array],
-      default: ''
+      type: Array,
+      default: () => []
     },
-    type: {
-      type: String as PropType<'radio' | 'checkbox'>,
-      default: 'radio'
+    index: {
+      // 题目是第几道
+      type: Number,
+      default: 1
     },
-    answers: {
+    data: {
       type: Object,
-      default: {}
+      default: () => ({})
     },
     /* 只读 */
     readOnly: {
@@ -35,46 +36,9 @@ export default defineComponent({
       drag: false,
       sortable: null as any,
       list: [] as any,
-      options: [
-        {
-          index: 1,
-          order: 1,
-          value: 'Sol'
-        },
-        {
-          index: 2,
-          order: 2,
-          value: 'Sal'
-        },
-        {
-          index: 3,
-          order: 3,
-          value: 'La'
-        },
-        {
-          index: 4,
-          order: 4,
-          value: 'Si'
-        }
-      ]
+      options: [] as any
     })
 
-    // const onSelect = (item: any) => {
-    //   if (props.type === 'checkbox') {
-    //     // 判断是否已选过
-    //     const value: any = props.value
-    //     if (value.includes(item.index)) {
-    //       const index = value.findIndex((v: any) => v === item.index)
-    //       value.splice(index, 1)
-    //       emit('update:value', [...value])
-    //     } else {
-    //       emit('update:value', [item.index, ...value])
-    //     }
-    //   } else {
-    //     emit('update:value', item.index)
-    //   }
-    // }
-
     onMounted(() => {
       nextTick(() => {
         const el = document.getElementById(state.domId)
@@ -84,37 +48,102 @@ export default defineComponent({
           sort: true,
           fallbackTolerance: 3,
           onUpdate: (evt: any) => {
-            // console.log(evt, 'update')
             const updatePosition = (list: any) =>
               list.splice(evt.newIndex, 0, list.splice(evt.oldIndex, 1)[0])
-
-            // const list = deepClone(state.options)
-            // updatePosition(list)
-
-            // state.options = list
             if (state.list && state.list.length > 0) {
               updatePosition(state.list)
-              return
+            } else {
+              state.list = [...state.options]
+              updatePosition(state.list)
             }
-            state.list = [...state.options]
-            updatePosition(state.list)
-            // console.log(updatePosition(state.options))
+            onSelect()
           }
         })
       })
     })
+
+    // 返回选中的结果
+    const onSelect = () => {
+      const options = state.options || []
+      const list = state.list || []
+      const result: any = []
+
+      list.forEach((item: any, index: number) => {
+        const rightOption = options[index]
+        result.push({
+          answerId: item.index,
+          answer: item.leftValue,
+          extra: rightOption.rightValue
+        })
+      })
+      emit('update:value', result)
+    }
+
+    const mediaUrls = computed(() => (props.data.mediaUrls ? props.data.mediaUrls.split(',') : ''))
+
+    const initOptions = () => {
+      const answers = props.data.answers || []
+      const userAnswer = props.data.userAnswer || [] // 用户填写的答案
+      if (userAnswer.length > 0) {
+        userAnswer.forEach((answer: any) => {
+          const rightOption = answers.find(
+            (child: any) => answer.answerId === child.examinationQuestionAnswerId
+          )
+          const rightValue = answers.find((child: any) => answer.extra === child.questionExtra)
+          const tmp = {
+            index: answer.answerId, // 左边的值
+            leftValue: answer.answer, // 左边的值
+            rightValue: answer.extra, // 右边的值
+            leftType: rightOption.questionAnswerTypeCode || 'TXT', // 左边类型
+            rightType: rightOption.questionExtraTypeCode || 'TXT', // 右边类型
+            rightIndex: rightValue ? rightValue.examinationQuestionAnswerId : ''
+          }
+
+          state.options.push(tmp)
+        })
+      } else {
+        const resultValue: any = []
+        answers.forEach((answer: any) => {
+          const tmp = {
+            index: answer.examinationQuestionAnswerId, // 左边的值
+            leftValue: answer.questionAnswer, // 左边的值
+            rightValue: answer.questionExtra, // 右边的值
+            leftType: answer.questionAnswerTypeCode || 'TXT', // 左边类型
+            rightType: answer.questionExtraTypeCode || 'TXT' // 右边类型
+          }
+          resultValue.push({
+            answerId: answer.examinationQuestionAnswerId,
+            answer: answer.questionAnswer,
+            extra: answer.questionExtra
+          })
+          state.options.push(tmp)
+        })
+        // 进页面就默认初始化答案
+        emit('update:value', resultValue)
+      }
+    }
+
+    onMounted(() => {
+      initOptions()
+    })
+
     return () => (
       <div class={styles.unitSubject}>
         <div class={styles.unitSubjectTitle}>
-          1、选出与方框内音符时值相同的节奏阶段 <span class={styles.unitScore}>(5分)</span>
+          {props.index}、{props.data.name}{' '}
+          <span class={styles.unitScore}>({props.data.totalScore || 0}分)</span>
           <Tag type="primary">排序题</Tag>
         </div>
-        <div class={styles.unitTitleSection}>
-          <Image
-            class={styles.unitTitleImg}
-            src="https://lanhu-dds-backend.oss-cn-beijing.aliyuncs.com/merge_image/imgs/dbb27307d428424c8efb9f26032cfa1a_mergeImage.png"
-          />
-        </div>
+
+        {props.data.questionDetail || mediaUrls.value ? (
+          <div class={styles.unitDetail}>
+            <div v-html={props.data.questionDetail}></div>
+            {mediaUrls.value &&
+              mediaUrls.value.map((url: any) => <Image class={styles.unitTitleImg} src={url} />)}
+          </div>
+        ) : (
+          ''
+        )}
 
         <div class={[styles.unitAnswers, 'van-hairline--top']}>
           <div class={styles.sortReset}>
@@ -123,11 +152,17 @@ export default defineComponent({
               type="primary"
               round
               onClick={() => {
-                const order = state.sortable.toArray()
+                const ids: any = []
+                const answers = props.data.answers || []
+                answers.forEach((item: any) => {
+                  ids.push(item.examinationQuestionAnswerId)
+                })
                 state.sortable.sort(
-                  order.sort((a: any, b: any) => a - b),
+                  ids.sort((a: any, b: any) => a - b),
                   true
                 )
+
+                onSelect()
               }}
             >
               重置
@@ -135,9 +170,21 @@ export default defineComponent({
           </div>
           <div id={state.domId}>
             {state.options.map((item: any) => (
-              <Tag class={[styles.items]} data-id={item.index}>
-                {item.value + item.index}
-              </Tag>
+              <>
+                {item.leftType === AnswerType.TXT && (
+                  <Tag class={[styles.items]} data-id={item.index}>
+                    {item.leftValue}
+                  </Tag>
+                )}
+                {item.leftType === AnswerType.IMAGE && (
+                  <Image
+                    src={item.leftValue}
+                    data-id={item.index}
+                    class={styles.imgs}
+                    fit="cover"
+                  />
+                )}
+              </>
             ))}
           </div>
         </div>

+ 18 - 11
src/views/unit-test/model/keep-look-question/index.tsx

@@ -1,7 +1,8 @@
 import { Tag, Image, Button } from 'vant'
-import { defineComponent, nextTick, onMounted, PropType, reactive, ref } from 'vue'
+import { computed, defineComponent, nextTick, onMounted, PropType, reactive, ref } from 'vue'
 import styles from './index.module.less'
 import { useRect } from '@vant/use'
+import { AnswerType } from '../../unit'
 
 // 单选和多选题
 export default defineComponent({
@@ -359,17 +360,19 @@ export default defineComponent({
       })
     })
 
+    const mediaUrls = computed(() => (props.data.mediaUrls ? props.data.mediaUrls.split(',') : ''))
     return () => (
       <div class={styles.unitSubject}>
         <div class={styles.unitSubjectTitle}>
-          1、选出与方框内音符时值相同的节奏阶段 <span class={styles.unitScore}>(5分)</span>
+          {props.index}、{props.data.name}{' '}
+          <span class={styles.unitScore}>({props.data.totalScore || 0}分)</span>
           <Tag type="primary">连连看</Tag>
         </div>
-
-        <Image
-          class={styles.unitTitleImg}
-          src="https://lanhu-dds-backend.oss-cn-beijing.aliyuncs.com/merge_image/imgs/dbb27307d428424c8efb9f26032cfa1a_mergeImage.png"
-        />
+        <div class={styles.unitDetail}>
+          <div v-html={props.data.questionDetail}></div>
+          {mediaUrls.value &&
+            mediaUrls.value.map((url: any) => <Image class={styles.unitTitleImg} src={url} />)}
+        </div>
 
         <div class={[styles.unitAnswers]} id={state.answerDomId}>
           <canvas
@@ -385,16 +388,20 @@ export default defineComponent({
                 id={item.index + '-left'}
                 onClick={(e: any) => onLeftClick(e, item)}
               >
-                {item.leftType === 'TXT' && item.leftValue}
-                {item.leftType === 'IMAGE' && <Image src={item.leftValue} class={styles.img} />}
+                {item.leftType === AnswerType.TXT && item.leftValue}
+                {item.leftType === AnswerType.IMAGE && (
+                  <Image src={item.leftValue} class={styles.img} />
+                )}
               </div>
               <div
                 class={[styles.unitItem, item.right && styles.active]}
                 id={item.index + '-right'}
                 onClick={(e: any) => onRightClick(e, item)}
               >
-                {item.rightType === 'TXT' && item.rightValue}
-                {item.rightType === 'IMAGE' && <Image src={item.rightValue} class={styles.img} />}
+                {item.rightType === AnswerType.TXT && item.rightValue}
+                {item.rightType === AnswerType.IMAGE && (
+                  <Image src={item.rightValue} class={styles.img} />
+                )}
               </div>
             </div>
           ))}

+ 15 - 0
src/views/unit-test/unit.ts

@@ -9,4 +9,19 @@ export const labelOptions = {
   8: 'H',
   9: 'I',
   10: 'J'
+}
+
+
+export const QuestionType = {
+  RADIO: 'RADIO',
+  CHECKBOX: 'CHECKBOX',
+  LINK: 'LINK',
+  SORT: 'SORT',
+  PLAY: 'PLAY'
+}
+
+export const AnswerType = {
+  IMAGE: 'IMAGE',
+  TXT: 'TXT',
+  RADIO: 'RADIO',
 }