Browse Source

添加页面

lex 2 years ago
parent
commit
219b07cda9
30 changed files with 1429 additions and 109 deletions
  1. 11 0
      package-lock.json
  2. 1 0
      package.json
  3. 17 16
      public/project/initiation.html
  4. 9 9
      public/project/preRegister.html
  5. 3 0
      public/project/schoolRegister.html
  6. 4 4
      src/components/o-img-code/index.module.less
  7. 6 0
      src/constant/index.ts
  8. 14 0
      src/router/routes-school.ts
  9. 107 0
      src/school/companion-teacher/companion-detail.module.less
  10. 176 26
      src/school/companion-teacher/companion-detail.tsx
  11. 8 9
      src/school/companion-teacher/companion-teacher-register.module.less
  12. 7 6
      src/school/companion-teacher/companion-teacher-register.tsx
  13. 23 0
      src/school/companion-teacher/compontent/teacher.module.less
  14. 127 0
      src/school/companion-teacher/compontent/teacher.tsx
  15. 13 4
      src/school/companion-teacher/index.tsx
  16. 74 0
      src/school/companion-teacher/unbind.module.less
  17. 145 0
      src/school/companion-teacher/unbind.tsx
  18. 0 0
      src/school/manage-teacher/images/banner.png
  19. BIN
      src/school/manage-teacher/images/icon-close.png
  20. BIN
      src/school/manage-teacher/images/school-logo.png
  21. 0 0
      src/school/manage-teacher/images/top-banner.png
  22. 3 2
      src/school/manage-teacher/index.tsx
  23. 239 0
      src/school/manage-teacher/manage-teacher-register.module.less
  24. 337 0
      src/school/manage-teacher/manage-teacher-register.tsx
  25. 9 5
      src/school/orchestra/compontent/information.tsx
  26. 83 25
      src/school/orchestra/index.tsx
  27. 1 1
      src/school/orchestra/orchestra-detail.tsx
  28. 5 0
      src/views/layout/auth.tsx
  29. 5 0
      src/views/layout/login.tsx
  30. 2 2
      vite.config.ts

+ 11 - 0
package-lock.json

@@ -15,6 +15,7 @@
         "browserslist": "^4.20.2",
         "classnames": "^2.3.1",
         "clean-deep": "^3.4.0",
+        "countup.js": "^2.3.2",
         "dayjs": "^1.10.7",
         "echarts": "^5.3.3",
         "html-to-image": "^1.9.0",
@@ -3545,6 +3546,11 @@
         "semver": "bin/semver.js"
       }
     },
+    "node_modules/countup.js": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmmirror.com/countup.js/-/countup.js-2.3.2.tgz",
+      "integrity": "sha512-dQ7F/CmKGjaO6cDfhtEXwsKVlXIpJ89dFs8PvkaZH9jBVJ2Z8GU4iwG/qP7MgY8qwr+1skbwR6qecWWQLUzB8Q=="
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -12318,6 +12324,11 @@
         }
       }
     },
+    "countup.js": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmmirror.com/countup.js/-/countup.js-2.3.2.tgz",
+      "integrity": "sha512-dQ7F/CmKGjaO6cDfhtEXwsKVlXIpJ89dFs8PvkaZH9jBVJ2Z8GU4iwG/qP7MgY8qwr+1skbwR6qecWWQLUzB8Q=="
+    },
     "cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
     "browserslist": "^4.20.2",
     "classnames": "^2.3.1",
     "clean-deep": "^3.4.0",
+    "countup.js": "^2.3.2",
     "dayjs": "^1.10.7",
     "echarts": "^5.3.3",
     "html-to-image": "^1.9.0",

+ 17 - 16
public/project/initiation.html

@@ -197,13 +197,13 @@
           :rules="[{ required: true, message: '请选择性别' }]">
           <template #input>
             <van-radio-group v-model="stu.sex" :disabled='checkPhone' checked-color="#FF8057" direction="horizontal">
-              <van-tag size="large" type="primary" :plain="!(stu.sex === true)" :color="checkPhone ? '#ccc': '#FF8057'"
+              <van-tag size="large" type="primary" :plain="!(stu.sex === 1)" :color="checkPhone ? '#ccc': '#FF8057'"
                 class="radioSection">
-                <van-radio class="radioItem" :name="true"></van-radio>男生
+                <van-radio class="radioItem" :name="1"></van-radio>男生
               </van-tag>
-              <van-tag size="large" type="primary" :plain="!(stu.sex === false)" :color="checkPhone ? '#ccc': '#FF8057'"
+              <van-tag size="large" type="primary" :plain="!(stu.sex === 0)" :color="checkPhone ? '#ccc': '#FF8057'"
                 class="radioSection">
-                <van-radio class="radioItem" :name="false"></van-radio>女生
+                <van-radio class="radioItem" :name="0"></van-radio>女生
               </van-tag>
             </van-radio-group>
           </template>
@@ -229,13 +229,13 @@
           <template #input>
             <van-radio-group v-model="stu.hasLearningExperience" :disabled='checkPhone' checked-color="#FF8057"
               direction="horizontal">
-              <van-tag size="large" type="primary" :plain="!(stu.hasLearningExperience === true)"
+              <van-tag size="large" type="primary" :plain="!(stu.hasLearningExperience === 1)"
                 :color="checkPhone ? '#ccc': '#FF8057'" class="radioSection">
-                <van-radio class="radioItem" :name="true"></van-radio>是
+                <van-radio class="radioItem" :name="1"></van-radio>是
               </van-tag>
-              <van-tag size="large" type="primary" :plain="!(stu.hasLearningExperience === false)"
+              <van-tag size="large" type="primary" :plain="!(stu.hasLearningExperience === 0)"
                 :color="checkPhone ? '#ccc': '#FF8057'" class="radioSection">
-                <van-radio class="radioItem" :name="false"></van-radio>否
+                <van-radio class="radioItem" :name="0"></van-radio>否
               </van-tag>
             </van-radio-group>
           </template>
@@ -247,13 +247,13 @@
           <template #input>
             <van-radio-group v-model="stu.joinParentMeeting" :disabled='checkPhone' checked-color="#FF8057"
               direction="horizontal">
-              <van-tag size="large" type="primary" :plain="!(stu.joinParentMeeting === true)"
+              <van-tag size="large" type="primary" :plain="!(stu.joinParentMeeting === 1)"
                 :color="checkPhone ? '#ccc': '#FF8057'" class="radioSection">
-                <van-radio class="radioItem" :name="true"></van-radio>是
+                <van-radio class="radioItem" :name="1"></van-radio>是
               </van-tag>
-              <van-tag size="large" type="primary" :plain="!(stu.joinParentMeeting === false)"
+              <van-tag size="large" type="primary" :plain="!(stu.joinParentMeeting === 0)"
                 :color="checkPhone ? '#ccc': '#FF8057'" class="radioSection">
-                <van-radio class="radioItem" :name="false"></van-radio>否
+                <van-radio class="radioItem" :name="0"></van-radio>否
               </van-tag>
             </van-radio-group>
           </template>
@@ -379,23 +379,24 @@
               }
             })
             console.log(user.data.code)
-            if (user.data.code === 200 && userDetail.data.data) {
+            if (user.data.code === 200 && user.data.data) {
               var detail = user.data.data
+              console.log(detail, 'detail')
 
               var grade = this.currentGrade.find(item => item.value == detail.currentGrade)
               var cls = this.classList.find(item => item.value == detail.currentClass)
               this.stu = {
                 username: detail.username, // 姓名
-                sex: detail.sex, // 性别
+                sex: detail.sex ? 1 : 0, // 性别
                 phone: detail.phone, // 电话
                 currentGrade: grade.text, // 年级
                 currentGradeNum: detail.currentGrade, // 年级编号
                 currentClass: cls.text, // 班级
                 currentClassNum: detail.currentClass, // 年级编号
                 learningSubjectName: detail.learningSubjectName,
-                hasLearningExperience: detail.hasLearningExperience, // 是否有学习经验
+                hasLearningExperience: detail.hasLearningExperience ? 1 : 0, // 是否有学习经验
                 personalSuggestion: detail.personalSuggestion, // 个人建议
-                joinParentMeeting: detail.joinParentMeeting
+                joinParentMeeting: detail.joinParentMeeting ? 1 : 0
               }
             }
           } catch { }

+ 9 - 9
public/project/preRegister.html

@@ -197,13 +197,13 @@
           :rules="[{ required: true, message: '请选择性别' }]">
           <template #input>
             <van-radio-group v-model="stu.sex" :disabled='checkPhone' checked-color="#9A64FF" direction="horizontal">
-              <van-tag size="large" type="primary" :plain="!(stu.sex === true)" :color="checkPhone ? '#ccc': '#9A64FF'"
+              <van-tag size="large" type="primary" :plain="!(stu.sex === 1)" :color="checkPhone ? '#ccc': '#9A64FF'"
                 class="radioSection">
-                <van-radio class="radioItem" :name="true"></van-radio>男生
+                <van-radio class="radioItem" :name="1"></van-radio>男生
               </van-tag>
-              <van-tag size="large" type="primary" :plain="!(stu.sex === false)" :color="checkPhone ? '#ccc': '#9A64FF'"
+              <van-tag size="large" type="primary" :plain="!(stu.sex === 0)" :color="checkPhone ? '#ccc': '#9A64FF'"
                 class="radioSection">
-                <van-radio class="radioItem" :name="false"></van-radio>女生
+                <van-radio class="radioItem" :name="0"></van-radio>女生
               </van-tag>
             </van-radio-group>
           </template>
@@ -368,7 +368,7 @@
           })
           if (subjects.data.code === 200) {
             var rows = subjects.data.data.rows || []
-            console.log(rows, 'rows')
+            // console.log(rows, 'rows')
             rows.forEach(item => {
               this.subjectList.push({
                 text: item.name,
@@ -409,7 +409,7 @@
               var subjects = this.subjectList.find(item => item.value == detail.registerSubjectId)
               this.stu = {
                 username: detail.username, // 姓名
-                sex: detail.sex, // 性别
+                sex: detail.sex ? 1 : 0, // 性别
                 phone: detail.phone, // 电话
                 currentGrade: grade.text, // 年级
                 currentGradeNum: detail.currentGrade, // 年级编号
@@ -431,14 +431,14 @@
               }
             })
 
-            console.log(userDetail.data.code)
+            // console.log(userDetail.data.code)
             if (userDetail.data.code === 200 && userDetail.data.data) {
               var detail = userDetail.data.data
               var grade = this.currentGrade.find(item => item.value == detail.currentGrade)
               var cls = this.classList.find(item => item.value == detail.currentClass)
               this.stu = {
                 username: detail.username, // 姓名
-                sex: detail.sex, // 性别
+                sex: detail.sex ? 1 : 0, // 性别
                 phone: detail.phone, // 电话
                 currentGrade: grade.text, // 年级
                 currentGradeNum: detail.currentGrade, // 年级编号
@@ -515,7 +515,7 @@
         },
         onConfirm(options) {
           var stu = this.stu
-          console.log(options)
+          // console.log(options)
           if (this.pickerType == 'grade') {
             stu.currentGrade = options.selectedOptions[0].text
             stu.currentGradeNum = options.selectedOptions[0].value

+ 3 - 0
public/project/schoolRegister.html

@@ -173,6 +173,7 @@
             name: null,
             cityCode: null,
             cityCodeName: '',
+            provinceCode: null,
             schoolSystem: null,
             schoolNature: null,
             email: null,
@@ -258,6 +259,8 @@
           const selectedOptions = val.selectedOptions[1]
           this.forms.cityCode = selectedOptions.code
           this.forms.cityCodeName = selectedOptions.name
+          const selectedFirst = val.selectedOptions[0]
+          this.forms.provinceCode = selectedFirst.code
           this.showPicker = false
         }
       }

+ 4 - 4
src/components/o-img-code/index.module.less

@@ -4,7 +4,7 @@
   .codeTitle {
     text-align: center;
     font-size: 16px;
-    color: #4F4F4F;
+    color: #4f4f4f;
     margin: 0;
     padding-bottom: 16px;
   }
@@ -17,14 +17,14 @@
 
   .imgChange {
     display: block;
-    color: #AAAAAA;
+    color: #aaaaaa;
     font-size: 12px;
     text-align: center;
     padding-top: 5px;
   }
 
   .field {
-    background: #F4F4F4;
+    background: #f4f4f4;
     padding: 10px 12px !important;
   }
 }
@@ -32,7 +32,7 @@
 .imgCodePopup {
   width: 90%;
   border-radius: 5px;
-  overflow: inherit;
+  overflow: initial;
 
   :global {
     .van-popup__close-icon {

+ 6 - 0
src/constant/index.ts

@@ -99,3 +99,9 @@ export const courseEmnu = {
   MUSIC_THEORY: '乐理',
   INSTRUMENTAL_ENSEMBLE: '合奏'
 }
+
+// 乐团状态
+export const orchestraType = {
+  DELIVERY: '交付团',
+  PROMOTION: '晋升团'
+}

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

@@ -14,6 +14,13 @@ const noLoginRouter = [{
   meta: {
     title: '乐团伴学老师注册'
   }
+}, {
+  path: '/manage-teacher-register',
+  name: 'manage-teacher-register',
+  component: () => import('@/school/manage-teacher/manage-teacher-register'),
+  meta: {
+    title: '乐团管理老师注册'
+  }
 }]
 
 export default [
@@ -96,6 +103,13 @@ export default [
           title: '伴学老师详情'
         }
       }, {
+        path: '/companion-unbind',
+        name: 'companion-unbind',
+        component: () => import('@/school/companion-teacher/unbind'),
+        meta: {
+          title: '课程交接'
+        }
+      }, {
         path: '/manage-teacher',
         name: 'manage-teacher',
         component: () => import('@/school/manage-teacher/index'),

+ 107 - 0
src/school/companion-teacher/companion-detail.module.less

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

+ 176 - 26
src/school/companion-teacher/companion-detail.tsx

@@ -1,23 +1,101 @@
 import OHeader from '@/components/o-header'
-import { Button, Cell, CellGroup, Grid, GridItem, Image, Tag } from 'vant'
-import { defineComponent, onMounted } from 'vue'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Grid,
+  GridItem,
+  Icon,
+  Image,
+  Popup,
+  showDialog,
+  showToast,
+  Tag
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
 import styles from './companion-detail.module.less'
-
+import { postMessage } from '@/helpers/native-message'
 import iconTeacher from '@common/images/icon_teacher.png'
 import iconMessage from '@common/images/icon-message.png'
+import iconCallPhone from '@common/images/icon-call-phone.png'
+import iconCallMessage from '@common/images/icon-call-message.png'
 import OSticky from '@/components/o-sticky'
 import request from '@/helpers/request'
-import { useRoute } from 'vue-router'
+import { state as baseState } from '@/state'
+import { useRoute, useRouter } from 'vue-router'
+import OEmpty from '@/components/o-empty'
 
 export default defineComponent({
   name: 'companion-detail',
   setup(props, { slots, attrs, emit }) {
     const route = useRoute()
+    const router = useRouter()
+    const state = reactive({
+      showMessage: false,
+      detail: {} as any,
+      classList: [] as any
+    })
     const getDetail = async () => {
       try {
         const query = route.query
-        const { data } = await request.get('/api-school/teacher/detail/' + query.id)
-        console.log(data)
+        const { data } = await request.post('/api-school/teacher/detail', {
+          data: {
+            teacherId: query.id,
+            schoolId: baseState.user.data.school.id
+          }
+        })
+        state.detail = data
+        const subjects = data.subjectName ? data.subjectName.split(',') : []
+        state.detail.subjectNames = subjects
+      } catch {
+        //
+      }
+    }
+
+    const getClassDetail = async () => {
+      try {
+        const query = route.query
+        const { data } = await request.post('/api-school/classGroup/page', {
+          data: {
+            teacherId: query.id,
+            schoolId: baseState.user.data.school.id,
+            page: 1,
+            rows: 100
+          }
+        })
+        state.classList = data.rows || []
+      } catch {
+        //
+      }
+    }
+
+    const onDetail = async () => {
+      if (state.classList.length > 0) {
+        router.push({
+          path: '/companion-unbind',
+          query: { id: route.query.id }
+        })
+        return
+      }
+
+      try {
+        showDialog({
+          title: '提示',
+          message: '是否解除绑定',
+          showCancelButton: true
+        }).then(async () => {
+          await request.post('/api-school/classGroup/handoverTeacher', {
+            data: {
+              teacherId: route.query.id
+            }
+          })
+          setTimeout(() => {
+            showToast('解绑成功')
+          }, 100)
+          setTimeout(() => {
+            router.back()
+          }, 1000)
+        })
       } catch {
         //
       }
@@ -25,6 +103,7 @@ export default defineComponent({
 
     onMounted(() => {
       getDetail()
+      getClassDetail()
     })
     return () => (
       <>
@@ -33,27 +112,37 @@ export default defineComponent({
         <CellGroup inset class={styles.detailCellGroup}>
           <Cell center class={styles.detailCell}>
             {{
-              icon: () => (
-                <Image
-                  class={styles.img}
-                  src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-                />
-              ),
+              icon: () => <Image class={styles.img} src={state.detail.avatar || iconTeacher} />,
               title: () => (
                 <div class={styles.teacherContent}>
                   <div class={styles.content}>
-                    <p class={[styles.name, 'van-ellipsis']}>121212</p>
-                    <p class={styles.subjects}>
-                      <Tag type="primary">{'1212'}</Tag>
-                    </p>
+                    <p class={[styles.name, 'van-ellipsis']}>{state.detail.nickname}</p>
+                    {state.detail.subjectName ? (
+                      <p class={styles.subjects}>
+                        {state.detail.subjectNames.map((subject: any) => (
+                          <Tag type="primary">{subject}</Tag>
+                        ))}
+                      </p>
+                    ) : (
+                      ''
+                    )}
                   </div>
                   <div class={styles.classNum}>
-                    <p class={styles.num}>1/1212</p>
+                    <p class={styles.num}>
+                      {state.detail.completedCourseScheduleNum || 0}/
+                      {state.detail.totalCourseScheduleNum || 0}
+                    </p>
                     <p class={styles.numText}>课时</p>
                   </div>
                 </div>
               ),
-              value: () => <Image class={styles.messageImg} src={iconMessage} />
+              value: () => (
+                <Image
+                  class={styles.messageImg}
+                  src={iconMessage}
+                  onClick={() => (state.showMessage = true)}
+                />
+              )
             }}
           </Cell>
         </CellGroup>
@@ -64,9 +153,9 @@ export default defineComponent({
         </div>
 
         <CellGroup inset class={styles.detailCellGroup}>
-          <Cell title="手机号码" value="13000000001"></Cell>
-          <Cell title="性别" value="女"></Cell>
-          <Cell title="声部" value="长笛"></Cell>
+          <Cell title="手机号码" value={state.detail.phone}></Cell>
+          <Cell title="性别" value={state.detail.gender ? '男' : '女'}></Cell>
+          <Cell title="声部" value={state.detail.subjectName}></Cell>
         </CellGroup>
 
         <div class={styles.sectionTitle}>
@@ -74,33 +163,94 @@ export default defineComponent({
           所在班级
         </div>
         <CellGroup inset class={styles.detailCellGroup}>
-          {[1, 2, 3, 4, 5, 6].map((i) => (
+          {state.classList.map((item: any) => (
             <Cell center class={styles.companionCell}>
               {{
                 title: () => (
                   <div class={styles.classInfo}>
-                    <p class={styles.className}>长笛班</p>
-                    <p class={styles.musicName}>武汉小学2022校团</p>
+                    <p class={styles.className}>{item.name}</p>
+                    <p class={styles.musicName}>{item.orchestraName}</p>
                   </div>
                 ),
                 value: () => (
                   <div class={styles.num}>
-                    <p class={styles.nums}>10/16</p>
+                    <p class={styles.nums}>
+                      {item.completeCourseScheduleNum}/{item.courseScheduleNum}
+                    </p>
                     <p class={styles.numTip}>总课时</p>
                   </div>
                 )
               }}
             </Cell>
           ))}
+          {state.classList.length <= 0 && <OEmpty btnStatus={false} tips="暂无班级" />}
         </CellGroup>
 
         <OSticky position="bottom">
           <div class={['btnGroup']} style={{ paddingLeft: '13px', paddingRight: '13px' }}>
-            <Button type="primary" round block>
+            <Button type="primary" round block onClick={onDetail}>
               解除绑定
             </Button>
           </div>
         </OSticky>
+
+        <Popup
+          v-model:show={state.showMessage}
+          position="bottom"
+          style={{ background: 'transparent' }}
+          safeAreaInsetBottom={true}
+        >
+          <div class={styles.codeContainer}>
+            <div class={styles.codeBottom}>
+              <Icon
+                name="cross"
+                size={22}
+                class={styles.close}
+                color="#666"
+                onClick={() => (state.showMessage = false)}
+              />
+
+              <h3 class={styles.title}>
+                <i></i>联系方式
+              </h3>
+              <Grid columnNum={2} border={false}>
+                <GridItem
+                  onClick={() => {
+                    postMessage({
+                      api: 'joinChatGroup',
+                      content: {
+                        type: 'single', // single 单人 multi 多人
+                        id: state.detail.id
+                      }
+                    })
+                    state.showMessage = false
+                  }}
+                >
+                  {{
+                    icon: () => <Image class={styles.shareImg} src={iconCallMessage} />,
+                    text: () => <div class={styles.shareText}>发送消息</div>
+                  }}
+                </GridItem>
+                <GridItem
+                  onClick={() => {
+                    postMessage({
+                      api: 'callPhone',
+                      content: {
+                        id: state.detail.phone
+                      }
+                    })
+                    state.showMessage = false
+                  }}
+                >
+                  {{
+                    icon: () => <Image class={styles.shareImg} src={iconCallPhone} />,
+                    text: () => <div class={styles.shareText}>拨打电话</div>
+                  }}
+                </GridItem>
+              </Grid>
+            </div>
+          </div>
+        </Popup>
       </>
     )
   }

+ 8 - 9
src/school/companion-teacher/companion-teacher-register.module.less

@@ -46,11 +46,15 @@ span {
     }
 
     .van-form {
-      margin-top: 194px;
+      margin-top: 174px;
       /* background: #F8F8F8; */
       overflow: hidden;
       /* margin: 290px 13px 14px; */
     }
+
+    .van-tag + .van-tag {
+      margin-left: 8px;
+    }
   }
 }
 
@@ -60,6 +64,9 @@ span {
   font-size: 0;
 }
 
+.radioSection + .radioSection {
+  margin-left: 12px;
+}
 .btn-submit {
   width: 90%;
   margin: 20px auto;
@@ -138,10 +145,6 @@ span {
   opacity: 0;
 }
 
-.radioSection + .radioSection {
-  margin-left: 12px;
-}
-
 .van-picker__confirm {
   color: #f67146 !important;
 }
@@ -212,10 +215,6 @@ span {
   color: #ffffff;
 }
 
-.van-tag + .van-tag {
-  margin-left: 8px;
-}
-
 .protocol {
   display: flex;
   align-items: center;

+ 7 - 6
src/school/companion-teacher/companion-teacher-register.tsx

@@ -18,7 +18,7 @@ import {
   Popup,
   CountDown
 } from 'vant'
-import { defineComponent, nextTick, onMounted, reactive } from 'vue'
+import { defineComponent, onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'
 import styles from './companion-teacher-register.module.less'
 import ImgCode from '@/components/o-img-code'
@@ -58,7 +58,7 @@ export default defineComponent({
       checked: true,
       columnSubject: [] as any,
       countDownStatus: true, // 是否发送验证码
-      countDownTime: 10, // 倒计时时间
+      countDownTime: 120, // 倒计时时间
       countDownRef: null as any, // 倒计时实例
       imgCodeStatus: false
     })
@@ -78,8 +78,9 @@ export default defineComponent({
             schoolId: state.id
           }
         })
+        state.submitStatus = true
       } catch {
-        showToast('保存失败,请重试')
+        // showToast('保存失败,请重试')
       }
       state.btnLoading = false
     }
@@ -228,9 +229,9 @@ export default defineComponent({
               required
               label="手机号码"
               v-model={state.forms.phone}
-              rules={[{ required: true, message: '请输入学校手机号码' }]}
+              rules={[{ required: true, message: '请输入手机号码' }]}
               name="phone"
-              placeholder="请输入学校手机号码"
+              placeholder="请输入手机号码"
             ></Field>
             <Field
               required
@@ -262,7 +263,7 @@ export default defineComponent({
             </Field>
             <div class={styles.phoneTips}>
               <Icon name="warning" size="16" />
-              提示:手机号码将成为您管乐团管理端登录账
+              提示:手机号码将成为您管乐团管理端登录账
             </div>
 
             <Field

+ 23 - 0
src/school/companion-teacher/compontent/teacher.module.less

@@ -0,0 +1,23 @@
+.name {
+  font-size: 16px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 22px;
+  max-width: 270px;
+}
+
+.img {
+  width: 48px;
+  height: 48px;
+  overflow: hidden;
+  border-radius: 50%;
+  margin-right: 10px;
+}
+
+.subjects {
+  :global {
+    .van-tag + .van-tag {
+      margin-left: 6px;
+    }
+  }
+}

+ 127 - 0
src/school/companion-teacher/compontent/teacher.tsx

@@ -0,0 +1,127 @@
+import OHeader from '@/components/o-header'
+import OSearch from '@/components/o-search'
+import OSticky from '@/components/o-sticky'
+import { Cell, Image, List, Tag } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './teacher.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import OEmpty from '@/components/o-empty'
+
+export default defineComponent({
+  name: 'teacher',
+  emits: ['close', 'select'],
+  setup(props, { slots, attrs, emit }) {
+    const form = reactive({
+      schoolId: null,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        keyword: null,
+        page: 1,
+        rows: 20
+      },
+      selectItem: {} as any
+    })
+
+    const getList = async () => {
+      try {
+        const res = await request.post('/api-school/teacher/page', {
+          data: {
+            ...form.params,
+            schoolId: state.user.data.school.id
+          }
+        })
+        form.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (form.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        rows.forEach((item: any) => {
+          item.subjectNames = item.subjectName ? item.subjectName.split(',') : []
+        })
+        form.list = form.list.concat(rows)
+        form.listState.finished = result.current >= result.pages
+        form.params.page = result.current + 1
+        form.listState.dataShow = form.list.length > 0
+      } catch {
+        form.listState.dataShow = false
+        form.listState.finished = true
+      }
+    }
+
+    const onSearch = () => {
+      form.params.page = 1
+      form.list = []
+      form.listState.dataShow = true // 判断是否有数据
+      form.listState.loading = false
+      form.listState.finished = false
+      getList()
+    }
+
+    // 选择老师
+    const onSelectTeacher = (item: any) => {
+      emit('select', item)
+      emit('close')
+    }
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <>
+        <OSticky position="top">
+          <OHeader title="交接老师" />
+          <OSearch
+            placeholder="请输入老师姓名"
+            inputBackground="white"
+            background="#F8F8F8"
+            onSearch={(val: any) => {
+              form.params.keyword = val
+              onSearch()
+            }}
+          />
+        </OSticky>
+        {form.listState.dataShow ? (
+          <List
+            v-model:loading={form.listState.loading}
+            finished={form.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            {form.list.map((item: any) => (
+              <Cell onClick={() => onSelectTeacher(item)}>
+                {{
+                  icon: () => <Image class={styles.img} src={item.avatar || iconTeacher} />,
+                  title: () => (
+                    <div class={styles.content}>
+                      <p class={[styles.name, 'van-ellipsis']}>{item.nickname}</p>
+
+                      <p class={styles.subjects}>
+                        {item.subjectNames &&
+                          item.subjectNames.length > 0 &&
+                          item.subjectNames.map((subject: any) => (
+                            <Tag type="primary">{subject}</Tag>
+                          ))}
+                      </p>
+                    </div>
+                  )
+                }}
+              </Cell>
+            ))}
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无伴学老师" />
+        )}
+      </>
+    )
+  }
+})

+ 13 - 4
src/school/companion-teacher/index.tsx

@@ -79,7 +79,7 @@ export default defineComponent({
         form.schoolId = res.data.schoolId
         form.url =
           location.origin +
-          '/orchestra-school/companionTeacher.html?id=' +
+          '/orchestra-school/#/companion-teacher-register?id=' +
           res.data.schoolId +
           '&name=' +
           res.data.schoolName
@@ -92,7 +92,8 @@ export default defineComponent({
       try {
         const res = await request.post('/api-school/teacher/page', {
           data: {
-            ...form.params
+            ...form.params,
+            schoolId: state.user.data.school.id
           }
         })
         form.listState.loading = false
@@ -101,7 +102,11 @@ export default defineComponent({
         if (form.list.length > 0 && result.pageNo === 1) {
           return
         }
-        form.list = form.list.concat(result.rows || [])
+        const rows = result.rows || []
+        rows.forEach((item: any) => {
+          item.subjectNames = item.subjectName ? item.subjectName.split(',') : []
+        })
+        form.list = form.list.concat(rows)
         form.listState.finished = result.current >= result.pages
         form.params.page = result.current + 1
         form.listState.dataShow = form.list.length > 0
@@ -195,7 +200,11 @@ export default defineComponent({
                       <div class={styles.content}>
                         <p class={[styles.name, 'van-ellipsis']}>{item.nickname}</p>
                         <p class={styles.subjects}>
-                          {item.subjectName && <Tag type="primary">{item.subjectName}</Tag>}
+                          {item.subjectNames &&
+                            item.subjectNames.length > 0 &&
+                            item.subjectNames.map((subject: any) => (
+                              <Tag type="primary">{subject}</Tag>
+                            ))}
                         </p>
                       </div>
                       <div class={styles.classNum}>

+ 74 - 0
src/school/companion-teacher/unbind.module.less

@@ -0,0 +1,74 @@
+.unbindTips {
+  font-size: 13px;
+  padding: 10px 12px;
+  font-weight: 500;
+  color: #f67146;
+  line-height: 18px;
+  background: #ffebdd;
+  border-radius: 10px;
+  margin: 12px 13px;
+}
+
+.detailCellGroup {
+  margin: 12px 13px;
+  overflow: hidden;
+  border-radius: 10px;
+}
+
+.detailCell {
+  padding: 15px 13px;
+
+  :global {
+    .van-cell__title {
+      flex: 1 auto;
+      flex-basis: 48%;
+    }
+  }
+
+  .teacherName {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+  }
+
+  .teacherContent {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+
+    .content {
+      width: 70px;
+    }
+
+    .classNum {
+      text-align: center;
+      width: 60px;
+    }
+  }
+
+  .className {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 22px;
+  }
+  .musicName {
+    font-size: 14px;
+    color: #777777;
+    line-height: 20px;
+  }
+
+  .nums {
+    font-size: 20px;
+    font-weight: bold;
+    color: #f67146;
+    line-height: 24px;
+  }
+
+  .numTip {
+    font-size: 14px;
+    color: #777777;
+    line-height: 20px;
+  }
+}

+ 145 - 0
src/school/companion-teacher/unbind.tsx

@@ -0,0 +1,145 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import { Button, Cell, CellGroup, Image, showDialog, showToast } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './unbind.module.less'
+import { state as baseState } from '@/state'
+import { useRoute, useRouter } from 'vue-router'
+import request from '@/helpers/request'
+import OPopup from '@/components/o-popup'
+import Teacher from './compontent/teacher'
+
+export default defineComponent({
+  name: 'unbind',
+  setup() {
+    const route = useRoute()
+    const router = useRouter()
+    const state = reactive({
+      teacherStatus: false,
+      classList: [] as any,
+      selectTeacher: {} as any
+    })
+    const getClassDetail = async () => {
+      try {
+        const query = route.query
+        const { data } = await request.post('/api-school/classGroup/page', {
+          data: {
+            teacherId: query.id,
+            schoolId: baseState.user.data.school.id,
+            page: 1,
+            rows: 100
+          }
+        })
+        state.classList = data.rows || []
+      } catch {
+        //
+      }
+    }
+
+    // 选择交接老师
+    const onSelectTeacher = (item: any) => {
+      state.teacherStatus = true
+      state.selectTeacher = item
+    }
+    // 选择了交接老师之后
+    const onSelectItem = (item: any) => {
+      console.log(item, 'steacher')
+      state.selectTeacher.sTeacher = item
+    }
+
+    const onSubmit = () => {
+      console.log('submit')
+      let isSelectAll = false // 是否有没有选择交接老师的数据
+      const courseInfo = [] as any
+      state.classList.forEach((item: any) => {
+        if (!item.sTeacher || (item.sTeacher && !item.sTeacher.id)) {
+          isSelectAll = true
+        }
+
+        if (item.sTeacher) {
+          courseInfo.push({
+            classGroupId: item.id,
+            teacherId: item.sTeacher.id
+          })
+        }
+      })
+
+      if (isSelectAll) {
+        showToast('请选择交接老师')
+        return
+      }
+
+      try {
+        showDialog({
+          title: '提示',
+          message: '是否确认交接',
+          showCancelButton: true
+        }).then(async () => {
+          await request.post('/api-school/classGroup/handoverTeacher', {
+            data: {
+              teacherId: route.query.id,
+              updateTeacherList: [...courseInfo]
+            }
+          })
+          setTimeout(() => {
+            showToast('交接成功')
+          }, 100)
+          setTimeout(() => {
+            router.replace('/companion-teacher')
+          }, 1000)
+        })
+      } catch {
+        //
+      }
+    }
+
+    onMounted(() => {
+      getClassDetail()
+    })
+    return () => (
+      <>
+        <OHeader />
+
+        <div class={styles.unbindTips}>该伴学老师存在以下班级及课程未开始,请选择交接老师</div>
+
+        <CellGroup inset class={styles.detailCellGroup}>
+          {state.classList.map((item: any) => (
+            <Cell center class={styles.detailCell} isLink onClick={() => onSelectTeacher(item)}>
+              {{
+                title: () => (
+                  <div class={styles.teacherContent}>
+                    <div class={styles.classInfo}>
+                      <p class={styles.className}>{item.name}</p>
+                      <p class={styles.musicName}>{item.orchestraName}</p>
+                    </div>
+                    <div class={styles.classNum}>
+                      <p class={styles.nums}>
+                        {item.courseScheduleNum - item.completeCourseScheduleNum}
+                      </p>
+                      <p class={styles.numTip}>剩余课时</p>
+                    </div>
+                  </div>
+                ),
+                value: () => (
+                  <span class={styles.teacherName}>{item.sTeacher && item.sTeacher.nickname}</span>
+                )
+              }}
+            </Cell>
+          ))}
+        </CellGroup>
+
+        <OSticky position="bottom">
+          <div class={['btnGroup']} style={{ paddingLeft: '13px', paddingRight: '13px' }}>
+            <Button type="primary" round block onClick={onSubmit}>
+              确认交接
+            </Button>
+          </div>
+        </OSticky>
+
+        <OPopup v-model:modelValue={state.teacherStatus}>
+          <Teacher onClose={() => (state.teacherStatus = false)} onSelect={onSelectItem} />
+        </OPopup>
+      </>
+    )
+  }
+})

+ 0 - 0
src/school/companion-teacher/images/banner.png → src/school/manage-teacher/images/banner.png


BIN
src/school/manage-teacher/images/icon-close.png


BIN
src/school/manage-teacher/images/school-logo.png


+ 0 - 0
src/school/companion-teacher/images/top-banner.png → src/school/manage-teacher/images/top-banner.png


+ 3 - 2
src/school/manage-teacher/index.tsx

@@ -48,7 +48,7 @@ export default defineComponent({
         form.schoolId = res.data.schoolId
         form.url =
           location.origin +
-          '/orchestra-school/project/manageTeacher.html?id=' +
+          '/orchestra-school/#/manage-teacher-register?id=' +
           res.data.schoolId +
           '&name=' +
           res.data.schoolName
@@ -61,7 +61,8 @@ export default defineComponent({
       try {
         const res = await request.post('/api-school/schoolStaff/page', {
           data: {
-            ...form.params
+            ...form.params,
+            schoolId: state.user.data.school.id
           }
         })
         form.listState.loading = false

+ 239 - 0
src/school/manage-teacher/manage-teacher-register.module.less

@@ -0,0 +1,239 @@
+html,
+body,
+p,
+div,
+span {
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+.van-field--error .van-field__control,
+.van-field--error .van-field__control::placeholder {
+  color: #c8c9cc;
+  -webkit-text-fill-color: currentColor;
+}
+
+.register {
+  background: url('./images/banner.png') no-repeat top center #f8f8f8;
+  background-size: contain;
+  max-width: 750px;
+  margin: 0 auto;
+  min-height: 100vh;
+  overflow: hidden;
+
+  :global {
+    .van-cell {
+      flex-direction: column;
+      font-size: 16px;
+      padding: 14px 13px;
+    }
+
+    .van-field__label {
+      width: 100%;
+      margin-right: 0;
+      color: #333;
+      font-size: 16px;
+      font-weight: 500;
+    }
+
+    .van-cell--required::before {
+      left: 15px;
+    }
+
+    .van-field__body {
+      margin-top: 10px;
+    }
+
+    .van-form {
+      margin-top: 174px;
+      /* background: #F8F8F8; */
+      overflow: hidden;
+      /* margin: 290px 13px 14px; */
+    }
+
+    .van-tag + .van-tag {
+      margin-left: 8px;
+    }
+  }
+}
+
+.banner,
+.banner img {
+  width: 100%;
+  font-size: 0;
+}
+
+.btn-submit {
+  width: 90%;
+  margin: 20px auto;
+}
+
+.system h2 {
+  font-size: 18px;
+  font-weight: 500;
+  margin: 10px 24px;
+  color: #444444;
+}
+
+.system .van-cell--required::before {
+  left: 25px;
+}
+
+.cell-group {
+  margin: 0 13px 14px;
+  border-radius: 10px;
+  padding-bottom: 10px;
+}
+
+.top-tips {
+  margin: 30px 13px 20px;
+  padding: 9px 7px;
+  background: #ffffff;
+  border-radius: 10px;
+  border: 5px solid #be93ff;
+  font-size: 14px;
+  font-weight: 500;
+  color: #724da9;
+  line-height: 20px;
+}
+
+.title {
+  position: absolute;
+  top: 0;
+  left: 0;
+  padding: 115px 24px 0;
+  width: 57%;
+  /* height: 154px; */
+  font-size: 28px;
+  font-weight: 600;
+  color: #ffffff;
+  line-height: 34px;
+  letter-spacing: 1px;
+  /* text-shadow: 0px 2px 3px rgba(0, 75, 255, 0.5); */
+}
+
+.tips {
+  font-size: 16px;
+  font-weight: 500;
+  color: #ffffff;
+  line-height: 22px;
+  text-shadow: 0px 1px 5px #ff5e20;
+  display: flex;
+  align-items: center;
+}
+
+.tips img {
+  margin-right: 8px;
+  width: 18px;
+  height: 18px;
+}
+
+.radioSection {
+  position: relative;
+}
+
+.radioItem {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  opacity: 0;
+}
+
+.radioSection + .radioSection {
+  margin-left: 12px;
+}
+
+.van-picker__confirm {
+  color: #f67146 !important;
+}
+
+/* 弹窗 */
+.stautsS {
+  position: relative;
+}
+
+.submit-container {
+  padding: 20px 26px 26px;
+
+  text-align: center;
+}
+
+.icon-close {
+  position: absolute;
+  width: 26px;
+  height: 26px;
+  top: 12px;
+  right: 12px;
+}
+
+.submit-img {
+  width: 100%;
+}
+
+.submit-title {
+  font-size: 18px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 25px;
+}
+
+.submit-o {
+  padding-top: 10px;
+  font-size: 15px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 21px;
+}
+
+.submit-o span {
+  color: #f67146;
+}
+
+.submit-tips {
+  font-size: 14px;
+  color: #777777;
+  line-height: 20px;
+  padding-top: 5px;
+  padding-bottom: 20px;
+}
+
+.submit-container .van-button {
+  font-size: 18px;
+  font-weight: 500;
+}
+
+.cell_title {
+  margin: 0 13px 8px;
+  display: inline-block;
+  padding: 2px 6px 3px;
+  background: #64a9ff;
+  border-radius: 6px;
+  font-size: 15px;
+  font-weight: 600;
+  color: #ffffff;
+}
+
+.protocol {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  color: #aaaaaa;
+  line-height: 17px;
+}
+
+.protocol .c {
+  color: #f67146;
+}
+
+.phoneTips {
+  margin: 12px 12px 3px;
+  background: #ffebdd;
+  border-radius: 6px;
+  font-size: 13px;
+  color: #f67146;
+  padding: 9px 10px;
+}

+ 337 - 0
src/school/manage-teacher/manage-teacher-register.tsx

@@ -0,0 +1,337 @@
+import { areas } from '@/helpers/area'
+import request from '@/helpers/request'
+import {
+  CellGroup,
+  Form,
+  Field,
+  RadioGroup,
+  Tag,
+  Icon,
+  Checkbox,
+  Radio,
+  Button,
+  showToast,
+  showDialog,
+  showLoadingToast,
+  closeToast,
+  Picker,
+  Popup,
+  CountDown
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import styles from './manage-teacher-register.module.less'
+import ImgCode from '@/components/o-img-code'
+import schoolLogo from './images/school-logo.png'
+import iconClose from './images/icon-close.png'
+import topBanner1 from './images/top-banner.png'
+import { checkPhone } from '@/helpers/validate'
+
+export default defineComponent({
+  name: 'companion-teacher-register',
+
+  setup() {
+    const route = useRoute()
+    const state = reactive({
+      showPicker: false,
+      showSubject: false,
+      submitStatus: false,
+      id: route.query.id,
+      name: route.query.name,
+      pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
+      columns: [] as any,
+      pickerType: null, // 下拉类型
+      forms: {
+        realName: '',
+        phone: null,
+        gender: 1,
+        idCardNo: null,
+        smsValidCode: ''
+      },
+      btnLoading: false,
+      checkPhone: false,
+      checked: true,
+      columnSubject: [] as any,
+      countDownStatus: true, // 是否发送验证码
+      countDownTime: 120, // 倒计时时间
+      // countDownRef: null as any, // 倒计时实例
+      imgCodeStatus: false
+    })
+
+    const onSubmit = async () => {
+      if (!state.checked) {
+        showToast('请阅读并同意协议')
+        return
+      }
+      state.btnLoading = true
+      try {
+        const forms = state.forms
+        await request.post('/api-school/open/schoolTeacherStudent/registerTeacher', {
+          data: {
+            ...forms,
+            schoolId: state.id
+          }
+        })
+      } catch {
+        showToast('保存失败,请重试')
+      }
+      state.btnLoading = false
+    }
+
+    const onSendCode = () => {
+      // 发送验证码
+      if (!checkPhone(state.forms.phone as any)) {
+        return showToast('请输入正确的手机号码')
+      }
+      state.imgCodeStatus = true
+    }
+    const onCodeSend = () => {
+      state.countDownStatus = false
+      const clearTimer = setInterval(() => {
+        state.countDownTime = state.countDownTime - 1
+        if (state.countDownTime <= 0) {
+          state.countDownTime = 120
+          state.countDownStatus = true
+          clearInterval(clearTimer)
+        }
+      }, 1000)
+    }
+    const onFinished = () => {
+      state.countDownStatus = true
+      // ;(this.$refs.countDownRef as any).reset()
+    }
+
+    onMounted(async () => {
+      if (!state.id) {
+        showToast('信息获取失败,请联系老师')
+      }
+      try {
+        const tempareas: any = []
+        areas.forEach((item) => {
+          const temp = {
+            name: item.name,
+            code: item.code,
+            areas: [] as any
+          }
+          if (item.areas && item.areas.length > 0) {
+            item.areas.forEach((child) => {
+              temp.areas.push({
+                name: child.name,
+                code: child.code
+              })
+            })
+          }
+          tempareas.push(temp)
+        })
+        state.columns = tempareas || []
+
+        const { data } = await request.post('/api-school/open/subject/page', {
+          data: {
+            page: 1,
+            rows: 50
+          }
+        })
+
+        const rows = data.rows || []
+        const tempSubjects: any = []
+        rows.forEach((item) => {
+          tempSubjects.push({
+            text: item.name,
+            value: item.id
+          })
+        })
+        state.columnSubject = tempSubjects
+      } catch {
+        showDialog({
+          message: '信息获取失败,请联系老师',
+          theme: 'round-button',
+          confirmButtonColor: '#64A9FF'
+        })
+      }
+    })
+
+    return () => (
+      <div class={styles.register}>
+        <div class={styles.title}>
+          <p class={styles.tips}>
+            <img src={schoolLogo} />
+            <span>{state.name}</span>
+          </p>
+        </div>
+        <Form validateFirst scrollToError onSubmit={onSubmit} ref="form" class={styles.form}>
+          <CellGroup inset class={styles['cell-group']}>
+            <Field
+              required
+              label="真实姓名"
+              v-model={state.forms.realName}
+              rules={[{ required: true, message: '请填写真实姓名' }]}
+              name="realName"
+              placeholder="请填写真实姓名"
+              maxlength="50"
+            ></Field>
+
+            <Field
+              required
+              label="手机号码"
+              v-model={state.forms.phone}
+              rules={[{ required: true, message: '请输入手机号码' }]}
+              name="phone"
+              placeholder="请输入手机号码"
+            ></Field>
+            <Field
+              required
+              label="验证码"
+              v-model={state.forms.smsValidCode}
+              name="smsValidCode"
+              rules={[{ required: true, message: '请选择声部', trigger: 'onChange' }]}
+              placeholder="请输入验证码"
+            >
+              {{
+                button: () =>
+                  state.countDownStatus ? (
+                    <Button type="primary" round size="small" color="#64A9FF" onClick={onSendCode}>
+                      发送验证码
+                    </Button>
+                  ) : (
+                    <Button
+                      type="default"
+                      round
+                      size="small"
+                      disabled
+                      style={{ minWidth: '60px' }}
+                      onClick={onSendCode}
+                    >
+                      {state.countDownTime + 's'}
+                    </Button>
+                  )
+              }}
+            </Field>
+            <div class={styles.phoneTips}>
+              <Icon name="warning" size="16" />
+              提示:手机号码将成为您管乐团管理端登录账号
+            </div>
+
+            <Field
+              required
+              label="身份证号码"
+              v-model={state.forms.idCardNo}
+              rules={[
+                { required: true, message: '请输入身份证号' },
+                {
+                  pattern:
+                    /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
+                  message: '请输入正确的身份证号'
+                }
+              ]}
+              name="idCardNo"
+              placeholder="请输入身份证号码"
+            ></Field>
+
+            <Field
+              required
+              label="性别"
+              name="gender"
+              rules={[{ required: true, message: '请选择性别' }]}
+            >
+              {{
+                input: () => (
+                  <RadioGroup
+                    checked-color="#64A9FF"
+                    v-model={state.forms.gender}
+                    direction="horizontal"
+                  >
+                    <Tag
+                      size="large"
+                      type="primary"
+                      plain={!(state.forms.gender === 1)}
+                      color="#64A9FF"
+                      class={styles.radioSection}
+                    >
+                      <Radio class={styles.radioItem} name={1}></Radio>男
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      plain={!(state.forms.gender === 0)}
+                      color="#64A9FF"
+                      class={styles.radioSection}
+                    >
+                      <Radio class={styles.radioItem} name={0}></Radio>女
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+          </CellGroup>
+
+          <div class={styles.protocol}>
+            <Checkbox
+              v-model={state.checked}
+              icon-size="16"
+              style="margin-right: 6px"
+              checked-color="#64A9FF"
+            ></Checkbox>
+            <span
+              onClick={() => {
+                state.checked = !state.checked
+              }}
+            >
+              请认真阅读并勾选
+            </span>
+            <span class={styles.c}>《乐团伴学老师注册协议》</span>
+          </div>
+
+          <Button
+            size="large"
+            block
+            round
+            class={styles['btn-submit']}
+            color="#64A9FF"
+            loading={state.btnLoading}
+            native-type="submit"
+          >
+            完成
+          </Button>
+        </Form>
+
+        <Popup v-model:show={state.submitStatus} round style="width: 75%" closeOnClickOverlay>
+          <div class={styles.stautsS}>
+            <img
+              class={styles['icon-close']}
+              src={iconClose}
+              onClick={() => (state.submitStatus = false)}
+            />
+            <img src={topBanner1} class={styles['submit-img']} />
+            <div class={styles['submit-container']}>
+              <p class={styles['submit-title']}>恭喜您已成功登记为</p>
+              <p class={styles['submit-o']}>
+                {state.name} <span>【管理老师】</span>
+              </p>
+              <p class={styles['submit-tips']}>请下载管乐团管理端APP进行授课</p>
+              <Button
+                type="primary"
+                color="#64A9FF"
+                block
+                round
+                onClick={() => (state.submitStatus = false)}
+              >
+                立即下载
+              </Button>
+            </div>
+          </div>
+        </Popup>
+
+        {state.imgCodeStatus ? (
+          <ImgCode
+            v-model:value={state.imgCodeStatus}
+            phone={state.forms.phone as any}
+            onClose={() => {
+              state.imgCodeStatus = false
+            }}
+            onSendCode={onCodeSend}
+          />
+        ) : null}
+      </div>
+    )
+  }
+})

+ 9 - 5
src/school/orchestra/compontent/information.tsx

@@ -12,9 +12,13 @@ export default defineComponent({
     const state = reactive({
       showPopover: false,
       actions: [
-        { text: '全部乐团', color: 'var(--van-primary-color)' },
-        { text: '交付团' },
-        { text: '晋升团' }
+        { text: '全部乐团', color: 'var(--van-primary-color)', value: 'ALL' },
+        { text: '交付团', value: 'DELIVERY' },
+        { text: '晋升团', value: 'PROMOTION' }
+      ],
+      actionTerm: [
+        { text: '上学期', color: 'var(--van-primary-color)', value: 'ALL' },
+        { text: '下学期', value: 'DELIVERY' }
       ],
       oPopover: false,
       check: [],
@@ -42,7 +46,7 @@ export default defineComponent({
           </Popover>
           <Popover
             v-model:show={state.oPopover}
-            actions={state.actions}
+            actions={state.actionTerm}
             showArrow={false}
             placement="bottom"
             offset={[0, 12]}
@@ -51,7 +55,7 @@ export default defineComponent({
             {{
               reference: () => (
                 <div class={styles.searchBand} style="margin-left: 16px">
-                  武汉小学2022预备团 <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
+                  上学期 <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
                 </div>
               )
             }}

+ 83 - 25
src/school/orchestra/index.tsx

@@ -1,23 +1,63 @@
 import OHeader from '@/components/o-header'
 import OSticky from '@/components/o-sticky'
-import { Cell, Icon, Popover, Tag } from 'vant'
-import { defineComponent, reactive } from 'vue'
+import request from '@/helpers/request'
+import { Cell, Icon, List, Popover, Tag } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
 import { useRouter } from 'vue-router'
 import styles from './index.module.less'
+import { state } from '@/state'
+import OEmpty from '@/components/o-empty'
+import { orchestraType } from '@/constant'
 
 export default defineComponent({
   name: 'my-orchestra',
   setup() {
     const router = useRouter()
-    const state = reactive({
+    const form = reactive({
       showPopover: false,
       actions: [
         { text: '全部乐团', color: 'var(--van-primary-color)' },
         { text: '交付团' },
         { text: '晋升团' }
-      ]
+      ],
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        keyword: null,
+        status: null,
+        page: 1,
+        rows: 20
+      }
     })
 
+    const getList = async () => {
+      try {
+        const res = await request.post('/api-school/orchestra/page', {
+          data: {
+            ...form.params,
+            schoolId: state.user.data.school.id
+          }
+        })
+        form.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (form.list.length > 0 && result.current === 1) {
+          return
+        }
+        form.list = form.list.concat(result.rows || [])
+        form.listState.finished = result.current >= result.pages
+        form.params.page = result.current + 1
+        form.listState.dataShow = form.list.length > 0
+      } catch {
+        form.listState.dataShow = false
+        form.listState.finished = true
+      }
+    }
+
     const onDetail = (item: any) => {
       console.log(item)
       router.push({
@@ -27,6 +67,10 @@ export default defineComponent({
         }
       })
     }
+
+    onMounted(() => {
+      getList()
+    })
     return () => (
       <>
         <OSticky position="top">
@@ -46,8 +90,8 @@ export default defineComponent({
           </OHeader>
           <div style={{ padding: '12px 13px', background: '#F8F8F8' }}>
             <Popover
-              v-model:show={state.showPopover}
-              actions={state.actions}
+              v-model:show={form.showPopover}
+              actions={form.actions}
               showArrow={false}
               placement="bottom-start"
               offset={[0, 12]}
@@ -55,7 +99,7 @@ export default defineComponent({
               {{
                 reference: () => (
                   <div class={styles.searchBand}>
-                    全部乐团 <Icon name={state.showPopover ? 'arrow-up' : 'arrow-down'} />
+                    全部乐团 <Icon name={form.showPopover ? 'arrow-up' : 'arrow-down'} />
                   </div>
                 )
               }}
@@ -63,24 +107,38 @@ export default defineComponent({
           </div>
         </OSticky>
 
-        {[1, 2, 3, 4, 5, 6].map((item: any) => (
-          <Cell isLink center class={styles.oCell} onClick={() => onDetail(item)}>
-            {{
-              title: () => (
-                <div class={styles.oTitle}>
-                  武汉小学2022上学期团
-                  {/* <Tag style={{ marginLeft: '6px' }} type="primary">
-                    交付团
-                  </Tag> */}
-                  <Tag style={{ marginLeft: '6px' }} color="#64A9FF">
-                    晋升团
-                  </Tag>
-                </div>
-              ),
-              label: () => <p>学生人数:65人</p>
-            }}
-          </Cell>
-        ))}
+        {form.listState.dataShow ? (
+          <List
+            v-model:loading={form.listState.loading}
+            finished={form.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            {form.list.map((item: any) => (
+              <Cell isLink center class={styles.oCell} onClick={() => onDetail(item)}>
+                {{
+                  title: () => (
+                    <div class={styles.oTitle}>
+                      {item.name}
+
+                      <Tag
+                        style={{ marginLeft: '6px' }}
+                        color={item.type === 'DELIVERY' ? '#FF8057' : '#64A9FF'}
+                      >
+                        {orchestraType[item.type]}
+                      </Tag>
+                    </div>
+                  ),
+                  label: () => <p>学生人数:{item.currentStudentNum}人</p>
+                }}
+              </Cell>
+            ))}
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无乐团" />
+        )}
       </>
     )
   }

+ 1 - 1
src/school/orchestra/orchestra-detail.tsx

@@ -10,7 +10,7 @@ import styles from './orchestra-detail.module.less'
 export default defineComponent({
   name: 'orchestra-detail',
   setup() {
-    const tabValue = ref('phone')
+    const tabValue = ref('information')
     return () => (
       <div class={styles.orchestraDetail}>
         <OSticky position="top">

+ 5 - 0
src/views/layout/auth.tsx

@@ -48,6 +48,11 @@ export default defineComponent({
             initRequest: true, // 初始化接口
             requestType: 'form'
           })
+          // 初始化学校信息
+          if (state.platformType === 'SCHOOL') {
+            const schoolInfo = res.data.schoolInfos ? res.data.schoolInfos[0] : {}
+            res.data.school = schoolInfo
+          }
           setLogin(res.data)
         } catch (e: any) {
           // console.log(e, 'e')

+ 5 - 0
src/views/layout/login.tsx

@@ -86,6 +86,11 @@ export default defineComponent({
         const userCash = await request.get(state.platformApi + '/appLoginUser/getUserInfo', {
           initRequest: true // 初始化接口
         })
+        // 初始化学校信息
+        if (state.platformType === 'SCHOOL') {
+          const schoolInfo = userCash.data.schoolInfos ? userCash.data.schoolInfos[0] : {}
+          userCash.data.school = schoolInfo
+        }
         setLogin(userCash.data)
 
         this.directNext()

+ 2 - 2
vite.config.ts

@@ -12,8 +12,8 @@ function resolve(dir: string) {
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
 // const proxyUrl = 'https://mstutest.dayaedu.com/';
-// const proxyUrl = 'http://47.98.131.38:8989/'
-const proxyUrl = 'http://192.168.3.26:8989/'
+const proxyUrl = 'http://47.98.131.38:8989/'
+// const proxyUrl = 'http://192.168.3.26:8989/'
 export default defineConfig({
   base: './',
   plugins: [