123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- import {
- Button,
- Cell,
- DatetimePicker,
- Field,
- Popup,
- Radio,
- RadioGroup,
- Stepper,
- Tag,
- Toast
- } from 'vant'
- import { computed, defineComponent, onMounted, reactive, ref } 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'
- const fieldProps = {
- 'is-link': true,
- readonly: true,
- 'arrow-direction': 'down'
- }
- export default defineComponent({
- name: 'ClassArrangement',
- setup() {
- 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 subjectList = ref<[]>([]) // 声部分类
- const getSubjectSelect = async () => {
- try {
- const res = await request.get('/api-teacher/subject/subjectSelect')
- subjectList.value = res.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 (!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 () => {
- try {
- let { code, data } = await request.post(
- '/api-teacher/courseSchedule/arrangeCourse',
- {
- data: {
- classNum: params.classNum, //课时数
- consumeTime: Math.ceil(
- students.value.length * 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
- Toast('排课成功')
- }
- } 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 (
- <>
- <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="请输入课程时长"
- modelValue={params.singleClssTime}
- onUpdate:modelValue={t => {
- if (Math.abs(t) > 60) {
- Toast('时长不能大于60分钟')
- return
- }
- if (Math.abs(t) === 0) {
- Toast('时长不能小于1分钟')
- return
- }
- params.singleClssTime = Math.abs(t)
- }}
- // 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
- disabled={
- params.isSkipHolidays &&
- (n === '周六' || n === '周日')
- }
- 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}
- onChange={() => {
- if (
- params.isSkipHolidays &&
- (params.week === '周六' || params.week === '周日')
- ) {
- params.week = ''
- }
- }}
- >
- <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()}
- >
- 下一步
- </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
- >
- <OrganSearch
- subjectList={subjectList.value}
- v-model={params.subjectId}
- v-model:subjectName={params.subjectName}
- onSort={() => (voiceShow.value = false)}
- />
- </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={() => {
- timeShow.value = false
- }}
- onCancel={() => (timeShow.value = false)}
- />
- </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()
- }}
- />
- </Popup>
- </>
- )
- }
- }
- })
|