lex vor 2 Jahren
Ursprung
Commit
8dc6a9f8c8

+ 8 - 0
src/router/routes-school.ts

@@ -230,6 +230,14 @@ export default [
         }
       },
       {
+        path: '/practice-detail',
+        name: 'practice-detail',
+        component: () => import('@/school/train-planning/component/practice-detail'),
+        meta: {
+          title: '训练详情'
+        }
+      },
+      {
         path: '/course-preview',
         name: 'course-preview',
         component: () => import('@/school/train-planning/component/course-preview'),

+ 32 - 14
src/school/approval-manage/course-adjust.tsx

@@ -1,5 +1,5 @@
 import OHeader from '@/components/o-header'
-import { CellGroup, Cell, Button, showToast } from 'vant'
+import { CellGroup, Cell, Button, showToast, Field } from 'vant'
 import { defineComponent, reactive, ref, onMounted } from 'vue'
 import { postMessage } from '@/helpers/native-message'
 import styles from './course-adjust.module.less'
@@ -81,10 +81,12 @@ export default defineComponent({
     // 获取排课空闲时间
     const getList = async (date?: any) => {
       try {
-        const { data } = await request.post('/api-school/orchestra/trainingPlanTime', {
+        const { data } = await request.post('/api-school/orchestra/calendarDateQuery', {
           data: {
+            teacherId: forms.teacherId,
             schoolId: baseState.user.data.school.id,
-            type: state.arrangeType,
+            courseScheduleId: forms.courseScheduleId,
+            cacheId: state.cacheId,
             skipHoliday: false,
             calendarDate: dayjs(date).format('YYYY-MM-DD')
           }
@@ -98,7 +100,14 @@ export default defineComponent({
 
     onMounted(async () => {
       await getDetail()
-      await getList()
+      await getList(forms.classDate)
+
+      // 初始化课程开始时间
+      state.calendarList.forEach((item: any) => {
+        if (dayjs(item.calendarDate).isSame(forms.classDate)) {
+          state.timerList = { ...item }
+        }
+      })
     })
     const reset = async () => {
       // await getDetail()
@@ -156,17 +165,23 @@ export default defineComponent({
                 }}
                 is-link
               />
-
-              <Cell
-                title="课程开始日期"
-                value={forms.classDate ? dayjs(forms.classDate).format('YYYY-MM-DD') : ''}
-                is-link
+              <Field
+                label="课程开始日期"
+                inputAlign="right"
+                readonly
+                isLink
+                placeholder="请选择课程开始日期"
                 onClick={() => (state.showPopoverTime = true)}
+                modelValue={forms.classDate ? dayjs(forms.classDate).format('YYYY-MM-DD') : ''}
               />
-              <Cell
-                title="课程开始时间"
-                value={forms.startTime ? dayjs(forms.startTime).format('hh:mm') : ''}
-                is-link
+
+              <Field
+                label="课程开始时间"
+                inputAlign="right"
+                readonly
+                isLink
+                placeholder="请选择课程开始时间"
+                modelValue={forms.startTime ? dayjs(forms.startTime).format('HH:mm') : ''}
                 onClick={() => {
                   state.showPopoverCourseTime = true
                 }}
@@ -201,6 +216,8 @@ export default defineComponent({
                     }, 100)
                   }
                 })
+
+                forms.startTime = ''
               }}
               v-model:calendarDate={state.calendarDate}
             />
@@ -219,6 +236,7 @@ export default defineComponent({
               onClose={() => (state.showPopoverCourseTime = false)}
               onConfirm={(val: any) => {
                 forms.startTime = dayjs(val).format('YYYY-MM-DD HH:mm:ss')
+
                 forms.endTime = dayjs(val)
                   .add(courseDetail.value.singleCourseTime, 'minute')
                   .format('YYYY-MM-DD HH:mm:ss')
@@ -228,7 +246,7 @@ export default defineComponent({
 
           <OPopup v-model:modelValue={state.showPopoverTeacher} position="bottom">
             <TeacherList
-              subjectId={courseDetail.value.subjectIds}
+              courseType={courseDetail.value.type}
               onClose={() => (state.showPopoverTeacher = false)}
               onSelect={(val: any) => {
                 // 换老师之后重置数据

+ 11 - 1
src/school/orchestra/create-orchestra/select-teacher.tsx

@@ -20,6 +20,8 @@ export default defineComponent({
       status: false
     })
 
+    console.log(state.selectLastTeacherSubjects)
+
     const onSubmit = async () => {
       // forms.status = true
       showDialog({
@@ -57,6 +59,14 @@ export default defineComponent({
       })
     }
 
+    const formatSubjectIds = (id: any) => {
+      if (id) {
+        const tempId = id.toString()
+        return tempId.split(',')
+      }
+      return id
+    }
+
     const onConfirm = () => {
       resestState()
       router.replace('/train-planning')
@@ -107,7 +117,7 @@ export default defineComponent({
 
         <OPopup v-model:modelValue={forms.teacherStatus} position="bottom">
           <TeacherList
-            subjectId={state.selectTeacher.id}
+            subjectIdList={formatSubjectIds(state.selectTeacher.id)}
             onClose={() => (forms.teacherStatus = false)}
             onSelect={(item: any) => {
               state.selectTeacher.teacher = item

+ 6 - 2
src/school/orchestra/modal/teacher-list.tsx

@@ -23,9 +23,13 @@ export default defineComponent({
       type: String as PropType<'fixed' | 'sticky'>,
       default: 'fixed'
     },
-    subjectId: {
+    courseType: {
       type: String,
       default: ''
+    },
+    subjectIdList: {
+      type: Array,
+      default: () => []
     }
   },
   emits: ['close', 'select'],
@@ -41,7 +45,7 @@ export default defineComponent({
       },
       params: {
         keyword: null,
-        subjectId: props.subjectId,
+        courseType: props.courseType,
         page: 1,
         rows: 20
       }

+ 33 - 27
src/school/train-planning/component/course-preview/index.tsx

@@ -13,7 +13,7 @@ import {
   Tabs,
   Tag
 } from 'vant'
-import { defineComponent, onMounted, reactive } from 'vue'
+import { defineComponent, onMounted, reactive, ref } from 'vue'
 import styles from './index.module.less'
 import iconTimer from '../../images/icon-timer.png'
 import iconTeacher from '@common/images/icon_teacher.png'
@@ -39,9 +39,9 @@ export default defineComponent({
       selectClasses: [] as any, // 选中的班级列表
       selectCourse: [] as any, // 选中的课程
       choiceCourse: {}, // 选中需要调整的课程
-
       isClick: false
     })
+    const courseTabsRef: any = ref()
 
     // 获取所有
     const getClasses = async () => {
@@ -66,9 +66,8 @@ export default defineComponent({
             : forms.planList.classes[selectOrchestra.orchestraId]
             ? forms.planList.classes[selectOrchestra.orchestraId][0]
             : {}
-          state.selectClasses = forms.planList.classes[selectOrchestra.orchestraId] || []
           state.courseValue = selectClasses.classGroupId
-
+          state.selectClasses = forms.planList.classes[selectOrchestra.orchestraId] || []
           state.selectCourse = forms.planList.course[selectClasses.classGroupId]
 
           // 判断是否有数据
@@ -84,7 +83,7 @@ export default defineComponent({
     const formatClasses = async (data: any) => {
       // 判断是否有班级编号,如果有就说明接口只会返回该班的数据
       if (forms.selectClassGroupId) {
-        forms.planList.classes[forms.selectClassGroupId] = data || []
+        forms.planList.course[forms.selectClassGroupId] = data || []
         return
       }
 
@@ -183,6 +182,7 @@ export default defineComponent({
       <div class={styles.coursePreview}>
         <OSticky position="top">
           <OHeader border={false} />
+
           <Tabs
             lineWidth={20}
             lineHeight={4}
@@ -190,15 +190,17 @@ export default defineComponent({
             swipeThreshold={3}
             class={styles.orchestraTabs}
             onChange={(val: any) => {
+              console.log(val, 'val', state.tabValue)
               // 乐团变化时
-              state.selectClasses = forms.planList.classes[val] || []
-
-              const selectClasses = forms.planList.classes[val]
-                ? forms.planList.classes[val][0]
-                : {}
-              state.courseValue = selectClasses.classGroupId
+              if (!forms.selectClassGroupId) {
+                state.selectClasses = forms.planList.classes[val] || []
 
-              state.selectCourse = forms.planList.course[selectClasses.classGroupId]
+                const selectClasses = forms.planList.classes[val]
+                  ? forms.planList.classes[val][0]
+                  : {}
+                state.selectCourse = forms.planList.course[selectClasses.classGroupId]
+                state.courseValue = selectClasses.classGroupId
+              }
             }}
           >
             {forms.planList.orchestra.map((item: any) => (
@@ -206,20 +208,24 @@ export default defineComponent({
             ))}
           </Tabs>
 
-          <Tabs
-            swipeThreshold={3}
-            class={styles.courseTabs}
-            v-model:active={state.courseValue}
-            lineHeight={0}
-            shrink
-            onChange={(val: any) => {
-              state.selectCourse = forms.planList.course[val]
-            }}
-          >
-            {state.selectClasses.map((item: any) => (
-              <Tab title={item.className} name={item.classGroupId}></Tab>
-            ))}
-          </Tabs>
+          {state.courseValue && (
+            <Tabs
+              swipeThreshold={3}
+              class={styles.courseTabs}
+              v-model:active={state.courseValue}
+              lineHeight={0}
+              shrink
+              lazyRender
+              ref={courseTabsRef}
+              onChange={(val: any) => {
+                state.selectCourse = forms.planList.course[val]
+              }}
+            >
+              {state.selectClasses.map((item: any) => (
+                <Tab title={item.className} name={item.classGroupId}></Tab>
+              ))}
+            </Tabs>
+          )}
         </OSticky>
 
         {state.selectCourse.map((item: any) => (
@@ -325,7 +331,7 @@ export default defineComponent({
         <Dialog
           v-model:show={state.conflictStatus}
           message={state.conflictMessage}
-          messageAlign="left"
+          messageAlign="center"
           confirmButtonText="去调整"
           cancelButtonText="知道了"
           showCancelButton

+ 37 - 0
src/school/train-planning/component/practice-detail/index.module.less

@@ -0,0 +1,37 @@
+.title {
+  display: flex;
+  align-items: center;
+  padding: 12px 13px;
+  font-size: 18px;
+  font-weight: 500;
+  color: #333333;
+
+  i {
+    display: inline-block;
+    width: 4px;
+    height: 13px;
+    background: #ff8057;
+    border-radius: 2px;
+    margin-right: 6px;
+  }
+}
+
+.cellGroup {
+  margin: 0 13px 8px;
+  border-radius: 10px;
+  overflow: hidden;
+
+  :global {
+    .van-cell {
+      font-size: 16px;
+      padding: 18px 12px;
+    }
+    .van-cell__value {
+      color: #333;
+    }
+  }
+
+  .tips {
+    color: #c8c9cc;
+  }
+}

+ 272 - 0
src/school/train-planning/component/practice-detail/index.tsx

@@ -0,0 +1,272 @@
+import OHeader from '@/components/o-header'
+import OPopup from '@/components/o-popup'
+import OSticky from '@/components/o-sticky'
+import { trainCourseEmnu } from '@/constant'
+import request from '@/helpers/request'
+import { verifiyNumberInteger } from '@/helpers/toolsValidate'
+import { state } from '@/state'
+import dayjs from 'dayjs'
+import { Button, Cell, CellGroup, Field, Popup, showToast, TimePicker } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRouter } from 'vue-router'
+import { forms } from '../../create'
+import PracticeClass from '../../modal/practice-class'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'practice-detail',
+  setup() {
+    const router = useRouter()
+    const f = reactive({
+      selectItem: {} as any,
+      currentTime: [] as any,
+      minHour: 0,
+      minMinute: 0,
+      maxHour: 24,
+      maxMinute: 60,
+      firstTime: null as any,
+      lastTime: null as any
+    })
+
+    const configParams = async () => {
+      // 获取基础数据
+      const { data } = await request.get('/api-school/sysParamConfig/queryByParamNameList', {
+        params: {
+          paramNames: 'course_start_time,course_end_time'
+        }
+      })
+      const tempData = data || []
+      tempData.forEach((item: any) => {
+        console.log(item.paramValue, 'paramValue')
+        const day = dayjs(forms.trainStartDate).format('YYYY-MM-DD')
+        if (item.paramName === 'course_start_time') {
+          const firstTime = dayjs(day + ' ' + item.paramValue)
+          f.minHour = Number(firstTime.format('HH'))
+          f.minMinute = Number(firstTime.format('mm'))
+          f.firstTime = firstTime
+        } else if (item.paramName === 'course_end_time') {
+          const lastTime = dayjs(day + ' ' + item.paramValue)
+          f.maxHour = Number(lastTime.format('HH'))
+          f.lastTime = lastTime
+        }
+      })
+    }
+
+    const onChange = (val: any) => {
+      // 判断是否选择小时
+      if (val.columnIndex === 1) return
+
+      // 选择时间
+      const selectHour = Number(val.selectedValues[0])
+
+      if (selectHour === f.minHour) {
+        f.minMinute = Number(f.firstTime.format('mm'))
+        f.maxMinute = 60
+      } else if (selectHour === f.maxHour) {
+        console.log(selectHour, 'hour')
+        f.minMinute = 0
+        f.maxMinute = Number(f.lastTime.format('mm'))
+      } else {
+        f.minMinute = 0
+        f.maxMinute = 60
+      }
+    }
+
+    // 选择日期
+    const onConfirmTimer = (item: any) => {
+      const times = dayjs(
+        dayjs(f.lastTime).format('YYYY-MM-DD') + ' ' + item.selectedValues.join(':') + ':00'
+      ).add(f.selectItem.trainTimer, 'minute')
+
+      // console.log(times.isAfter(f.lastTime), times, f.lastTime)
+      if (times.isAfter(f.lastTime)) {
+        showToast('开始时间超过可选时间范围')
+        return
+      }
+
+      f.selectItem.startTime = dayjs(
+        dayjs(f.lastTime).format('YYYY-MM-DD') + ' ' + item.selectedValues.join(':') + ':00'
+      ).format('YYYY-MM-DD HH:mm:ss')
+      f.selectItem.endTime = times.format('YYYY-MM-DD HH:mm:ss')
+
+      forms.timerStatus = false
+    }
+
+    const onSubmit = async () => {
+      try {
+        const list = forms.classPracticeList
+        const trainingPlanClassList: any = []
+
+        list.forEach((item: any) => {
+          trainingPlanClassList.push({
+            classGroupIdList: item.classIdList,
+            courseNum: item.times,
+            startTime: dayjs(item.startTime).format('HH:mm:ss'),
+            endTime: dayjs(item.endTime).format('HH:mm:ss'),
+            singleCourseTime: item.trainTimer
+          })
+        })
+        const params = {
+          week: forms.week,
+          schoolId: state.user.data.school.id,
+          skipHoliday: forms.skipHoliday ? true : false,
+          type: 'PRACTISE',
+          startDate: dayjs(forms.trainStartDate).format('YYYY-MM-DD'),
+          trainingPlanClassList
+        }
+        console.log(params)
+
+        const { data } = await request.post('/api-school/orchestra/trainingPlanList', {
+          data: {
+            ...params
+          }
+        })
+        // 初始化 课程预览时选中的乐团编号 课程预览时选中的课程组编号
+        forms.selectOrchestraId = null
+        forms.selectClassGroupId = null
+        forms.planList = {
+          orchestra: [] as any, // 所有的乐团
+          classes: {} as any, // 所有的班级
+          course: {} as any // 所有的课程
+        }
+        console.log(data, 'date')
+        router.push({
+          path: '/course-preview',
+          query: {
+            cacheId: data
+          }
+        })
+      } catch {
+        //
+      }
+    }
+
+    const onFormatterInt = (val: any) => {
+      if (val && val >= 1) {
+        return verifiyNumberInteger(val)
+      } else {
+        return ''
+      }
+    }
+
+    onMounted(() => {
+      configParams()
+    })
+    return () => (
+      <div class={styles.practiceDetail}>
+        <OHeader />
+
+        {forms.classPracticeList.map((item: any) => (
+          <>
+            <div class={styles.title}>
+              <i></i>
+              {trainCourseEmnu[item.classType]}
+            </div>
+            {/* classType: item,
+          startTime: null as any,
+          trainTimer: null as any,
+          times: null as any,
+          classIdList: [] as any */}
+            <CellGroup inset class={styles.cellGroup}>
+              <Field
+                label="训练时长"
+                placeholder="请输入训练时长"
+                inputAlign="right"
+                v-model={item.trainTimer}
+                formatter={onFormatterInt}
+                maxlength={3}
+              >
+                {{ extra: () => '分钟' }}
+              </Field>
+              <Field
+                label="开始时间"
+                placeholder="请选择开始时间"
+                inputAlign="right"
+                readonly
+                isLink
+                modelValue={item.startTime ? dayjs(item.startTime).format('HH:mm') : ''}
+                onClick={() => {
+                  if (!item.trainTimer) {
+                    showToast('请输入训练时长')
+                    return
+                  }
+                  f.selectItem = item
+                  forms.timerStatus = true
+                }}
+              />
+              <Field
+                label="课时数"
+                placeholder="请输入课时数"
+                inputAlign="right"
+                v-model={item.times}
+                formatter={onFormatterInt}
+                maxlength={2}
+              >
+                {{ extra: () => '课时' }}
+              </Field>
+              <Cell
+                title="训练班级"
+                isLink
+                onClick={() => {
+                  f.selectItem = item
+                  forms.classStatus = true
+                }}
+              >
+                {{
+                  value: () => (
+                    <div class={styles.value}>
+                      {item.classIdList.length <= 0 ? (
+                        <div class={styles.tips}>请选择训练班级</div>
+                      ) : (
+                        <div>
+                          已选<span style={{ padding: '0 4px' }}>{item.classIdList.length}</span>
+                          个班级
+                        </div>
+                      )}
+                    </div>
+                  )
+                }}
+              </Cell>
+            </CellGroup>
+          </>
+        ))}
+
+        <OSticky position="bottom">
+          <div class={'btnGroup'}>
+            <Button type="primary" block round onClick={onSubmit}>
+              下一步
+            </Button>
+          </div>
+        </OSticky>
+
+        <OPopup
+          v-model:modelValue={forms.classStatus}
+          position="bottom"
+          style={{ background: '#f6f6f6' }}
+          destroy
+        >
+          <PracticeClass
+            onClose={() => (forms.classStatus = false)}
+            onConfirm={(val: any) => {
+              console.log(val, 'val')
+              f.selectItem.classIdList = val
+            }}
+          />
+        </OPopup>
+
+        <Popup v-model:show={forms.timerStatus} position="bottom" round>
+          <TimePicker
+            v-model={f.currentTime}
+            minHour={f.minHour}
+            minMinute={f.minMinute}
+            maxHour={f.maxHour}
+            maxMinute={f.maxMinute}
+            onChange={onChange}
+            onCancel={() => (forms.timerStatus = false)}
+            onConfirm={(val: any) => onConfirmTimer(val)}
+          />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 60 - 0
src/school/train-planning/component/practice/index.module.less

@@ -0,0 +1,60 @@
+.tips {
+  display: flex;
+  align-items: center;
+  margin: 12px 13px;
+  background: #ffebdd;
+  border-radius: 10px;
+  padding: 7px 19px;
+  font-size: 14px;
+  color: #f67146;
+  line-height: 20px;
+
+  .icon {
+    font-size: 24px;
+    margin-right: 6px;
+  }
+}
+
+.cellGroup {
+  margin: 0 13px;
+  border-radius: 10px;
+  overflow: hidden;
+
+  .classType {
+    flex: 0 auto;
+  }
+
+  :global {
+    .van-cell {
+      font-size: 16px;
+      padding: 18px 12px;
+    }
+    .van-cell__value {
+      color: #333;
+    }
+
+    .van-radio-group,
+    .van-checkbox-group {
+      justify-content: flex-end;
+    }
+  }
+
+  .radioSection {
+    position: relative;
+    min-width: 32px;
+    justify-content: center;
+  }
+
+  .radioItem {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    opacity: 0;
+  }
+
+  .radioSection + .radioSection {
+    margin-left: 12px;
+  }
+}

+ 195 - 3
src/school/train-planning/component/practice/index.tsx

@@ -1,8 +1,200 @@
-import { defineComponent } from 'vue'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Checkbox,
+  CheckboxGroup,
+  DatePicker,
+  Field,
+  Icon,
+  Picker,
+  Popup,
+  Radio,
+  RadioGroup,
+  showToast,
+  Sticky,
+  Tag
+} from 'vant'
+import { defineComponent, reactive } from 'vue'
+import { weekdays, weekFormat } from '../../create'
+import styles from './index.module.less'
+import { forms } from '../../create'
+import dayjs from 'dayjs'
+import { useRouter } from 'vue-router'
 
 export default defineComponent({
-  name: 'standard',
+  name: 'practice',
   setup() {
-    return () => '标准加练'
+    const router = useRouter()
+    const onSubmit = () => {
+      if (forms.classType.length <= 0) {
+        showToast('请选择课程类型')
+        return
+      }
+
+      if (!forms.trainStartDate) {
+        showToast('请选择课程开始日期')
+        return
+      }
+
+      if (!forms.week) {
+        showToast('请选择周次')
+        return
+      }
+
+      // 初始化 训练详情
+      const classPracticeList: any = []
+      forms.classType.forEach((item: any) => {
+        classPracticeList.push({
+          classType: item,
+          startTime: null as any,
+          endTime: null as any,
+          trainTimer: null as any,
+          times: null as any,
+          classIdList: [] as any
+        })
+      })
+
+      forms.classPracticeList = classPracticeList
+
+      router.push('/practice-detail')
+    }
+    return () => (
+      <div class={styles.practice}>
+        <div class={styles.tips}>
+          <Icon name="warning" class={styles.icon} />
+          乐团加练可对任意班级进行排课
+        </div>
+
+        <CellGroup inset class={styles.cellGroup}>
+          <Cell title="课程类型" titleClass={styles.classType}>
+            {{
+              value: () => (
+                <CheckboxGroup
+                  checked-color="#FF8057"
+                  v-model={forms.classType}
+                  direction="horizontal"
+                >
+                  <Tag
+                    size="large"
+                    type="primary"
+                    plain={!forms.classType.includes('SINGLE')}
+                    color="#FF8057"
+                    class={styles.radioSection}
+                  >
+                    <Checkbox class={styles.radioItem} name={'SINGLE'}></Checkbox>声部课
+                  </Tag>
+                  <Tag
+                    size="large"
+                    type="primary"
+                    plain={!forms.classType.includes('MUSIC_THEORY')}
+                    color="#FF8057"
+                    class={styles.radioSection}
+                  >
+                    <Checkbox class={styles.radioItem} name={'MUSIC_THEORY'}></Checkbox>乐理课
+                  </Tag>
+                  <Tag
+                    size="large"
+                    type="primary"
+                    plain={!forms.classType.includes('INSTRUMENTAL_ENSEMBLE')}
+                    color="#FF8057"
+                    class={styles.radioSection}
+                  >
+                    <Checkbox class={styles.radioItem} name={'INSTRUMENTAL_ENSEMBLE'}></Checkbox>
+                    合奏课
+                  </Tag>
+                </CheckboxGroup>
+              )
+            }}
+          </Cell>
+          <Field
+            label="课程开始日期"
+            inputAlign="right"
+            placeholder="请选择课程开始日期"
+            readonly
+            isLink
+            modelValue={
+              forms.trainStartDate ? dayjs(forms.trainStartDate).format('YYYY年MM月DD日') : ''
+            }
+            onClick={() => (forms.calendarStatus = true)}
+          />
+          <Field
+            label="课程周次"
+            inputAlign="right"
+            placeholder="请选择课程周次"
+            readonly
+            isLink
+            modelValue={weekFormat(forms.week)}
+            onClick={() => {
+              forms.weekStatus = true
+            }}
+          />
+
+          <Cell title="跳过节假日">
+            {{
+              value: () => (
+                <RadioGroup
+                  checked-color="#FF8057"
+                  v-model={forms.skipHoliday}
+                  direction="horizontal"
+                >
+                  <Tag
+                    size="large"
+                    type="primary"
+                    plain={!(forms.skipHoliday === 1)}
+                    color="#FF8057"
+                    class={styles.radioSection}
+                  >
+                    <Radio class={styles.radioItem} name={1}></Radio>是
+                  </Tag>
+                  <Tag
+                    size="large"
+                    type="primary"
+                    plain={!(forms.skipHoliday === 0)}
+                    color="#FF8057"
+                    class={styles.radioSection}
+                  >
+                    <Radio class={styles.radioItem} name={0}></Radio>否
+                  </Tag>
+                </RadioGroup>
+              )
+            }}
+          </Cell>
+        </CellGroup>
+
+        <Sticky position="bottom">
+          <div class={'btnGroup'} style={{ marginTop: '24px' }}>
+            <Button type="primary" block round size="large" onClick={onSubmit}>
+              下一步
+            </Button>
+          </div>
+        </Sticky>
+
+        {/* 训练周次 */}
+        <Popup v-model:show={forms.weekStatus} position="bottom" round>
+          <Picker
+            columns={weekdays}
+            onCancel={() => (forms.weekStatus = false)}
+            onConfirm={(val: any) => {
+              forms.week = val.selectedValues[0]
+              forms.weekStatus = false
+            }}
+          />
+        </Popup>
+
+        {/* 训练开始日期 */}
+        <Popup v-model:show={forms.calendarStatus} position="bottom" round>
+          <DatePicker
+            minDate={new Date()}
+            v-model={forms.classDate}
+            onCancel={() => (forms.calendarStatus = false)}
+            onConfirm={(date: any) => {
+              forms.calendarStatus = false
+              forms.trainStartDate = date.selectedValues.join('-')
+            }}
+          />
+        </Popup>
+      </div>
+    )
   }
 })

+ 31 - 17
src/school/train-planning/component/standard/index.tsx

@@ -8,6 +8,7 @@ import {
   Cell,
   CellGroup,
   Dialog,
+  Field,
   Icon,
   Picker,
   Popup,
@@ -65,7 +66,6 @@ export default defineComponent({
             calendarDate: dayjs(date).format('YYYY-MM-DD')
           }
         })
-        // console.log(data)
         forms.calendarList = data || []
       } catch {
         //
@@ -101,7 +101,6 @@ export default defineComponent({
         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++) {
@@ -155,8 +154,6 @@ export default defineComponent({
       getList()
       getClasses()
       getStandardCourseNum()
-
-      // console.log(route)
     })
 
     return () => (
@@ -167,16 +164,24 @@ export default defineComponent({
         </div>
 
         <CellGroup inset class={styles.cellGroup}>
-          <Cell
-            title="训练开始日期"
+          <Field
+            label="训练开始日期"
+            placeholder="请选择训练开始日期"
             isLink
-            value={forms.trainStartDate ? dayjs(forms.trainStartDate).format('YYYY年MM月DD日') : ''}
+            readonly
+            inputAlign="right"
             onClick={() => (forms.calendarStatus = true)}
-          ></Cell>
-          <Cell
-            title="训练开始时间"
-            value={forms.trainStartTime ? dayjs(forms.trainStartTime).format('HH:mm') : ''}
+            modelValue={
+              forms.trainStartDate ? dayjs(forms.trainStartDate).format('YYYY年MM月DD日') : ''
+            }
+          />
+          <Field
+            label="训练开始时间"
             isLink
+            readonly
+            placeholder="请选择训练开始日期"
+            inputAlign="right"
+            modelValue={forms.trainStartTime ? dayjs(forms.trainStartTime).format('HH:mm') : ''}
             onClick={() => {
               if (!forms.trainStartDate) {
                 showToast('请选择训练开始日期')
@@ -184,16 +189,19 @@ export default defineComponent({
               }
               forms.timerStatus = true
             }}
-          ></Cell>
+          />
           <Cell title="训练时长" value={forms.trainTimer + '分钟'}></Cell>
-          <Cell
-            title="训练周次"
+          <Field
+            label="训练周次"
+            placeholder="请选择训练周次"
+            modelValue={weekFormat(forms.week)}
             isLink
-            value={weekFormat(forms.week)}
+            inputAlign="right"
+            readonly
             onClick={() => {
               forms.weekStatus = true
             }}
-          ></Cell>
+          />
           <Cell
             title="训练次数"
             isLink={forms.times <= 0 ? false : true}
@@ -210,6 +218,13 @@ export default defineComponent({
                   checked-color="#FF8057"
                   v-model={forms.skipHoliday}
                   direction="horizontal"
+                  onChange={() => {
+                    forms.trainStartDate = null
+                    forms.trainStartTime = null
+                    forms.calendarDate = null
+                    // 初始化日历时间
+                    getList()
+                  }}
                 >
                   <Tag
                     size="large"
@@ -288,7 +303,6 @@ export default defineComponent({
             times={forms.trainTimer}
             onClose={() => (forms.timerStatus = false)}
             onConfirm={(val: any) => {
-              console.log(val, 'val info')
               forms.trainStartTime = val
             }}
           />

+ 5 - 2
src/school/train-planning/component/train-content/index.tsx

@@ -85,6 +85,9 @@ export default defineComponent({
             ...params
           }
         })
+        // 初始化 课程预览时选中的乐团编号 课程预览时选中的课程组编号
+        forms.selectOrchestraId = null
+        forms.selectClassGroupId = null
 
         console.log(data, 'date')
         router.push({
@@ -121,8 +124,8 @@ export default defineComponent({
                 ),
                 value: () => (
                   <span class={styles.classTime}>
-                    每{weekFormat(forms.week)} {dayjs(forms.trainStartTime).format('HH:mm')}-
-                    {dayjs(forms.trainStartTime)
+                    每{weekFormat(forms.week)} {dayjs(forms.trainStartTime || '').format('HH:mm')}-
+                    {dayjs(forms.trainStartTime || '')
                       .add(base[item.deliveryType][item.classType], 'minute')
                       .format('HH:mm')}
                   </span>

+ 12 - 8
src/school/train-planning/create.ts

@@ -46,14 +46,14 @@ export const weekFormat = (val: any) => {
 
 const original = () => {
   return {
-    status: false,
-    weekStatus: false,
-    calendarStatus: false,
-    classStatus: false,
-    timerStatus: false,
-    skipHoliday: 1,
-    week: null,
-    times: 16,
+    status: false, // 未设置伴学老师弹窗
+    weekStatus: false, // 时间
+    calendarStatus: false, // 日期
+    classStatus: false, // 班级设置伴学老师
+    timerStatus: false, // 时间状态
+    skipHoliday: 1, // 是否节假日
+    week: null, // 周次
+    times: 16, // 训练次数
     trainTimer: 120, // 默认120分钟
     classList: [] as any, // 没有设置伴学指导的数据
     calendarList: [] as any,
@@ -72,6 +72,10 @@ const original = () => {
       classes: {} as any, // 所有的班级
       course: {} as any // 所有的课程
     } as any,
+
+    classDate: [] as any,
+    classType: [] as any, // 乐团加课的课程类型
+    classPracticeList: [] as any, // 乐团加课课程列表初始化数据
   }
 }
 

+ 16 - 3
src/school/train-planning/index.tsx

@@ -4,19 +4,32 @@ import { Sticky, Tab, Tabs } from 'vant'
 import { defineComponent, ref } from 'vue'
 import Practice from './component/practice'
 import Standard from './component/standard'
+import { resestState } from './create'
 import styles from './index.module.less'
 
 export default defineComponent({
   name: 'train-planning',
   setup() {
-    const tabValue = ref('standard')
+    const trainType = sessionStorage.getItem('trainType')
+    const tabValue = ref(trainType || 'standard')
+    // sessionStorage.removeItem('trainType')
     return () => (
       <div class={styles.train}>
         <OSticky position="top">
           <OHeader />
-          <Tabs sticky lineWidth={20} lineHeight={4} v-model:active={tabValue.value}>
+          <Tabs
+            sticky
+            lineWidth={20}
+            lineHeight={4}
+            v-model:active={tabValue.value}
+            onChange={(val: any) => {
+              // 切换时间重置表单数据
+              resestState()
+              sessionStorage.setItem('trainType', val)
+            }}
+          >
             <Tab title="标准训练" name="standard">
-              <Standard />
+              {tabValue.value === 'standard' && <Standard />}
             </Tab>
             <Tab title="乐团加练" name="practice">
               <Practice />

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

@@ -79,11 +79,19 @@ export default defineComponent({
   },
   mounted() {
     // 初始化标题和最大显示日期
-    this.subtitle = dayjs().add(1, 'day').format('YYYY年MM月')
-    this.maxDate = dayjs().add(1, 'day').endOf('month').toDate()
-    this.minDate = dayjs().add(1, 'day').toDate()
+    this.subtitle = dayjs(this.calendarDate || '')
+      .add(1, 'day')
+      .format('YYYY年MM月')
+    this.maxDate = dayjs(this.calendarDate || '')
+      .add(1, 'day')
+      .endOf('month')
+      .toDate()
+    this.minDate = dayjs(this.calendarDate || '')
+      .add(1, 'day')
+      .toDate()
 
     console.log(this.list, 'this.list')
+    console.log(this.calendarDate, 'calendarDate')
   },
   methods: {
     formatter(date: any) {
@@ -154,6 +162,7 @@ export default defineComponent({
           rowHeight={62}
           minDate={this.minDate}
           maxDate={this.maxDate}
+          defaultDate={dayjs(this.calendarDate || '').toDate()}
           color="var(--van-primary)"
           formatter={this.formatter}
           onSelect={this.onDateSelect}

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

@@ -125,7 +125,7 @@ export default defineComponent({
           <TeacherList
             header={false}
             mode={'sticky'}
-            subjectId={state.selectItem.subjectIds}
+            courseType={state.selectItem.type}
             onClose={() => (state.teacherStatus = false)}
             onSelect={(val: any) => {
               state.selectItem.teacherId = val.id

+ 110 - 0
src/school/train-planning/modal/practice-class/index.module.less

@@ -0,0 +1,110 @@
+.searchBand {
+  display: inline-block;
+  font-size: 14px;
+  font-weight: 600;
+  color: #333333;
+}
+
+.gridContainer {
+  margin: 0 13px 12px;
+  // background: #ffffff;
+
+  .title {
+    font-size: 26px;
+    font-weight: bold;
+    color: #333;
+    i {
+      font-style: normal;
+      font-size: 12px;
+      color: #333333;
+    }
+  }
+  .red {
+    color: #f67146;
+  }
+  .name {
+    padding-top: 8px;
+    font-size: 12px;
+    color: #777777;
+  }
+}
+
+.gridClass {
+  .img {
+    width: 40px;
+    height: 40px;
+    margin-right: 12px;
+    border-radius: 50%;
+    overflow: hidden;
+  }
+  .teacherName {
+    display: flex;
+    align-items: center;
+    font-size: 16px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 22px;
+    :global {
+      .van-tag {
+        margin-left: 6px;
+      }
+    }
+  }
+  .classCheckbox {
+    display: flex;
+    justify-content: flex-end;
+  }
+  .orchestraName {
+    padding-top: 3px;
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+  }
+  .title {
+    font-size: 24px;
+  }
+
+  .className {
+    padding: 17px 15px 0;
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+    .line {
+      display: inline-block;
+      width: 4px;
+      height: 12px;
+      background: #ff8057;
+      border-radius: 3px;
+      margin-right: 6px;
+    }
+  }
+
+  :global {
+    .van-grid-item {
+      &:after {
+        content: ' ';
+        position: absolute;
+        top: 50%;
+        right: 0;
+        margin-top: -10px;
+        width: 1px;
+        height: 20px;
+        background: #eaeaea;
+        border-radius: 1px;
+      }
+
+      &:last-child {
+        &::after {
+          display: none;
+        }
+      }
+    }
+  }
+}
+
+.classCellGroup {
+  margin-bottom: 12px;
+  border-radius: 10px;
+  overflow: hidden;
+}

+ 222 - 0
src/school/train-planning/modal/practice-class/index.tsx

@@ -0,0 +1,222 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Checkbox,
+  CheckboxGroup,
+  Grid,
+  GridItem,
+  Icon,
+  Image,
+  List,
+  Picker,
+  Popup,
+  Tag
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import { state as baseState } from '@/state'
+import request from '@/helpers/request'
+import OEmpty from '@/components/o-empty'
+
+export default defineComponent({
+  name: 'practice-class',
+  emits: ['close', 'confirm'],
+  setup(props, { slots, attrs, emit }) {
+    const forms = reactive({
+      showPopover: false,
+      orchestraId: null as any,
+      orchestraName: null as any,
+      orchestraList: [] as any,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        type: null,
+        page: 1,
+        rows: 20
+      },
+      check: [] as any,
+      checkboxRefs: [] as any
+    })
+    // 获取乐团列表
+    const getOrchestras = async () => {
+      try {
+        const { data } = await request.post('/api-school/orchestra/page', {
+          data: {
+            page: 1,
+            rows: 100,
+            schoolId: baseState.user.data.school.id
+          }
+        })
+        const temps = data.rows || []
+        const s = [] as any
+        temps.forEach((item: any) => {
+          s.push({
+            text: item.name,
+            value: item.id
+          })
+        })
+        forms.orchestraList = [...s]
+
+        // 判断是否有乐团
+        if (s.length > 0) {
+          forms.orchestraId = s[0].value
+          forms.orchestraName = s[0].text
+        }
+      } catch {
+        //
+      }
+    }
+
+    // 获取班级
+    const getList = async () => {
+      // 查询没有设置指导老师的班级
+      try {
+        const { data } = await request.post('/api-school/classGroup/page', {
+          data: {
+            page: 1,
+            rows: 20,
+            schoolId: baseState.user.data.school.id,
+            orchestraId: forms.orchestraId
+            // orchestraType: 'DELIVERY'
+          }
+        })
+        // 班级数据
+        forms.listState.loading = false
+        const result = data || {}
+        // 处理重复请求数据
+        if (forms.list.length > 0 && result.current === 1) {
+          return
+        }
+        forms.list = forms.list.concat(result.rows || [])
+        forms.listState.finished = result.current >= result.pages
+        forms.params.page = result.current + 1
+        forms.listState.dataShow = forms.list.length > 0
+      } catch {
+        forms.listState.dataShow = false
+        forms.listState.finished = true
+      }
+    }
+
+    const onSelect = (type: string) => {
+      forms.checkboxRefs[type].toggle()
+    }
+
+    // 确定选择班级
+    const onSubmit = () => {
+      console.log(forms.check)
+      emit('confirm', forms.check)
+      emit('close')
+    }
+
+    onMounted(async () => {
+      await getOrchestras()
+      await getList()
+    })
+
+    return () => (
+      <div class={styles.practiceClass}>
+        <OSticky position="top">
+          <OHeader title="选择班级" />
+          <div style={{ padding: '12px 13px', background: '#f6f6f6' }}>
+            <div class={styles.searchBand} onClick={() => (forms.showPopover = true)}>
+              {forms.orchestraName} <Icon name={forms.showPopover ? 'arrow-up' : 'arrow-down'} />
+            </div>
+          </div>
+        </OSticky>
+
+        {forms.listState.dataShow ? (
+          <List
+            v-model:loading={forms.listState.loading}
+            finished={forms.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup class={[styles.gridContainer, styles.gridClass]} v-model={forms.check}>
+              {forms.list.map((item: any) => (
+                <CellGroup class={styles.classCellGroup} onClick={() => onSelect(item.id)}>
+                  <Cell center titleStyle={{ flex: '0 auto' }} valueClass={styles.classCheckbox}>
+                    {{
+                      icon: () => <Image src={iconTeacher} class={styles.img} />,
+                      title: () => (
+                        <div class={styles.content}>
+                          <div class={styles.teacherName}>
+                            {item.teacherName} <Tag type="primary">{item.name}</Tag>
+                          </div>
+                          <div class={styles.orchestraName}>{item.orchestraName}</div>
+                        </div>
+                      ),
+                      value: () => (
+                        <Checkbox
+                          name={item.id}
+                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                          onClick={(e: any) => {
+                            e.stopPropagation()
+                          }}
+                        ></Checkbox>
+                      )
+                    }}
+                  </Cell>
+                  <Grid border={false} columnNum={3}>
+                    <GridItem>
+                      <p class={styles.title}>{item.preStudentNum}</p>
+                      <p class={styles.name}>学生人数</p>
+                    </GridItem>
+                    <GridItem>
+                      <p class={[styles.title]}>
+                        {item.courseScheduleNum - item.completeCourseScheduleNum}
+                      </p>
+                      <p class={styles.name}>剩余课时</p>
+                    </GridItem>
+                    <GridItem>
+                      <p class={styles.title}>{item.courseScheduleNum}</p>
+                      <p class={styles.name}>总课时</p>
+                    </GridItem>
+                  </Grid>
+                </CellGroup>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无班级" />
+        )}
+
+        <OSticky position="bottom">
+          <div class={'btnGroup'}>
+            <Button block round type="primary" onClick={onSubmit}>
+              确认
+            </Button>
+          </div>
+        </OSticky>
+
+        <Popup v-model:show={forms.showPopover} position="bottom" round>
+          <Picker
+            columns={forms.orchestraList}
+            onCancel={() => (forms.showPopover = false)}
+            onConfirm={(val: any) => {
+              forms.orchestraId = val.selectedOptions[0].value
+              forms.orchestraName = val.selectedOptions[0].text
+              forms.showPopover = false
+
+              forms.params.page = 1
+              forms.list = []
+              forms.listState.dataShow = true // 判断是否有数据
+              forms.listState.loading = false
+              forms.listState.finished = false
+              getList()
+            }}
+          />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 101 - 0
src/student/music-group/pre-apply/order-detail.module.less

@@ -92,3 +92,104 @@
     }
   }
 }
+
+.codeContainer {
+  .codeImg {
+    width: 323px;
+    height: 465px;
+    // padding-left: 8px;
+    background: url('../images/download.png') no-repeat center center;
+    background-size: contain;
+    margin: 0 auto;
+
+    .codeContent {
+      padding-left: 8px;
+    }
+
+    .codeTitle {
+      text-align: center;
+      padding-top: 13px;
+      font-size: 24px;
+      font-weight: bold;
+      color: #ffffff;
+      text-shadow: 1px 1px 7px #f4672a;
+    }
+
+    .codeName {
+      padding: 40px 12px 0;
+      font-size: 18px;
+      font-weight: 600;
+      color: #ffffff;
+      text-align: center;
+    }
+    .codeQr {
+      margin: 23px auto 0;
+      width: 241px;
+      height: 241px;
+      background: linear-gradient(180deg, #ffffff 0%, #ffffff 100%);
+      border-radius: 11px;
+      overflow: hidden;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .codeBtnText {
+      margin: 15px auto 0;
+      display: inline-block;
+      background: linear-gradient(135deg, #ff9c63 0%, #ff7144 100%);
+      border-radius: 18px;
+      padding: 6px 16px;
+      font-size: 16px;
+      font-weight: 600;
+      color: #ffffff;
+    }
+
+    .codeTips {
+      padding-top: 10px;
+      font-size: 13px;
+      font-weight: 600;
+      color: #f16437;
+      line-height: 18px;
+      text-align: center;
+    }
+  }
+  .close {
+    position: absolute;
+    top: 12px;
+    right: 15px;
+  }
+  .codeBottom {
+    position: relative;
+    margin-top: 32px;
+    background: #ffffff;
+    border-radius: 20px 20px 0px 0px;
+    padding-bottom: 10px;
+  }
+  .title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 22px;
+    padding: 15px 15px 0;
+    i {
+      display: inline-block;
+      margin-right: 6px;
+      width: 4px;
+      height: 12px;
+      background: #ff8057;
+      border-radius: 2px;
+    }
+  }
+  .shareImg {
+    width: 47px;
+    height: 47px;
+  }
+  .shareText {
+    padding-top: 6px;
+    font-size: 14px;
+    color: #333333;
+    line-height: 20px;
+  }
+}