mo 3 vuotta sitten
vanhempi
commit
136d622673

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
dist/app.0d786a2d02851567a375.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 0
dist/index.html


+ 1 - 1
public/index.html

@@ -19,7 +19,7 @@
     <title>管乐迷</title>
     <!-- <script type="text/javascript" src="http://webapi.amap.com/maps?v=1.4.4&key=c7856e7c812d299cff150e74d60ea608"></script> -->
     <style>html{color:#000;overflow-y:scroll;overflow-x:hidden;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;font-size:100px;-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch}.link,.link:hover,.link:visited,a{color:#333}body,html{font-family:"PingFang SC","Heiti SC","SF UI Text","Helvetica Neue",Roboto,"Droid Sans Fallback",arial,sans-serif;font-weight:normal}body{font-size:.12rem;line-height:1.5}*{margin:0;padding:0;outline:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:transparent}input,select,textarea{font-size:100%}table{border-collapse:collapse;border-spacing:0}img{border:0}del{text-decoration:line-through}.link:active,a{text-decoration:none}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-weight:500}h1{font-size:.36rem}h2{font-size:.28rem}h3{font-size:.24rem}h4{font-size:.2rem;line-height:.26rem}h5{font-size:.18rem;line-height:.24rem}h6{font-size:.16rem;line-height:.2rem}q:after,q:before{content:''}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}.link:active{color:#e61414}ins,u{text-decoration:underline;text-decoration-color:#eee}</style>
-    <script>!function(e,t){var n=t.documentElement,d=e.devicePixelRatio||1;function i(){var e=n.clientWidth/3.75;n.style.fontSize=e+"px"}if(function e(){t.body?t.body.style.fontSize="16px":t.addEventListener("DOMContentLoaded",e)}(),i(),e.addEventListener("resize",i),e.addEventListener("pageshow",function(e){e.persisted&&i()}),2<=d){var o=t.createElement("body"),a=t.createElement("div");a.style.border=".5px solid transparent",o.appendChild(a),n.appendChild(o),1===a.offsetHeight&&n.classList.add("hairlines"),n.removeChild(o)}}(window,document)</script>
+    <script>!function(e,t){var n=t.documentElement,d=e.devicePixelRatio||1;function i(){var e=n.clientWidth/3.75; e=e>110?110:e;n.style.fontSize=e+"px"}if(function e(){t.body?t.body.style.fontSize="16px":t.addEventListener("DOMContentLoaded",e)}(),i(),e.addEventListener("resize",i),e.addEventListener("pageshow",function(e){e.persisted&&i()}),2<=d){var o=t.createElement("body"),a=t.createElement("div");a.style.border=".5px solid transparent",o.appendChild(a),n.appendChild(o),1===a.offsetHeight&&n.classList.add("hairlines"),n.removeChild(o)}}(window,document)</script>
   </head>
   <body>
     <style>

+ 40 - 2
src/api/teacher.js

@@ -393,6 +393,15 @@ const queryStudentsWithTeacher = (data) => {
   })
 }
 
