|
@@ -1,9 +1,26 @@
|
|
|
-import { Button, Cell, DatetimePicker, Field, Popup, Stepper } from 'vant'
|
|
|
-import { defineComponent, ref } from 'vue'
|
|
|
+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,
|
|
@@ -12,106 +29,440 @@ const fieldProps = {
|
|
|
export default defineComponent({
|
|
|
name: 'ClassArrangement',
|
|
|
setup() {
|
|
|
- const dateShow = ref<boolean>(false)
|
|
|
- const setDate = (time: Date) => {
|
|
|
- console.log(time)
|
|
|
- dateShow.value = false
|
|
|
+ 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 subjectList = ref<[]>([]) // 声部分类
|
|
|
const getSubjectSelect = async () => {
|
|
|
try {
|
|
|
const res = await request.get('/api-teacher/subject/subjectSelect')
|
|
|
- // this.subjectList = res.data || []
|
|
|
+ subjectList.value = res.data || []
|
|
|
} catch {}
|
|
|
}
|
|
|
+ onMounted(() => {
|
|
|
+ getSubjectSelect()
|
|
|
+ })
|
|
|
+
|
|
|
+ //开始时间
|
|
|
+ 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 (!students.value.length) {
|
|
|
+ Toast('请选择上课学员')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!params.singleClssTime) {
|
|
|
+ Toast('请填写单课时时长')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!params.date) {
|
|
|
+ Toast('请选择开始日期')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!params.week) {
|
|
|
+ Toast('请选择循环周次')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!startTime.value) {
|
|
|
+ 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(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
|
|
|
+ }
|
|
|
+ } catch (error) {}
|
|
|
+
|
|
|
+ }
|
|
|
+ const week = {
|
|
|
+ 周一: 1,
|
|
|
+ 周二: 2,
|
|
|
+ 周三: 3,
|
|
|
+ 周四: 4,
|
|
|
+ 周五: 5,
|
|
|
+ 周六: 6,
|
|
|
+ 周日: 0
|
|
|
+ }
|
|
|
+ // console.log(Object.values(week))
|
|
|
return () => (
|
|
|
- <div class={styles.container}>
|
|
|
- <Field label="课程名称" placeholder="请输入课程名称" />
|
|
|
- <Field label="训练声部" placeholder="请选择训练声部" {...fieldProps} />
|
|
|
- <Field label="上课学员" placeholder="请选择上课学员" {...fieldProps} />
|
|
|
- <Field
|
|
|
- label="课时数"
|
|
|
- placeholder="请输入课时数"
|
|
|
- v-slots={{
|
|
|
- input: () => <Stepper></Stepper>
|
|
|
- }}
|
|
|
- />
|
|
|
- {/* <Field label="单课时时长" placeholder="请输入课程时长" /> */}
|
|
|
- <Field
|
|
|
- label="开始日期"
|
|
|
- placeholder="请选择开始日期"
|
|
|
- {...fieldProps}
|
|
|
- onClick={() => (dateShow.value = true)}
|
|
|
- />
|
|
|
- <Cell title="循环周次" />
|
|
|
- <Field label="开始时间" placeholder="请选择开始时间" {...fieldProps} />
|
|
|
- <Cell title="是否跳过节假日" />
|
|
|
- <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、琴房时长不足时,您将无法排课,请确保琴房剩余时长充足。
|
|
|
+ <>
|
|
|
+ <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
|
|
|
+ }
|
|
|
+ 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' }}
|
|
|
- >
|
|
|
- 下一步
|
|
|
- </Button>
|
|
|
+ <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={new Date()}
|
|
|
+ minDate={dayjs().year(2022).toDate()}
|
|
|
formatter={formatterDate}
|
|
|
- onConfirm={setDate}
|
|
|
+ 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
|
|
|
- show={this.searchStatus}
|
|
|
+ <Popup
|
|
|
+ v-model:show={voiceShow.value}
|
|
|
position="bottom"
|
|
|
round
|
|
|
closeable
|
|
|
safe-area-inset-bottom
|
|
|
>
|
|
|
- {this.openStatus && (
|
|
|
- <OrganSearch
|
|
|
- subjectList={this.subjectList}
|
|
|
- onSort={this.onSort}
|
|
|
- isReset
|
|
|
- v-model={this.params.subjectId}
|
|
|
- v-model:subjectName={this.params.subjectName}
|
|
|
+ <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"
|
|
|
+ maxHour="22"
|
|
|
+ onConfirm={() => {
|
|
|
+ timeShow.value = false
|
|
|
+ console.log(startTime.value)
|
|
|
+ }}
|
|
|
+ onCancel={() => (timeShow.value = false)}
|
|
|
/>
|
|
|
- )}
|
|
|
- </Popup> */}
|
|
|
- </div>
|
|
|
+ </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>
|
|
|
+ </>
|
|
|
)
|
|
|
}
|
|
|
})
|