lex 2 years ago
parent
commit
85f2cb035d

+ 1 - 1
public/project/preRegister.html

@@ -480,7 +480,7 @@
               vant.showToast(res.data.message)
             }
           } catch {
-            vant.showToast('保存失败,请重试')
+            // vant.showToast('保存失败,请重试')
           }
           this.btnLoading = false
         },

+ 6 - 0
src/components/o-sticky/index.module.less

@@ -1,3 +1,9 @@
+.sticky {
+  position: sticky;
+  top: 0;
+  z-index: 99;
+}
+
 .white {
   background-color: #fff;
   > div {

+ 16 - 5
src/components/o-sticky/index.tsx

@@ -1,5 +1,5 @@
 import { useRect } from '@vant/use'
-import { defineComponent } from 'vue'
+import { defineComponent, nextTick, PropType } from 'vue'
 import styles from './index.module.less'
 
 export default defineComponent({
@@ -12,6 +12,10 @@ export default defineComponent({
     background: {
       type: String,
       default: ''
+    },
+    mode: {
+      type: String as PropType<'fixed' | 'sticky'>,
+      default: 'fixed'
     }
   },
   data() {
@@ -29,15 +33,22 @@ export default defineComponent({
     } else {
       this.divStyle.bottom = '0px'
     }
-    const { height } = useRect((this as any).$refs.div)
-    this.sectionStyle.height = `${height}px`
+
+    nextTick(() => {
+      const { height } = useRect((this as any).$refs.div)
+      this.sectionStyle.height = `${height}px`
+    })
   },
   render() {
     return (
-      <div style={this.sectionStyle}>
+      <div style={[this.sectionStyle]} class={this.mode === 'sticky' && styles.sticky}>
         <div
           ref="div"
-          class={['van-sticky van-sticky--fixed', styles[this.background]]}
+          class={[
+            'van-sticky',
+            this.mode === 'fixed' ? 'van-sticky--fixed' : '',
+            styles[this.background]
+          ]}
           style={[this.divStyle, this.sectionStyle]}
         >
           {this.$slots.default && this.$slots.default()}

+ 7 - 0
src/constant/index.ts

@@ -100,6 +100,13 @@ export const courseEmnu = {
   INSTRUMENTAL_ENSEMBLE: '合奏'
 }
 
+// trainCourseEmnu 训练内容类型
+export const trainCourseEmnu = {
+  SINGLE: '单技课',
+  MUSIC_THEORY: '乐理课',
+  INSTRUMENTAL_ENSEMBLE: '合奏课'
+}
+
 // 乐团状态
 export const orchestraType = {
   DELIVERY: '交付团',

+ 1 - 1
src/router/index.ts

@@ -5,7 +5,7 @@ import { postMessage } from '@/helpers/native-message'
 import routesTeacher from './routes-teacher'
 import routesStudent from './routes-student'
 import routesSchool from './routes-school'
-;(window as any).paymentType = 'SCHOOL'
+
 const paymentType = (window as any).paymentType
 let routes: any = []
 let baseUrl = null as any

+ 4 - 1
src/school/companion-teacher/companion-detail.tsx

@@ -154,7 +154,10 @@ export default defineComponent({
 
         <CellGroup inset class={styles.detailCellGroup}>
           <Cell title="手机号码" value={state.detail.phone}></Cell>
-          <Cell title="性别" value={state.detail.gender ? '男' : '女'}></Cell>
+          <Cell
+            title="性别"
+            value={state.detail.gender == 1 ? '男' : state.detail.gender == 0 ? '女' : ''}
+          ></Cell>
           <Cell title="声部" value={state.detail.subjectName}></Cell>
         </CellGroup>
 

+ 1 - 0
src/school/companion-teacher/companion-teacher-register.tsx

@@ -253,6 +253,7 @@ export default defineComponent({
               name="smsValidCode"
               rules={[{ required: true, message: '请选择声部', trigger: 'onChange' }]}
               placeholder="请输入验证码"
+              maxlength={6}
             >
               {{
                 button: () =>

+ 1 - 0
src/school/manage-teacher/manage-teacher-register.tsx

@@ -186,6 +186,7 @@ export default defineComponent({
               name="smsValidCode"
               rules={[{ required: true, message: '请选择声部', trigger: 'onChange' }]}
               placeholder="请输入验证码"
+              maxlength={6}
             >
               {{
                 button: () =>

+ 2 - 1
src/school/orchestra/create-orchestra/index.tsx

@@ -8,7 +8,7 @@ import styles from '../index.module.less'
 import { state as baseState } from '@/state'
 import StudentList from '../modal/student-list'
 import SubjectList from '../modal/subject-list'
-import { createState as state } from './create'
+import { createState as state, resestState } from './create'
 import { useRouter } from 'vue-router'
 import deepClone from '@/helpers/deep-clone'
 
@@ -166,6 +166,7 @@ export default defineComponent({
     }
 
     onMounted(() => {
+      resestState()
       getSubjects()
       getOrchestras()
     })

+ 2 - 0
src/school/orchestra/create-orchestra/select-teacher.tsx

@@ -66,6 +66,7 @@ export default defineComponent({
       resestState()
       router.replace('/my-orchestra')
     }
+
     return () => (
       <div>
         <OHeader title="选择老师" />
@@ -106,6 +107,7 @@ export default defineComponent({
 
         <OPopup v-model:modelValue={forms.teacherStatus} position="bottom">
           <TeacherList
+            subjectId={state.selectTeacher.id}
             onClose={() => (forms.teacherStatus = false)}
             onSelect={(item: any) => {
               state.selectTeacher.teacher = item

+ 28 - 3
src/school/orchestra/modal/teacher-list.tsx

@@ -3,7 +3,7 @@ import OPopup from '@/components/o-popup'
 import OSticky from '@/components/o-sticky'
 import { state } from '@/state'
 import { Button, Cell, CellGroup, Field, List, Image, Tag } from 'vant'
-import { defineComponent, onMounted, reactive } from 'vue'
+import { defineComponent, onMounted, PropType, reactive, watch } from 'vue'
 import TeacherList from '../modal/teacher-list'
 import styles from './teacher-list.module.less'
 import iconTeacher from '@common/images/icon_teacher.png'
@@ -13,6 +13,21 @@ import OSearch from '@/components/o-search'
 
 export default defineComponent({
   name: 'teacher-list',
+  props: {
+    header: {
+      // 是否显示头部
+      type: Boolean,
+      default: true
+    },
+    mode: {
+      type: String as PropType<'fixed' | 'sticky'>,
+      default: 'fixed'
+    },
+    subjectId: {
+      type: String,
+      default: ''
+    }
+  },
   emits: ['close', 'select'],
   setup(props, { slots, attrs, emit }) {
     const forms = reactive({
@@ -26,6 +41,7 @@ export default defineComponent({
       },
       params: {
         keyword: null,
+        subjectId: props.subjectId,
         page: 1,
         rows: 20
       }
@@ -79,14 +95,23 @@ export default defineComponent({
       emit('select', item)
     }
 
+    // 声部变化时重新请求接口
+    watch(
+      () => props.subjectId,
+      () => {
+        forms.params.subjectId = props.subjectId
+        onSearch()
+      }
+    )
+
     onMounted(() => {
       getList()
     })
 
     return () => (
       <div>
-        <OSticky position="top">
-          <OHeader title="选择老师" />
+        <OSticky position="top" mode={props.mode}>
+          {props.header && <OHeader title="选择老师" />}
           <OSearch
             inputBackground="white"
             background="#F8F8F8"

+ 12 - 0
src/school/train-planning/component/course-preview/index.module.less

@@ -67,6 +67,8 @@
   }
 
   .cellDate {
+    display: flex;
+    align-items: center;
     font-size: 14px;
     font-weight: 500;
     color: #777777;
@@ -94,12 +96,22 @@
   }
 
   .cellTimeRange {
+    display: flex;
+    align-items: center;
     padding: 12px 12px 0;
     font-size: 30px;
     font-weight: bold;
     color: #333333;
     line-height: 35px;
   }
+
+  .conflict {
+    font-size: 12px;
+    padding: 2px 4px;
+    border-radius: 3px;
+    margin-left: 8px;
+  }
+
   .teacherName {
     font-size: 16px;
     font-weight: 600;

+ 17 - 1
src/school/train-planning/component/course-preview/index.tsx

@@ -59,7 +59,15 @@ export default defineComponent({
               value: () => <span class={styles.cellTime}>45分钟</span>
             }}
           </Cell>
-          <div class={styles.cellTimeRange}>14:00-15:30</div>
+          <div class={styles.cellTimeRange}>
+            14:00-15:30
+            <Tag class={styles.conflict} color="#F44541">
+              学生冲突
+            </Tag>
+            <Tag class={styles.conflict} color="#F44541">
+              学校冲突
+            </Tag>
+          </div>
           <Cell center class={styles.cellTeacher}>
             {{
               icon: () => <Image src={iconTeacher} class={styles.img} />,
@@ -78,6 +86,14 @@ export default defineComponent({
           </Cell>
         </CellGroup>
 
+        <OSticky position="bottom">
+          <div class={'btnGroup'}>
+            <Button round block type="primary" size="large">
+              确认排课
+            </Button>
+          </div>
+        </OSticky>
+
         <Dialog
           v-model:show={forms.conflictStatus}
           message={forms.conflictMessage}

+ 185 - 34
src/school/train-planning/component/standard/index.tsx

@@ -13,38 +13,54 @@ import {
   Popup,
   Radio,
   RadioGroup,
+  showToast,
   Sticky,
   Tag
 } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
 import { weekdays, weekFormat } from '../../create'
 import Calendar from '../../modal/calendar'
 import ClassList from '../../modal/class-list'
+import Timer from '../../modal/timer'
 import styles from './index.module.less'
+import { forms } from '../../create'
+
+// orchestra
 
 export default defineComponent({
   name: 'standard',
   setup() {
-    const forms = reactive({
-      status: false,
-      weekStatus: false,
-      calendarStatus: false,
-      classStatus: false,
-      holiday: 1,
-      week: null,
-      times: 1,
-      classList: [] as any,
-      calendarList: [] as any,
-      calendarDate: null as any,
-      trainStartDate: null
-    })
+    const route = useRoute()
+    const router = useRouter()
+    // const forms = reactive({
+    //   status: false,
+    //   weekStatus: false,
+    //   calendarStatus: false,
+    //   classStatus: false,
+    //   timerStatus: false,
+    //   skipHoliday: 1,
+    //   week: null,
+    //   times: 16,
+    //   classList: [] as any, // 没有设置伴学指导的数据
+    //   calendarList: [] as any,
+    //   calendarDate: null as any,
+    //   trainStartDate: null, // 开始日期
+    //   trainStartTime: null, // 开始时间
+    //   timerList: {} as any, // 可选和不可选时间段
+    //   numberStatus: false,
+    //   numberDialogStatus: false, // 提示暂无训练次数提示
+    //   pickerNum: 16, // 默认16次
+    //   timerPickerList: [] as any // 可排课次数
+    // })
 
+    // 获取排课空闲时间
     const getList = async (date?: any) => {
       try {
         const { data } = await request.post('/api-school/orchestra/trainingPlanTime', {
           data: {
             schoolId: state.user.data.school.id,
-            skipHoliday: forms.holiday ? true : false,
+            skipHoliday: forms.skipHoliday ? true : false,
             type: 'STANDARD',
             calendarDate: dayjs(date).format('YYYY-MM-DD')
           }
@@ -57,12 +73,12 @@ export default defineComponent({
     }
 
     // 查询没有设置指导老师的班级
-    const getClasses = async () => {
+    const getClasses = async (show = true) => {
       try {
         const { data } = await request.post('/api-school/classGroup/page', {
           data: {
             page: 1,
-            rows: 20,
+            rows: 200,
             schoolId: state.user.data.school.id,
             hasTeacher: false,
             orchestraType: 'DELIVERY'
@@ -71,7 +87,7 @@ export default defineComponent({
         // 班级数据
         forms.classList = data.rows || []
         // 判断没有设置伴学指导的班级
-        if (forms.classList.length > 0) {
+        if (forms.classList.length > 0 && show) {
           forms.status = true
         }
       } catch {
@@ -79,10 +95,68 @@ export default defineComponent({
       }
     }
 
+    // 获取已排课次数
+    const getStandardCourseNum = async () => {
+      try {
+        const { data } = await request.get(
+          '/api-school/orchestra/semesterStandardCourseNum/' + state.user.data.school.id
+        )
+        console.log(data)
+        const tempPicker = Number(forms.pickerNum - data)
+        forms.times = tempPicker
+        for (let i = 0; i < tempPicker; i++) {
+          forms.timerPickerList.push({
+            text: i + 1 + '次',
+            value: i + 1
+          })
+        }
+
+        if (tempPicker <= 0) {
+          forms.numberDialogStatus = true
+        }
+      } catch {
+        //
+      }
+    }
+
+    // 下一步
+    const onSubmit = () => {
+      // 判断是否有训练次数
+      if (forms.times <= 0) {
+        forms.numberDialogStatus = true
+        return
+      }
+
+      // 判断是否有班级没有设置伴学指导
+      if (forms.classList.length > 0) {
+        forms.status = true
+        return
+      }
+
+      if (!forms.trainStartDate) {
+        showToast('请选择训练开始日期')
+        return
+      }
+
+      if (!forms.trainStartTime) {
+        showToast('请选择训练开始时间')
+        return
+      }
+
+      if (!forms.week) {
+        showToast('请选择周次')
+        return
+      }
+
+      router.push('/train-content')
+    }
+
     onMounted(() => {
       getList()
-
       getClasses()
+      getStandardCourseNum()
+
+      // console.log(route)
     })
 
     return () => (
@@ -99,23 +173,48 @@ export default defineComponent({
             value={forms.trainStartDate ? dayjs(forms.trainStartDate).format('YYYY年MM月DD日') : ''}
             onClick={() => (forms.calendarStatus = true)}
           ></Cell>
-          <Cell title="训练开始时间" isLink value=""></Cell>
+          <Cell
+            title="训练开始时间"
+            value={forms.trainStartTime ? dayjs(forms.trainStartTime).format('HH:mm') : ''}
+            isLink
+            onClick={() => {
+              if (!forms.trainStartDate) {
+                showToast('请选择训练开始日期')
+                return
+              }
+              forms.timerStatus = true
+            }}
+          ></Cell>
           <Cell title="训练时长" value="120分钟"></Cell>
           <Cell
             title="训练周次"
             isLink
             value={weekFormat(forms.week)}
-            onClick={() => (forms.weekStatus = true)}
+            onClick={() => {
+              forms.weekStatus = true
+            }}
+          ></Cell>
+          <Cell
+            title="训练次数"
+            isLink={forms.times <= 0 ? false : true}
+            value={forms.times + '次'}
+            onClick={() => {
+              if (forms.times <= 0) return
+              forms.numberStatus = true
+            }}
           ></Cell>
-          <Cell title="训练次数" isLink value={forms.times + '次'}></Cell>
           <Cell title="跳过节假日">
             {{
               value: () => (
-                <RadioGroup checked-color="#FF8057" v-model={forms.holiday} direction="horizontal">
+                <RadioGroup
+                  checked-color="#FF8057"
+                  v-model={forms.skipHoliday}
+                  direction="horizontal"
+                >
                   <Tag
                     size="large"
                     type="primary"
-                    plain={!(forms.holiday === 1)}
+                    plain={!(forms.skipHoliday === 1)}
                     color="#FF8057"
                     class={styles.radioSection}
                   >
@@ -124,7 +223,7 @@ export default defineComponent({
                   <Tag
                     size="large"
                     type="primary"
-                    plain={!(forms.holiday === 0)}
+                    plain={!(forms.skipHoliday === 0)}
                     color="#FF8057"
                     class={styles.radioSection}
                   >
@@ -138,15 +237,7 @@ export default defineComponent({
 
         <Sticky position="bottom">
           <div class={'btnGroup'} style={{ marginTop: '24px' }}>
-            <Button
-              type="primary"
-              block
-              round
-              size="large"
-              onClick={() => {
-                // forms.status = true
-              }}
-            >
+            <Button type="primary" block round size="large" onClick={onSubmit}>
               下一步
             </Button>
           </div>
@@ -163,6 +254,7 @@ export default defineComponent({
           />
         </Popup>
 
+        {/* 选择训练开始日期 */}
         <OPopup v-model:modelValue={forms.calendarStatus} position="bottom">
           <Calendar
             list={forms.calendarList}
@@ -171,11 +263,47 @@ export default defineComponent({
             onSelect={(date: any) => {
               forms.calendarStatus = false
               forms.trainStartDate = date
+              forms.calendarList.forEach((item: any) => {
+                if (dayjs(item.calendarDate).isSame(date)) {
+                  forms.timerList = { ...item }
+                  setTimeout(() => {
+                    forms.timerStatus = true
+                  }, 100)
+                }
+              })
             }}
             v-model:calendarDate={forms.calendarDate}
           />
         </OPopup>
 
+        {/* 选择开始时间 */}
+        <OPopup
+          v-model:modelValue={forms.timerStatus}
+          position="bottom"
+          style={{ background: '#F6F6F6' }}
+          destroy
+        >
+          <Timer
+            timerList={forms.timerList}
+            onClose={() => (forms.timerStatus = false)}
+            onConfirm={(val: any) => {
+              console.log(val, 'val info')
+              forms.trainStartTime = val
+            }}
+          />
+        </OPopup>
+
+        <Popup v-model:show={forms.numberStatus} position="bottom" round>
+          <Picker
+            columns={forms.timerPickerList}
+            onClick={() => (forms.numberStatus = false)}
+            onConfirm={(val: any) => {
+              const selectedValue = val.selectedValues[0]
+              forms.times = selectedValue
+            }}
+          />
+        </Popup>
+
         <Dialog
           v-model:show={forms.status}
           message={`您有${forms.classList.length}个班级尚未指定伴学指导,请完成指定后再进行训练规划。`}
@@ -197,12 +325,35 @@ export default defineComponent({
           }}
         </Dialog>
 
+        <Dialog
+          v-model:show={forms.numberDialogStatus}
+          message={`暂无可训练次数`}
+          messageAlign="center"
+          confirmButtonText="确定"
+        >
+          {{
+            title: () => (
+              <div class={styles.dialogTitle}>
+                <i></i>
+                训练次数
+              </div>
+            )
+          }}
+        </Dialog>
+
         <OPopup
           v-model:modelValue={forms.classStatus}
           position="bottom"
           style={{ background: '#F6F6F6' }}
+          destroy
         >
-          <ClassList onClose={() => (forms.classStatus = false)} />
+          <ClassList
+            classList={forms.classList}
+            onClose={() => (forms.classStatus = false)}
+            onConfirm={() => {
+              getClasses(false)
+            }}
+          />
         </OPopup>
       </div>
     )

+ 64 - 28
src/school/train-planning/component/train-content/index.tsx

@@ -1,44 +1,80 @@
+import OEmpty from '@/components/o-empty'
 import OHeader from '@/components/o-header'
 import OSticky from '@/components/o-sticky'
+import { trainCourseEmnu } from '@/constant'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import dayjs from 'dayjs'
 import { Button, Cell, CellGroup, Tag } from 'vant'
-import { defineComponent } from 'vue'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { forms, weekFormat } from '../../create'
 import styles from './index.module.less'
 
 export default defineComponent({
   name: 'train-content',
   setup() {
+    const base = reactive({
+      contentList: [] as any
+    })
+    const getClasses = async () => {
+      try {
+        const { data } = await request.get(
+          '/api-school/orchestra/trainingContent/' + state.user.data.school.id
+        )
+        console.log(data)
+        base.contentList = data || []
+      } catch {
+        //
+      }
+    }
+
+    onMounted(() => {
+      getClasses()
+    })
+
     return () => (
       <>
         <OHeader />
         {/* 训练内容 */}
 
-        <CellGroup inset class={styles.cellGroup}>
-          <Cell center>
-            {{
-              title: () => (
-                <div class={styles.classType}>
-                  乐理课
-                  <Tag round type="primary" size="medium" class={styles.classNum}>
-                    16课时
-                  </Tag>
-                </div>
-              ),
-              value: () => <span class={styles.classTime}>每周三 14:00-14:45</span>
-            }}
-          </Cell>
-          <Cell center>
-            {{
-              title: () => (
-                <div class={styles.orchestra}>
-                  <p class={styles.name}>武汉洪山区第二小学2022下学期团</p>
-                  <p class={styles.class}>
-                    共<span>3</span>个班级
-                  </p>
-                </div>
-              )
-            }}
-          </Cell>
-        </CellGroup>
+        {base.contentList.map((item: any) => (
+          <CellGroup inset class={styles.cellGroup}>
+            <Cell center>
+              {{
+                title: () => (
+                  <div class={styles.classType}>
+                    {trainCourseEmnu[item.classType]}
+                    <Tag round type="primary" size="medium" class={styles.classNum}>
+                      {forms.times}课时
+                    </Tag>
+                  </div>
+                ),
+                value: () => (
+                  <span class={styles.classTime}>
+                    每{weekFormat(forms.week)} {dayjs(forms.trainStartTime).format('HH:mm')}-
+                    {dayjs(forms.trainStartTime).add(120, 'minute').format('HH:mm')}
+                  </span>
+                )
+              }}
+            </Cell>
+            <Cell center>
+              {{
+                title: () => (
+                  <div class={styles.orchestra}>
+                    <p class={styles.name}>{item.orchestraName}</p>
+                    <p class={styles.class}>
+                      共<span>{item.classGroupIdList && item.classGroupIdList.length}</span>个班级
+                    </p>
+                  </div>
+                )
+              }}
+            </Cell>
+          </CellGroup>
+        ))}
+
+        {base.contentList && base.contentList.length <= 0 && (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无训练内容" />
+        )}
 
         <OSticky position="bottom">
           <div class={'btnGroup'}>

+ 37 - 1
src/school/train-planning/create.ts

@@ -1,3 +1,5 @@
+import { reactive } from "vue";
+
 // 训练周次
 export const weekdays = [{
   text: '周一',
@@ -36,4 +38,38 @@ export const weekFormat = (val: any) => {
     return template[val]
   }
   return val
-}
+}
+
+
+
+
+
+const original = () => {
+  return {
+    status: false,
+    weekStatus: false,
+    calendarStatus: false,
+    classStatus: false,
+    timerStatus: false,
+    skipHoliday: 1,
+    week: null,
+    times: 16,
+    classList: [] as any, // 没有设置伴学指导的数据
+    calendarList: [] as any,
+    calendarDate: null as any,
+    trainStartDate: null, // 开始日期
+    trainStartTime: null, // 开始时间
+    timerList: {} as any, // 可选和不可选时间段
+    numberStatus: false,
+    numberDialogStatus: false, // 提示暂无训练次数提示
+    pickerNum: 16, // 默认16次
+    timerPickerList: [] as any // 可排课次数
+  }
+}
+
+export const forms = reactive(original())
+
+// 重置对象
+export const resestState = () => {
+  Object.assign(forms, original())
+}

+ 0 - 12
src/school/train-planning/modal/calendar/index.tsx

@@ -94,7 +94,6 @@ export default defineComponent({
           isActive = true
         }
       })
-
       // 判断是否有课程 并且 时间在当前时间之后
       if (isActive && dayjs().isBefore(dayjs(date.date))) {
         date.bottomInfo = '可选'
@@ -129,19 +128,8 @@ export default defineComponent({
       this.minDate = dayjs(currentMinDate).isAfter(monthMinDate) ? currentMinDate : monthMinDate
       this.maxDate = date.endOf('month').toDate()
       this.currentDate = date.toDate()
-      this.$emit('update:calendarDate', date.toDate())
       this.subtitle = date.format('YYYY年MM月')
     },
-    onPrevDay() {
-      // 获取上一天的数据
-      const tempDate = dayjs(this.currentDate).subtract(1, 'day')
-      this._dayChange(tempDate.toDate())
-    },
-    onNextDay() {
-      // 获取下一天的数据
-      const tempDate = dayjs(this.currentDate).add(1, 'day')
-      this._dayChange(tempDate.toDate())
-    },
     onDateSelect(date: any) {
       // 选择日历上某一个日期
       this._dayChange(date)

+ 117 - 33
src/school/train-planning/modal/class-list/index.tsx

@@ -1,54 +1,138 @@
+import OEmpty from '@/components/o-empty'
 import OHeader from '@/components/o-header'
 import OSticky from '@/components/o-sticky'
-import { Button, Cell } from 'vant'
-import { defineComponent } from 'vue'
+import request from '@/helpers/request'
+import TeacherList from '@/school/orchestra/modal/teacher-list'
+import { Button, Cell, Popup, showToast, Sticky } from 'vant'
+import { defineComponent, onMounted, reactive, watch } from 'vue'
 import styles from './index.module.less'
 
 export default defineComponent({
   name: 'class-list',
-  emits: ['close'],
+  props: {
+    classList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'confirm'],
   setup(props, { slots, attrs, emit }) {
+    const state = reactive({
+      teacherStatus: false,
+      list: [] as any,
+      isClick: false,
+      selectItem: {} as any // 选择的班级
+    })
+
+    // 可以不用全部设置完
     const onSubmit = async () => {
-      emit('close')
+      try {
+        const tempList: any = []
+        state.list.forEach((item: any) => {
+          // 判断是否已经设置过伴学老师
+          if (item.teacherId) {
+            tempList.push({
+              classGroupId: item.id,
+              teacherId: item.teacherId
+            })
+          }
+        })
+        if (tempList.length <= 0) {
+          emit('close')
+          return
+        }
+        state.isClick = true
+        await request.post('/api-school/classGroup/updateTeacher', {
+          data: tempList
+        })
+
+        setTimeout(() => {
+          showToast('设置成功')
+        }, 100)
+
+        setTimeout(() => {
+          state.isClick = false
+          emit('confirm')
+          emit('close')
+        }, 1100)
+      } catch {
+        //
+        state.isClick = false
+      }
+      // emit('close')
     }
+
+    // 监听变化
+    watch(
+      () => props.classList,
+      () => {
+        state.list = [...props.classList]
+      }
+    )
+
+    onMounted(() => {
+      state.list = [...props.classList]
+    })
     return () => (
       <div class={styles.classList}>
         <OHeader title="指定伴学老师" />
 
-        <Cell class={styles.cell} center isLink>
-          {{
-            title: () => (
-              <div class={styles.content}>
-                <div class={styles.title}>
-                  <i></i>长笛班
-                </div>
-                <div class={styles.name}>武汉洪山区第二小学2022标准团</div>
-              </div>
-            ),
-            value: () => <span class={styles.teacherName}>张老师</span>
-          }}
-        </Cell>
-        <Cell class={styles.cell} center isLink>
-          {{
-            title: () => (
-              <div class={styles.content}>
-                <div class={styles.title}>
-                  <i></i>长笛班
+        {state.list.map((item: any) => (
+          <Cell
+            class={styles.cell}
+            center
+            isLink
+            onClick={() => {
+              state.selectItem = item
+              state.teacherStatus = true
+            }}
+          >
+            {{
+              title: () => (
+                <div class={styles.content}>
+                  <div class={styles.title}>
+                    <i></i>
+                    {item.name}
+                  </div>
+                  <div class={styles.name}>{item.orchestraName}</div>
                 </div>
-                <div class={styles.name}>武汉洪山区第二小学2022标准团</div>
-              </div>
-            ),
-            value: () => <span class={styles.teacherName}>张老师</span>
-          }}
-        </Cell>
-
-        <OSticky position="buttom">
+              ),
+              value: () => <span class={styles.teacherName}>{item.teacherName}</span>
+            }}
+          </Cell>
+        ))}
+        {/* 判断是否有班级没有设置伴学指导 */}
+        {props.classList.length <= 0 && (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无班级" />
+        )}
+
+        <Sticky position="bottom">
           <div class={'btnGroup'}>
-            <Button round block type="primary" size="large" onClick={onSubmit}>
+            <Button
+              round
+              block
+              type="primary"
+              size="large"
+              onClick={onSubmit}
+              disabled={state.isClick}
+            >
               完成
             </Button>
           </div>
-        </OSticky>
+        </Sticky>
+
+        <Popup v-model:show={state.teacherStatus} position="bottom" round style={{ height: '80%' }}>
+          <TeacherList
+            header={false}
+            mode={'sticky'}
+            subjectId={state.selectItem.subjectIds}
+            onClose={() => (state.teacherStatus = false)}
+            onSelect={(val: any) => {
+              state.selectItem.teacherId = val.id
+              state.selectItem.teacherName = val.nickname
+            }}
+          />
+        </Popup>
       </div>
     )
   }

+ 35 - 0
src/school/train-planning/modal/timer/index.module.less

@@ -0,0 +1,35 @@
+.selectTimer {
+  padding: 12px 13px 14px;
+  font-size: 14px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 20px;
+}
+
+.cellGroup {
+  margin: 0 13px 12px;
+  border-radius: 8px;
+  overflow: hidden;
+
+  :global {
+    .van-cell {
+      padding: 18px 12px;
+      font-size: 14px;
+      font-weight: 500;
+      color: #333333;
+      line-height: 20px;
+    }
+    .van-cell__value {
+      color: #333;
+    }
+  }
+
+  .noTime {
+    color: #aaaaaa;
+    :global {
+      .van-cell__value {
+        color: #aaaaaa;
+      }
+    }
+  }
+}

+ 238 - 0
src/school/train-planning/modal/timer/index.tsx

@@ -0,0 +1,238 @@
+import OHeader from '@/components/o-header'
+import item from '@/student/coupons/item'
+import dayjs from 'dayjs'
+import { Button, Cell, CellGroup, Popup, showToast, Sticky, TimePicker } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'timer',
+  props: {
+    timerList: {
+      type: Object,
+      default: () => {}
+    },
+    times: {
+      // 默认时长
+      type: Number,
+      default: 120
+    }
+  },
+  emits: ['close', 'confirm'],
+  setup(props, { slots, attrs, emit }) {
+    const defaultTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
+    const state = reactive({
+      calendarDate: null,
+      selectTimeStatus: false,
+      selectTime: null as any,
+      useTimer: [] as any, // 可排课时间段
+      useTimerFormat: [] as any,
+      usedTimer: [] as any, // 不可排课时间段
+      minMinute: 0,
+      maxMinute: 60
+    })
+
+    const onFormatter = (type: any, option: any) => {
+      if (type === 'hour') {
+        option.text += '时'
+      }
+      if (type === 'minute') {
+        option.text += '分'
+      }
+      return option
+    }
+
+    const onFilter = (type: any, option: any) => {
+      console.log(type, option)
+      // 时间
+      if (type === 'hour') {
+        const hour: any = []
+        option.forEach((o: any) => {
+          state.useTimerFormat.forEach((time: any) => {
+            if (o.value >= time.startHour && o.value <= time.endHour) {
+              hour.push(o)
+            }
+          })
+        })
+        console.log(hour, 'hour')
+        return hour
+      }
+      return option
+    }
+
+    // 时间切换时
+    // [6:30, 12:00] [15:00, 18:00]
+    const onChange = (val: any) => {
+      console.log(val, 'val')
+      // 判断是否选择小时
+      if (val.columnIndex === 1) return
+
+      // 选择时间
+      const selectHour = Number(val.selectedValues[0])
+
+      let minute = 0 // 获取开始的分钟数
+      state.useTimerFormat.forEach((item: any) => {
+        if (selectHour === item.startHour) {
+          minute = item.startMinute
+        } else if (selectHour === item.endHour) {
+          minute = item.endMinute
+        }
+      })
+
+      state.minMinute = minute
+      state.maxMinute = 60
+    }
+
+    //
+    const onFormatTimer = (val: Array<any>) => {
+      const format: any = []
+      val.forEach((item: any) => {
+        format.push({
+          startHour: Number(dayjs(item.startTime).format('HH')),
+          startMinute: Number(dayjs(item.startTime).format('mm')),
+          endHour: Number(dayjs(item.endTime).format('HH')),
+          endMinute: Number(dayjs(item.endTime).format('mm'))
+        })
+      })
+      return format
+    }
+
+    // 确认时间
+    const onConfirm = (val: any) => {
+      console.log(val, 'val')
+      const selectedValues = val.selectedValues
+      const tempDate = dayjs(state.calendarDate)
+        .hour(selectedValues[0])
+        .minute(selectedValues[1])
+        .second(0)
+      console.log(dayjs(tempDate).format('YYYY-MM-DD HH:mm:ss'), 'first', dayjs(tempDate).minute())
+      // 时间加上每节课的时间,
+      const lastDate = dayjs(tempDate).minute(props.times + dayjs(tempDate).minute())
+      console.log(dayjs(lastDate).format('YYYY-MM-DD HH:mm:ss'), 'second')
+      console.log(
+        dayjs(tempDate).format('YYYY-MM-DD HH:mm:ss'),
+        tempDate.toDate(),
+        'second tempDate'
+      )
+
+      let isActive = false
+      state.useTimer.forEach((item: any) => {
+        if (dayjs(lastDate).isAfter(item.endTime)) {
+          isActive = true
+        }
+      })
+
+      console.log(isActive, 'isActive')
+      if (isActive) {
+        showToast('您选择的时间超过可排课时间范围')
+        return
+      }
+
+      state.selectTime = tempDate.toDate()
+      state.selectTimeStatus = false
+    }
+
+    onMounted(() => {
+      console.log(props.timerList, 'timerList')
+      state.calendarDate = props.timerList?.calendarDate
+      const timeDetailList = props.timerList?.timeDetailList || []
+      const useTimer: any = [] // 可排课时间段
+      const usedTimer: any = [] // 不可排课时间段
+
+      timeDetailList.forEach((time: any) => {
+        if (time.enable) {
+          useTimer.push(time)
+        } else {
+          usedTimer.push(time)
+        }
+      })
+      // 初始化时间
+      state.useTimer = [...useTimer]
+      const useFormat = onFormatTimer(useTimer)
+      state.useTimerFormat = useFormat
+      state.usedTimer = [...usedTimer]
+      console.log(onFormatTimer(useTimer), 'onFormatTimer')
+      console.log(state.useTimer, state.usedTimer, 'onUseTimer')
+
+      // 判断有可排课数据
+      if (useFormat.length > 0) {
+        const temp = useFormat[0]
+        state.minMinute = temp.startMinute
+        state.maxMinute = 60
+      }
+    })
+    return () => (
+      <div class={styles.timer}>
+        <OHeader title="训练时间" />
+
+        <div class={styles.selectTimer}>{dayjs(state.calendarDate).format('YYYY年MM月DD日')}</div>
+
+        <CellGroup inset class={styles.cellGroup}>
+          {state.useTimer.map((item: any) => (
+            <Cell
+              center
+              title={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
+                'HH:mm'
+              )}`}
+              value="可选时间"
+            ></Cell>
+          ))}
+
+          {state.usedTimer.map((item: any) => (
+            <Cell
+              center
+              title={`${dayjs(item.startTime).format('HH:mm')}~${dayjs(item.endTime).format(
+                'HH:mm'
+              )}`}
+              value="冲突时间"
+              class={styles.noTime}
+            ></Cell>
+          ))}
+        </CellGroup>
+
+        <CellGroup inset class={styles.cellGroup}>
+          <Cell
+            center
+            title={'训练开始时间'}
+            value={state.selectTime ? dayjs(state.selectTime).format('HH:mm') : ''}
+            isLink
+            onClick={() => (state.selectTimeStatus = true)}
+          ></Cell>
+        </CellGroup>
+
+        <Sticky position="bottom">
+          <div class={'btnGroup'}>
+            <Button
+              round
+              block
+              type="primary"
+              size="large"
+              onClick={() => {
+                if (!state.selectTime) {
+                  showToast('请选择训练开始时间')
+                  return
+                }
+                emit('confirm', state.selectTime)
+                emit('close')
+              }}
+            >
+              确认
+            </Button>
+          </div>
+        </Sticky>
+
+        <Popup v-model:show={state.selectTimeStatus} position="bottom" round>
+          <TimePicker
+            minMinute={state.minMinute}
+            maxMinute={state.maxMinute}
+            formatter={onFormatter}
+            filter={onFilter}
+            onChange={onChange}
+            onConfirm={onConfirm}
+            onCancel={() => (state.selectTimeStatus = false)}
+          />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 309 - 58
src/student/music-group/pre-apply/component/apply.tsx

@@ -1,74 +1,325 @@
-import { Button, Cell, CellGroup, Field, Radio, RadioGroup, Tag } from 'vant'
-import { defineComponent } from 'vue'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Field,
+  Form,
+  Picker,
+  Popup,
+  Radio,
+  RadioGroup,
+  showToast,
+  Tag
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import request from '../../request-music'
 import styles from '../index.module.less'
 
+// 乐团交付,乐团停止或关闭,有新的交付团;则不允许报名
+const classList: any = []
+for (let i = 1; i <= 40; i++) {
+  classList.push({ text: i + '班', value: i })
+}
+
 export default defineComponent({
   name: 'apply',
+  props: {
+    schoolSystem: {
+      type: String,
+      default: 'sixYearSystem' // 默认为六年制
+    }
+  },
   emits: ['next'],
   setup(props, { slots, attrs, emit }) {
-    const onSubmit = () => {
-      emit('next', 'payment')
+    const route = useRoute()
+    const state = reactive({
+      detail: {} as any, // 学生详情
+      currentGrade: [
+        { text: '一年级', value: 1 },
+        { text: '二年级', value: 2 },
+        { text: '三年级', value: 3 },
+        { text: '四年级', value: 4 },
+        { text: '五年级', value: 5 }
+      ], // 年级数组列表
+      classList: classList,
+      subjectList: [] as any, // 声部列表
+      gradeStatus: false,
+      classStatus: false,
+      subjectStatus: false,
+      pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
+      nameReg: /^[\u4E00-\u9FA5]+$/
+    })
+    const forms = reactive({
+      username: null,
+      sex: null,
+      currentGrade: null,
+      currentGradeTxt: null, // 年级编号
+      currentClass: '', // 班级
+      currentClassTxt: null, // 年级编号
+      registerSubjectId: '',
+      registerSubjectTxt: null, // 所在声部
+      parentName: null,
+      phone: null
+    })
+
+    // 获取乐团报名信息
+    const studentRegister = async () => {
+      try {
+        const { data } = await request.get(
+          '/api-student/orchestraRegister/register/' + route.query.id
+        )
+        const detail = data || {}
+        state.detail = detail
+
+        const grade: any = state.currentGrade.find((item: any) => item.value == detail.currentGrade)
+        const cls: any = state.classList.find((item: any) => item.value == detail.currentClass)
+        const subjects: any = state.subjectList.find(
+          (item: any) => item.value == detail.registerSubjectId
+        )
+        forms.username = detail.username
+        forms.sex = detail.sex
+        forms.currentGrade = detail.currentGrade
+        forms.currentGradeTxt = grade.text
+        forms.currentClass = detail.currentClass
+        forms.currentClassTxt = cls.text
+        forms.registerSubjectId = detail.registerSubjectId
+        forms.registerSubjectTxt = subjects.text
+        forms.parentName = detail.parentName
+        forms.phone = detail.phone
+      } catch {
+        //
+      }
+    }
+
+    // 获取声部信息
+    const getSubjects = async () => {
+      try {
+        const subjects = await request.post(
+          '/api-student/open/orchestraSubjectConfig/pageByOrchestraId',
+          {
+            data: {
+              orchestraId: route.query.id,
+              page: 1,
+              rows: 100
+            }
+          }
+        )
+        console.log(subjects, 'subject')
+        const rows = subjects.data.rows || []
+        rows.forEach((item: any) => {
+          state.subjectList.push({
+            text: item.name,
+            value: item.subjectId
+          })
+        })
+      } catch {
+        //
+      }
     }
+
+    const validator = (val: any) => {
+      // 校验函数返回 true 表示校验通过,false 表示不通过
+      return state.nameReg.test(val) && val.length >= 2 && val.length <= 15
+    }
+    const message = (value: any) => {
+      if (!value) {
+        return '请填写学员真实姓名'
+      } else if (!state.nameReg.test(value)) {
+        return '学员姓名必须为中文'
+      } else if (value.length < 2 || value.length > 15) {
+        return '学员姓名必须为2~15个字'
+      } else {
+        return ''
+      }
+    }
+
+    // 乐团报名
+    const onSubmit = async () => {
+      try {
+        const params: any = {
+          orchestraId: route.query.id,
+          schoolId: state.detail.schoolId,
+          ...forms
+        }
+        // 判断是否已报过名
+        if (state.detail.id) {
+          params.id = state.detail.id
+        }
+        await request.post('/api-student/orchestraRegister/save', {
+          data: {
+            ...params
+          }
+        })
+        setTimeout(() => {
+          showToast('报名成功')
+          emit('next', 'payment')
+        }, 100)
+      } catch {
+        //
+      }
+    }
+
+    onMounted(() => {
+      studentRegister()
+
+      getSubjects()
+
+      // 判断学年制
+      if (props.schoolSystem === 'sixYearSystem') {
+        state.currentGrade.push({ text: '一年级', value: 1 })
+      }
+    })
     return () => (
       <>
-        <div class={styles.applyTitle}>学生信息</div>
-        <CellGroup inset class={styles.applyCellGroup}>
-          <Field required label="学生信息" placeholder="请填写学生真实姓名" inputAlign="right" />
-          <Field required label="性别" inputAlign="right">
-            {{
-              input: () => (
-                <RadioGroup>
-                  <Tag size="large" type="primary" plain class={styles.radioSection}>
-                    <Radio class={styles.radioItem} name={true}></Radio>男生
-                  </Tag>
-                  <Tag size="large" type="primary" plain class={styles.radioSection}>
-                    <Radio class={styles.radioItem} name={true}></Radio>女生
-                  </Tag>
-                </RadioGroup>
-              )
+        <Form validateFirst scrollToError onSubmit={onSubmit} ref="form" class={styles.form}>
+          <div class={styles.applyTitle}>学生信息</div>
+          <CellGroup inset class={styles.applyCellGroup}>
+            <Field
+              required
+              label="学生信息"
+              placeholder="请填写学生真实姓名"
+              inputAlign="right"
+              v-model={forms.username}
+              rules={[{ validator, message }]}
+            />
+            <Field
+              required
+              label="性别"
+              inputAlign="right"
+              rules={[{ required: true, message: '请选择性别' }]}
+            >
+              {{
+                input: () => (
+                  <RadioGroup v-model={forms.sex}>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      plain={!(forms.sex === 1)}
+                      class={styles.radioSection}
+                    >
+                      <Radio class={styles.radioItem} name={1}></Radio>男生
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      plain={!(forms.sex === 0)}
+                      class={styles.radioSection}
+                    >
+                      <Radio class={styles.radioItem} name={0}></Radio>女生
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+            <Field
+              required
+              label="年级"
+              inputAlign="right"
+              readonly
+              isLink
+              placeholder="请选择年级"
+              v-model={forms.currentGradeTxt}
+              onClick={() => (state.gradeStatus = true)}
+              rules={[{ required: true, message: '请选择年级' }]}
+            />
+            <Field
+              required
+              label="班级"
+              inputAlign="right"
+              readonly
+              isLink
+              placeholder="请选择班级"
+              v-model={forms.currentClassTxt}
+              onClick={() => (state.classStatus = true)}
+              rules={[{ required: true, message: '请选择班级' }]}
+            />
+          </CellGroup>
+
+          <div class={styles.applyTitle}>声部信息</div>
+          <CellGroup inset class={styles.applyCellGroup}>
+            <Field
+              required
+              label="声部"
+              inputAlign="right"
+              readonly
+              isLink
+              placeholder="请选择声部"
+              v-model={forms.registerSubjectTxt}
+              onClick={() => (state.subjectStatus = true)}
+              rules={[{ required: true, message: '请选择声部' }]}
+            />
+          </CellGroup>
+
+          <div class={styles.applyTitle}>家长信息</div>
+          <CellGroup inset class={styles.applyCellGroup}>
+            <Field
+              required
+              label="家长姓名"
+              inputAlign="right"
+              placeholder="请填写家长真实姓名"
+              v-model={forms.parentName}
+              rules={[{ required: true, message: '请填写家长真实姓名' }]}
+            />
+            <Field
+              required
+              label="手机号"
+              inputAlign="right"
+              placeholder="请输入手机号"
+              v-model={forms.phone}
+              rules={[{ pattern: state.pattern, message: '输入监护人手机号码有误' }]}
+            />
+          </CellGroup>
+
+          <div class={'btnGroup'} style={{ paddingTop: '30px' }}>
+            <Button type="primary" round block native-type="submit">
+              下一步
+            </Button>
+          </div>
+        </Form>
+
+        {/* 年级 */}
+        <Popup v-model:show={state.gradeStatus} position="bottom" round>
+          <Picker
+            showToolbar
+            columns={state.currentGrade}
+            onCancel={() => (state.gradeStatus = false)}
+            onConfirm={(val: any) => {
+              const selectedOption = val.selectedOptions[0]
+              forms.currentGrade = selectedOption.value
+              forms.currentGradeTxt = selectedOption.text
+              state.gradeStatus = false
             }}
-          </Field>
-          <Field
-            required
-            label="年级"
-            inputAlign="right"
-            readonly
-            isLink
-            placeholder="请选择年级"
           />
-          <Field
-            required
-            label="班级"
-            inputAlign="right"
-            readonly
-            isLink
-            placeholder="请选择班级"
+        </Popup>
+        {/* 班级 */}
+        <Popup v-model:show={state.classStatus} position="bottom" round>
+          <Picker
+            showToolbar
+            columns={state.classList}
+            onCancel={() => (state.classStatus = false)}
+            onConfirm={(val: any) => {
+              const selectedOption = val.selectedOptions[0]
+              forms.currentClass = selectedOption.value
+              forms.currentClassTxt = selectedOption.text
+              state.classStatus = false
+            }}
           />
-        </CellGroup>
-
-        <div class={styles.applyTitle}>声部信息</div>
-        <CellGroup inset class={styles.applyCellGroup}>
-          <Field
-            required
-            label="声部"
-            inputAlign="right"
-            readonly
-            isLink
-            placeholder="请选择声部"
+        </Popup>
+        {/* 声部 */}
+        <Popup v-model:show={state.subjectStatus} position="bottom" round>
+          <Picker
+            showToolbar
+            columns={state.subjectList}
+            onCancel={() => (state.subjectStatus = false)}
+            onConfirm={(val: any) => {
+              const selectedOption = val.selectedOptions[0]
+              forms.registerSubjectId = selectedOption.value
+              forms.registerSubjectTxt = selectedOption.text
+              state.subjectStatus = false
+            }}
           />
-        </CellGroup>
-
-        <div class={styles.applyTitle}>家长信息</div>
-        <CellGroup inset class={styles.applyCellGroup}>
-          <Field required label="家长名称" inputAlign="right" placeholder="请输入家长名称" />
-          <Field required label="手机号" inputAlign="right" placeholder="请输入手机号" />
-        </CellGroup>
-
-        <div class={'btnGroup'} style={{ paddingTop: '30px' }}>
-          <Button type="primary" round block onClick={onSubmit}>
-            下一步
-          </Button>
-        </div>
+        </Popup>
       </>
     )
   }

+ 82 - 40
src/student/music-group/pre-apply/component/payment.tsx

@@ -1,29 +1,78 @@
 import OSticky from '@/components/o-sticky'
 import { Button, Cell, CellGroup, Checkbox, CheckboxGroup, Icon, Image, Tag } from 'vant'
-import { defineComponent, reactive } from 'vue'
+import { defineComponent, onMounted, reactive } from 'vue'
 import styles from '../index.module.less'
 import radioCheck from '@/common/images/icon-radio-check.png'
 import radioDefault from '@/common/images/icon-radio-default.png'
-import { useRouter } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
+import request from '../../request-music'
+import { moneyFormat } from '@/helpers/utils'
+import { text } from 'stream/consumers'
 
 export default defineComponent({
   name: 'payment',
   emits: ['next'],
   setup() {
+    const route = useRoute()
     const router = useRouter()
     const state = reactive({
       check: ['in'],
-      checkboxRefs: [] as any
+      checkboxRefs: [] as any,
+      goodsInfo: {} as any, // 商品
+      textBookInfo: {} as any, // 教材
+      repaireInfo: {} as any, // 乐器保养
+      vipInfo: {} as any, // 团练宝
+      paymentOrderDetails: [] as any // 购买状态
     })
 
+    // 获取商品信息
+    const registerGoods = async () => {
+      try {
+        const { data } = await request.get(
+          '/api-student/orchestraRegister/registerGoods/' + route.query.id
+        )
+
+        const details = data.details || []
+
+        details.forEach((item: any) => {
+          if (item.goodsType === 'INSTRUMENTS') {
+            const img = item.goodsUrl ? item.goodsUrl.split(',')[0] : ''
+            state.goodsInfo = { ...item, goodsUrl: img }
+          } else if (item.goodsType === 'TEXTBOOK') {
+            const img = item.goodsUrl ? item.goodsUrl.split(',')[0] : ''
+            state.textBookInfo = { ...item, goodsUrl: img }
+          } else if (item.goodsType === 'REPAIR') {
+            state.repaireInfo = { ...item }
+          } else if (item.goodsType === 'VIP') {
+            state.vipInfo = { ...item }
+          }
+        })
+        state.paymentOrderDetails = data.paymentOrderDetails || []
+      } catch {
+        //
+      }
+    }
+
     const onSelect = (type: string) => {
       state.checkboxRefs[type].toggle()
     }
 
     // 购买
-    const onSubmit = () => {
-      router.push('/orderDetail')
+    const onSubmit = async () => {
+      try {
+        // 创建订单
+        await request.post('/api-student/userPaymentOrder/executeOrder', {
+          data: {}
+        })
+      } catch {
+        //
+      }
+      // router.push('/orderDetail')
     }
+
+    onMounted(() => {
+      registerGoods()
+    })
     return () => (
       <>
         <div class={styles.applyTitle}>报名须知</div>
@@ -39,15 +88,15 @@ export default defineComponent({
           <CellGroup
             inset
             class={[styles.mlr13, styles.sectionCell]}
-            onClick={() => onSelect('in')}
+            onClick={() => onSelect(state.goodsInfo.goodsId)}
           >
             <Cell border={false}>
               {{
                 icon: () => (
                   <Checkbox
-                    name="in"
+                    name={state.goodsInfo.goodsId}
                     class={styles.checkbox}
-                    ref={(el: any) => (state.checkboxRefs['in'] = el)}
+                    ref={(el: any) => (state.checkboxRefs[state.goodsInfo.goodsId] = el)}
                     v-slots={{
                       icon: (props: any) => (
                         <Icon
@@ -60,14 +109,11 @@ export default defineComponent({
                 ),
                 title: () => (
                   <div class={styles.section}>
-                    <Image
-                      class={styles.img}
-                      src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-                    />
+                    <Image class={styles.img} src={state.goodsInfo.goodsUrl} />
                     <div class={styles.sectionContent}>
-                      <h2>长笛标准配置</h2>
-                      <Tag type="primary">品牌型号</Tag>
-                      <p class={styles.model}>含笛头、笛身、笛尾、擦拭布、节拍器、谱架</p>
+                      <h2>{state.goodsInfo.goodsName}</h2>
+                      <Tag type="primary">{state.goodsInfo.brandName}</Tag>
+                      <p class={styles.model}>{state.goodsInfo.desciption}</p>
                     </div>
                   </div>
                 )
@@ -79,13 +125,15 @@ export default defineComponent({
                   <div class={styles.extra}>
                     <div class={styles.sectionPrice}>
                       <p class={styles.price}>
-                        新团特惠:<span>¥3,860</span>
+                        新团特惠:<span>¥{moneyFormat(state.goodsInfo.currentPrice)}</span>
                       </p>
                       <p class={styles.originPrice}>
-                        原价:<del>¥3,580.00</del>
+                        原价:<del>¥{moneyFormat(state.goodsInfo.originalPrice)}</del>
                       </p>
                     </div>
-                    <div class={styles.sectionTips}>赠价值500元乐器维保服务一年</div>
+                    <div class={styles.sectionTips}>
+                      赠价值{state.repaireInfo.originalPrice}元乐器维保服务一年
+                    </div>
                   </div>
                 )
               }}
@@ -96,15 +144,15 @@ export default defineComponent({
           <CellGroup
             inset
             class={[styles.mlr13, styles.sectionCell]}
-            onClick={() => onSelect('teaching')}
+            onClick={() => onSelect(state.textBookInfo.goodsId)}
           >
             <Cell border={false}>
               {{
                 icon: () => (
                   <Checkbox
-                    name="teaching"
+                    name={state.textBookInfo.goodsId}
                     class={styles.checkbox}
-                    ref={(el: any) => (state.checkboxRefs['teaching'] = el)}
+                    ref={(el: any) => (state.checkboxRefs[state.textBookInfo.goodsId] = el)}
                     v-slots={{
                       icon: (props: any) => (
                         <Icon
@@ -117,14 +165,11 @@ export default defineComponent({
                 ),
                 title: () => (
                   <div class={styles.section}>
-                    <Image
-                      class={styles.img}
-                      src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-                    />
+                    <Image class={styles.img} src={state.textBookInfo.goodsUrl} />
                     <div class={styles.sectionContent}>
-                      <h2>大雅金唐教材</h2>
-                      <Tag type="primary">品牌型号</Tag>
-                      <p class={styles.model}>含笛头、笛身、笛尾、擦拭布、节拍器、谱架</p>
+                      <h2>{state.textBookInfo.goodsName}</h2>
+                      <Tag type="primary">{state.textBookInfo.brandName}</Tag>
+                      <p class={styles.model}>{state.textBookInfo.description}</p>
                     </div>
                   </div>
                 )
@@ -139,7 +184,7 @@ export default defineComponent({
                         新团特惠:<span class={styles.free}>免费赠送</span>
                       </p>
                       <p class={styles.originPrice}>
-                        原价:<del>¥3,580.00</del>
+                        原价:<del>¥{moneyFormat(state.textBookInfo.originalPrice)}</del>
                       </p>
                     </div>
                   </div>
@@ -152,15 +197,15 @@ export default defineComponent({
           <CellGroup
             inset
             class={[styles.mlr13, styles.sectionCell]}
-            onClick={() => onSelect('system')}
+            onClick={() => onSelect(state.vipInfo.goodsId)}
           >
             <Cell border={false}>
               {{
                 icon: () => (
                   <Checkbox
-                    name="system"
+                    name={state.vipInfo.goodsId}
                     class={styles.checkbox}
-                    ref={(el: any) => (state.checkboxRefs['system'] = el)}
+                    ref={(el: any) => (state.checkboxRefs[state.vipInfo.goodsId] = el)}
                     v-slots={{
                       icon: (props: any) => (
                         <Icon
@@ -173,14 +218,11 @@ export default defineComponent({
                 ),
                 title: () => (
                   <div class={styles.section}>
-                    <Image
-                      class={styles.img}
-                      src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-                    />
+                    <Image class={styles.img} src={state.vipInfo.goodsUrl} />
                     <div class={styles.sectionContent}>
-                      <h2>团练宝</h2>
+                      <h2>{state.vipInfo.goodsName}</h2>
                       <Tag type="primary">6个月</Tag>
-                      <p class={styles.model}>含乐团课件、课后训练、乐器练习、云教练等</p>
+                      <p class={styles.model}>{state.vipInfo.description}</p>
                     </div>
                   </div>
                 )
@@ -192,10 +234,10 @@ export default defineComponent({
                   <div class={styles.extra}>
                     <div class={styles.sectionPrice}>
                       <p class={styles.price}>
-                        新团特惠:<span>¥1,380.00</span>
+                        新团特惠:<span>¥{moneyFormat(state.vipInfo.currentPrice)}</span>
                       </p>
                       <p class={styles.originPrice}>
-                        原价:<del>¥3,580.00</del>
+                        原价:<del>¥{moneyFormat(state.vipInfo.originalPrice)}</del>
                       </p>
                     </div>
                   </div>

+ 4 - 0
src/student/music-group/pre-apply/index.module.less

@@ -9,6 +9,10 @@
     .van-tabs__wrap {
       padding-bottom: 3px;
     }
+
+    .van-field__error-message {
+      text-align: right;
+    }
   }
 
   .banner {

+ 43 - 12
src/student/music-group/pre-apply/index.tsx

@@ -1,46 +1,77 @@
-import { defineComponent, onMounted, ref } from 'vue'
+import { defineComponent, onMounted, reactive, ref } from 'vue'
 import { Image, Sticky, Tab, Tabs } from 'vant'
 import styles from './index.module.less'
 import { useRect } from '@vant/use'
 import Apply from './component/apply'
 import Payment from './component/payment'
 import Order from './component/order'
+import { useRoute } from 'vue-router'
+import request from '../request-music'
 // import banner from './images/banner.png'
 
 export default defineComponent({
   name: 'pre-apply',
   setup() {
+    const route = useRoute()
     const bannerRef = ref()
-    const tabValue = ref('payment')
-    const heightV = ref(235)
+    const state = reactive({
+      tabValue: 'apply',
+      heightV: 235,
+      registerInfo: {} as any,
+      purchase: false // 购买状态
+    })
 
     const onNext = (name: string) => {
-      tabValue.value = name
+      state.tabValue = name
+    }
+
+    const getRegisterStatus = async () => {
+      try {
+        const { data } = await request.get(
+          '/api-student/orchestraRegister/registerStatus/' + route.query.id
+        )
+        state.registerInfo = data || {}
+
+        if (state.registerInfo.register) {
+          state.tabValue = 'payment'
+        }
+
+        if (state.registerInfo.purchase) {
+          state.tabValue = 'order'
+          state.purchase = state.registerInfo.purchase
+        }
+      } catch {
+        //
+      }
     }
 
     onMounted(() => {
       const { height } = useRect(bannerRef.value)
-      heightV.value = height
+      state.heightV = height
+
+      getRegisterStatus()
     })
     return () => (
       <div class={styles.preApply}>
         <div class={styles.banner} ref={bannerRef}>
           <span>
-            武汉小学2022标准团 <br />
+            {state.registerInfo.orchestraName} <br />
             乐团报名
           </span>
         </div>
         <Sticky position="top">
-          <Tabs lineWidth={20} lineHeight={4} v-model:active={tabValue.value}>
-            <Tab title="报名信息" name="apply"></Tab>
-            <Tab title="缴费信息" name="payment"></Tab>
+          <Tabs lineWidth={20} lineHeight={4} v-model:active={state.tabValue}>
+            <Tab title="报名信息" name="apply" disabled={state.purchase}></Tab>
+            <Tab title="缴费信息" name="payment" disabled={state.purchase}></Tab>
             <Tab title="我的订单" name="order"></Tab>
           </Tabs>
         </Sticky>
 
-        {tabValue.value === 'apply' && <Apply onNext={onNext} />}
-        {tabValue.value === 'payment' && <Payment onNext={onNext} />}
-        {tabValue.value === 'order' && <Order onNext={onNext} />}
+        {state.tabValue === 'apply' && (
+          <Apply onNext={onNext} schoolSystem={state.registerInfo.schoolSystem} />
+        )}
+        {state.tabValue === 'payment' && <Payment onNext={onNext} />}
+        {state.tabValue === 'order' && <Order onNext={onNext} />}
       </div>
     )
   }

+ 2 - 1
vite.config.ts

@@ -13,7 +13,8 @@ function resolve(dir: string) {
 // https://github.com/vitejs/vite/issues/1930 .env
 // const proxyUrl = 'https://mstutest.dayaedu.com/';
 const proxyUrl = 'http://47.98.131.38:8989/'
-// const proxyUrl = 'http://192.168.3.26:8989/'
+// const proxyUrl = 'http://192.168.3.143:8989/' // 尚科
+// const proxyUrl = 'http://192.168.3.26:8989/' // 刘俊驰
 export default defineConfig({
   base: './',
   plugins: [