|
@@ -1,546 +1,50 @@
|
|
|
-import {
|
|
|
- Button,
|
|
|
- Cell,
|
|
|
- DatetimePicker,
|
|
|
- Field,
|
|
|
- Popup,
|
|
|
- Radio,
|
|
|
- RadioGroup,
|
|
|
- Stepper,
|
|
|
- Tag,
|
|
|
- Toast
|
|
|
-} from 'vant'
|
|
|
-import { computed, defineComponent, onMounted, reactive, ref } from 'vue'
|
|
|
+import { computed, defineComponent, onMounted, reactive, ref, watch } from 'vue'
|
|
|
import styles from './index.module.less'
|
|
|
-import iconTips from '../images/icon_tips.png'
|
|
|
-import { formatterDate } from '@/helpers/utils'
|
|
|
-import request from '@/helpers/request'
|
|
|
-import OrganSearch from '@/student/practice-class/model/organ-search'
|
|
|
-import dayjs from 'dayjs'
|
|
|
import ColHeader from '@/components/col-header'
|
|
|
-import ColPopup from '@/components/col-popup'
|
|
|
-import SelectStudents, { IStudent } from './select-students'
|
|
|
-import CourseSchedule from './course-schedule'
|
|
|
-import { checkNumberInteger } from '@/helpers/toolsValidate'
|
|
|
-import Voice from '../model/voice'
|
|
|
-import { useRouter } from 'vue-router'
|
|
|
-const fieldProps = {
|
|
|
- 'is-link': true,
|
|
|
- readonly: true,
|
|
|
- 'arrow-direction': 'down'
|
|
|
-}
|
|
|
+import { Icon } from 'vant'
|
|
|
+import nameActive from '../images/icon_name_active.png'
|
|
|
+import education from '../images/icon_education.png'
|
|
|
+import educationActive from '../images/icon_education_active.png'
|
|
|
+import ClassInfo from './class-info'
|
|
|
+import CreateClass from './create-class'
|
|
|
+export const active = ref(1)
|
|
|
export default defineComponent({
|
|
|
name: 'ClassArrangement',
|
|
|
setup() {
|
|
|
- const router = useRouter()
|
|
|
- const dateShow = ref(false)
|
|
|
- const timeShow = ref(false)
|
|
|
- const voiceShow = ref(false)
|
|
|
- const selectStudentShow = ref(false)
|
|
|
- const confirmShow = ref(false)
|
|
|
-
|
|
|
- // 参数
|
|
|
- const params = reactive({
|
|
|
- courseName: '', // 课程名称
|
|
|
- classNum: 1, // 课时数
|
|
|
- singleClssTime: 45, //单课时长
|
|
|
- studentIds: [], //学员id集合
|
|
|
- timeList: [] as any, // 上课时间
|
|
|
- date: '',
|
|
|
- time: '',
|
|
|
- subjectId: 0,
|
|
|
- subjectName: '',
|
|
|
- week: '', // 周几
|
|
|
- isSkipHolidays: true
|
|
|
- })
|
|
|
- const startTime = ref('')
|
|
|
- const endTime = ref('')
|
|
|
-
|
|
|
- // 上课时间
|
|
|
- const timeScope = computed(() => {
|
|
|
- // if (startTime.value && endTime.value) {
|
|
|
- // let start = startTime.value.split(':')
|
|
|
- // let end = endTime.value.split(':')
|
|
|
- // let min = parseInt(start[0]) * 60 + parseInt(start[1])
|
|
|
- // let max = parseInt(end[0]) * 60 + parseInt(end[1])
|
|
|
- // // params.singleClssTime = max - min
|
|
|
- // return startTime.value + ' ~ ' + endTime.value
|
|
|
- // }
|
|
|
- // params.singleClssTime = 0
|
|
|
- return startTime.value
|
|
|
- })
|
|
|
-
|
|
|
- // 学员
|
|
|
- const students = ref<IStudent[]>([])
|
|
|
- // 设置学员
|
|
|
- const onSetStudents = (result: IStudent[]) => {
|
|
|
- students.value = result
|
|
|
- selectStudentShow.value = false
|
|
|
- }
|
|
|
- const onDeleteStudent = index => {
|
|
|
- const n = students.value.splice(index, 1)[0]
|
|
|
- studentRef?.value.onDelete(n)
|
|
|
- }
|
|
|
- const studentRef = ref('') as any
|
|
|
-
|
|
|
- // 训练声部
|
|
|
- const choiceSubjectIds = ref<[]>([])
|
|
|
- const subjectList2 = ref<[]>([])
|
|
|
- const subjectList = ref<[]>([]) // 声部分类
|
|
|
- const getSubjectSelect = async () => {
|
|
|
- try {
|
|
|
- const res = await request.get('/api-teacher/subject/subjectSelect')
|
|
|
- subjectList2.value = res.data
|
|
|
- const teachRes = await request.post('/api-teacher/teacher/querySubject')
|
|
|
- subjectList.value = teachRes.data || []
|
|
|
- } catch {}
|
|
|
- }
|
|
|
-
|
|
|
- //上课时间
|
|
|
- const startClassTime = ref<string>('')
|
|
|
- const endClassTime = ref<string>('')
|
|
|
- const getClassTime = async () => {
|
|
|
- try {
|
|
|
- const res = await request.get(
|
|
|
- '/api-teacher/sysConfig/queryByParamNameList',
|
|
|
- {
|
|
|
- params: {
|
|
|
- paramNames: 'course_start_setting,course_end_setting'
|
|
|
- }
|
|
|
- }
|
|
|
- )
|
|
|
- if (res.code === 200) {
|
|
|
- for (let i = 0, len = res.data.length; i < len; i++) {
|
|
|
- if (res.data[i].paramName === 'course_start_setting') {
|
|
|
- startClassTime.value = res.data[i].paramValue
|
|
|
- }
|
|
|
- if (res.data[i].paramName === 'course_end_setting') {
|
|
|
- endClassTime.value = res.data[i].paramValue
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (error) {}
|
|
|
- }
|
|
|
- onMounted(() => {
|
|
|
- getSubjectSelect()
|
|
|
- getClassTime()
|
|
|
- })
|
|
|
-
|
|
|
- //检查上课时间是否满足后台设置的最晚时间
|
|
|
- const checkClassTimeIsSatisfyLastTime = () => {
|
|
|
- const baseTime = dayjs()
|
|
|
- const _endTime = baseTime
|
|
|
- .set('hour', Number(startTime.value.split(':')[0]))
|
|
|
- .set('minute', Number(startTime.value.split(':')[1]))
|
|
|
- .add(params.singleClssTime, 'minute')
|
|
|
- const _endClassTime = baseTime
|
|
|
- .set('hour', Number(endClassTime.value.split(':')[0]))
|
|
|
- .set('minute', Number(endClassTime.value.split(':')[1]))
|
|
|
- // console.log(_endTime.format('HH:mm'),_endClassTime.format('HH:mm'))
|
|
|
- return {
|
|
|
- isOk: _endTime.isBefore(_endClassTime),
|
|
|
- _endClassTime: _endClassTime.format('HH:mm')
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //开始时间
|
|
|
- const onSetTime = async (time: string) => {
|
|
|
- console.log(time)
|
|
|
- params.time = time
|
|
|
- timeShow.value = false
|
|
|
- }
|
|
|
-
|
|
|
- const holidays = ref('') // 节假日
|
|
|
- const getHolidays = async (year: string) => {
|
|
|
- try {
|
|
|
- let result = await request.get(
|
|
|
- '/api-teacher/courseSchedule/selectHoliday',
|
|
|
- { params: { year } }
|
|
|
- )
|
|
|
- holidays.value = result?.data?.holidaysFestivalsJson || ''
|
|
|
- } catch (error) {}
|
|
|
- }
|
|
|
-
|
|
|
- // 计算日期
|
|
|
- const calcDate = () => {
|
|
|
- const timeList = [] as any
|
|
|
- const curriculumList = [] as any
|
|
|
- let total = 0
|
|
|
- let index = 0
|
|
|
- const selectWeekIndex = week[params.week]
|
|
|
- const endTime = dayjs()
|
|
|
- .set('hour', Number(startTime.value.split(':')[0]))
|
|
|
- .set('minute', Number(startTime.value.split(':')[1]))
|
|
|
- .add(params.singleClssTime, 'minute')
|
|
|
- .format('HH:mm')
|
|
|
- while (total < params.classNum) {
|
|
|
- const time = dayjs(params.date).add(index, 'day')
|
|
|
- index++
|
|
|
- const weekIndex = time.get('day')
|
|
|
- if (weekIndex !== selectWeekIndex) {
|
|
|
- continue
|
|
|
- }
|
|
|
- const year_month_date = time.format('YYYY-MM-DD')
|
|
|
- if (params.isSkipHolidays) {
|
|
|
- // 只需要后台配置的
|
|
|
- if (
|
|
|
- // ![6, 0].includes(time.get('day')) &&
|
|
|
- !holidays.value.includes(year_month_date)
|
|
|
- ) {
|
|
|
- total++
|
|
|
- timeList.push({
|
|
|
- startTime: year_month_date + ` ${startTime.value}`,
|
|
|
- endTime: year_month_date + ` ${endTime}`
|
|
|
- })
|
|
|
- curriculumList.push(
|
|
|
- year_month_date + ` ${startTime.value} ~ ${endTime}`
|
|
|
- )
|
|
|
- }
|
|
|
- } else {
|
|
|
- total++
|
|
|
- timeList.push({
|
|
|
- startTime: year_month_date + ` ${startTime.value}`,
|
|
|
- endTime: year_month_date + ` ${endTime}`
|
|
|
- })
|
|
|
- curriculumList.push(
|
|
|
- year_month_date + ` ${startTime.value} ~ ${endTime}`
|
|
|
- )
|
|
|
- }
|
|
|
- }
|
|
|
- return { timeList, curriculumList }
|
|
|
- }
|
|
|
-
|
|
|
- const curriculum = ref<string[]>([])
|
|
|
- // 设置排课数据
|
|
|
- const setParmas = () => {
|
|
|
- if (!params.courseName) {
|
|
|
- Toast('请填写课程名称')
|
|
|
- return
|
|
|
- }
|
|
|
- if (!params.subjectId) {
|
|
|
- Toast('请选择训练声部')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!params.singleClssTime) {
|
|
|
- Toast('请填写单课时时长')
|
|
|
- return
|
|
|
- }
|
|
|
- if (
|
|
|
- checkNumberInteger(String(params.singleClssTime)) ||
|
|
|
- params.singleClssTime < 0
|
|
|
- ) {
|
|
|
- Toast('课时时长为正整数')
|
|
|
- return
|
|
|
- }
|
|
|
- if (!params.date) {
|
|
|
- Toast('请选择开始日期')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!params.week) {
|
|
|
- Toast('请选择循环周次')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!startTime.value) {
|
|
|
- Toast('请选择上课时间')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- let checkData = checkClassTimeIsSatisfyLastTime()
|
|
|
- if (!checkData.isOk) {
|
|
|
- Toast(`上课结束时间不能晚于${checkData._endClassTime}`)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!students.value.length) {
|
|
|
- Toast('请选择上课学员')
|
|
|
- return
|
|
|
- }
|
|
|
- const { timeList, curriculumList } = calcDate()
|
|
|
- params.timeList = timeList
|
|
|
- curriculum.value = curriculumList
|
|
|
- // console.log(curriculumList)
|
|
|
- confirmShow.value = true
|
|
|
- }
|
|
|
-
|
|
|
- // 排课
|
|
|
- const onCourseSchedule = async () => {
|
|
|
- const n = students.value.length + 1
|
|
|
- try {
|
|
|
- let { code, data } = await request.post(
|
|
|
- '/api-teacher/courseSchedule/arrangeCourse',
|
|
|
- {
|
|
|
- data: {
|
|
|
- classNum: params.classNum, //课时数
|
|
|
- consumeTime: Math.ceil(
|
|
|
- n * (n - 1) * params.classNum * params.singleClssTime
|
|
|
- ), //消耗时长
|
|
|
- courseName: params.courseName, //课程名称
|
|
|
- singleClssTime: params.singleClssTime, //单课时长
|
|
|
- studentIds: students.value.map(n => n.userId), //学员id集合
|
|
|
- subjectId: params.subjectId, //声部id
|
|
|
- timeList: params.timeList
|
|
|
- }
|
|
|
- }
|
|
|
- )
|
|
|
- if (code === 200) {
|
|
|
- confirmShow.value = false
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- Toast({
|
|
|
- icon: 'success',
|
|
|
- message: '排课成功',
|
|
|
- duration: 1500,
|
|
|
- onClose: () => {
|
|
|
- router.back()
|
|
|
- }
|
|
|
- })
|
|
|
- }, 100)
|
|
|
- }
|
|
|
- } catch (error) {}
|
|
|
- }
|
|
|
- const week = {
|
|
|
- 周一: 1,
|
|
|
- 周二: 2,
|
|
|
- 周三: 3,
|
|
|
- 周四: 4,
|
|
|
- 周五: 5,
|
|
|
- 周六: 6,
|
|
|
- 周日: 0
|
|
|
- }
|
|
|
- // console.log(Object.values(week))
|
|
|
return () => {
|
|
|
- const minStartHour = startClassTime.value.split(':')[0] || ''
|
|
|
- const minStartMimute = startClassTime.value.split(':')[1] || ''
|
|
|
return (
|
|
|
- <>
|
|
|
+ <div class={styles.classWrap}>
|
|
|
<ColHeader />
|
|
|
- <div class={styles.container}>
|
|
|
- <Field
|
|
|
- label="课程名称"
|
|
|
- placeholder="请输入课程名称"
|
|
|
- v-model={params.courseName}
|
|
|
- />
|
|
|
- <Field
|
|
|
- label="训练声部"
|
|
|
- placeholder="请选择训练声部"
|
|
|
- {...fieldProps}
|
|
|
- modelValue={params.subjectName}
|
|
|
- onClick={() => (voiceShow.value = true)}
|
|
|
- />
|
|
|
- <Cell style={{ padding: 0 }}>
|
|
|
- <Field
|
|
|
- style={{ margin: 0 }}
|
|
|
- border={false}
|
|
|
- label="上课学员"
|
|
|
- placeholder="请选择上课学员"
|
|
|
- {...fieldProps}
|
|
|
- onClick={() => (selectStudentShow.value = true)}
|
|
|
- />
|
|
|
- {students.value.length ? (
|
|
|
- <div class={styles.tags}>
|
|
|
- {students.value.map((n: IStudent, index: number) => (
|
|
|
- <Tag closeable onClose={() => onDeleteStudent(index)}>
|
|
|
- {n.userName}
|
|
|
- </Tag>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
- </Cell>
|
|
|
- <Field
|
|
|
- label="课时数"
|
|
|
- placeholder="请输入课时数"
|
|
|
- v-slots={{
|
|
|
- input: () => <Stepper v-model={params.classNum}></Stepper>
|
|
|
- }}
|
|
|
- />
|
|
|
- <Field
|
|
|
- class={styles.singleClssTime}
|
|
|
- type="number"
|
|
|
- label="单课时时长"
|
|
|
- placeholder="请输入课程时长"
|
|
|
- v-model={params.singleClssTime}
|
|
|
- v-slots={{
|
|
|
- 'right-icon': () => <div>分钟</div>
|
|
|
- }}
|
|
|
- />
|
|
|
- <Field
|
|
|
- label="开始日期"
|
|
|
- placeholder="请选择开始日期"
|
|
|
- {...fieldProps}
|
|
|
- modelValue={params.date}
|
|
|
- onClick={() => (dateShow.value = true)}
|
|
|
- />
|
|
|
- <Cell
|
|
|
- title="循环周次"
|
|
|
- v-slots={{
|
|
|
- label: () => (
|
|
|
- <RadioGroup class={styles.week} v-model={params.week}>
|
|
|
- {Object.keys(week).map((n: string) => {
|
|
|
- return <Radio name={n}>{n}</Radio>
|
|
|
- })}
|
|
|
- </RadioGroup>
|
|
|
- )
|
|
|
- }}
|
|
|
- />
|
|
|
- <Field
|
|
|
- label="上课时间"
|
|
|
- placeholder="请选择上课时间"
|
|
|
- {...fieldProps}
|
|
|
- modelValue={timeScope.value}
|
|
|
- onClick={() => (timeShow.value = true)}
|
|
|
- />
|
|
|
- <Cell
|
|
|
- title="是否跳过节假日"
|
|
|
- v-slots={{
|
|
|
- value: () => (
|
|
|
- <RadioGroup
|
|
|
- class={styles.holdays}
|
|
|
- v-model={params.isSkipHolidays}
|
|
|
- >
|
|
|
- <Radio name={true} style={{ marginRight: '10px' }}>
|
|
|
- 是
|
|
|
- </Radio>
|
|
|
- <Radio name={false}>否</Radio>
|
|
|
- </RadioGroup>
|
|
|
- )
|
|
|
- }}
|
|
|
- />
|
|
|
- <Cell
|
|
|
- v-slots={{
|
|
|
- title: () => (
|
|
|
- <div class={styles.tips}>
|
|
|
- <img class={styles.icon} src={iconTips} />
|
|
|
- <span>温馨提醒</span>
|
|
|
- </div>
|
|
|
- ),
|
|
|
- label: () => (
|
|
|
- <div class={styles.tipsContent}>
|
|
|
- 1、云酷琴房时长按课程人数扣减(含老师),以45分钟1对1课程师生2人为例,课程结束后将消耗时长:2人*45分钟=90分钟;
|
|
|
- <br />
|
|
|
- <br />
|
|
|
- 2、每节线上课平台赠送10分钟免费时长,分别为课前5分钟及课后5分钟,赠送时长不计算费用;
|
|
|
- <br />
|
|
|
- <br />
|
|
|
- 3、课程消耗时长按排课人数计算,无论实际到课人数是否为排课人数,都会按照排课人数扣费;
|
|
|
- <br />
|
|
|
- <br />
|
|
|
- 4、课程结束后费用立即结算;
|
|
|
- <br />
|
|
|
- <br />
|
|
|
- 5、琴房时长不足时,您将无法排课,请确保琴房剩余时长充足。
|
|
|
- </div>
|
|
|
- )
|
|
|
- }}
|
|
|
- />
|
|
|
-
|
|
|
- <Button
|
|
|
- block
|
|
|
- type="primary"
|
|
|
- round
|
|
|
- style={{ margin: '0 auto', width: '90%', marginTop: '20px' }}
|
|
|
- onClick={() => setParmas()}
|
|
|
+ <div class={styles.tabs}>
|
|
|
+ <div class={[styles.tabItem, styles.tabItemActive]}>
|
|
|
+ <Icon name={nameActive} size={38} />
|
|
|
+ <span class={styles.title}>课程信息</span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ styles.tabItem,
|
|
|
+ styles.tabItemRight,
|
|
|
+ active.value > 1 ? styles.tabItemActive : ''
|
|
|
+ ]}
|
|
|
>
|
|
|
- 下一步
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <Popup position="bottom" v-model:show={dateShow.value}>
|
|
|
- <DatetimePicker
|
|
|
- type="date"
|
|
|
- minDate={dayjs().year(2022).toDate()}
|
|
|
- formatter={formatterDate}
|
|
|
- onConfirm={(time: Date) => {
|
|
|
- params.date = dayjs(time).format('YYYY-MM-DD')
|
|
|
- dateShow.value = false
|
|
|
- getHolidays(dayjs(time).format('YYYY'))
|
|
|
- }}
|
|
|
- onCancel={() => (dateShow.value = false)}
|
|
|
- />
|
|
|
- </Popup>
|
|
|
-
|
|
|
- <Popup
|
|
|
- v-model:show={voiceShow.value}
|
|
|
- position="bottom"
|
|
|
- round
|
|
|
- closeable
|
|
|
- safe-area-inset-bottom
|
|
|
- class={styles.voicePopup}
|
|
|
- >
|
|
|
- <Voice
|
|
|
- class={styles.voicePopupContent}
|
|
|
- single
|
|
|
- selectType={'Radio'}
|
|
|
- subjectList={subjectList.value}
|
|
|
- onChoice={val => {
|
|
|
- const voice: any = subjectList.value.filter(
|
|
|
- (n: any) => n.id === val
|
|
|
- )[0]
|
|
|
- if (voice) {
|
|
|
- params.subjectId = voice.id
|
|
|
- params.subjectName = voice.name
|
|
|
- voiceShow.value = false
|
|
|
- } else {
|
|
|
- params.subjectId = 0
|
|
|
- params.subjectName = ''
|
|
|
- }
|
|
|
- }}
|
|
|
- />
|
|
|
- </Popup>
|
|
|
-
|
|
|
- <Popup position="bottom" v-model:show={timeShow.value} round>
|
|
|
- <div class={styles.picker}>
|
|
|
- <DatetimePicker
|
|
|
- v-model={startTime.value}
|
|
|
- type="time"
|
|
|
- minHour={minStartHour}
|
|
|
- minMinute={minStartMimute}
|
|
|
- onConfirm={() => {
|
|
|
- if (!startTime.value) {
|
|
|
- startTime.value = dayjs()
|
|
|
- .set('hour', Number(minStartHour))
|
|
|
- .set('minute', Number(minStartMimute))
|
|
|
- .format('HH:mm')
|
|
|
- }
|
|
|
- timeShow.value = false
|
|
|
- }}
|
|
|
- onCancel={() => (timeShow.value = false)}
|
|
|
+ <Icon
|
|
|
+ name={active.value > 1 ? educationActive : education}
|
|
|
+ size={38}
|
|
|
/>
|
|
|
+ <span class={styles.title}>课程信息</span>
|
|
|
</div>
|
|
|
- </Popup>
|
|
|
-
|
|
|
- {/* 选择学员 */}
|
|
|
- <ColPopup v-model={selectStudentShow.value}>
|
|
|
- <SelectStudents
|
|
|
- ref={studentRef}
|
|
|
- subjectList={subjectList.value}
|
|
|
- onSetStudents={onSetStudents}
|
|
|
- />
|
|
|
- </ColPopup>
|
|
|
-
|
|
|
- {/* 确认排课 */}
|
|
|
- <Popup
|
|
|
- position="bottom"
|
|
|
- class={styles.coursePopup}
|
|
|
- v-model:show={confirmShow.value}
|
|
|
- closeable
|
|
|
- round
|
|
|
- >
|
|
|
- <CourseSchedule
|
|
|
- item={params}
|
|
|
- students={students.value}
|
|
|
- curriculum={curriculum.value}
|
|
|
- onClose={() => {
|
|
|
- confirmShow.value = false
|
|
|
- }}
|
|
|
- onComfirm={() => {
|
|
|
- onCourseSchedule()
|
|
|
+ </div>
|
|
|
+ <div style={{ display: active.value === 1 ? 'block' : 'none' }}>
|
|
|
+ <ClassInfo
|
|
|
+ onSubmit={val => {
|
|
|
+ active.value = 2
|
|
|
}}
|
|
|
/>
|
|
|
- </Popup>
|
|
|
- </>
|
|
|
+ </div>
|
|
|
+ <div style={{ display: active.value === 2 ? 'block' : 'none' }}>
|
|
|
+ <CreateClass />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
)
|
|
|
}
|
|
|
}
|