+// 获取当前老师主分部学生列表
+const queryStudentsWithTeacherByOrganId = (data) => {
+  return axios({
+    url: '/api-teacher/teacherVipGroup/queryStudentsWithTeacherByOrganId',
+    method: 'get',
+    params: data
+  })
+}
+
 // 获取双十一学生列表
 const queryDouble11Students = (data) => {
   return axios({
@@ -471,6 +480,31 @@ const queryUserById = (params) => {
   })
 }
 
+const queryPracticeGroupSellPrice = (params) => {
+  return axios({
+    url: '/api-teacher/teacherPracticeGroup/queryPracticeGroupSellPrice',
+    method: 'get',
+    params
+  })
+}
+
+const getPracticeGroupCostCount = (params) => {
+  return axios({
+    url: '/api-teacher/teacherPracticeGroup/getPracticeGroupCostCount',
+    method: 'get',
+    params
+  })
+}
+
+// vip课申请
+const practiceGroupApply = (data) => {
+  return axios({
+    url: api + '/teacherPracticeGroup/practiceGroupApply',
+    method: 'post',
+    data: data
+  })
+}
+
 export {
   queryMyCreatedList,
   queryWaitList,
@@ -523,5 +557,9 @@ export {
   newsQuery,
   newsList,
   getCourseStudents,
-  queryUserById
-}
+  queryUserById,
+  queryPracticeGroupSellPrice,
+  practiceGroupApply,
+  getPracticeGroupCostCount,
+  queryStudentsWithTeacherByOrganId
+}

+ 5 - 0
src/assets/commonLess/common.less

@@ -166,4 +166,9 @@ textarea:-ms-input-placeholder {
 }
 .HIGH_ONLINE {
   background: @color15;
+}
+
+.img-icon {
+  width: 20px;
+  height: 20px;
 }

+ 2 - 22
src/common/vueFilters.js

@@ -1,4 +1,5 @@
 import Vue from 'vue'
+import * as constant from '../constant'
 
 // 乐团状态
 Vue.filter('bandStatus', value => {
@@ -13,28 +14,7 @@ Vue.filter('bandStatus', value => {
 })
 
 // 课程类型
-Vue.filter('coursesType', (value) => {
-    let template = {
-      NORMAL: '声部课',
-      SINGLE: '声部课',
-      MIX: "合奏课",
-      HIGH: "基础技能课",
-      VIP: "VIP课",
-      DEMO: "试听课",
-      COMPREHENSIVE: '综合课',
-      ENLIGHTENMENT: '启蒙课',
-      TRAINING: '集训课',
-      TRAINING_SINGLE: '集训声部课',
-      TRAINING_MIX: '集训合奏课',
-      CLASSROOM: '课堂课',
-      PRACTICE: '网管课',
-      COMM: '对外课',
-      MUSIC: '乐团课',
-      HIGH_ONLINE: '线上基础技能课',
-      MUSIC_NETWORK: '乐团网管课'
-    }
-    return template[value]
-  })
+Vue.filter('coursesType', val => constant.courseType[val])
 
 // 合并数组
 Vue.filter('joinArray', (value, type) => {

+ 19 - 0
src/constant/index.js

@@ -0,0 +1,19 @@
+export const courseType = {
+  NORMAL: '声部课',
+  SINGLE: '声部课',
+  MIX: "合奏课",
+  HIGH: "基础技能课",
+  VIP: "VIP课",
+  DEMO: "试听课",
+  COMPREHENSIVE: '综合课',
+  ENLIGHTENMENT: '启蒙课',
+  TRAINING: '集训课',
+  TRAINING_SINGLE: '集训声部课',
+  TRAINING_MIX: '集训合奏课',
+  CLASSROOM: '课堂课',
+  PRACTICE: '网管课',
+  COMM: '对外课',
+  MUSIC: '乐团课',
+  HIGH_ONLINE: '线上基础技能课',
+  MUSIC_NETWORK: '乐团网管课'
+}

+ 9 - 0
src/main.js

@@ -24,6 +24,15 @@ Vue.config.productionTip = false
 
 // import Vconsole from 'vconsole'
 // const vconsole = new Vconsole()
+// 将selects全局混入当前vue实例中
+Vue.mixin({
+    data() {
+      return {
+        activeButtonIcon: require('@/assets/images/common/icon_check.png'),
+        inactiveButtonIcon: require('@/assets/images/common/icon_default.png'),
+      }
+    }
+})
 
 import VueAMap from 'vue-amap'
 Vue.use(VueAMap)

+ 24 - 0
src/router/teacherRouter.js

@@ -290,6 +290,30 @@ let teacherRouter = [
         descrition: '评测详情',
         weight: 3 // 页面权重
     }
+  }, {
+    path: '/activeProgram',
+    name: 'activeProgram',
+    component: () => import(/* webpackChunkName:'activeProgram'*/'@/views/activeProgram/index.vue'),
+    meta: {
+        descrition: '活动方案',
+        weight: 3 // 页面权重
+    }
+  }, {
+    path: '/activeDetail',
+    name: 'activeDetail',
+    component: () => import(/* webpackChunkName:'activeDetail'*/'@/views/activeProgram/activeDetail.vue'),
+    meta: {
+        descrition: '活动详情',
+        weight: 3 // 页面权重
+    }
+  }, {
+    path: '/program',
+    name: 'program',
+    component: () => import(/* webpackChunkName:'program'*/'@/views/activeProgram/program.vue'),
+    meta: {
+        descrition: '活动详情',
+        weight: 3 // 页面权重
+    }
   }
 ];
 

+ 207 - 0
src/views/activeProgram/activeDetail.vue

@@ -0,0 +1,207 @@
+<template>
+    <div class="activeDetail">
+        <van-cell-group class="van-cell-group--inset" v-if="vipGroup.name">
+            <van-cell :title="vipGroup.name" class="titleContent" title-class="titleStyle" label-class="labelStyle">
+                <template #label>
+                    <p>{{ vipGroup.description }}</p>
+                </template>
+            </van-cell>
+        </van-cell-group>
+
+        <h2 class="van-block__title">详细规则</h2>
+        <van-row class="active-row">
+            <van-col span="10">排课时间范围</van-col>
+            <van-col span="14" v-if="vipGroup.coursesStartTime && vipGroup.coursesEndTime">{{ vipGroup.coursesStartTime }} 至 {{ vipGroup.coursesEndTime }}</van-col>
+            <van-col span="14" v-else>--</van-col>
+            <van-col span="10">是否扣减课程余额</van-col>
+            <van-col span="14">{{ vipGroup.payToBalance ? '是' : '否' }}</van-col>
+        </van-row>
+
+        <h2 class="van-block__title">付费课程</h2>
+        <div class="active-row">
+            <van-row>
+                <van-col span="8">课程类型</van-col>
+                <van-col span="16">{{ vipGroup.courseType | coursesType }}&nbsp;</van-col>
+                <van-col span="8" v-if="vipGroup.courseType == 'VIP'">课程形式</van-col>
+                <van-col span="16" v-if="vipGroup.courseType == 'VIP'">{{ vipGroup.vipGroupCategoryNames }}&nbsp;</van-col>
+                <van-col span="8">上课模式</van-col>
+                <van-col span="16" v-if="vipGroup.giveCourseType == 'PRACTICE'">线上&nbsp;</van-col>
+                <van-col span="16" v-else>{{ vipGroup.giveTeachMode | formatTeachModel }}&nbsp;</van-col>
+                <van-col span="8">单课时时长</van-col>
+                <van-col span="16">{{ vipGroup.singleCourseTime }}分钟</van-col>
+                <van-col span="8">课时数</van-col>
+                <van-col span="16">{{ vipGroup.avgCourseNum }}&nbsp;</van-col>
+            </van-row>
+            <van-cell is-link class="teaching" :clickable="false">
+                <template #title>
+                    剩余 <span style="color: #01C1B5">
+                        {{vipGroup.courseType == 'VIP' ? vipDetail.vipNum : null}}
+                        {{vipGroup.courseType == 'PRACTICE' ? vipDetail.practiceNum : null}}
+                    </span> 名学员未排课
+                </template>
+                <template #default>
+                    <span  v-if="vipGroup.courseType == 'VIP' && vipDetail.vipNum || vipGroup.courseType == 'PRACTICE' && vipDetail.practiceNum" style="color: #01C1B5" @click="onProgram('pay')">立即排课</span>
+                    <span v-else style="color: #c0c0c0">立即排课</span>
+                </template>
+            </van-cell>
+        </div>
+
+        <!-- 赠送课程类型,只有VIP和网管课的时候才有赠送课程 -->
+        <template v-if="vipGroup.giveCourseType != 'MEMBER'">
+            <h2 class="van-block__title">赠送课程</h2>
+            <div class="active-row">
+                <van-row>
+                    <van-col span="8">课程类型</van-col>
+                    <van-col span="16">{{ vipGroup.giveCourseType | coursesType }}&nbsp;</van-col>
+                    <van-col span="8" v-if="vipGroup.giveCourseType == 'VIP'">课程形式</van-col>
+                    <van-col span="16" v-if="vipGroup.giveCourseType == 'VIP'">{{ vipGroup.giveCategoryName }}&nbsp;</van-col>
+                    <van-col span="8">上课模式</van-col>
+                    <van-col span="16" v-if="vipGroup.giveCourseType == 'PRACTICE'">线上&nbsp;</van-col>
+                    <van-col span="16" v-else>{{ vipGroup.giveTeachMode | formatTeachModel }}&nbsp;</van-col>
+                    <van-col span="8">单课时时长</van-col>
+                    <van-col span="16">{{ vipGroup.giveSingleCourseTime }}分钟</van-col>
+                    <van-col span="8">课时数</van-col>
+                    <van-col span="16">{{ vipGroup.giveCourseNum }}课时</van-col>
+                </van-row>
+                <van-cell is-link class="teaching" :clickable="false">
+                    <template #title>
+                        剩余 <span style="color: #01C1B5">
+                            {{vipGroup.giveCourseType == 'VIP' ? vipDetail.giveVipNum : null}}
+                            {{vipGroup.giveCourseType == 'PRACTICE' ? vipDetail.givePracticeNum : null}}
+                        </span> 名学员未排课
+                    </template>
+                    <template #default>
+                        <span v-if="vipGroup.giveCourseType == 'VIP' && vipDetail.giveVipNum || vipGroup.giveCourseType == 'PRACTICE' && vipDetail.givePracticeNum" style="color: #01C1B5" @click="onProgram('give')">立即排课</span>
+                        <span v-else style="color: #c0c0c0">立即排课</span>
+                    </template>
+                </van-cell>
+            </div>
+        </template>
+
+        <!-- <m-empty v-if="!vipDetail.giveVipNum && !vipDetail.givePracticeNum && !vipDetail.vipNum && !vipDetail.practiceNum" msg="暂无排课内容" /> -->
+    </div>
+</template>
+
+<script>
+import { getActivityWaitCourseStudentNum } from './api'
+import MEmpty from '@/components/MEmpty'
+import dayjs from 'dayjs'
+export default {
+    components: {
+        MEmpty
+    },
+    data() {
+        const query = this.$route.query
+        return {
+            activityId: query.activityId,
+            vipDetail: {},
+            vipGroup: {}
+        }
+    },
+    mounted() {
+        document.title = '活动详情'
+        this.__init()
+    },
+    methods: {
+        async __init() {
+            try {
+                let res = await getActivityWaitCourseStudentNum({ activityId: this.activityId })
+                this.vipDetail = res.data
+                let vipGroup = res.data.vipGroupActivity
+                vipGroup.coursesStartTime = vipGroup.coursesStartTime ? dayjs(vipGroup.coursesStartTime).format('YYYY-MM-DD') : null
+                vipGroup.coursesEndTime = vipGroup.coursesEndTime ? dayjs(vipGroup.coursesEndTime).format('YYYY-MM-DD') : null
+                if(vipGroup.minCourseNum > 0) {
+                    if(vipGroup.minCourseNum != vipGroup.maxCourseNum) {
+                        vipGroup.avgCourseNum = vipGroup.minCourseNum + '课时 ~ ' + vipGroup.maxCourseNum + '课时'
+                    } else {
+                        vipGroup.avgCourseNum = vipGroup.maxCourseNum + '课时'
+                    }
+                } else {
+                    vipGroup.avgCourseNum = '自定义'
+                }
+                this.vipGroup = vipGroup
+            } catch {
+                //
+            }
+        },
+        onProgram(type) {
+            // type pay 付费课 give 赠送课
+            this.$router.push({
+                path: '/program',
+                query: {
+                    activityId: this.activityId,
+                    type: type
+                }
+            })
+        }
+    },
+    filters: {
+        formatTeachModel(val) {
+            if(val === -1) {
+                return '线上,线下'
+            } else if(val === 0) {
+                return '线上'
+            } else if(val === 1) {
+                return '线下'
+            }
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.activeDetail {
+    background-color: #F5F5F5;
+    min-height: 97vh;
+    overflow: hidden;
+    padding-bottom: 3vh;
+}
+.van-cell-group--inset {
+    margin: .12rem .12rem 0;
+    overflow: hidden;
+    border-radius: 8px;
+    .titleContent {
+        padding: .14rem .16rem;
+    }
+    .titleStyle {
+        font-size: .2rem;
+        color: #333333;
+        font-size: 500;
+    }
+    .labelStyle {
+        padding-top: .08rem;
+        color: #666666;
+        font-size: .13rem;
+        line-height: .2rem;
+    }
+}
+.van-block__title {
+    padding: .12rem .14rem .06rem;
+    color: #808080;
+    font-size: .14rem;
+    line-height: .2rem;
+}
+.active-row {
+    padding: .15rem .14rem;
+    background: #FFF;
+    font-size: .14rem;
+    color: #1A1A1A;
+    .van-col {
+        border: 1px solid #E5E5E5;
+        padding: .09rem .08rem;
+        margin-bottom: -1px;
+    }
+    .van-col--8, .van-col--10 {
+        margin-right: -1px;
+        padding-left: .14rem;
+        background: #F8F8F8;
+        font-weight: 500;
+    }
+    .teaching {
+        margin-top: .2rem;
+        padding: 0;
+        font-size: .16rem;
+        color: #1A1A1A;
+    }
+}
+</style>

+ 40 - 0
src/views/activeProgram/api.js

@@ -0,0 +1,40 @@
+import request from '@/helpers/request'
+
+export const queryWaitCourseActivity = (data) => {
+    return request({
+        url: '/vipGroupActivity/queryWaitCourseActivity',
+        method: 'get',
+        params: data
+    })
+}
+
+export const getActivityWaitCourseStudentNum = (data) => {
+    return request({
+        url: '/vipGroupActivity/getActivityWaitCourseStudentNum',
+        method: 'get',
+        params: data
+    })
+}
+
+export const getActivityStudentCanCourseNum = (data) => {
+    return request({
+        url: '/vipGroupActivity/getActivityStudentCanCourseNum',
+        method: 'get',
+        params: data
+    })
+}
+
+export const createVipGroup = (data) => {
+    return request({
+        url: '/teacherVipGroup/createVipGroup',
+        method: 'post',
+        data
+    })
+}
+export const createPracticeGroup = (data) => {
+    return request({
+        url: '/teacherPracticeGroup/createPracticeGroup',
+        method: 'post',
+        data
+    })
+}

+ 86 - 0
src/views/activeProgram/index.vue

@@ -0,0 +1,86 @@
+<template>
+    <div class="activeProgram">
+        <van-cell-group :border="false" v-if="dataShow">
+            <van-cell v-for="(item, index) in dataList" :key="index"
+                :title="item.activityName"
+                title-class="titleStyle"
+                :value="item.studentNum"
+                value-class="valueStyle"
+                class="activeItem" is-link
+                @click="onDetail(item)" />
+        </van-cell-group>
+        <m-empty class="empty" msg="暂无活动方案" v-else key="data" />
+    </div>
+</template>
+
+<script>
+import MEmpty from "@/components/MEmpty";
+import { queryWaitCourseActivity } from './api'
+export default {
+    name: 'activeProgram',
+    components: {
+        MEmpty
+    },
+    data() {
+        return {
+            dataShow: true, // 是否有数据
+            dataList: [],
+        }
+    },
+    mounted() {
+        let params = this.$route.query;
+        if (params.Authorization) {
+            localStorage.setItem("Authorization", decodeURI(params.Authorization));
+            localStorage.setItem("userInfo", decodeURI(params.Authorization));
+        }
+        document.title = '活动方案'
+        this.getActiveList()
+    },
+    methods: {
+        async getActiveList() {
+            try {
+                const res = await queryWaitCourseActivity()
+                this.dataList = [...res.data]
+                if(this.dataList.length <= 0) {
+                    this.dataShow = false
+                }
+            } catch {
+                //
+            }
+        },
+        onDetail(item) {
+            this.$router.push({
+                path: '/activeDetail',
+                query: {
+                    activityId: item.activityId
+                }
+            })
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.activeProgram {
+    background-color: #F5F5F5;
+    min-height: 100vh;
+    overflow: hidden;
+}
+.activeItem {
+    padding: .14rem 16px;
+    font-size: .16rem;
+    line-height: .24rem;
+    .titleStyle {
+        color: #1A1A1A;
+        flex: 0 auto;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+    }
+    .valueStyle {
+        color: #01C1B5;
+        font-weight: 500;
+        flex-basis: 20%;
+    }
+}
+</style>

+ 147 - 0
src/views/activeProgram/modal/course.vue

@@ -0,0 +1,147 @@
+<template>
+    <van-picker
+        :columns="columns"
+        show-toolbar
+        @cancel="$listeners.close()"
+        @confirm="onTeachingConfirm"
+    />
+</template>
+
+<script>
+let minutes = []; // 分钟数
+for (let i = 0; i < 60; i++) {
+    let mi = i < 10 ? "0" + i : i;
+    minutes.push(mi + "分");
+}
+export default {
+    props: ['scheduleList', 'singleClassMinutes'],
+    data() {
+        return {
+            // 排课弹窗
+            columns: [{
+                // 课程选项
+                values: ["线上", "线下"],
+                className: "type",
+            }, {
+                values: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
+                className: "week",
+            }, {
+                values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
+                className: "hours",
+                defaultIndex: 7,
+            }, {
+                values: minutes,
+                className: "minutes",
+            }],
+        }
+    },
+    methods: {
+        onTeachingConfirm(value) {
+            // 添加课程
+            let scheduleList = this.scheduleList;
+            let startTime =
+                (value[2] >= 10 ? value[2] : "0" + value[2]) +
+                ":" +
+                value[3].split("分")[0];
+            let endTime = this.MinutesTest(
+                value[2],
+                value[3],
+                this.singleClassMinutes
+            );
+
+            let isAdd = true;
+            scheduleList.forEach((item) => {
+                let isStartTime = this.timeIsRange(startTime, endTime, item.startTime);
+                let isEndTime = this.timeIsRange(startTime, endTime, item.endTime);
+                if (isAdd) {
+                    if (value[1] == item.weekStr) {
+                        if (isStartTime || isEndTime) {
+                            isAdd = false;
+                        } else {
+                            isAdd = true;
+                        }
+                    } else if (value[1] != item.weekStr) {
+                        isAdd = true;
+                    }
+                }
+            });
+
+            if (isAdd) {
+                // 判断时间范围是否有重复
+                scheduleList.push({
+                    type: value[0], // 线上还是线下
+                    weekStr: value[1],
+                    weekIndex: this.getWeek(value[1]),
+                    startTime: startTime,
+                    endTime: endTime,
+                    id: Date.now(),
+                });
+
+                // this.courseForm.teachingStatus = false;
+                this.$listeners.close()
+
+                // this.setTimeTable();
+            } else {
+                this.$toast("该时间段已排课请重选时间");
+                return;
+            }
+        },
+        // 分钟小时相加减
+        MinutesTest(hour, mins, interval) {
+            let min = mins.split("分")[0];
+            let sDate1 = new Date(1900, 1, 1, hour, min);
+            sDate1.setMinutes(sDate1.getMinutes() + parseInt(interval));
+            let H = sDate1.getHours();
+            let M = sDate1.getMinutes();
+            if (H < 10) H = "0" + H;
+            if (M < 10) M = "0" + M;
+            return H + ":" + M;
+        },
+        // 判断时间是否在时间段内
+        timeIsRange(beginTime, endTime, nowTime) {
+            var strB = beginTime.split(":");
+            if (strB.length != 2) {
+                return false;
+            }
+            var strE = endTime.split(":");
+            if (strE.length != 2) {
+                return false;
+            }
+            var strN = nowTime.split(":");
+            if (strE.length != 2) {
+                return false;
+            }
+            var b = new Date();
+            var e = new Date();
+            var n = new Date();
+            b.setHours(strB[0]);
+            b.setMinutes(strB[1]);
+            e.setHours(strE[0]);
+            e.setMinutes(strE[1]);
+            n.setHours(strN[0]);
+            n.setMinutes(strN[1]);
+
+            if (n.getTime() - b.getTime() >= 0 && n.getTime() - e.getTime() <= 0) {
+                // 在时间范围内
+                return true;
+            } else {
+                // 不在时间范围内
+                return false;
+            }
+        },
+        getWeek(str) {
+            // 获取周几索引值
+            let template = {
+                '周一': 1,
+                '周二': 2,
+                '周三': 3,
+                '周四': 4,
+                '周五': 5,
+                '周六': 6,
+                '周日': 0,
+            };
+            return template[str];
+        },
+    }
+}
+</script>

+ 260 - 0
src/views/activeProgram/modal/studentList.vue

@@ -0,0 +1,260 @@
+<template>
+    <div>
+        <!-- <van-sticky>
+            <van-search
+            show-action
+            shape="round"
+            @search="onSearch"
+            v-model="params.search"
+            placeholder="请输入学生名或手机号"
+            >
+            <template #action>
+                <div @click="onSearch">搜索</div>
+            </template>
+            </van-search>
+        </van-sticky> -->
+        <div class="paddingB80">
+            <!-- <van-list
+                v-model="loading"
+                class="studentContainer"
+                v-if="dataShow"
+                key="data"
+                :finished="finished"
+                finished-text=""
+                @load="getStudent"
+            > -->
+            <div class="studentContainer" v-if="dataShow" key="data">
+                <van-checkbox-group v-model="checkboxSelect">
+                    <van-cell-group :border="false">
+                        <van-cell
+                            v-for="(item, index) in dataList"
+                            :key="index"
+                            @click="onCheckboxSelect(item)"
+                            class="input-cell"
+                            value-class="value-times"
+                            :center="true"
+                        >
+                            <template slot="icon">
+                                <img
+                                    class="logo"
+                                    v-if="item.avatar"
+                                    :src="item.avatar"
+                                    alt=""
+                                />
+                                <img
+                                    class="logo"
+                                    v-else
+                                    src="@/assets/images/icon_student.png"
+                                    alt=""
+                                />
+                            </template>
+                            <template slot="title">
+                                {{ item.username }}
+                            </template>
+                            <template slot="default">
+                                <span style="font-size: .16rem;color: #1A1A1A;">可排课次数:<span style="color: #01C1B5;">{{ item.showStudentNum }}</span></span>
+                            </template>
+                            <template slot="extra">
+                                <van-checkbox :name="item.userId">
+                                    <template #icon="props">
+                                        <img v-if="!item.radioDisabled" class="img-icon" :src="props.checked ? activeButtonIcon : inactiveButtonIcon" />
+                                    </template>
+                                </van-checkbox>
+                            </template>
+                        </van-cell>
+                    </van-cell-group>
+                </van-checkbox-group>
+            </div>
+            <!-- </van-list> -->
+            <m-empty class="empty" msg="暂无学生" v-else key="data" />
+        </div>
+        <div class="button-group-popup">
+            <span class="btn" @click="onPopupCancel">取消</span>
+            <span class="btn primary" @click="onPopupSubmit">确定</span>
+        </div>
+    </div>
+</template>
+
+<script>
+import MEmpty from "@/components/MEmpty";
+import { getActivityStudentCanCourseNum } from '../api'
+export default {
+    components: {
+        MEmpty
+    },
+    // courseTypeIsVip 当前排课的类型,可能是赠送课程
+    props: ['studentList', 'activityId', 'courseTypeIsVip', 'typeStatus', 'studentNum', 'isMusicTheory'],
+    data() {
+        return {
+            params: {
+                search: null,
+                activityId: this.activityId
+            },
+            dataShow: true, // 是否有数据
+            dataList: [],
+            checkboxSelect: [],
+        }
+    },
+    watch: {
+        studentList(newVal) {
+            if(newVal) {
+                let tempVal = newVal || []
+                this.checkboxSelect = []
+                tempVal.forEach(item => {
+                    this.checkboxSelect.push(item.userId)
+                })
+            }
+        }
+    },
+    mounted() {
+        this.getStudent()
+    },
+    methods: {
+        // 搜索
+        // onSearch() {
+        //     this.dataList = [];
+        //     this.getStudent();
+        // },
+        async getStudent() {
+            let params = this.params;
+            try {
+                const res = await getActivityStudentCanCourseNum(params)
+                let result = res.data || []
+                let showResult = []
+                result.forEach(item => {
+                    let showStudentNum = 0
+                    if (this.typeStatus) {
+                        showStudentNum = this.courseTypeIsVip ? item.vipNum : item.practiceNum
+                    } else {
+                        showStudentNum = this.courseTypeIsVip ? item.giveVipNum : item.givePracticeNum
+                    }
+                    item.showStudentNum = showStudentNum
+                    // 判断次数大于0的学生展示
+                    if(showStudentNum > 0) {
+                        showResult.push(item)
+                    }
+                })
+                this.dataList = showResult
+                if(showResult.length > 0) {
+                    this.dataShow = true
+                } else {
+                    this.dataShow = false
+                }
+            } catch {
+                //
+            }
+        },
+        onCheckboxSelect(value) {
+            if (this.checkboxSelect.includes(value.userId)) {
+                this.checkboxSelect.forEach((item, index) => {
+                    if(item === value.userId) {
+                        this.checkboxSelect.splice(index, 1)
+                    }
+                })
+            } else {
+                this.checkboxSelect.push(value.userId)
+            }
+        },
+        onPopupCancel() {
+            this.$listeners.close()
+        },
+        onPopupSubmit() {
+            if (this.isMusicTheory) {
+                if (!(this.checkboxSelect.length >= 1 && this.checkboxSelect.length <= this.studentNum)) {
+                    this.$toast(`请选择1-${this.studentNum}名学生,当前选择${this.checkboxSelect.length}名`);
+                    return;
+                }
+            } else {
+                if (this.checkboxSelect.length != this.studentNum) {
+                    this.$toast(`请选择学生${this.studentNum}名,当前选择${this.checkboxSelect.length}名`);
+                    return;
+                }
+            }
+            let dataList = this.dataList || []
+            let checkList = []
+            dataList.forEach(item => {
+                if(this.checkboxSelect.includes(item.userId)) {
+                    checkList.push(item)
+                }
+            })
+            this.$emit('submit', checkList)
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+@import url("../../../assets/commonLess/variable.less");
+.studentContainer {
+    padding-top: .1rem;
+    background-color: #fff;
+    /deep/.van-cell__title {
+        font-size: 0.16rem;
+        color: @mFontColor;
+        // flex: 1 auto;
+    }
+
+    .logo {
+        width: 0.35rem;
+        height: 0.35rem;
+        margin-right: 0.12rem;
+        border-radius: 100%;
+    }
+
+    .input-cell {
+        padding: 0.12rem 0.16rem 0.2rem;
+
+        .van-checkbox {
+            justify-content: flex-end;
+        }
+    }
+
+    /deep/.van-cell__value {
+        height: 0.2rem;
+    }
+
+    /deep/.van-checkbox__icon .van-icon {
+        border-color: @sFontColor;
+    }
+    /deep/.van-checkbox__icon--checked .van-icon {
+        border-color: #01C1B5;
+    }
+
+    .van-tag {
+        margin-left: 0.08rem;
+    }
+}
+.value-times {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+.paddingB80 {
+    padding-bottom: 0.8rem;
+}
+.button-group-popup {
+    position: fixed;
+    bottom: 0;
+    padding: 0.2rem 0;
+    width: 100%;
+    text-align: center;
+    background-color: #ffffff;
+    .btn {
+        padding: 0 0.45rem;
+        line-height: 0.4rem;
+        display: inline-block;
+        border: 1px solid @mColor;
+        border-radius: 1rem;
+        color: @mColor;
+        background: #fff;
+        font-size: 0.18rem;
+        &.primary {
+        color: #fff;
+        background: @mColor;
+        }
+    }
+    .btn + .btn {
+        margin-left: 0.1rem;
+    }
+}
+</style>

+ 1028 - 0
src/views/activeProgram/program.vue

@@ -0,0 +1,1028 @@
+<template>
+    <div class="program">
+        <van-cell-group class="van-cell-group--inset">
+            <van-cell :title="vipGroup.name" class="titleContent" title-class="titleStyle" label-class="labelStyle">
+                <template #label>
+                    <p>{{ vipGroup.description }}</p>
+                    <!-- <p>排课时间范围:{{ vipGroup.coursesStartTime }} 至 {{ vipGroup.coursesEndTime }}</p> -->
+                </template>
+            </van-cell>
+        </van-cell-group>
+
+        <h2 class="van-block__title">{{ typeStatus ? '付费' : '赠送' }}课程排课</h2>
+        <van-cell-group>
+            <van-field
+                :value="typeStatus ? courseType[vipGroup.courseType] : courseType[vipGroup.giveCourseType]"
+                label="课程类型"
+                :readonly="true"
+                input-align="right"
+                size="large"
+                placeholder="请选择"
+            />
+            <van-field
+                :value="typeStatus ? vipGroup.vipGroupCategoryNames : vipGroup.giveCategoryName"
+                label="课程形式"
+                v-if="courseTypeIsVip"
+                :readonly="true"
+                input-align="right"
+                size="large"
+                placeholder="请选择"
+            />
+            <van-field
+                v-model="formName.subjectListName"
+                @click="onGetSheetList('subjectList')"
+                label="排课声部"
+                :readonly="true"
+                input-align="right"
+                is-link
+                size="large"
+                placeholder="请选择"
+            />
+            <van-field
+                v-model="formName.educationalTeacherName"
+                @click="onGetSheetList('teacherList')"
+                label="乐团主管"
+                :readonly="true"
+                input-align="right"
+                is-link
+                size="large"
+                placeholder="请选择"
+            />
+        </van-cell-group>
+
+        <template v-if="studentList.length > 0">
+            <h2 class="van-block__title">上课学员</h2>
+            <van-cell-group>
+                <van-cell title-style="flex: 1 auto; color: #1A1A1A;" size="large" v-for="(item, index) in studentList" :key="index">
+                    <template #title>
+                        {{ item.username }} - {{ item.phone }}
+                    </template>
+                    <template #default>
+                        <span @click="onDelete('student', item)"><van-icon name="delete-o" size=".14rem" /> <span style="font-size: .12rem;">删除</span></span>
+                    </template>
+                </van-cell>
+            </van-cell-group>
+        </template>
+        <div class="addButton" @click="studentStatus = true">
+            <van-icon name="plus" /> 添加学员
+        </div>
+
+        <h2 class="van-block__title">课时组成</h2>
+        <van-cell-group>
+            <van-field
+                v-if="statusList.hasOnline && teachMode == -1"
+                v-model="form.onlineClassesNums"
+                @keyup="onClassKeyUp"
+                label="线上课次数"
+                input-align="right"
+                size="large"
+                placeholder="请输入次数"
+                type="number"
+            />
+            <van-field
+                v-if="statusList.hasOffline && teachMode == -1"
+                v-model="form.offlineClassesNums"
+                @keyup="onClassKeyUp('offLine')"
+                label="线下课次数"
+                input-align="right"
+                size="large"
+                placeholder="请输入次数"
+                type="number"
+            />
+            <van-field
+                v-if="tempOfflineNum > 0"
+                v-model="formName.teacherSchoolName"
+                @click="onGetSheetList('teacherSchool')"
+                label="线下课地址"
+                :readonly="true"
+                input-align="right"
+                is-link
+                size="large"
+                placeholder="请选择"
+            />
+            <!-- 不影响判断逻辑 -->
+            <van-field
+                v-if="isMusicTheory"
+                :value="'1-' + (form.studentNum || 0) + '人'"
+                label="班级人数"
+                :readonly="true"
+                input-align="right"
+                size="large"
+            />
+            <van-field
+                v-else
+                :value="(form.studentNum || 0) + '人'"
+                label="班级人数"
+                :readonly="true"
+                input-align="right"
+                size="large"
+            />
+            <van-field
+                :value="(form.singleClassMinutes || 0) + '分钟'"
+                label="单课时时长"
+                :readonly="true"
+                input-align="right"
+                size="large"
+            />
+        </van-cell-group>
+
+        <h2 class="van-block__title">课时安排</h2>
+        <van-cell-group>
+            <van-cell
+                title="最早排课时间"
+                :readonly="true"
+                v-if="vipGroup.coursesStartTime"
+                input-align="right"
+                size="large"
+                value-class="showText"
+                :value="vipGroup.coursesStartTime"
+            >
+            </van-cell>
+            <van-cell
+                title="最晚排课时间"
+                :readonly="true"
+                v-if="vipGroup.coursesEndTime"
+                input-align="right"
+                size="large"
+                value-class="showText"
+                :value="vipGroup.coursesEndTime"
+            >
+            </van-cell>
+            <!-- 为了处理,付费网管课程 -->
+            <!-- {{ !courseTypeIsVip && isLimitNum && typeStatus ? false : true }} -->
+            <van-field
+                v-model="form.totalClassTime"
+                label="课时总数"
+                :readonly="!courseTypeIsVip && !isLimitNum && typeStatus ? false : true"
+                input-align="right"
+                size="large"
+                placeholder="请输入排课课时数"
+            >
+                <template #extra v-if="form.totalClassTime">
+                    <span style="color: #808080; font-size: 16px;">课时</span>
+                </template>
+            </van-field>
+            <van-field
+                v-model="form.courseStart"
+                label="排课开始时间"
+                :readonly="true"
+                input-align="right"
+                is-link
+                size="large"
+                placeholder="请选择"
+                @click="dataForm.status = true"
+            />
+        </van-cell-group>
+
+        <van-cell-group :border="false" style="margin-top: .1rem">
+            <van-cell
+                title-class="title-time"
+                v-for="(item, index) in scheduleList"
+                :key="index"
+            >
+                <template slot="title">
+                    <span class="online">{{ item.type }}</span>
+                    <span class="week">{{ item.weekStr }}</span>
+                    <span class="timer">{{ item.startTime + "~" + item.endTime }}</span>
+                </template>
+                <template slot="default">
+                    <span @click="onDelete('class', item)"><van-icon name="delete-o" size=".14rem" /> <span style="font-size: .12rem;">删除</span></span>
+                </template>
+            </van-cell>
+        </van-cell-group>
+        <div class="addButton" @click="teachingStatus = true">
+            <van-icon name="plus" /> 添加课时安排
+        </div>
+
+        <van-cell-group>
+            <van-field
+                label="排课列表"
+                v-if="scheduleList.length > 0"
+                disabled
+                input-align="right"
+                @click="onShowTimeTable"
+                is-link
+                size="large"
+            />
+        </van-cell-group>
+
+        <div class="button-group">
+            <van-button type="primary" @click="onSubmit" round size="large">确认</van-button>
+        </div>
+
+        <!-- 选择上课学员 -->
+        <van-popup
+            v-model="studentStatus"
+            :lock-scroll="true"
+            position="bottom"
+            :style="{ height: '80%' }"
+            class="studentChose"
+        >
+            <student-list
+                @close="studentStatus = false"
+                :studentList="studentList"
+                :activityId="activityId"
+                :studentNum="form.studentNum"
+                :courseTypeIsVip="courseTypeIsVip"
+                :typeStatus="typeStatus"
+                :isMusicTheory="isMusicTheory"
+                @submit="onSelectStudent" />
+        </van-popup>
+
+        <!-- 排课开始时间 -->
+        <van-popup v-model="dataForm.status" position="bottom">
+            <van-datetime-picker
+                v-model="dataForm.currentDate"
+                type="date"
+                :min-date="dataForm.minDate"
+                :max-date="dataForm.maxDate"
+                :formatter="formatter"
+                @cancel="dataForm.status = false"
+                @confirm="onCurrentConfirm"
+            />
+        </van-popup>
+        <!-- 课时安排 -->
+        <van-popup v-model="teachingStatus" position="bottom">
+            <course-modal :scheduleList="scheduleList" :singleClassMinutes="form.singleClassMinutes" @close="teachingStatus = false" />
+        </van-popup>
+
+        <van-popup v-model="sheetForm.sheetStatus" position="bottom">
+            <van-picker
+                :loading="sheetForm.loading"
+                :default-index="sheetForm.index"
+                :columns="sheetForm.columns"
+                show-toolbar
+                @cancel="sheetForm.sheetStatus = false"
+                @confirm="onSheetConfirm"
+            />
+        </van-popup>
+
+        <!-- 课表展示 -->
+        <van-popup v-model="statusList.classTime" position="bottom" >
+            <van-row>
+                <van-col span="12">上课类型</van-col>
+                <van-col span="12">上课时间</van-col>
+            </van-row>
+            <div class="tableContainer">
+                <van-row v-for="(item, index) in timeTable" :key="index">
+                <van-col span="12">
+                    {{ item.teachMode == "ONLINE" ? "线上" : "线下" }}
+                </van-col>
+                <van-col span="12">
+                    {{ item.classDate }} {{ item.startClassTimeStr }}
+                </van-col>
+                </van-row>
+            </div>
+        </van-popup>
+    </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import studentList from './modal/studentList'
+import courseModal from './modal/course'
+import { courseType } from '../../constant'
+import { getActivityWaitCourseStudentNum, createVipGroup, createPracticeGroup } from './api'
+import { findSubSubjects, findEducationUsers, findVipSchoolByTeacher2 } from "@/api/teacher";
+export default {
+    components: { studentList, courseModal },
+    data() {
+        const query = this.$route.query
+        return {
+            courseType,
+            type: query.type,
+            activityId: query.activityId,
+            vipDetail: {},
+            vipGroup: {},
+            studentStatus: false,
+            studentList: [],
+            checkboxSelectIds: [],
+            teachMode: null, // -1:所有;0:线上;1:线下"
+            sheetForm: {
+                // 上拉弹窗
+                currentType: null, // 当前选择的类型
+                sheetStatus: false,
+                loading: true, // 加载数据
+                index: 0, // 选中的索引值
+                columns: [],
+            },
+            timeTable: [], // 生成的课表
+            loadData: {
+                // 下拉加载数据
+                subjectList: [], // 声部列表
+                teacherList: [],
+                teacherSchool: [], // 线下课地址
+            },
+            tempOfflineNum: 0, // 临时存放线下课次数
+            form: {
+                vipGroupCategoryId: null,
+                subjectIdList: null,
+                educationalTeacherId: null,
+                singleClassMinutes: null,
+                onlineClassesNums: null,
+                offlineClassesNums: null,
+                totalClassTime: null, // 总课时数
+                studentNum: null, // 每班人数
+                courseStart: null, // 排课开始时间
+                teacherSchoolId: null,
+                vipGroupActivityId: query.activityId,
+            },
+            formName: {
+                vipGroupCategoryId: null,
+                subjectListName: null,
+                subjectListIndex: 0, // 声部名称
+                educationalTeacherName: null, // 乐团主管
+                educationalTeacherIndex: 0,
+                teacherSchoolName: null,
+                teacherSchoolIndex: 0, // 线下课地址
+            },
+            statusList: {
+                hasOnline: false, // 是否显示线上
+                hasOffline: false, // 是否显示线下
+                classTime: false, // 查看排课列表
+            },
+            scheduleList: [],
+            // 排课弹窗
+            teachingStatus: false, // 课时安排状态
+            dataForm: {
+                // 时间下拉框
+                status: false,
+                minDate: new Date(),
+                maxDate: new Date(2035, 10, 1),
+                currentDate: new Date(),
+            },
+            isMusicTheory: false,
+        }
+    },
+    computed: {
+        typeStatus() { // 是否是付费课程
+            return this.type == 'pay' ? true : false
+        },
+        courseTypeIsVip() { // 目前只有两种课程,VIP 网管课,则可以这样判断
+            const type = this.typeStatus ? this.vipGroup.courseType : this.vipGroup.giveCourseType
+            return type == 'VIP' ? true : false
+        },
+        isLimitNum() { // 是否限制排课
+            return this.vipGroup.minCourseNum > 0 ? true : false
+        }
+    },
+    mounted() {
+        this.__init()
+    },
+    methods: {
+        async __init() {
+            try {
+                let res = await getActivityWaitCourseStudentNum({ activityId: this.activityId })
+                this.vipDetail = res.data
+                let vipGroup = res.data.vipGroupActivity
+                vipGroup.coursesStartTime = vipGroup.coursesStartTime ? dayjs(vipGroup.coursesStartTime).format('YYYY-MM-DD') : null
+                vipGroup.coursesEndTime = vipGroup.coursesEndTime ? dayjs(vipGroup.coursesEndTime).format('YYYY-MM-DD') : null
+                this.vipGroup = vipGroup
+                let form = this.form
+                // 课程形式
+                form.vipGroupCategoryId = this.typeStatus ? vipGroup.vipGroupCategoryIdList : vipGroup.giveCategoryId
+                // 单课时长
+                form.singleClassMinutes = this.typeStatus ? vipGroup.singleCourseTime : vipGroup.giveSingleCourseTime
+
+                this.isMusicTheory = vipGroup.giveCategoryName === '乐理课'
+
+                if(this.courseTypeIsVip) {
+                    // 每班人数
+                    form.studentNum = this.typeStatus ? vipGroup.vipGroupCategoryNum : vipGroup.giveCategoryNum
+                    this.statusList.hasOnline = this.typeStatus ? this.formatStatus('online', vipGroup.teachMode) : this.formatStatus('online', vipGroup.giveTeachMode)
+                    this.statusList.hasOffline = this.typeStatus ? this.formatStatus('offline', vipGroup.teachMode) : this.formatStatus('offline', vipGroup.giveTeachMode)
+                } else {
+                    form.totalClassTime = null
+                    form.studentNum = 1
+                    this.statusList.hasOnLine = false
+                    this.statusList.hasOffLine = false
+                }
+
+                if(this.isLimitNum || !this.typeStatus) { // 是否限制了排课
+                    // 排课次数,活动排课没有范围一说,最大次数和最小次数必须一致
+                    form.totalClassTime = this.typeStatus ? vipGroup.minCourseNum : vipGroup.giveCourseNum
+                }
+
+                // 如果
+                if(this.teachMode == 0) {
+                    form.onlineClassesNums = form.totalClassTime || 0
+                    form.offlineClassesNums = 0
+                } else if(this.teachMode == 1) {
+                    form.onlineClassesNums = 0
+                    form.offlineClassesNums = form.totalClassTime || 0
+                    this.tempOfflineNum = form.totalClassTime || 0
+                }
+            } catch {
+                //
+            }
+        },
+        onGetSheetList(name) {
+            // 获取科目列表
+            let sheetForm = this.sheetForm;
+            sheetForm.columns = [];
+            sheetForm.sheetStatus = true;
+            sheetForm.loading = true;
+            sheetForm.currentType = name;
+            sheetForm.index = 0;
+            let arr = this.loadData[name];
+            if (arr.length > 0) {
+                sheetForm.columns = arr;
+                sheetForm.index = this.formName[name + "Index"];
+                sheetForm.loading = false;
+            } else {
+                this.onLoadingData(name);
+            }
+        },
+        onLoadingData() {
+            // 加载数据
+            let sheetForm = this.sheetForm;
+            if (sheetForm.currentType == "subjectList") {
+                // 声部列表
+                findSubSubjects().then((res) => {
+                let result = res.data;
+                if (result.code == 200 && result.data.length > 0) {
+                    let tempArr = [];
+                    result.data.forEach((item) => {
+                        item.value = item.id;
+                        item.text = item.name;
+                        tempArr.push(item);
+                    });
+                    this.loadData.subjectList = tempArr;
+                    sheetForm.columns = tempArr;
+                    sheetForm.loading = false;
+                } else {
+                    this.$toast("暂无科目列表");
+                    sheetForm.loading = false;
+                }
+                });
+            } else if (sheetForm.currentType == "teacherSchool") {
+                // 教师教学点
+                findVipSchoolByTeacher2().then((res) => {
+                    let result = res.data;
+                    if (result.code == 200 && result.data.length > 0) {
+                        let tempArr = [];
+                        result.data.forEach((item) => {
+                            item.value = item.id;
+                            item.text = item.name;
+                            tempArr.push(item);
+                        });
+                        this.loadData.teacherSchool = tempArr;
+                        sheetForm.columns = tempArr;
+                        sheetForm.loading = false;
+                    } else {
+                        this.$toast("暂无教学点");
+                        sheetForm.loading = false;
+                    }
+                });
+            } else if (sheetForm.currentType == "teacherList") {
+                // 乐团主管
+                findEducationUsers().then((res) => {
+                    let result = res.data;
+                    if (result.code == 200 && result.data.length > 0) {
+                        let tempArr = [];
+                        result.data.forEach((item) => {
+                            item.value = item.userId;
+                            item.text = item.userName;
+                            tempArr.push(item);
+                        });
+                        this.loadData.teacherList = tempArr;
+                        sheetForm.columns = tempArr;
+                        sheetForm.loading = false;
+                    } else {
+                        this.$toast("暂无乐团主管");
+                        sheetForm.loading = false;
+                    }
+                });
+            }
+        },
+        onSheetConfirm(value, index) {
+            // 上拉弹窗
+            let sheetForm = this.sheetForm,
+                form = this.form,
+                formName = this.formName
+            if (sheetForm.currentType == "subjectList") {
+                // 科目名称赋值
+                form.subjectIdList = value.value;
+                formName.subjectListName = value.text;
+                formName.subjectListIndex = index;
+            } else if (sheetForm.currentType == "teacherSchool") {
+                // 线下课地址
+                form.teacherSchoolId = value.value;
+                formName.teacherSchoolName = value.text;
+                formName.teacherSchoolIndex = index;
+            } else if (sheetForm.currentType == "teacherList") {
+                // 乐团主管
+                form.educationalTeacherId = value.value;
+                formName.educationalTeacherName = value.text;
+                formName.educationalTeacherIndex = index;
+            }
+
+            sheetForm.sheetStatus = false;
+        },
+        async onSubmit() {
+            // 次数限制是否可以继续创建
+            let form = this.form;
+            let statusList = this.statusList;
+
+            if (!form.subjectIdList) {
+                this.$toast("请选择排课声部");
+                return false;
+            }
+            if (!form.educationalTeacherId) {
+                this.$toast("请选择乐团主管");
+                return;
+            }
+            if (this.checkboxSelectIds.length <= 0) {
+                this.$toast("请选择上课学员");
+                return;
+            }
+
+            if (this.isMusicTheory) {
+                if (!(this.checkboxSelectIds.length >= 1 && this.checkboxSelectIds.length <= this.form.studentNum)) {
+                    this.$toast(`请选择1-${this.form.studentNum}名学生,当前选择${this.checkboxSelectIds.length}名`);
+                    return;
+                }
+            } else {
+                if (this.checkboxSelectIds.length != this.form.studentNum) {
+                    this.$toast(`请选择学生${this.form.studentNum}名,当前选择${this.checkboxSelectIds.length}名`);
+                    return;
+                }
+            }
+
+            let onlineClassesStatus = !form.onlineClassesNums && form.onlineClassesNums <= 0 ? true : false;
+            let offlineClassesStatus = !form.offlineClassesNums && form.offlineClassesNums <= 0 ? true : false;
+
+            if (statusList.hasOnline && onlineClassesStatus) {
+                this.$toast("请输入线上课次数");
+                return false;
+            }
+            if (statusList.hasOffline && !statusList.hasOnline) {
+                if (offlineClassesStatus) {
+                    this.$toast("请输入线下课次数");
+                    return false;
+                }
+
+                // 判断是否有线下
+                if (form.offlineClassesNums > 0 && !form.teacherSchoolId) {
+                    this.$toast("请选择线下课地址");
+                    return false;
+                }
+            }
+
+            if (
+                statusList.hasOffline &&
+                statusList.hasOnline &&
+                parseFloat(form.onlineClassesNums || 0) + parseFloat(form.offlineClassesNums || 0) != this.form.totalClassTime
+            ) {
+                this.$toast('线上课次数+线下课次数不等于总课次数')
+                return
+            }
+
+            if (this.scheduleList.length <= 0) {
+                this.$toast("课时安排不能为空");
+                return false;
+            }
+            if (!this.checkCourseList()) {
+                return;
+            }
+            // 排课
+            this.setTimeTable();
+
+            form.studentIdList = this.checkboxSelectIds.join(",");
+
+            form.firstStudentId = this.studentList.length > 0 ? this.studentList[0].userId : null;
+            form.onlineClassesNum = Number(form.onlineClassesNums);
+            form.offlineClassesNum = Number(form.offlineClassesNums);
+            let params = {
+                courseSchedules: this.timeTable
+            }
+            if(this.courseTypeIsVip) {
+                params.vipGroupApplyBaseInfo = form
+                params.giveFlag = !this.typeStatus
+                await this.onPayVip(params)
+            } else {
+                params.practiceGroupApplyBaseInfoDto = form
+                params.practiceGroupApplyBaseInfoDto.studentId = form.studentIdList
+                params.practiceGroupApplyBaseInfoDto.allCourseNum = form.totalClassTime
+                params.practiceGroupApplyBaseInfoDto.subjectId = form.subjectIdList
+                params.giveFlag = !this.typeStatus
+                await this.onPayPractice(params)
+            }
+        },
+        async onPayVip(params) {
+            try {
+                await createVipGroup(params)
+                this.$toast("排课成功");
+                setTimeout(() => {
+                    this.$router.back()
+                }, 1000);
+            } catch {
+                //
+            }
+        },
+        async onPayPractice(params) {
+            try {
+                await createPracticeGroup(params)
+                this.$toast("排课成功");
+                setTimeout(() => {
+                    this.$router.back()
+                }, 1000);
+            } catch {
+                //
+            }
+        },
+        onSelectStudent(items) {
+            // 选中的数据
+            const tempItems = items || []
+            this.studentList = tempItems
+            // if(tempItems.length <= 0) { // 判断是否有选择学员
+                this.checkboxSelectIds = []
+            // }
+            tempItems.forEach(item => {
+                this.checkboxSelectIds.push(item.userId)
+            })
+            this.studentStatus = false
+        },
+        onDelete(type, item) {
+            if(type == 'student') {
+                // 删除上课学员
+                this.$dialog.confirm({
+                    title: '提示',
+                    message: '是否删除该学员?',
+                    confirmButtonText: '确定',
+                    confirmButtonColor: '#269a93',
+                    cancelButtonText: '取消'
+                }).then(() => {
+                    let index = this.studentList.indexOf(item);
+                    if (index !== -1) {
+                        this.studentList.splice(index, 1);
+                        this.checkboxSelectIds.splice(index, 1);
+                    }
+                })
+            } else if(type == 'class') {
+                // 删除上课学员
+                this.$dialog.confirm({
+                    title: '提示',
+                    message: '是否删除该课时安排?',
+                    confirmButtonText: '确定',
+                    confirmButtonColor: '#269a93',
+                    cancelButtonText: '取消'
+                }).then(() => {
+                    let index = this.scheduleList.indexOf(item);
+                    if (index !== -1) {
+                        this.scheduleList.splice(index, 1);
+                    }
+                })
+            }
+        },
+        onCurrentConfirm(value) {
+            // 排课开始时间
+            this.form.courseStart = dayjs(value).format('YYYY-MM-DD')
+            this.dataForm.status = false;
+        },
+        onClassKeyUp(type) {
+            // 线上课&线下课修改时
+            if(this.teachMode != -1) return
+            let form = this.form
+            let onlineNum = form.onlineClassesNums
+            let offLineNum = form.offlineClassesNums
+            // 重置次数,不能
+            if(parseInt(onlineNum || 0) + parseInt(offLineNum || 0) >= form.totalClassTime) {
+                if(type == 'offLine') {
+                    let diffNum = form.totalClassTime - parseInt(onlineNum || 0)
+                    offLineNum = diffNum < 0 ? 0 : diffNum
+                } else {
+                    let diffNum = form.totalClassTime - parseInt(offLineNum || 0)
+                    onlineNum = diffNum < 0 ? 0 : diffNum
+                }
+            }
+            this.form.onlineClassesNums = onlineNum
+            this.form.offlineClassesNums = offLineNum
+            this.tempOfflineNum = offLineNum || 0
+        },
+        onShowTimeTable() {
+            // 显示排课列表
+            if (!this.checkCourseList()) {
+                return;
+            }
+
+            const checkmMsg = this.checkTimeTable()
+            if (checkmMsg) {
+                this.$toast(checkmMsg)
+                return
+            }
+            this.statusList.classTime = true;
+            this.setTimeTable();
+        },
+        checkTimeTable() {
+            let form = this.form,
+                scheduleList = this.scheduleList;
+            let online = parseInt(
+                form.onlineClassesNums ? form.onlineClassesNums : 0
+            );
+            let offline = parseInt(
+                form.offlineClassesNums ? form.offlineClassesNums : 0
+            );
+            // 网管课默认只有线上课次
+            if(!this.courseTypeIsVip) {
+                online = parseInt(form.totalClassTime || 0)
+            }
+            // let totalCount = Number(online) + Number(offline)
+            let hasOnlineSchedule = false,
+                hasOfflineSchedule = false
+
+            for (let i = 0; i < scheduleList.length; i++) {
+                const item = scheduleList[i];
+                if (item.type == '线上') {
+                    hasOnlineSchedule = true;
+                }
+                if (item.type == '线下') {
+                    hasOfflineSchedule = true;
+                }
+                if (hasOnlineSchedule && hasOfflineSchedule) {
+                    break;
+                }
+            }
+            if (online > 0 && !hasOnlineSchedule) {
+                return '请添加线上课时安排';
+            }
+            if (offline > 0 && !hasOfflineSchedule) {
+                return '请添加线下课时安排';
+            }
+            console.log({...form}, online, offline, hasOnlineSchedule, hasOfflineSchedule)
+        },
+        setTimeTable() {
+            if (!this.checkCourseList(false)) {
+                return;
+            }
+            // 重置排课列表
+            this.timeTable = [];
+
+            let form = this.form,
+                scheduleList = this.scheduleList;
+
+            // 拿到线上课数与线下课数 以及
+            let online = parseInt(
+                form.onlineClassesNums ? form.onlineClassesNums : 0
+            );
+            let offline = parseInt(
+                form.offlineClassesNums ? form.offlineClassesNums : 0
+            );
+            // 网管课默认只有线上课次
+            if(!this.courseTypeIsVip) {
+                online = parseInt(form.totalClassTime || 0)
+            }
+            // 判断是否有课程安排
+            if (scheduleList.length <= 0) {
+                return;
+            }
+            let totalCount = Number(online) + Number(offline);
+            let tempCourseStart = form.courseStart.replace(/-/gi, "/");
+            let dateOperation = new Date(tempCourseStart);
+            let forMark = 0;
+            while (totalCount && totalCount > 0) {
+                for (let i = 0; i < scheduleList.length; i++) {
+                    if (online == 0 && offline == 0) break;
+                    let num = scheduleList[i].weekIndex - dateOperation.getDay();
+                    // 如果是同一天一个周期会出现排课都排到一天
+                    if (forMark > 0 && num == 0 && i == 0) {
+                        num = num + 7;
+                    }
+                    if (num < 0) {
+                        // 如果为负数则为下周
+                        num = num + 7;
+                    }
+                    let dataStr = this.getThinkDate(dateOperation, num);
+
+                    // 判断是否大于当前时间
+                    let nowGetTime = new Date().getTime();
+                    let courseTime = new Date(dataStr.replace(/-/gi, "/") +" " + scheduleList[i].startTime + ":00").getTime();
+                    if (nowGetTime < courseTime) {
+                        let tempArr = {
+                            classDate: dataStr,
+                            startClassTimeStr: scheduleList[i].startTime,
+                            endClassTimeStr: scheduleList[i].endTime,
+                        };
+                        // console.log(scheduleList[i].type, online, offline)
+                        if (scheduleList[i].type == "线上" && online > 0) {
+                            tempArr.teachMode = "ONLINE";
+                            this.timeTable.push(tempArr);
+                            online--;
+
+                            totalCount--;
+                        } else if (scheduleList[i].type == "线下" && offline > 0) {
+                            tempArr.teachMode = "OFFLINE";
+                            this.timeTable.push(tempArr);
+                            offline--;
+
+                            totalCount--;
+                        }
+                    }
+                }
+                // 加一周
+                if (scheduleList.length == 1) {
+                    dateOperation.setDate(dateOperation.getDate() + 7);
+                } else if (
+                    scheduleList.every((item) => item.weekStr === scheduleList[0].weekStr)
+                ) {
+                    // 标记循环次数(标记判断课程安排是不是同一天)
+                    forMark++;
+                }
+            }
+
+            this.timeTable.sort((a, b) => {
+                let aStr = dayjs(dayjs(a.classDate).format("YYYY-MM-DD") + " " + a.startClassTimeStr + ":00").valueOf();
+                let bStr = dayjs(dayjs(b.classDate).format("YYYY-MM-DD") + " " + b.startClassTimeStr + ":00").valueOf();
+                return aStr - bStr;
+            });
+        },
+        getThinkDate(date, num) {
+            let Stamp = date;
+            Stamp.setDate(date.getDate() + num); // 获取当前月数的第几天
+            return dayjs(Stamp).format('YYYY-MM-DD')
+        },
+        checkCourseList(isShowToast = true) {
+            let form = this.form;
+            let scheduleList = this.scheduleList || [];
+            let hasOnLine = false; // 是否有线上课时安排
+            let hasOffLine = false;
+            scheduleList.forEach((item) => {
+                if (item.type == "线上") {
+                    hasOnLine = true;
+                }
+                if (item.type == "线下") {
+                    hasOffLine = true;
+                }
+            });
+            let statusList = this.statusList;
+            let onlineClassesStatus = !form.onlineClassesNums && form.onlineClassesNums <= 0 ? true : false;
+            let offlineClassesStatus = !form.offlineClassesNums && form.offlineClassesNums <= 0 ? true : false;
+            if (statusList.hasOnline) {
+                if (onlineClassesStatus) {
+                    if (isShowToast) {
+                        this.$toast("请输入线上课次数");
+                    }
+                    return false;
+                }
+                if (!onlineClassesStatus && !hasOnLine && form.onlineClassesNums > 0) {
+                    if (isShowToast) {
+                        this.$toast("课时安排缺少线上课类型");
+                    }
+                    return false;
+                }
+            }
+            if (statusList.hasOffline && !statusList.hasOnline) {
+                if (offlineClassesStatus) {
+                    if (isShowToast) {
+                        this.$toast("请输入线下课次数");
+                    }
+                    return false;
+                }
+                if (
+                !offlineClassesStatus &&
+                !hasOffLine &&
+                form.offlineClassesNums > 0
+                ) {
+                    if (isShowToast) {
+                        this.$toast("课时安排缺少线下课类型");
+                    }
+                    return false;
+                }
+            }
+            if (
+                statusList.hasOffline &&
+                statusList.hasOnline &&
+                parseFloat(form.onlineClassesNums || 0) + parseFloat(form.offlineClassesNums || 0) != this.form.totalClassTime
+            ) {
+                this.$toast('线上课次数+线下课次数不等于总课次数')
+                return false
+            }
+            return true;
+        },
+        formatStatus(type, teachMode) {
+            // -1:所有;0:线上;1:线下
+            this.teachMode = teachMode
+            if(type == 'online' && teachMode == 0) {
+                return true
+            } else if(type == 'offline' && teachMode == 1) {
+                return true
+            } else if(teachMode == -1) {
+                return true
+            } else {
+                return false
+            }
+        },
+        formatter(type, value) {
+            if (type === "year") {
+                return `${value}年`;
+            } else if (type === "month") {
+                return `${value}月`;
+            } else if (type === "day") {
+                return `${value}日`;
+            }
+            return value;
+        },
+    }
+}
+</script>
+
+<style lang="less" scoped>
+@import url("../../assets/commonLess/variable.less");
+.program {
+    background-color: #F5F5F5;
+    min-height: 100vh;
+    overflow: hidden;
+}
+.van-cell-group--inset {
+    margin: .12rem .12rem 0;
+    overflow: hidden;
+    border-radius: 8px;
+    .titleContent {
+        padding: .14rem .16rem;
+    }
+    .titleStyle {
+        font-size: .2rem;
+        color: #333333;
+        font-size: 500;
+    }
+    .labelStyle {
+        padding-top: .08rem;
+        color: #666666;
+        font-size: .13rem;
+        line-height: .2rem;
+    }
+}
+.van-row {
+    line-height: 0.4rem;
+    border-top: 1px solid #edeef0;
+    text-align: center;
+    font-size: 0.14rem;
+
+    &:first-child {
+        border-top: 0;
+        background: #edeef0;
+        color: #444;
+        font-size: 0.15rem;
+    }
+}
+.tableContainer {
+    max-height: 2.44rem;
+    overflow: auto;
+    .van-row {
+        color: #444;
+        &:first-child {
+            border-top: 0;
+            background: #fff;
+            font-size: 0.14rem;
+        }
+    }
+}
+.van-block__title {
+    padding: .12rem .14rem .06rem;
+    color: #808080;
+    font-size: .14rem;
+    line-height: .2rem;
+}
+.button-group {
+    margin: 0.3rem 0.26rem 0.2rem;
+
+    .van-button--primary {
+        background: @mColor;
+        border-color: @mColor;
+        font-size: 0.18rem;
+    }
+}
+.title-time {
+    display: flex;
+    align-items: center;
+    flex: 1 auto;
+    color: #1A1A1A;
+    font-size: .16rem;
+    .week {
+        padding-left: 0.4rem;
+        padding-right: 0.15rem;
+    }
+}
+/deep/.studentChose {
+    border-radius: .1rem .1rem 0px 0px;
+    overflow: auto;
+    background: #F5F5F5;
+}
+/deep/.van-field__label {
+    color: #1A1A1A;
+}
+/deep/.van-field__control, .showText {
+    font-size: 16px;
+    color: #808080;
+}
+.addButton {
+    margin: .1rem .28rem;
+    border: 1px dashed #CFCFCF;
+    line-height: .42rem;
+    text-align: center;
+    background: #FBFBFB;
+    color: #666666;
+    font-size: .14rem;
+    border-radius: .05rem;
+}
+</style>

+ 3 - 3
src/views/audition/ArrangeWork.vue

@@ -148,8 +148,8 @@ export default {
         musicScoreId: null,
         musicScoreName: null,
       },
-      title: null,
-      content: null, // 课程编号
+      title: '',
+      content: '', // 课程编号
       expiryDate: null, // 作业截止日期
       accompanimentStatus: false, // 伴奏弹窗
       tabActive: 0,
@@ -486,4 +486,4 @@ export default {
     margin-left: 0.1rem;
   }
 }
-</style>
+</style>

+ 4 - 4
src/views/audition/CourseEvaluation.vue

@@ -162,12 +162,12 @@ export default {
       classGroupName: null,
       teachMode: null,
       classType: null, // 课程类型
-      teachingMaterial: null, //教材
+      teachingMaterial: '', //教材
       song: null, // 曲目
       pronunciation: null, // 发音
       tempo: null, //节奏
       musicTheory: null, // 乐理
-      memo: null, // 备注
+      memo: '', // 备注
       homeWork: null, // 作业
       hasLiaison: null,
       subjectNames: null,
@@ -574,7 +574,7 @@ export default {
 }
 .talk {
   padding:16px .21rem;
-} 
+}
 .evTitle {
   padding: 16px .21rem 0;
   color: #333;
@@ -631,4 +631,4 @@ textarea:-ms-input-placeholder {
     line-height: 16px;
     padding: 0 5px;
 }
-</style>
+</style>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 306 - 298
src/views/teacher/VIP00Apply.vue


+ 28 - 19
src/views/teacher/VIPApply.vue

@@ -1,5 +1,5 @@
 <template>
-	<van-tabs v-model="active" swipe-threshold="3" sticky class="vanTabs" @change="onChange" color="#01C1B5"> 
+	<!-- <van-tabs v-model="active" swipe-threshold="3" sticky class="vanTabs" @change="onChange" color="#01C1B5"> 
 		<van-tab title="VIP申请" :name="1">
 			<vip-00-apply v-if="active === 1" />
 		</van-tab>
@@ -12,38 +12,47 @@
 		<van-tab title="考级乐理排课" :name="4">
 			<theory-course v-if="active === 4" />
 		</van-tab>
-	</van-tabs>
+	</van-tabs> -->
+	<vip-00-apply />
 </template>
 
 <script>
 import vip00Apply from './VIP00Apply'
-import vip11Apply from './VIP11Apply'
-import VipCourse from "../applyActive/components/vipCourse";
-import TheoryCourse from "../applyActive/components/theoryCourse";
+// import vip11Apply from './VIP11Apply'
+// import VipCourse from "../applyActive/components/vipCourse";
+// import TheoryCourse from "../applyActive/components/theoryCourse";
 export default {
 	components: {
 		vip00Apply,
-		vip11Apply,
-		VipCourse,
-		TheoryCourse
+		// vip11Apply,
+		// VipCourse,
+		// TheoryCourse
 	},
 	data() {
 		return {
 			active: 1
 		}
 	},
+	mounted() {
+		let params = this.$route.query;
+    if (params.Authorization) {
+      localStorage.setItem("Authorization", decodeURI(params.Authorization));
+      localStorage.setItem("userInfo", decodeURI(params.Authorization));
+    }
+		document.title = '课程申请'
+	},
 	methods: {
-		onChange(value) {
-			if(value == 1) {
-				document.title = 'VIP课程申请'
-			} else if(value == 2) {
-				document.title = '双十一排课'
-			} else if(value == 3) {
-				document.title = '考级VIP排课'
-			} else if(value == 4) {
-				document.title = '考级乐理排课'
-			}
-		}
+		// onChange(value) {
+		// 	if(value == 1) {
+		// 		document.title = 'VIP课程申请'
+		// 	} else if(value == 2) {
+		// 		document.title = '双十一排课'
+		// 	} else if(value == 3) {
+		// 		document.title = '考级VIP排课'
+		// 	} else if(value == 4) {
+		// 		document.title = '考级乐理排课'
+		// 	}
+		// }
 	}
 }
 </script>

+ 2 - 2
vue.config.js

@@ -2,7 +2,7 @@ let targetUrl = 'https://mteatest.dayaedu.com'
 // let targetUrl = 'http://192.168.3.139:8000' // 箭河
 // let targetUrl = 'https://online.dayaedu.com'
 // let targetUrl = 'http://dev.dayaedu.com/'
-// let targetUrl = 'http://192.168.3.196'
+// let targetUrl = 'http://192.168.3.124:8000'
 module.exports = {
   chainWebpack: config => {
     config.devtool('inline-source-map')
@@ -39,7 +39,7 @@ module.exports = {
     open: process.platform === 'darwin',
     host: '0.0.0.0',
     port: 9999,
-    https: true,
+    // https: true,
     hotOnly: false,
     // 查阅 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/cli-service.md#配置代理
     proxy: {

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä