lex 2 年之前
父节点
当前提交
ebc7384e92
共有 25 个文件被更改,包括 2137 次插入145 次删除
  1. 二进制
      src/common/images/icon_student.png
  2. 二进制
      src/common/images/icon_teacher.png
  3. 27 6
      src/components/o-dialog/index.tsx
  4. 1 0
      src/school/companion-teacher/companion-teacher-register.tsx
  5. 0 5
      src/school/companion-teacher/index.tsx
  6. 57 3
      src/school/manage-teacher/index.tsx
  7. 115 0
      src/school/mass-message/component/class-list/index.module.less
  8. 268 0
      src/school/mass-message/component/class-list/index.tsx
  9. 46 0
      src/school/mass-message/component/manage-list/index.module.less
  10. 200 0
      src/school/mass-message/component/manage-list/index.tsx
  11. 46 0
      src/school/mass-message/component/student-list/index.module.less
  12. 196 0
      src/school/mass-message/component/student-list/index.tsx
  13. 46 0
      src/school/mass-message/component/teacher-list/teacher-list.module.less
  14. 218 0
      src/school/mass-message/component/teacher-list/teacher-list.tsx
  15. 535 15
      src/school/mass-message/create-message.tsx
  16. 34 0
      src/school/mass-message/index.module.less
  17. 48 8
      src/school/mass-message/index.tsx
  18. 98 0
      src/school/mass-message/select-sned.tsx
  19. 3 1
      src/school/orchestra/orchestra-information.tsx
  20. 1 3
      src/school/train-planning/modal/practice-class/index.tsx
  21. 2 2
      src/student/music-group/pre-apply/component/payment.tsx
  22. 18 5
      src/student/my-orchestra/apply-withdrawal.tsx
  23. 6 0
      src/student/my-orchestra/index.module.less
  24. 164 96
      src/student/my-orchestra/index.tsx
  25. 8 1
      src/student/trade-record/component/wait-pay.tsx

二进制
src/common/images/icon_student.png


二进制
src/common/images/icon_teacher.png


+ 27 - 6
src/components/o-dialog/index.tsx

@@ -1,5 +1,5 @@
 import { Dialog } from 'vant'
-import { defineComponent } from 'vue'
+import { defineComponent, PropType, reactive, watch } from 'vue'
 import styles from './index.module.less'
 
 export default defineComponent({
@@ -32,21 +32,42 @@ export default defineComponent({
     showCancelButton: {
       type: Boolean,
       default: false
+    },
+    messageAlign: {
+      type: String as PropType<'left' | 'center' | 'right'>,
+      default: 'center'
     }
   },
-  emits: ['cancel', 'confirm'],
+  emits: ['cancel', 'confirm', 'update:show'],
   setup(props, { slots, attrs, emit }) {
+    const state = reactive({
+      show: props.show || false
+    })
+
+    // 监听状态
+    watch(
+      () => props.show,
+      () => {
+        state.show = props.show
+      }
+    )
     return () => (
       <Dialog
-        v-model:show={props.show}
+        v-model:show={state.show}
         message={props.message}
-        messageAlign="left"
+        messageAlign={props.messageAlign}
         confirmButtonText={props.confirmButtonText}
         cancelButtonText={props.cancelButtonText}
         showConfirmButton={props.showConfirmButton}
         showCancelButton={props.showCancelButton}
-        onConfirm={() => emit('confirm')}
-        onCancel={() => emit('cancel')}
+        onConfirm={() => {
+          emit('update:show', false)
+          emit('confirm')
+        }}
+        onCancel={() => {
+          emit('update:show', false)
+          emit('cancel')
+        }}
       >
         {{
           title: () => (

+ 1 - 0
src/school/companion-teacher/companion-teacher-register.tsx

@@ -307,6 +307,7 @@ export default defineComponent({
                 }
               ]}
               name="idCardNo"
+              maxlength={18}
               placeholder="请输入身份证号码"
             ></Field>
 

+ 0 - 5
src/school/companion-teacher/index.tsx

@@ -195,16 +195,13 @@ export default defineComponent({
       }
     }
     const onShare = () => {
-      console.log('1')
       if (imgs.shareLoading) {
         return
       }
       imgs.shareLoading = true
       if (imgs.image) {
-        console.log('1')
         openShare()
       } else {
-        console.log('2')
         const container: any = document.getElementById(`preview-container`)
         html2canvas(container, {
           allowTaint: true,
@@ -214,7 +211,6 @@ export default defineComponent({
           .then(async (canvas) => {
             const url = canvas.toDataURL('image/png')
             imgs.image = url
-            console.log('4')
             openShare()
           })
           .catch(() => {
@@ -224,7 +220,6 @@ export default defineComponent({
       }
     }
     const openShare = () => {
-      console.log('5')
       const image = imgs.image
       setTimeout(() => {
         imgs.shareLoading = false

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

@@ -14,7 +14,8 @@ import {
   Popup,
   showFailToast,
   showLoadingToast,
-  showSuccessToast
+  showSuccessToast,
+  showToast
 } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
 import styles from './index.module.less'
@@ -116,8 +117,61 @@ export default defineComponent({
 
     const imgs = reactive({
       saveLoading: false,
-      image: null as any
+      image: null as any,
+      shareLoading: false
     })
+    const onShare = () => {
+      if (imgs.shareLoading) {
+        return
+      }
+      imgs.shareLoading = true
+      if (imgs.image) {
+        openShare()
+      } else {
+        const container: any = document.getElementById(`preview-container`)
+        html2canvas(container, {
+          allowTaint: true,
+          useCORS: true,
+          backgroundColor: null
+        })
+          .then(async (canvas) => {
+            const url = canvas.toDataURL('image/png')
+            imgs.image = url
+            openShare()
+          })
+          .catch(() => {
+            closeToast()
+            imgs.shareLoading = false
+          })
+      }
+    }
+    const openShare = () => {
+      const image = imgs.image
+      setTimeout(() => {
+        imgs.shareLoading = false
+      }, 100)
+      if (image) {
+        postMessage(
+          {
+            api: 'shareTripartite',
+            content: {
+              title: '',
+              desc: '',
+              image,
+              video: '',
+              type: 'image',
+              // button: ['copy']
+              shareType: 'wechat'
+            }
+          },
+          (res: any) => {
+            if (res && res.content) {
+              showToast(res.content.message || (res.content.status ? '分享成功' : '分享失败'))
+            }
+          }
+        )
+      }
+    }
     const onSaveImg = async () => {
       // 判断是否在保存中...
       if (imgs.saveLoading) {
@@ -274,7 +328,7 @@ export default defineComponent({
                     text: () => <div class={styles.shareText}>保存图片</div>
                   }}
                 </GridItem>
-                <GridItem>
+                <GridItem onClick={onShare}>
                   {{
                     icon: () => <Image class={styles.shareImg} src={iconWechat} />,
                     text: () => <div class={styles.shareText}>微信</div>

+ 115 - 0
src/school/mass-message/component/class-list/index.module.less

@@ -0,0 +1,115 @@
+.searchBand {
+  display: inline-block;
+  font-size: 14px;
+  font-weight: 600;
+  color: #333333;
+}
+
+.gridContainer {
+  margin: 0 13px 12px;
+  // background: #ffffff;
+
+  .title {
+    font-size: 26px;
+    font-weight: bold;
+    color: #333;
+    i {
+      font-style: normal;
+      font-size: 12px;
+      color: #333333;
+    }
+  }
+  .red {
+    color: #f67146;
+  }
+  .name {
+    padding-top: 8px;
+    font-size: 12px;
+    color: #777777;
+  }
+}
+
+.gridClass {
+  .img {
+    width: 40px;
+    height: 40px;
+    margin-right: 12px;
+    border-radius: 50%;
+    overflow: hidden;
+  }
+  .teacherName {
+    display: flex;
+    align-items: center;
+    font-size: 16px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 22px;
+    .name {
+      padding: 0;
+      max-width: 120px;
+    }
+    :global {
+      .van-tag {
+        margin-left: 6px;
+      }
+    }
+  }
+  .classCheckbox {
+    display: flex;
+    justify-content: flex-end;
+  }
+  .orchestraName {
+    padding-top: 3px;
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+    max-width: 220px;
+  }
+  .title {
+    font-size: 24px;
+  }
+
+  .className {
+    padding: 17px 15px 0;
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+    .line {
+      display: inline-block;
+      width: 4px;
+      height: 12px;
+      background: #ff8057;
+      border-radius: 3px;
+      margin-right: 6px;
+    }
+  }
+
+  :global {
+    .van-grid-item {
+      &:after {
+        content: ' ';
+        position: absolute;
+        top: 50%;
+        right: 0;
+        margin-top: -10px;
+        width: 1px;
+        height: 20px;
+        background: #eaeaea;
+        border-radius: 1px;
+      }
+
+      &:last-child {
+        &::after {
+          display: none;
+        }
+      }
+    }
+  }
+}
+
+.classCellGroup {
+  margin-bottom: 12px;
+  border-radius: 10px;
+  overflow: hidden;
+}

+ 268 - 0
src/school/mass-message/component/class-list/index.tsx

@@ -0,0 +1,268 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Checkbox,
+  CheckboxGroup,
+  Grid,
+  GridItem,
+  Icon,
+  Image,
+  List,
+  Picker,
+  Popup,
+  Sticky,
+  Tag
+} from 'vant'
+import { defineComponent, onMounted, reactive, watch } from 'vue'
+import styles from './index.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import { state as baseState } from '@/state'
+import request from '@/helpers/request'
+import OEmpty from '@/components/o-empty'
+
+export default defineComponent({
+  name: 'practice-class',
+  props: {
+    height: {
+      type: [String, Number],
+      default: 'auto'
+    },
+    selectItem: {
+      type: Array,
+      default: []
+    }
+  },
+  emits: ['close', 'confirm', 'update:selectItem'],
+  setup(props, { emit }) {
+    const forms = reactive({
+      showPopover: false,
+      orchestraId: null as any,
+      orchestraName: null as any,
+      orchestraList: [] as any,
+      isClick: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        type: null,
+        page: 1,
+        rows: 20
+      },
+      check: [] as any,
+      checkboxRefs: [] as any
+    })
+    // 获取乐团列表
+    const getOrchestras = async () => {
+      try {
+        const { data } = await request.post('/api-school/orchestra/page', {
+          data: {
+            page: 1,
+            rows: 100,
+            schoolId: baseState.user.data.school.id
+          }
+        })
+        const temps = data.rows || []
+        const s = [] as any
+        temps.forEach((item: any) => {
+          s.push({
+            text: item.name,
+            value: item.id
+          })
+        })
+        forms.orchestraList = [...s]
+
+        // 判断是否有乐团
+        if (s.length > 0) {
+          forms.orchestraId = s[0].value
+          forms.orchestraName = s[0].text
+        }
+      } catch {
+        //
+      }
+    }
+
+    // 获取班级
+    const getList = async () => {
+      // 查询没有设置指导老师的班级
+      try {
+        if (forms.isClick) return
+        forms.isClick = true
+        const { data } = await request.post('/api-school/classGroup/page', {
+          data: {
+            ...forms.params,
+            schoolId: baseState.user.data.school.id
+          }
+        })
+        forms.isClick = false
+        // 班级数据
+        forms.listState.loading = false
+        const result = data || {}
+        // 处理重复请求数据
+        if (forms.list.length > 0 && result.current === 1) {
+          return
+        }
+        forms.list = forms.list.concat(result.rows || [])
+        forms.listState.finished = result.current >= result.pages
+        forms.params.page = result.current + 1
+        forms.listState.dataShow = forms.list.length > 0
+      } catch {
+        forms.listState.dataShow = false
+        forms.listState.finished = true
+        forms.isClick = false
+      }
+    }
+
+    const onSelect = (type: string) => {
+      forms.checkboxRefs[type].toggle()
+
+      const list: any = []
+      forms.list.forEach((item: any) => {
+        if (forms.check.includes(item.id)) {
+          list.push({
+            id: item.id,
+            value: item.name,
+            avatar: ''
+          })
+        }
+      })
+      emit('update:selectItem', list)
+    }
+
+    watch(
+      () => props.selectItem,
+      () => {
+        initSelectItem()
+      },
+      { deep: true }
+    )
+
+    const initSelectItem = () => {
+      const selectItem = props.selectItem || []
+      const temp: any = []
+      selectItem.forEach((item: any) => {
+        temp.push(item.id)
+      })
+      forms.check = temp
+    }
+    onMounted(async () => {
+      await getOrchestras()
+      await getList()
+      initSelectItem()
+    })
+
+    return () => (
+      <div class={styles.practiceClass}>
+        <Sticky position="top" offsetTop={props.height}>
+          <div style={{ padding: '12px 13px', background: '#f6f6f6' }}>
+            <div class={styles.searchBand} onClick={() => (forms.showPopover = true)}>
+              {forms.orchestraName} <Icon name={forms.showPopover ? 'arrow-up' : 'arrow-down'} />
+            </div>
+          </div>
+        </Sticky>
+
+        {forms.listState.dataShow ? (
+          <List
+            v-model:loading={forms.listState.loading}
+            finished={forms.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup
+              class={[styles.gridContainer, styles.gridClass]}
+              v-model={forms.check}
+              // onChange={(val: any) => {
+              //   console.log(val, '1212')
+              //   const list: any = []
+              //   forms.list.forEach((item: any) => {
+              //     if (val.includes(item.id)) {
+              //       list.push({
+              //         id: item.id,
+              //         value: item.name,
+              //         avatar: ''
+              //       })
+              //     }
+              //   })
+              //   emit('change', list)
+              // }}
+            >
+              {forms.list.map((item: any) => (
+                <CellGroup class={styles.classCellGroup} onClick={() => onSelect(item.id)}>
+                  <Cell center titleStyle={{ flex: '0 auto' }} valueClass={styles.classCheckbox}>
+                    {{
+                      icon: () => <Image src={iconTeacher} class={styles.img} />,
+                      title: () => (
+                        <div class={styles.content}>
+                          <div class={styles.teacherName}>
+                            <span class={['van-ellipsis', styles.name]}>{item.teacherName}</span>
+                            <Tag type="primary">{item.name}</Tag>
+                          </div>
+                          <div class={[styles.orchestraName, 'van-ellipsis']}>
+                            {item.orchestraName}
+                          </div>
+                        </div>
+                      ),
+                      value: () => (
+                        <Checkbox
+                          name={item.id}
+                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                          onClick={(e: any) => {
+                            e.stopPropagation()
+                          }}
+                        ></Checkbox>
+                      )
+                    }}
+                  </Cell>
+                  <Grid border={false} columnNum={3}>
+                    <GridItem>
+                      <p class={styles.title}>{item.preStudentNum}</p>
+                      <p class={styles.name}>学生人数</p>
+                    </GridItem>
+                    <GridItem>
+                      <p class={[styles.title]}>
+                        {item.courseScheduleNum - item.completeCourseScheduleNum}
+                      </p>
+                      <p class={styles.name}>剩余课时</p>
+                    </GridItem>
+                    <GridItem>
+                      <p class={styles.title}>{item.courseScheduleNum}</p>
+                      <p class={styles.name}>总课时</p>
+                    </GridItem>
+                  </Grid>
+                </CellGroup>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无班级" />
+        )}
+
+        <Popup v-model:show={forms.showPopover} position="bottom" round>
+          <Picker
+            columns={forms.orchestraList}
+            onCancel={() => (forms.showPopover = false)}
+            onConfirm={(val: any) => {
+              forms.orchestraId = val.selectedOptions[0].value
+              forms.orchestraName = val.selectedOptions[0].text
+              forms.showPopover = false
+
+              forms.params.page = 1
+              forms.list = []
+              forms.listState.dataShow = true // 判断是否有数据
+              forms.listState.loading = false
+              forms.listState.finished = false
+              getList()
+            }}
+          />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 46 - 0
src/school/mass-message/component/manage-list/index.module.less

@@ -0,0 +1,46 @@
+.cellTeacher {
+  .img {
+    width: 48px;
+    height: 48px;
+    overflow: hidden;
+    border-radius: 50%;
+    margin-right: 12px;
+    flex-shrink: 0;
+  }
+
+  .name {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+    max-width: 120px;
+  }
+
+  .class {
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+  }
+
+  :global {
+    .van-tag {
+      margin-top: 3px;
+      margin-right: 8px;
+    }
+  }
+
+  .checkboxValue {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+.subjectContainer {
+  display: flex;
+  & > span {
+    flex-shrink: 0;
+  }
+  .tagSubject {
+    margin-right: 10px;
+  }
+}

+ 200 - 0
src/school/mass-message/component/manage-list/index.tsx

@@ -0,0 +1,200 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import { state } from '@/state'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Field,
+  List,
+  Image,
+  Tag,
+  Sticky,
+  Checkbox,
+  CheckboxGroup
+} from 'vant'
+import { defineComponent, onMounted, PropType, reactive, watch } from 'vue'
+import styles from './index.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import OSearch from '@/components/o-search'
+
+export default defineComponent({
+  name: 'manage-list',
+  props: {
+    height: {
+      type: [String, Number],
+      default: 'auto'
+    },
+    removeTeacherId: {
+      type: String,
+      default: ''
+    },
+    subjectIdList: {
+      type: Array,
+      default: () => []
+    },
+    selectItem: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'select', 'update:selectItem'],
+  setup(props, { slots, attrs, emit }) {
+    const forms = reactive({
+      teacherStatus: false,
+      isLoad: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        keyword: null,
+        subjectIdList: props.subjectIdList,
+        page: 1,
+        rows: 20
+      },
+      check: (props.selectItem || []) as any,
+      checkboxRefs: [] as any
+    })
+
+    const getList = async () => {
+      try {
+        if (forms.isLoad) return
+        forms.isLoad = true
+        const res = await request.post('/api-school/schoolStaff/page', {
+          data: {
+            ...forms.params,
+            schoolId: state.user.data.school.id,
+            status: 'ACTIVATION'
+          }
+        })
+        forms.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (forms.list.length > 0 && result.current === 1) {
+          return
+        }
+        const rows = result.rows || []
+        rows.forEach((item: any) => {
+          item.subjectNames = item.subjectName ? item.subjectName.split(',') : []
+        })
+        forms.list = forms.list.concat(rows)
+        forms.listState.finished = result.current >= result.pages
+        forms.params.page = result.current + 1
+        forms.listState.dataShow = forms.list.length > 0
+
+        forms.isLoad = false
+      } catch {
+        forms.listState.dataShow = false
+        forms.listState.finished = true
+        forms.isLoad = false
+      }
+    }
+
+    // 搜索
+    const onSearch = () => {
+      forms.params.page = 1
+      forms.list = []
+      forms.listState.dataShow = true // 判断是否有数据
+      forms.listState.loading = false
+      forms.listState.finished = false
+      getList()
+    }
+
+    const onSelect = (type: string) => {
+      forms.checkboxRefs[type].toggle()
+
+      const list: any = []
+      forms.list.forEach((item: any) => {
+        if (forms.check.includes(item.id)) {
+          list.push({
+            id: item.id,
+            value: item.nickname,
+            avatar: item.avatar
+          })
+        }
+      })
+      emit('update:selectItem', list)
+    }
+
+    watch(
+      () => props.selectItem,
+      () => {
+        initSelectItem()
+      },
+      { deep: true }
+    )
+
+    const initSelectItem = () => {
+      const selectItem = props.selectItem || []
+      const temp: any = []
+      selectItem.forEach((item: any) => {
+        temp.push(item.id)
+      })
+      forms.check = temp
+    }
+
+    onMounted(() => {
+      getList()
+      initSelectItem()
+    })
+
+    return () => (
+      <div>
+        <Sticky position="top" offsetTop={props.height}>
+          <OSearch
+            inputBackground="white"
+            background="#F8F8F8"
+            placeholder="老师名称/手机号"
+            onSearch={(val: any) => {
+              forms.params.keyword = val
+              onSearch()
+            }}
+          />
+        </Sticky>
+
+        {forms.listState.dataShow ? (
+          <List
+            v-model:loading={forms.listState.loading}
+            finished={forms.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup class={[styles.gridContainer, styles.gridClass]} v-model={forms.check}>
+              {forms.list.map((item: any) => (
+                <CellGroup inset style={{ marginBottom: '12px' }} onClick={() => onSelect(item.id)}>
+                  <Cell center class={styles.cellTeacher} valueClass={styles.checkboxValue}>
+                    {{
+                      icon: () => <Image class={styles.img} src={item.avatar || iconTeacher} />,
+                      title: () => (
+                        <div class={styles.content}>
+                          <p class={[styles.name, 'van-ellipsis']}>{item.nickname}</p>
+                        </div>
+                      ),
+                      value: () => (
+                        <Checkbox
+                          name={item.id}
+                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                          onClick={(e: any) => {
+                            e.stopPropagation()
+                          }}
+                        ></Checkbox>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无老师" />
+        )}
+      </div>
+    )
+  }
+})

+ 46 - 0
src/school/mass-message/component/student-list/index.module.less

@@ -0,0 +1,46 @@
+.cellTeacher {
+  .img {
+    width: 48px;
+    height: 48px;
+    overflow: hidden;
+    border-radius: 50%;
+    margin-right: 12px;
+    flex-shrink: 0;
+  }
+
+  .name {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+    max-width: 120px;
+  }
+
+  .class {
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+  }
+
+  :global {
+    .van-tag {
+      margin-top: 3px;
+      margin-right: 8px;
+    }
+  }
+
+  .checkboxValue {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+.subjectContainer {
+  display: flex;
+  & > span {
+    flex-shrink: 0;
+  }
+  .tagSubject {
+    margin-right: 10px;
+  }
+}

+ 196 - 0
src/school/mass-message/component/student-list/index.tsx

@@ -0,0 +1,196 @@
+import { state } from '@/state'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Field,
+  List,
+  Image,
+  Tag,
+  Sticky,
+  Checkbox,
+  CheckboxGroup
+} from 'vant'
+import { defineComponent, onMounted, PropType, reactive, watch } from 'vue'
+import styles from './index.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import OSearch from '@/components/o-search'
+
+export default defineComponent({
+  name: 'teacher-list',
+  props: {
+    height: {
+      type: [String, Number],
+      default: 'auto'
+    },
+    selectItem: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'select', 'update:selectItem'],
+  setup(props, { slots, attrs, emit }) {
+    const forms = reactive({
+      teacherStatus: false,
+      isLoad: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        keyword: null,
+        page: 1,
+        rows: 20
+      },
+      check: (props.selectItem || []) as any,
+      checkboxRefs: [] as any
+    })
+
+    const getList = async () => {
+      try {
+        if (forms.isLoad) return
+        forms.isLoad = true
+        const res = await request.post('/api-school/student/page', {
+          data: {
+            ...forms.params,
+            schoolId: state.user.data.school.id
+          }
+        })
+        forms.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (forms.list.length > 0 && result.current === 1) {
+          return
+        }
+        const rows = result.rows || []
+        rows.forEach((item: any) => {
+          item.subjectNames = item.subjectNames ? item.subjectNames.split(',') : []
+        })
+        forms.list = forms.list.concat(rows)
+        forms.listState.finished = result.current >= result.pages
+        forms.params.page = result.current + 1
+        forms.listState.dataShow = forms.list.length > 0
+
+        forms.isLoad = false
+      } catch {
+        forms.listState.dataShow = false
+        forms.listState.finished = true
+        forms.isLoad = false
+      }
+    }
+
+    // 搜索
+    const onSearch = () => {
+      forms.params.page = 1
+      forms.list = []
+      forms.listState.dataShow = true // 判断是否有数据
+      forms.listState.loading = false
+      forms.listState.finished = false
+      getList()
+    }
+
+    const onSelect = (type: string) => {
+      forms.checkboxRefs[type].toggle()
+
+      const list: any = []
+      forms.list.forEach((item: any) => {
+        if (forms.check.includes(item.id)) {
+          list.push({
+            id: item.id,
+            value: item.nickname,
+            avatar: item.avatar
+          })
+        }
+      })
+      emit('update:selectItem', list)
+    }
+
+    watch(
+      () => props.selectItem,
+      () => {
+        initSelectItem()
+      },
+      { deep: true }
+    )
+
+    const initSelectItem = () => {
+      const selectItem = props.selectItem || []
+      const temp: any = []
+      selectItem.forEach((item: any) => {
+        temp.push(item.id)
+      })
+      forms.check = temp
+    }
+
+    onMounted(() => {
+      getList()
+      initSelectItem()
+    })
+
+    return () => (
+      <div>
+        <Sticky position="top" offsetTop={props.height}>
+          <OSearch
+            inputBackground="white"
+            background="#F8F8F8"
+            placeholder="老师名称/手机号"
+            onSearch={(val: any) => {
+              forms.params.keyword = val
+              onSearch()
+            }}
+          />
+        </Sticky>
+
+        {forms.listState.dataShow ? (
+          <List
+            v-model:loading={forms.listState.loading}
+            finished={forms.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup class={[styles.gridContainer, styles.gridClass]} v-model={forms.check}>
+              {forms.list.map((item: any) => (
+                <CellGroup inset style={{ marginBottom: '12px' }} onClick={() => onSelect(item.id)}>
+                  <Cell center class={styles.cellTeacher} valueClass={styles.checkboxValue}>
+                    {{
+                      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.class}>
+                            {item.subjectNames &&
+                              item.subjectNames.map((subject: any) => (
+                                <Tag type="primary" class={styles.tagSubject}>
+                                  {subject}
+                                </Tag>
+                              ))}
+                          </p>
+                        </div>
+                      ),
+                      value: () => (
+                        <Checkbox
+                          name={item.id}
+                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                          onClick={(e: any) => {
+                            e.stopPropagation()
+                          }}
+                        ></Checkbox>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无老师" />
+        )}
+      </div>
+    )
+  }
+})

+ 46 - 0
src/school/mass-message/component/teacher-list/teacher-list.module.less

@@ -0,0 +1,46 @@
+.cellTeacher {
+  .img {
+    width: 48px;
+    height: 48px;
+    overflow: hidden;
+    border-radius: 50%;
+    margin-right: 12px;
+    flex-shrink: 0;
+  }
+
+  .name {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+    max-width: 120px;
+  }
+
+  .class {
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+  }
+
+  :global {
+    .van-tag {
+      margin-top: 3px;
+      margin-right: 8px;
+    }
+  }
+
+  .checkboxValue {
+    display: flex;
+    justify-content: flex-end;
+  }
+}
+
+.subjectContainer {
+  display: flex;
+  & > span {
+    flex-shrink: 0;
+  }
+  .tagSubject {
+    margin-right: 10px;
+  }
+}

+ 218 - 0
src/school/mass-message/component/teacher-list/teacher-list.tsx

@@ -0,0 +1,218 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import { state } from '@/state'
+import {
+  Button,
+  Cell,
+  CellGroup,
+  Field,
+  List,
+  Image,
+  Tag,
+  Sticky,
+  Checkbox,
+  CheckboxGroup
+} from 'vant'
+import { defineComponent, onMounted, PropType, reactive, watch } from 'vue'
+import styles from './teacher-list.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import OSearch from '@/components/o-search'
+
+export default defineComponent({
+  name: 'teacher-list',
+  props: {
+    height: {
+      type: [String, Number],
+      default: 'auto'
+    },
+    removeTeacherId: {
+      type: String,
+      default: ''
+    },
+    subjectIdList: {
+      type: Array,
+      default: () => []
+    },
+    selectItem: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'select', 'update:selectItem'],
+  setup(props, { slots, attrs, emit }) {
+    const forms = reactive({
+      teacherStatus: false,
+      isLoad: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        keyword: null,
+        subjectIdList: props.subjectIdList,
+        page: 1,
+        rows: 20
+      },
+      check: (props.selectItem || []) as any,
+      checkboxRefs: [] as any
+    })
+
+    const getList = async () => {
+      try {
+        if (forms.isLoad) return
+        forms.isLoad = true
+        const res = await request.post('/api-school/teacher/page', {
+          data: {
+            ...forms.params,
+            schoolId: state.user.data.school.id,
+            removeTeacherId: props.removeTeacherId, // 移除的老师id
+            delFlag: false // 绑定解绑 false:绑定 true:解绑
+          }
+        })
+        forms.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (forms.list.length > 0 && result.current === 1) {
+          return
+        }
+        const rows = result.rows || []
+        rows.forEach((item: any) => {
+          item.subjectNames = item.subjectName ? item.subjectName.split(',') : []
+        })
+        forms.list = forms.list.concat(rows)
+        forms.listState.finished = result.current >= result.pages
+        forms.params.page = result.current + 1
+        forms.listState.dataShow = forms.list.length > 0
+
+        forms.isLoad = false
+      } catch {
+        forms.listState.dataShow = false
+        forms.listState.finished = true
+        forms.isLoad = false
+      }
+    }
+
+    // 搜索
+    const onSearch = () => {
+      forms.params.page = 1
+      forms.list = []
+      forms.listState.dataShow = true // 判断是否有数据
+      forms.listState.loading = false
+      forms.listState.finished = false
+      getList()
+    }
+
+    const onSelect = (type: string) => {
+      forms.checkboxRefs[type].toggle()
+
+      const list: any = []
+      forms.list.forEach((item: any) => {
+        if (forms.check.includes(item.id)) {
+          list.push({
+            id: item.id,
+            value: item.nickname,
+            avatar: item.avatar
+          })
+        }
+      })
+      emit('update:selectItem', list)
+    }
+
+    watch(
+      () => props.selectItem,
+      () => {
+        initSelectItem()
+      },
+      { deep: true }
+    )
+
+    const initSelectItem = () => {
+      const selectItem = props.selectItem || []
+      const temp: any = []
+      selectItem.forEach((item: any) => {
+        temp.push(item.id)
+      })
+      forms.check = temp
+    }
+
+    onMounted(() => {
+      getList()
+      initSelectItem()
+    })
+
+    return () => (
+      <div>
+        <Sticky position="top" offsetTop={props.height}>
+          <OSearch
+            inputBackground="white"
+            background="#F8F8F8"
+            placeholder="老师名称/手机号"
+            onSearch={(val: any) => {
+              forms.params.keyword = val
+              onSearch()
+            }}
+          />
+        </Sticky>
+
+        {forms.listState.dataShow ? (
+          <List
+            v-model:loading={forms.listState.loading}
+            finished={forms.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup class={[styles.gridContainer, styles.gridClass]} v-model={forms.check}>
+              {forms.list.map((item: any) => (
+                <CellGroup inset style={{ marginBottom: '12px' }} onClick={() => onSelect(item.id)}>
+                  <Cell center class={styles.cellTeacher} valueClass={styles.checkboxValue}>
+                    {{
+                      icon: () => <Image class={styles.img} src={item.avatar || iconTeacher} />,
+                      title: () => (
+                        <div class={styles.content}>
+                          <p class={[styles.name, 'van-ellipsis']}>{item.nickname}</p>
+                        </div>
+                      ),
+                      value: () => (
+                        <Checkbox
+                          name={item.id}
+                          ref={(el: any) => (forms.checkboxRefs[item.id] = el)}
+                          onClick={(e: any) => {
+                            e.stopPropagation()
+                          }}
+                        ></Checkbox>
+                      )
+                    }}
+                  </Cell>
+                  <Cell>
+                    {{
+                      title: () => (
+                        <div class={styles.subjectContainer}>
+                          <span>声部:</span>
+                          <div>
+                            {item.subjectNames &&
+                              item.subjectNames.map((subject: any) => (
+                                <Tag type="primary" class={styles.tagSubject}>
+                                  {subject}
+                                </Tag>
+                              ))}
+                          </div>
+                        </div>
+                      )
+                    }}
+                  </Cell>
+                </CellGroup>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无老师" />
+        )}
+      </div>
+    )
+  }
+})

+ 535 - 15
src/school/mass-message/create-message.tsx

@@ -1,53 +1,573 @@
-import OHeader from '@/components/o-header'
+import OPopup from '@/components/o-popup'
 import { sendType } from '@/constant'
-import { state } from '@/state'
-import { ActionSheet, Cell, CellGroup, Field, Uploader } from 'vant'
-import { defineComponent, reactive } from 'vue'
+import request from '@/helpers/request'
+import { getOssUploadUrl } from '@/state'
+import dayjs from 'dayjs'
+import umiRequest from 'umi-request'
+import {
+  ActionSheet,
+  Button,
+  Cell,
+  CellGroup,
+  closeToast,
+  DatePicker,
+  Field,
+  Icon,
+  Image,
+  PickerGroup,
+  Popup,
+  showLoadingToast,
+  showToast,
+  TimePicker,
+  Uploader
+} from 'vant'
+import { computed, defineComponent, getCurrentInstance, onMounted, reactive, watch } from 'vue'
 import styles from './index.module.less'
+import SelectSned from './select-sned'
+import iconStudent from '@common/images/icon_student.png'
+import iconTeacher from '@common/images/icon_teacher.png'
+import ODialog from '@/components/o-dialog'
+import OSticky from '@/components/o-sticky'
+import { useRoute, useRouter } from 'vue-router'
 
 export default defineComponent({
   name: 'create-message',
   setup() {
+    const router = useRouter()
+    const route = useRoute()
     const forms = reactive({
+      id: route.query.id,
+      type: 'ADD',
+      bucket: 'daya',
       sendStatus: false,
       sendType: null as any,
-      textMessage: null
+      textMessage: null,
+      sendTime: null as any,
+      sendTimeStatus: false,
+      maxDate: dayjs(new Date()).add(60, 'day').toDate(),
+      currentDate: [],
+      currentTime: [dayjs().format('HH'), dayjs().format('mm')],
+      attachments: [] as any, //群发消息附件
+      receives: [] as any, // 群发消息对象
+      selectStatus: false,
+      selectList: {} as any, // 选中发送的信息
+      delSelectItem: {} as any,
+      delStatus: false,
+      sureLoading: false,
+      updateLoading: false,
+      closeLoading: false
     })
+
+    const beforeRead = (file: any) => {
+      // console.log(file, 'beforeRead')
+      const isLt2M = file.size / 1024 / 1024 < 5
+      if (!isLt2M) {
+        showToast(`上传文件大小不能超过 5MB`)
+        return false
+      }
+      return true
+    }
+    const beforeDelete = (file: any, detail: { index: any }) => {
+      // this.dataModel.splice(detail.index, 1)
+      return true
+    }
+    const afterRead = async (file: any, detail: any) => {
+      try {
+        file.status = 'uploading'
+        file.message = '上传中...'
+        await uploadFile(file)
+      } catch (error) {
+        //
+        closeToast()
+      }
+    }
+
+    const uploadFile = async (files: any) => {
+      // 上传文件
+      try {
+        console.log(files, 'files')
+        const file = files.file
+        // 获取签名
+        const signUrl = '/api-school/open/getUploadSign'
+        const tempName = file.name || ''
+        const fileName = tempName && tempName.replace(/ /gi, '_')
+        const key = new Date().getTime() + fileName
+        showLoadingToast({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        })
+        const res = await request.post(signUrl, {
+          hideLoading: true,
+          data: {
+            filename: fileName,
+            bucketName: forms.bucket,
+            postData: {
+              filename: fileName,
+              acl: 'public-read',
+              key: key,
+              unknowValueField: []
+            }
+          }
+        })
+        // setTimeout(() => {
+
+        // }, 100)
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: 'public-read',
+          name: fileName
+        }
+        const formData = new FormData()
+        for (const key in obj) {
+          formData.append(key, obj[key])
+        }
+        formData.append('file', file, fileName)
+        await umiRequest(getOssUploadUrl(forms.bucket), {
+          method: 'POST',
+          data: formData
+        })
+        // console.log(getOssUploadUrl(state.bucket) + key)
+        const uploadUrl = getOssUploadUrl(forms.bucket) + key
+        closeToast()
+
+        // state.fileList.push({ url: uploadUrl })
+        files.url = uploadUrl
+        files.status = 'done'
+      } catch (error) {
+        files.status = 'failed'
+        closeToast()
+        console.log(error, 'uploadFile')
+      }
+    }
+
+    const onSubmit = async () => {
+      try {
+        if (!forms.sendType) {
+          showToast('请选择发送方式')
+          return
+        }
+
+        if (!forms.textMessage) {
+          showToast('请输入发送内容')
+          return
+        }
+
+        if (forms.receives.length <= 0) {
+          showToast('请选择发送对象')
+          return
+        }
+        const tempAttachments: any = []
+        forms.attachments.forEach((item: any) => {
+          tempAttachments.push({
+            imgUrl: item.url,
+            imgMessage: item.url
+          })
+        })
+
+        const tempReceives: any = []
+        forms.receives.forEach((item: any) => {
+          tempReceives.push({
+            receiveType: item.receiveType,
+            receiveId: item.receiveId
+          })
+        })
+
+        const params: any = {
+          sendType: forms.sendType,
+          textMessage: forms.textMessage,
+          attachments: tempAttachments,
+          receives: tempReceives,
+          sendTime: forms.sendTime
+        }
+
+        console.log(params, 'params')
+        if (forms.id) {
+          forms.updateLoading = true
+        } else {
+          forms.sureLoading = true
+        }
+
+        if (forms.id) {
+          params.id = forms.id
+          await request.post('/api-school/imMessageBatchSending/update', {
+            data: params
+          })
+        } else {
+          await request.post('/api-school/imMessageBatchSending/save', {
+            data: params
+          })
+        }
+
+        setTimeout(() => {
+          showToast(forms.id ? '修改成功' : '添加成功')
+        }, 100)
+        setTimeout(() => {
+          router.replace('/mass-message')
+          forms.sureLoading = false
+          forms.updateLoading = false
+        }, 1100)
+      } catch {
+        //
+        forms.sureLoading = false
+        forms.updateLoading = false
+      }
+    }
+
+    const getDetails = async () => {
+      try {
+        if (!forms.id) return
+        const { data } = await request.get('/api-school/imMessageBatchSending/detail/' + forms.id)
+        forms.sendType = data.sendType
+        forms.textMessage = data.textMessage
+        const receives = data.receives || []
+        const tempList: any = {
+          class: [] as any,
+          teacher: [] as any,
+          student: [] as any,
+          manage: [] as any
+        }
+        receives.forEach((item: any) => {
+          const temp = {
+            receiveType: item.receiveType,
+            receiveId: item.receiveId,
+            receiveName: item.receiveName,
+            avatar: item.avatar
+          }
+          forms.receives.push(temp)
+          const temp2 = {
+            id: item.receiveId,
+            value: item.receiveName,
+            avatar: item.avatar
+          }
+          if (item.receiveType === 'CLASS') {
+            tempList.class.push(temp2)
+          } else if (item.receiveType === 'STUDENT') {
+            tempList.student.push(temp2)
+          } else if (item.receiveType === 'TEACHER') {
+            tempList.teacher.push(temp2)
+          } else if (item.receiveType === 'SCHOOL') {
+            tempList.school.push(temp2)
+          }
+        })
+        forms.selectList = tempList
+        const attachments = data.attachments || []
+        const tempAtt: any = []
+        attachments.forEach((item: any) => {
+          tempAtt.push({
+            url: item.imgUrl || item.imgMessage
+          })
+        })
+        forms.attachments = tempAtt
+
+        forms.sendTime = data.sendTime
+        forms.type = data.sendStatus
+      } catch {
+        //
+      }
+    }
+
+    // 判断是否是查看
+    const formDisabled = computed(() => forms.type === 'SEND')
+
+    const onClose = async () => {
+      try {
+        forms.closeLoading = true
+        await request.post('/api-school/imMessageBatchSending/remove', {
+          requestType: 'form',
+          data: {
+            id: forms.id
+          }
+        })
+        setTimeout(() => {
+          showToast('撤销成功')
+        }, 100)
+        setTimeout(() => {
+          router.replace('/mass-message')
+          forms.closeLoading = false
+        }, 1100)
+      } catch {
+        //
+        forms.closeLoading = false
+      }
+    }
+
+    onMounted(() => {
+      getDetails()
+    })
+
     return () => (
       <div class={styles['create-message']}>
-        <OHeader />
-
+        {/* <OHeader /> */}
         <CellGroup inset class={styles.cellGroup}>
-          {/* <Cell title="发送方式" value={sendType[forms.sendType]} isLink /> */}
           <Field
             inputAlign="right"
             label="发送方式"
             modelValue={sendType[forms.sendType]}
             placeholder="请选择发送方式"
-            onClick={() => (forms.sendStatus = true)}
+            onClick={() => {
+              if (formDisabled.value) return
+              forms.sendStatus = true
+            }}
+            readonly
+            isLink={!formDisabled.value}
           />
-          <Cell title="发送时间" value={''} isLink />
+          {/* 定时发送才会有时间 */}
+          {forms.sendType === 'SCHEDULED' && (
+            <Field
+              inputAlign="right"
+              label="发送时间"
+              modelValue={forms.sendTime}
+              placeholder="请选择发送时间"
+              onClick={() => {
+                if (formDisabled.value) return
+                forms.sendTimeStatus = true
+              }}
+              readonly
+              isLink
+            />
+          )}
           <Cell title="发送内容">
             {{
               label: () => (
                 <Field
-                  style={{ padding: '0' }}
+                  style={{ padding: '0', marginTop: '12px' }}
                   placeholder="请输入发送内容"
                   v-model={forms.textMessage}
                   type="textarea"
                   rows={3}
+                  showWordLimit
+                  maxlength={400}
+                  readonly={formDisabled.value}
                 />
               )
             }}
           </Cell>
-          <Cell title="上传辅件">
-            <Uploader />
+          <Cell title="上传附件">
+            {{
+              label: () => (
+                <Uploader
+                  style={{ marginTop: '12px' }}
+                  v-model={forms.attachments}
+                  afterRead={afterRead}
+                  beforeRead={beforeRead}
+                  beforeDelete={beforeDelete}
+                  accept="image/*"
+                  maxCount={9}
+                  disabled={formDisabled.value}
+                />
+              )
+            }}
           </Cell>
 
-          <Cell title="发送对象"></Cell>
+          <Field
+            label="发送对象"
+            readonly
+            inputAlign="right"
+            placeholder={formDisabled.value ? '' : '请选择发送对象'}
+            isLink={!formDisabled.value}
+            border={false}
+            onClick={() => {
+              if (formDisabled.value) return
+              forms.selectStatus = true
+            }}
+          />
+          {forms.receives.map((item: any) => {
+            let img: any = iconStudent
+            if (item.receiveType === 'CLASS') {
+              img = ''
+            } else if (item.receiveType === 'STUDENT') {
+              img = iconStudent
+            } else if (item.receiveType === 'TEACHER' || item.receiveType === 'SCHOOL') {
+              img = iconTeacher
+            }
+            return (
+              <Cell class={styles.receives} title={item.receiveName} center border={false}>
+                {{
+                  icon: () => <Image class={styles.img} src={item.avatar || img} />,
+                  extra: () =>
+                    !formDisabled.value && (
+                      <Icon
+                        name="clear"
+                        color="#d7d7d7"
+                        size={20}
+                        onClick={() => {
+                          forms.delSelectItem = item
+                          forms.delStatus = true
+                        }}
+                      />
+                    )
+                }}
+              </Cell>
+            )
+          })}
         </CellGroup>
 
-        {/* <ActionSheet v-model:show={} /> */}
+        <OSticky position="bottom">
+          {forms.type === 'ADD' && (
+            <div class={'btnGroup'}>
+              <Button
+                round
+                block
+                type="primary"
+                size="large"
+                onClick={onSubmit}
+                disabled={forms.sureLoading}
+              >
+                确认发送
+              </Button>
+            </div>
+          )}
+
+          {forms.type === 'WAIT' && (
+            <div class={['btnGroup', 'btnMore']}>
+              <Button
+                round
+                type="primary"
+                size="large"
+                onClick={onSubmit}
+                disabled={forms.updateLoading}
+              >
+                修改
+              </Button>
+              <Button
+                round
+                color="#64A9FF"
+                size="large"
+                onClick={onClose}
+                disabled={forms.closeLoading}
+              >
+                撤销
+              </Button>
+            </div>
+          )}
+        </OSticky>
+
+        <ActionSheet
+          v-model:show={forms.sendStatus}
+          cancelText="取消"
+          actions={
+            [
+              { name: '即时发送', value: 'IMMEDIATELY' },
+              { name: '定时发送', value: 'SCHEDULED' }
+            ] as any
+          }
+          onSelect={(val: any) => {
+            console.log(val)
+            forms.sendType = val.value
+            forms.sendStatus = false
+          }}
+        />
+
+        <Popup v-model:show={forms.sendTimeStatus} position="bottom" round>
+          <PickerGroup
+            title="发送时间"
+            tabs={['选择日期', '选择时间']}
+            onCancel={() => (forms.sendTimeStatus = false)}
+            onConfirm={(val: any) => {
+              const first = val[0].selectedValues.join('-')
+              const second = val[1].selectedValues.join(':')
+              forms.sendTime = dayjs(first + ' ' + second).format('YYYY-MM-DD HH:mm:ss')
+              forms.sendTimeStatus = false
+            }}
+          >
+            <DatePicker minDate={new Date()} maxDate={forms.maxDate} v-model={forms.currentDate} />
+            <TimePicker v-model={forms.currentTime} />
+          </PickerGroup>
+        </Popup>
+
+        <OPopup v-model:modelValue={forms.selectStatus}>
+          <SelectSned
+            v-model:selectList={forms.selectList}
+            onClose={() => (forms.selectStatus = false)}
+            onConfirm={(val: any) => {
+              const classList = val.class || []
+              const studentList = val.student || []
+              const teacherList = val.teacher || []
+              const manageList = val.manage || []
+
+              const tempList: any = []
+              classList.forEach((item: any) => {
+                tempList.push({
+                  receiveType: 'CLASS',
+                  receiveId: item.id,
+                  receiveName: item.value,
+                  avatar: item.avatar
+                })
+              })
+              studentList.forEach((item: any) => {
+                tempList.push({
+                  receiveType: 'STUDENT',
+                  receiveId: item.id,
+                  receiveName: item.value,
+                  avatar: item.avatar
+                })
+              })
+              teacherList.forEach((item: any) => {
+                tempList.push({
+                  receiveType: 'TEACHER',
+                  receiveId: item.id,
+                  receiveName: item.value,
+                  avatar: item.avatar
+                })
+              })
+              manageList.forEach((item: any) => {
+                tempList.push({
+                  receiveType: 'SCHOOL',
+                  receiveId: item.id,
+                  receiveName: item.value,
+                  avatar: item.avatar
+                })
+              })
+
+              forms.receives = tempList
+            }}
+          />
+        </OPopup>
+
+        <ODialog
+          v-model:show={forms.delStatus}
+          showCancelButton
+          message="您是否删除该数据"
+          onConfirm={() => {
+            const selectList = forms.selectList
+            if (forms.delSelectItem.receiveType === 'CLASS') {
+              const tempClass = selectList.class || []
+              const sIndex = tempClass.findIndex(
+                (item: any) => item.id === forms.delSelectItem.receiveId
+              )
+              tempClass.splice(sIndex, 1)
+            } else if (forms.delSelectItem.receiveType === 'SCHOOL') {
+              const tempSchool = selectList.school || []
+              const sIndex = tempSchool.findIndex(
+                (item: any) => item.id === forms.delSelectItem.receiveId
+              )
+              tempSchool.splice(sIndex, 1)
+            } else if (forms.delSelectItem.receiveType === 'TEACHER') {
+              const tempTeacher = selectList.teacher || []
+              const sIndex = tempTeacher.findIndex(
+                (item: any) => item.id === forms.delSelectItem.receiveId
+              )
+              tempTeacher.splice(sIndex, 1)
+            } else if (forms.delSelectItem.receiveType === 'STUDENT') {
+              const tempStudent = selectList.student || []
+              const sIndex = tempStudent.findIndex(
+                (item: any) => item.id === forms.delSelectItem.receiveId
+              )
+              tempStudent.splice(sIndex, 1)
+            }
+            forms.selectList = selectList
+
+            const index = forms.receives.findIndex(
+              (item: any) => item.receiveId === forms.delSelectItem.receiveId
+            )
+            forms.receives.splice(index, 1)
+          }}
+        />
       </div>
     )
   }

+ 34 - 0
src/school/mass-message/index.module.less

@@ -47,11 +47,45 @@
   }
 }
 
+.create-message {
+  overflow: hidden;
+  --van-tab-active-text-color: var(--van-primary-color);
+  --van-tab-text-color: #333;
+  --van-tab-font-size: 16px;
+  :global {
+    .van-tab {
+      font-weight: 400;
+    }
+    .van-tabs__wrap {
+      // padding-bottom: 3px;
+    }
+  }
+}
 .cellGroup {
   margin-top: 12px;
+  margin-bottom: 12px;
+  --van-uploader-size: 94px;
   :global {
     .van-cell {
       padding: 18px 15px;
+      font-size: 16px;
+      color: #333333;
     }
   }
 }
+
+.receives {
+  padding-top: 6px !important;
+  padding-bottom: 6px !important;
+  &:last-child {
+    padding-bottom: 18px !important;
+  }
+
+  .img {
+    width: 40px;
+    height: 40px;
+    overflow: hidden;
+    border-radius: 50%;
+    margin-right: 12px;
+  }
+}

+ 48 - 8
src/school/mass-message/index.tsx

@@ -4,6 +4,7 @@ import OSearch from '@/components/o-search'
 import OSticky from '@/components/o-sticky'
 import { snedStatus } from '@/constant'
 import request from '@/helpers/request'
+import item from '@/student/coupons/item'
 import { Cell, CellGroup, Icon, List, Tab, Tabs } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
 import { useRouter } from 'vue-router'
@@ -13,24 +14,31 @@ export default defineComponent({
   name: 'mass-message',
   setup() {
     const router = useRouter()
+    const status = sessionStorage.getItem('mass-message-send')
     const state = reactive({
       list: [],
       dataShow: true, // 判断是否有数据
       loading: false,
       finished: false,
+      tabValue: status || 'WAIT',
       params: {
-        search: null,
+        keyword: null as any,
+        sendStatus: status || 'WAIT',
         page: 1,
         rows: 10
-      }
+      },
+      isClick: false
     })
     const getList = async () => {
       try {
+        if (state.isClick) return
+        state.isClick = true
         const res = await request.post('/api-school/imMessageBatchSending/page', {
           data: {
             ...state.params
           }
         })
+        state.isClick = false
         state.loading = false
         const result = res.data || {}
         // 处理重复请求数据
@@ -38,15 +46,36 @@ export default defineComponent({
           return
         }
         state.list = state.list.concat(result.rows || [])
-        state.finished = result.current >= result.totalPage
+        state.finished = result.current >= result.pages
         state.params.page = result.current + 1
         state.dataShow = state.list.length > 0
       } catch {
+        state.isClick = false
         state.dataShow = false
         state.finished = true
       }
     }
 
+    // 搜索
+    const onSearch = () => {
+      state.params.page = 1
+      state.list = []
+      state.dataShow = true // 判断是否有数据
+      state.loading = false
+      state.finished = false
+      getList()
+    }
+
+    // 查看详情
+    const onDetail = async (item: any) => {
+      router.push({
+        path: '/create-message',
+        query: {
+          id: item.id
+        }
+      })
+    }
+
     onMounted(() => {
       getList()
     })
@@ -67,9 +96,17 @@ export default defineComponent({
               )
             }}
           </OHeader>
-          <Tabs lineWidth={18}>
-            <Tab title="待发送"></Tab>
-            <Tab title="已发送"></Tab>
+          <Tabs
+            lineWidth={18}
+            v-model:active={state.tabValue}
+            onChange={(val: string) => {
+              state.params.sendStatus = val
+              onSearch()
+              sessionStorage.setItem('mass-message-send', val)
+            }}
+          >
+            <Tab title="待发送" name="WAIT"></Tab>
+            <Tab title="已发送" name="SEND"></Tab>
           </Tabs>
 
           <OSearch
@@ -78,6 +115,8 @@ export default defineComponent({
             placeholder="请输入群聊/学员名称"
             onSearch={(val: string) => {
               console.log('val', val)
+              state.params.keyword = val
+              onSearch()
             }}
           />
         </OSticky>
@@ -92,13 +131,14 @@ export default defineComponent({
             immediateCheck={false}
           >
             {state.list.map((item: any) => (
-              <CellGroup inset>
+              <CellGroup inset onClick={() => onDetail(item)}>
                 <Cell class={styles.waitSend} titleStyle={{ flex: '1 auto' }}>
                   {{
                     title: () => (
                       <div class={styles.time}>
                         <Icon name="clock-o" class={styles.clockO} />
-                        {item.sendTime}
+                        {item.sendStatus === 'WAIT' ? item.createTime : ''}
+                        {item.sendStatus === 'SEND' ? item.sendTime : ''}
                       </div>
                     ),
                     value: () => <span>{snedStatus[item.sendStatus]}</span>

+ 98 - 0
src/school/mass-message/select-sned.tsx

@@ -0,0 +1,98 @@
+import OSticky from '@/components/o-sticky'
+import { useRect } from '@vant/use'
+import { Button, Sticky, Tab, Tabs } from 'vant'
+import { defineComponent, onMounted, reactive, ref, watch } from 'vue'
+import ClassList from './component/class-list'
+import ManageList from './component/manage-list'
+import StudentList from './component/student-list'
+import TeacherList from './component/teacher-list/teacher-list'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'select-send',
+  props: {
+    selectList: {
+      type: Object,
+      default: {}
+    },
+    selectStatus: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['close', 'confirm', 'update:selectList'],
+  setup(props, { emit, expose }) {
+    const state = reactive({
+      height: 'auto' as any,
+      tabValue: 'class',
+      selectClass: [] as any,
+      selectStudent: [] as any,
+      selectTeacher: [] as any,
+      selectManage: [] as any
+    })
+
+    const onSubmit = async () => {
+      const params = {
+        class: state.selectClass,
+        student: state.selectStudent,
+        teacher: state.selectTeacher,
+        manage: state.selectManage
+      }
+      emit('close')
+      emit('update:selectList', params)
+      emit('confirm', params)
+    }
+
+    watch(
+      () => props.selectList,
+      () => {
+        console.log('watch', props.selectList)
+        resetSelectItems()
+      },
+      { deep: true }
+    )
+
+    const resetSelectItems = () => {
+      const list = props.selectList || {}
+      state.selectClass = list.class || []
+      state.selectTeacher = list.teacher || []
+      state.selectManage = list.manage || []
+      state.selectStudent = list.student || []
+    }
+
+    onMounted(() => {
+      const { height } = useRect(document.querySelector('.van-tab') as HTMLElement)
+      state.height = height
+
+      resetSelectItems()
+      console.log(state, 'select')
+    })
+
+    return () => (
+      <div class={styles.orchestraDetail} style={{ background: '#f6f6f6', minHeight: '100vh' }}>
+        <Tabs sticky lineWidth={20} lineHeight={4} v-model:active={state.tabValue}>
+          <Tab title="班级" name="class">
+            <ClassList height={state.height} v-model:selectItem={state.selectClass} />
+          </Tab>
+          <Tab title="学员" name="student">
+            <StudentList height={state.height} v-model:selectItem={state.selectStudent} />
+          </Tab>
+          <Tab title="伴学老师" name="teacher">
+            <TeacherList height={state.height} v-model:selectItem={state.selectTeacher} />
+          </Tab>
+          <Tab title="管理老师" name="manage">
+            <ManageList height={state.height} v-model:selectItem={state.selectManage} />
+          </Tab>
+        </Tabs>
+
+        <OSticky position="bottom">
+          <div class={'btnGroup'}>
+            <Button round block type="primary" size="large" onClick={onSubmit}>
+              确认
+            </Button>
+          </div>
+        </OSticky>
+      </div>
+    )
+  }
+})

+ 3 - 1
src/school/orchestra/orchestra-information.tsx

@@ -112,7 +112,9 @@ export default defineComponent({
                     <div>
                       <div class={[styles.title, 'van-ellipsis']}>{item.title}</div>
                       <div class={[styles.content, 'van-multi-ellipsis--l2']}>{item.memo}</div>
-                      <div class={styles.time}>{dayjs(item.createBy).format('YYYY年MM月DD日')}</div>
+                      <div class={styles.time}>
+                        {dayjs(item.createTime).format('YYYY年MM月DD日')}
+                      </div>
                     </div>
                   )
                 }}

+ 1 - 3
src/school/train-planning/modal/practice-class/index.tsx

@@ -54,7 +54,6 @@ export default defineComponent({
         finished: false
       },
       params: {
-        type: null,
         page: 1,
         rows: 20
       },
@@ -99,8 +98,7 @@ export default defineComponent({
         forms.isClick = true
         const { data } = await request.post('/api-school/classGroup/page', {
           data: {
-            page: 1,
-            rows: 20,
+            ...forms.params,
             schoolId: baseState.user.data.school.id,
             orchestraId: forms.orchestraId,
             classType: props.classType

+ 2 - 2
src/student/music-group/pre-apply/component/payment.tsx

@@ -244,8 +244,8 @@ export default defineComponent({
             paymentCashAmount: state.orderInfo.needPrice || 0,
             paymentCouponAmount: 0,
             goodsInfos: params,
-            orderName: '会员购买',
-            orderDesc: '会员购买'
+            orderName: '乐团报名缴费',
+            orderDesc: '乐团报名缴费'
           }
         })
 

+ 18 - 5
src/student/my-orchestra/apply-withdrawal.tsx

@@ -4,20 +4,33 @@ import iconStudent from '@common/images/icon_student.png'
 import styles from './apply-withdrawal.module.less'
 import { Button, Dialog, Field, Image } from 'vant'
 import OSticky from '@/components/o-sticky'
+import { useRoute } from 'vue-router'
+import request from '@/helpers/request'
+import { state } from '@/state'
 
 export default defineComponent({
   name: 'apply-withdrawal',
   setup() {
+    const route = useRoute()
     const headColor = reactive({
       headBg: 'transparent',
       textColor: '#fff'
     })
-    const state = reactive({
-      status: false
+    const forms = reactive({
+      status: false,
+      reason: null,
+      id: route.query.id
     })
 
     const onSubmit = async () => {
-      state.status = true
+      // forms.status = true
+      await request.post('/api-student/orchestra/leaveOrchestra', {
+        data: {
+          studentId: state.user.data.account.id,
+          orchestraId: forms.id,
+          reason: forms.reason
+        }
+      })
     }
     return () => (
       <>
@@ -49,7 +62,7 @@ export default defineComponent({
             </div>
             <div class={styles.nums}>0/400</div>
           </div>
-          <Field placeholder="请输入退团详细原因" type="textarea" rows={3} />
+          <Field v-model={forms.reason} placeholder="请输入退团详细原因" type="textarea" rows={3} />
         </div>
 
         <OSticky position="bottom">
@@ -61,7 +74,7 @@ export default defineComponent({
         </OSticky>
 
         <Dialog
-          v-model:show={state.status}
+          v-model:show={forms.status}
           message={'确定要提交退团申请吗?'}
           messageAlign="left"
           confirmButtonText="确定"

+ 6 - 0
src/student/my-orchestra/index.module.less

@@ -103,6 +103,12 @@
           margin-left: 6px;
         }
       }
+      .name {
+        font-size: 0.42667rem;
+        font-weight: 600;
+        padding-top: 0;
+        max-width: 120px;
+      }
     }
     .classCheckbox {
       display: flex;

+ 164 - 96
src/student/my-orchestra/index.tsx

@@ -1,5 +1,5 @@
 import OHeader from '@/components/o-header'
-import { Cell, CellGroup, Grid, GridItem, Image, List, Tag } from 'vant'
+import { Cell, CellGroup, Grid, GridItem, Image, List, Picker, Popup, Tag } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import styles from './index.module.less'
@@ -27,8 +27,9 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      selectItem: {} as any,
-      selectType: 'add'
+      orchestraStatus: false,
+      orchestraList: [] as any,
+      selectOrchestra: {} as any
     })
     const onSearch = () => {
       state.params.page = 1
@@ -47,7 +48,7 @@ export default defineComponent({
         const res = await request.post('/api-student/orchestraPhotoAlbum/page', {
           data: {
             ...state.params,
-            orchestraId: route.query.id
+            orchestraId: state.selectOrchestra.orchestraId
           }
         })
         state.listState.loading = false
@@ -83,122 +84,189 @@ export default defineComponent({
       try {
         const { data } = await request.post('/api-student/orchestra/studentOrchestra', {})
         console.log(data)
+        state.orchestraList = data || []
+        if (data && data.length > 0) {
+          state.selectOrchestra = data[0]
+        }
       } catch {
         //
       }
     }
 
-    onMounted(() => {
-      getOrchestras()
-      getList()
+    const onMessage = async (item: any) => {
+      console.log(item)
+      postMessage({
+        api: 'joinChatGroup',
+        content: {
+          type: 'multi', // single 单人 multi 多人
+          id: item.classGroupId
+        }
+      })
+    }
+
+    onMounted(async () => {
+      await getOrchestras()
+      await getList()
     })
     return () => (
       <div class={styles.myOrchestra}>
         <OHeader
           v-slots={{
-            right: () => (
-              <span
-                onClick={() => {
-                  router.push('/apply-withdrawal')
-                }}
-              >
-                申请退团
-              </span>
-            )
+            right: () =>
+              state.selectOrchestra.orchestraId && (
+                <span
+                  onClick={() => {
+                    router.push({
+                      path: '/apply-withdrawal',
+                      query: {
+                        id: state.selectOrchestra.orchestraId
+                      }
+                    })
+                  }}
+                >
+                  申请退团
+                </span>
+              )
           }}
         />
-
-        <CellGroup inset class={styles.oList}>
-          <Cell center clickable>
-            {{
-              title: () => (
-                <div class={styles.orchestra}>
-                  <i></i>
-                  <span class="van-ellipsis">
-                    武汉小学2022标准团武汉小学2022标准团武汉小学2022标准团
-                  </span>
-                </div>
-              ),
-              value: () => (
-                <div class={styles.iconChange}>
-                  切换乐团 <Image src={iconChange} class={styles.img} />
-                </div>
-              )
-            }}
-          </Cell>
-        </CellGroup>
-
-        <div class={[styles.gridContainer, styles.gridClass]}>
-          {[1, 2].map((item: any) => (
-            <CellGroup class={styles.classCellGroup}>
-              <Cell
-                center
-                titleStyle={{ flex: '0 auto' }}
-                valueClass={styles.classCheckbox}
-                border={false}
-              >
+        {state.orchestraList.length > 0 ? (
+          <>
+            <CellGroup inset class={styles.oList}>
+              <Cell center clickable>
                 {{
-                  icon: () => <Image src={iconTeacher} class={styles.img} />,
                   title: () => (
-                    <div class={styles.content}>
-                      <div class={styles.teacherName}>
-                        1211212 <Tag type="primary">长笛班</Tag>
-                      </div>
+                    <div class={styles.orchestra}>
+                      <i></i>
+                      <span class="van-ellipsis">{state.selectOrchestra.orchestraName}</span>
                     </div>
                   ),
-                  value: () => <Image class={styles.messageImg} src={iconMessage} />
+                  value: () =>
+                    state.selectOrchestra.classGroupIdList &&
+                    state.selectOrchestra.classGroupIdList.length > 0 && (
+                      <div
+                        class={styles.iconChange}
+                        onClick={() => {
+                          state.orchestraStatus = true
+                        }}
+                      >
+                        切换乐团 <Image src={iconChange} class={styles.img} />
+                      </div>
+                    )
                 }}
               </Cell>
-              <Grid border={false} columnNum={3}>
-                <GridItem>
-                  <p class={styles.title}>1/2</p>
-                  <p class={styles.name}>课程</p>
-                </GridItem>
-                <GridItem>
-                  <p class={[styles.title]}>1/2</p>
-                  <p class={styles.name}>课后练习</p>
-                </GridItem>
-                <GridItem>
-                  <p class={styles.title}>1/2</p>
-                  <p class={styles.name}>单元测试</p>
-                </GridItem>
-              </Grid>
             </CellGroup>
-          ))}
-        </div>
-
-        <div class={styles.title}>
-          <i></i>训练照片
-        </div>
+            <div class={[styles.gridContainer, styles.gridClass]}>
+              {state.selectOrchestra.classGroupIdList &&
+                state.selectOrchestra.classGroupIdList.map((item: any) => (
+                  <CellGroup class={styles.classCellGroup}>
+                    <Cell
+                      center
+                      titleStyle={{ flex: '0 auto' }}
+                      valueClass={styles.classCheckbox}
+                      border={false}
+                    >
+                      {{
+                        icon: () => (
+                          <Image src={item.teacherAvatar || iconTeacher} class={styles.img} />
+                        ),
+                        title: () => (
+                          <div class={styles.content}>
+                            <div class={styles.teacherName}>
+                              <span class={[styles.name, 'van-ellipsis']}>{item.teacherName}</span>
+                              <Tag type="primary">{item.classGroupName}</Tag>
+                            </div>
+                          </div>
+                        ),
+                        value: () => (
+                          <Image
+                            class={styles.messageImg}
+                            src={iconMessage}
+                            onClick={() => onMessage(item)}
+                          />
+                        )
+                      }}
+                    </Cell>
+                    <Grid border={false} columnNum={3}>
+                      <GridItem>
+                        <p class={styles.title}>
+                          {item.completeCourseNum || 0}/{item.totalCourseNum || 0}
+                        </p>
+                        <p class={styles.name}>课程</p>
+                      </GridItem>
+                      <GridItem>
+                        <p class={[styles.title]}>
+                          {item.completeTrainingNum || 0}/{item.totalTrainingNum || 0}
+                        </p>
+                        <p class={styles.name}>课后练习</p>
+                      </GridItem>
+                      <GridItem>
+                        <p class={styles.title}>
+                          {item.completeUnitTestNum || 0}/{item.totalUnitTestNum || 0}
+                        </p>
+                        <p class={styles.name}>单元测试</p>
+                      </GridItem>
+                    </Grid>
+                  </CellGroup>
+                ))}
+            </div>
+            <div class={styles.title}>
+              <i></i>训练照片
+            </div>
+            {state.listState.dataShow ? (
+              <List
+                v-model:loading={state.listState.loading}
+                finished={state.listState.finished}
+                finishedText=" "
+                onLoad={getList}
+                immediateCheck={false}
+              >
+                <div class={styles.phoneContainer}>
+                  {state.list.map((item: any) => (
+                    <div class={styles.item} onClick={() => onDetail(item)}>
+                      {item.coverUrl ? (
+                        <Image class={styles.img} src={item.coverUrl} />
+                      ) : (
+                        <div class={[styles.img, styles.default]}>
+                          <Image src={iconPhoneDefaut} class={styles.defaultImg} />
+                        </div>
+                      )}
 
-        {state.listState.dataShow ? (
-          <List
-            v-model:loading={state.listState.loading}
-            finished={state.listState.finished}
-            finishedText=" "
-            onLoad={getList}
-            immediateCheck={false}
-          >
-            <div class={styles.phoneContainer}>
-              {state.list.map((item: any) => (
-                <div class={styles.item} onClick={() => onDetail(item)}>
-                  {item.coverUrl ? (
-                    <Image class={styles.img} src={item.coverUrl} />
-                  ) : (
-                    <div class={[styles.img, styles.default]}>
-                      <Image src={iconPhoneDefaut} class={styles.defaultImg} />
+                      <p class={[styles.name, 'van-ellipsis']}>{item.name}</p>
+                      <p class={styles.num}>{item.photoCount}张</p>
                     </div>
-                  )}
-
-                  <p class={[styles.name, 'van-ellipsis']}>{item.name}</p>
-                  <p class={styles.num}>{item.photoCount}张</p>
+                  ))}
                 </div>
-              ))}
-            </div>
-          </List>
+              </List>
+            ) : (
+              <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无相册" />
+            )}
+          </>
         ) : (
-          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无相册" />
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无乐团" />
         )}
+
+        <Popup v-model:show={state.orchestraStatus} position="bottom" round>
+          <Picker
+            columns={state.orchestraList}
+            columnsFieldNames={{ text: 'orchestraName', value: 'orchestraId' }}
+            onCancel={() => (state.orchestraStatus = false)}
+            onConfirm={(val: any) => {
+              const selectValue = val.selectedValues[0]
+              if (selectValue === state.selectOrchestra.orchestraId) {
+                state.orchestraStatus = false
+                return
+              }
+
+              state.orchestraList.forEach((item: any) => {
+                if (item.orchestraId === selectValue) {
+                  state.selectOrchestra = item
+                }
+              })
+
+              state.orchestraStatus = false
+            }}
+          />
+        </Popup>
       </div>
     )
   }

+ 8 - 1
src/student/trade-record/component/wait-pay.tsx

@@ -116,7 +116,14 @@ export default defineComponent({
 
     const onConfirmOrder = async (item: any) => {
       console.log(item)
-      // const { data } = await request.get('/api-student/userPaymentOrder/unpaid')
+      const { data } = await request.get('/api-student/userPaymentOrder/unpaid', {
+        requestType: 'form',
+        data: {
+          orderNo: item.orderNo,
+          paymentType: item.orderType
+        }
+      })
+      console.log(data)
     }
 
     const onDetails = (item: any) => {