Bläddra i källkod

Merge branch 'master' of http://git.dayaedu.com/lex/orchestra-app

mo 2 år sedan
förälder
incheckning
3bfcb23850
33 ändrade filer med 569 tillägg och 150 borttagningar
  1. 1 1
      public/project/schoolRegister.html
  2. BIN
      src/common/images/icon_logo.png
  3. 6 1
      src/components/o-popup/index.tsx
  4. 1 1
      src/helpers/validate.ts
  5. 8 0
      src/router/routes-common.ts
  6. 14 1
      src/school/approval-manage/batch-adjust.tsx
  7. 1 0
      src/school/companion-teacher/companion-teacher-register.tsx
  8. BIN
      src/school/manage-teacher/images/banner.png
  9. 2 2
      src/school/manage-teacher/manage-teacher-register.module.less
  10. 9 9
      src/school/manage-teacher/manage-teacher-register.tsx
  11. 6 3
      src/school/save-share-image/index.tsx
  12. 7 1
      src/school/train-planning/modal/calendar/index.tsx
  13. 13 6
      src/student/music-group/pre-apply/order-detail.tsx
  14. 129 0
      src/student/music-group/pre-apply/qrcode-payment/index.module.less
  15. 50 0
      src/student/music-group/pre-apply/qrcode-payment/index.tsx
  16. 0 3
      src/student/my-orchestra/index.tsx
  17. 2 0
      src/views/coursewarePlay/index.module.less
  18. 15 18
      src/views/coursewarePlay/index.tsx
  19. BIN
      src/views/follow-account/images/bg.png
  20. BIN
      src/views/follow-account/images/bottom_bg.png
  21. BIN
      src/views/follow-account/images/btn.png
  22. BIN
      src/views/follow-account/images/content1.png
  23. BIN
      src/views/follow-account/images/content2.png
  24. BIN
      src/views/follow-account/images/icon_small.png
  25. BIN
      src/views/follow-account/images/qrcode.jpg
  26. BIN
      src/views/follow-account/images/top_bg.png
  27. 43 0
      src/views/follow-account/index.module.less
  28. 87 0
      src/views/follow-account/index.tsx
  29. 84 13
      src/views/mine-orchestra/index.tsx
  30. 52 61
      src/views/mine-orchestra/my-class/index.tsx
  31. 15 12
      src/views/mine-orchestra/photo-list/detail.tsx
  32. 9 2
      src/views/mine-orchestra/photo-list/index.module.less
  33. 15 16
      src/views/mine-orchestra/photo-list/index.tsx

+ 1 - 1
public/project/schoolRegister.html

@@ -144,7 +144,7 @@
       :close-on-click-overlay="false">
       <div class="submit-container">
         <p class="submit-title">提交成功</p>
-        <p class="submit-tips">感谢您的参与</p>
+        <p class="submit-tips">感谢您的参与!</p>
         <div @click="onLinkUrl" class="submit-btn"></div>
       </div>
     </van-popup>

BIN
src/common/images/icon_logo.png


+ 6 - 1
src/components/o-popup/index.tsx

@@ -28,6 +28,10 @@ export default defineComponent({
     zIndex: {
       type: Number,
       default: 2018
+    },
+    onClose: {
+      type: Function,
+      default: () => {}
     }
   },
   data() {
@@ -53,6 +57,7 @@ export default defineComponent({
     onHash() {
       this.$emit('update:modelValue', false)
       this.isDestroy = false
+      this.onClose && this.onClose()
     },
     onPopupClose(val: boolean) {
       this.$emit('update:modelValue', val)
@@ -65,7 +70,7 @@ export default defineComponent({
         const splitUrl = window.location.hash.slice(1).split('?')
         const query = qs.parse(splitUrl[1])
         let times = 0
-        for (let key in query) {
+        for (const key in query) {
           times++
         }
         const origin = window.location.href

+ 1 - 1
src/helpers/validate.ts

@@ -19,7 +19,7 @@ export function vaildStudentUrl() {
 }
 
 export function checkPhone(phone: string) {
-  const phoneRule = /^((13[0-9])|(14(0|[5-7]|9))|(15([0-3]|[5-9]))|(16(2|[5-7]))|(17[0-8])|(18[0-9])|(19([0-3]|[5-9])))\\d{8}$/;
+  const phoneRule = /^((13[0-9])|(14(0|[5-7]|9))|(15([0-3]|[5-9]))|(16(2|[5-7]))|(17[0-8])|(18[0-9])|(19([0-3]|[5-9])))\d{8}$/;
   return phoneRule.test(phone);
 }
 

+ 8 - 0
src/router/routes-common.ts

@@ -236,6 +236,14 @@ export const rootRouter = [
     }
   },
   {
+    path: '/follow-account',
+    name: 'follow-account',
+    component: () => import('@/views/follow-account'),
+    meta: {
+      title: '关注微信公众号'
+    }
+  },
+  {
     path: '/:pathMatch(.*)*',
     component: () => import('@/views/404'),
     meta: {

+ 14 - 1
src/school/approval-manage/batch-adjust.tsx

@@ -30,6 +30,9 @@ export default defineComponent({
   name: 'batch-adjust',
   setup() {
     const router = useRouter()
+    const form = reactive({
+      submitLoading: false
+    })
 
     // 获取乐团列表
     const getOrchestra = async () => {
@@ -55,7 +58,9 @@ export default defineComponent({
 
     const onSubmit = async () => {
       try {
+        form.submitLoading = true
         const { data } = await request.post('/api-school/courseSchedule/batchAdjust', {
+          hideLoading: true,
           data: {
             adjustDay: forms.changeType ? '-' + forms.adjustDay : forms.adjustDay,
             classGroupIdList: forms.classGroupIdList,
@@ -63,6 +68,7 @@ export default defineComponent({
             endTime: forms.endTime.join('-')
           }
         })
+        form.submitLoading = false
         router.push({
           path: '/course-preview',
           query: {
@@ -71,6 +77,7 @@ export default defineComponent({
         })
       } catch {
         //
+        form.submitLoading = false
       }
     }
 
@@ -195,7 +202,13 @@ export default defineComponent({
             >
               取消
             </Button>
-            <Button color="#FF8057" round onClick={onSubmit}>
+            <Button
+              color="#FF8057"
+              round
+              onClick={onSubmit}
+              disabled={form.submitLoading}
+              loading={form.submitLoading}
+            >
               下一步
             </Button>
           </div>

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

@@ -170,6 +170,7 @@ export default defineComponent({
 
     const onSendCode = () => {
       // 发送验证码
+      console.log(state.forms.phone)
       if (!checkPhone(state.forms.phone as any)) {
         return showToast('请输入正确的手机号码')
       }

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


+ 2 - 2
src/school/manage-teacher/manage-teacher-register.module.less

@@ -46,7 +46,7 @@ span {
     }
 
     .van-form {
-      margin-top: 174px;
+      margin-top: 220px;
       /* background: #F8F8F8; */
       overflow: hidden;
       /* margin: 290px 13px 14px; */
@@ -120,7 +120,7 @@ span {
   line-height: 22px;
   text-shadow: 0px 1px 5px #ff5e20;
   display: flex;
-  align-items: center;
+  align-items: flex-start;
 }
 
 .tips img {

+ 9 - 9
src/school/manage-teacher/manage-teacher-register.tsx

@@ -166,7 +166,7 @@ export default defineComponent({
             title: '提示',
             message: res.message,
             theme: 'round-button',
-            confirmButtonColor: '#64A9FF'
+            confirmButtonColor: '#FF8057'
           })
 
           state.qrCodeStatus = true
@@ -221,7 +221,7 @@ export default defineComponent({
         showDialog({
           message: '信息获取失败,请联系老师',
           theme: 'round-button',
-          confirmButtonColor: '#64A9FF'
+          confirmButtonColor: '#FF8057'
         })
       }
     })
@@ -363,14 +363,14 @@ export default defineComponent({
               {{
                 input: () => (
                   <RadioGroup
-                    checked-color="#64A9FF"
+                    checked-color="#FF8057"
                     v-model={state.forms.gender}
                     direction="horizontal"
                   >
                     <Tag
                       size="large"
                       type="primary"
-                      color={!(state.forms.gender === 1) ? '#EAEAEA' : '#64A9FF'}
+                      color={!(state.forms.gender === 1) ? '#EAEAEA' : '#FF8057'}
                       textColor={!(state.forms.gender === 1) ? '#AAA' : '#FFF'}
                       class={styles.radioSection}
                       round
@@ -380,7 +380,7 @@ export default defineComponent({
                     <Tag
                       size="large"
                       type="primary"
-                      color={!(state.forms.gender === 0) ? '#EAEAEA' : '#64A9FF'}
+                      color={!(state.forms.gender === 0) ? '#EAEAEA' : '#FF8057'}
                       textColor={!(state.forms.gender === 0) ? '#AAA' : '#FFF'}
                       class={styles.radioSection}
                       round
@@ -403,7 +403,7 @@ export default defineComponent({
               {{
                 button: () =>
                   state.countDownStatus ? (
-                    <Button type="primary" round size="small" color="#64A9FF" onClick={onSendCode}>
+                    <Button type="primary" round size="small" color="#FF8057" onClick={onSendCode}>
                       发送验证码
                     </Button>
                   ) : (
@@ -427,7 +427,7 @@ export default defineComponent({
               v-model={state.checked}
               icon-size="16"
               style="margin-right: 6px"
-              checked-color="#64A9FF"
+              checked-color="#FF8057"
             ></Checkbox>
             <div>
               <span
@@ -456,7 +456,7 @@ export default defineComponent({
             block
             round
             class={styles['btn-submit']}
-            color="#64A9FF"
+            color="#FF8057"
             loading={state.btnLoading}
             native-type="submit"
           >
@@ -476,7 +476,7 @@ export default defineComponent({
               <p class={styles['submit-tips']}>请下载管乐团管理端APP</p>
               <Button
                 type="primary"
-                color="#64A9FF"
+                color="#FF8057"
                 block
                 round
                 onClick={() => {

+ 6 - 3
src/school/save-share-image/index.tsx

@@ -21,6 +21,7 @@ import iconWeichat from './images/icon-weichat.png'
 import teacherTopBg from './images/teacher-top_bg.png'
 import manageTopBg from './images/manage-top_bg.png'
 import orchestraTopBg from './images/orchestra-top_bg.png'
+import defaultLogo from '@/common/images/logo@2x.png'
 
 export default defineComponent({
   name: 'save-share-image',
@@ -151,7 +152,9 @@ export default defineComponent({
 
         state.schoolName = res.data.name
         state.schoolId = res.data.id
-        state.schoolLogo = res.data.logo + '@base@tag=imgScale&w=570?t=' + +new Date()
+        state.schoolLogo = res.data.logo
+          ? res.data.logo + '@base@tag=imgScale&w=570?t=' + +new Date()
+          : ''
         // 生成二维码
         if (state.type === 'teacher') {
           state.url =
@@ -230,7 +233,7 @@ export default defineComponent({
             <>
               <img
                 class={[styles.schoolLogo]}
-                src={state.schoolLogo}
+                src={state.schoolLogo || defaultLogo}
                 crossorigin="anonymous"
                 style={{
                   objectFit: 'cover'
@@ -290,7 +293,7 @@ export default defineComponent({
                 <>
                   <img
                     class={[styles.schoolLogo]}
-                    src={state.schoolLogo}
+                    src={state.schoolLogo || defaultLogo}
                     crossorigin="anonymous"
                     style={{
                       objectFit: 'cover'

+ 7 - 1
src/school/train-planning/modal/calendar/index.tsx

@@ -132,8 +132,10 @@ export default defineComponent({
       // 上一月
       if (this.arrowStatus) return
       const tempDate = dayjs(this.currentDate).subtract(1, 'month')
+      // console.log(dayjs(tempDate).format('YYYY-MM-DD HH:mm:ss'), 'tempDate')
       this._monthChange(tempDate)
       // this._dayChange(this.minDate)
+      // console.log(dayjs(this.minDate).format('YYYY-MM-DD HH:mm:ss'), 'this.minDate')
       this.prevMonth && this.prevMonth(this.minDate)
     },
     onNextMonth() {
@@ -146,8 +148,12 @@ export default defineComponent({
     _monthChange(date: any) {
       // 月份改变
       // 需要判断是否是当月,需要单独处理最小时间
-      const currentMinDate = dayjs().add(1, 'day').toDate()
+      const currentMinDate = dayjs().toDate()
       const monthMinDate = date.startOf('month').toDate()
+      // console.log(date.startOf('month').format('YYYY-MM-DD HH:mm:ss'), 'temp ----- date')
+      // console.log(dayjs(date).format('YYYY-MM-DD HH:mm:ss'), 'date')
+      // console.log(dayjs(currentMinDate).format('YYYY-MM-DD HH:mm:ss'), 'currentMinDate')
+      // console.log(dayjs(monthMinDate).format('YYYY-MM-DD HH:mm:ss'), 'monthMinDate')
       this.minDate = dayjs(currentMinDate).isAfter(monthMinDate) ? currentMinDate : monthMinDate
       this.maxDate = date.endOf('month').toDate()
       this.currentDate = date.toDate()

+ 13 - 6
src/student/music-group/pre-apply/order-detail.tsx

@@ -18,6 +18,7 @@ import MemberBao from '../member-bao'
 import GoodsDetail from '../goods-detail'
 import ODialog from '@/components/o-dialog'
 import { orderStatus } from '@/constant'
+import QrcodePayment from './qrcode-payment'
 
 export default defineComponent({
   name: 'order-detail',
@@ -472,19 +473,27 @@ export default defineComponent({
           />
         </Popup>
 
-        <Popup
+        <OPopup
+          v-model:modelValue={state.showQrcode}
+          onClose={() => {
+            // 二维码关闭时清除定时器
+            clearInterval(state.orderTimer)
+          }}
+        >
+          <QrcodePayment url={state.qrCodeUrl} />
+        </OPopup>
+        {/* <Popup
           v-model:show={state.showQrcode}
           style={{ background: 'transparent', overflow: 'initial' }}
           safeAreaInsetBottom={true}
           class={styles.popupCode}
           closeable
           onClose={() => {
-            // 二维码关闭时清除订单器
+            // 二维码关闭时清除定时
             clearInterval(state.orderTimer)
           }}
         >
           <div class={styles.codeContainer}>
-            {/* <i class={styles.codeClose} onClick={() => (state.showQrcode = false)}></i> */}
             <div class={styles.codeImg}>
               <div class={styles.codeContent}>
                 <h2 class={styles.codeTitle}>
@@ -504,8 +513,6 @@ export default defineComponent({
                 <div class={styles.codeTips}>
                   <div class={styles.tipsTitle}>使用说明:</div>
                   <div class={styles.tipsContent}>
-                    {/* 1.长按二维码保存图片到相册(或截屏保存到相册) */}
-                    {/* <br /> */}
                     1.打开{state.pay_channel === 'wx_pub' ? '微信' : '支付宝'}扫一扫
                     <br />
                     2.选择相册中的二维码
@@ -516,7 +523,7 @@ export default defineComponent({
               </div>
             </div>
           </div>
-        </Popup>
+        </Popup> */}
 
         <OPopup v-model:modelValue={state.authShow}>
           <UserAuth onSuccess={onAuthSuccess} hideHeader={!browser().isApp} />

+ 129 - 0
src/student/music-group/pre-apply/qrcode-payment/index.module.less

@@ -0,0 +1,129 @@
+.saveShareImage {
+  position: relative;
+  min-height: 100vh;
+  overflow: hidden;
+  &::before {
+    content: ' ';
+    background: linear-gradient(134deg, #ff906c 0%, #ff602d 100%);
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: -1;
+  }
+}
+
+.previewSection {
+  z-index: -1;
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+}
+
+.topImage {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+}
+
+.shareContaienr {
+  position: relative;
+  margin: 212px 22px 0;
+  padding-top: 50px;
+  padding-bottom: 23px;
+  background: #ffffff;
+  border-radius: 18px;
+  text-align: center;
+
+  &.orchestraContainer {
+    margin-top: 168px;
+    padding-top: 20px;
+    .schoolName {
+      font-size: 20px;
+      font-weight: 500;
+      color: #f67146;
+      line-height: 28px;
+    }
+  }
+
+  &.tips {
+    margin-top: 15px;
+    padding: 12px 22px 15px;
+    text-align: left;
+    .tipsTitle {
+      font-size: 15px;
+      font-weight: 500;
+      color: #f16437;
+      line-height: 21px;
+    }
+    .tipsContent {
+      padding-top: 7px;
+      font-size: 13px;
+      color: #333333;
+      line-height: 20px;
+    }
+  }
+
+  .schoolLogo {
+    position: absolute;
+    left: 50%;
+    top: 0;
+    // transform: translate(-50%, -50%);
+    margin-top: -38px;
+    margin-left: -38px;
+    width: 76px;
+    height: 76px;
+    border-radius: 50%;
+    overflow: hidden;
+    border: 3px solid #fff;
+    background-color: #fff;
+  }
+
+  .schoolName {
+    font-size: 17px;
+    font-weight: 500;
+    color: #000000;
+    line-height: 24px;
+    padding: 0 30px 0;
+  }
+  .shareType {
+    font-size: 15px;
+    padding: 8px 0 20px;
+    color: #000000;
+    line-height: 21px;
+    span {
+      color: #f67146;
+    }
+  }
+  .qrcodeSection {
+    width: 150px;
+    height: 150px;
+    background: url('@/school/save-share-image/images/icon-qrcode-bg.png') no-repeat center center;
+    background-size: contain;
+    margin: 0 auto;
+    padding: 14px;
+  }
+  .memo {
+    display: inline-block;
+    margin: 17px 0 11px;
+    background: linear-gradient(135deg, #ff9c63 0%, #ff7144 100%);
+    border-radius: 18px;
+    font-size: 16px;
+    font-family: PingFangSC-Medium, PingFang SC;
+    font-weight: 500;
+    color: #ffffff;
+    line-height: 22px;
+    padding: 6px 16px;
+  }
+  .endTime {
+    font-size: 13px;
+    color: #666666;
+    line-height: 18px;
+    span {
+      color: #ff8057;
+    }
+  }
+}

+ 50 - 0
src/student/music-group/pre-apply/qrcode-payment/index.tsx

@@ -0,0 +1,50 @@
+import { defineComponent } from 'vue'
+import { Image } from 'vant'
+import styles from './index.module.less'
+import orchestraTopBg from '@/school/save-share-image/images/orchestra-top_bg.png'
+import OQrcode from '@/components/o-qrcode'
+
+export default defineComponent({
+  name: 'qrcode-payment',
+  props: {
+    url: {
+      type: String,
+      default: ''
+    },
+    pay_channel: {
+      type: String,
+      default: 'wx_pub'
+    }
+  },
+  setup(props) {
+    return () => (
+      <div class={[styles.saveShareImage]}>
+        <Image src={orchestraTopBg} class={styles.topImage} />
+        <div class={[styles.shareContaienr, styles.orchestraContainer]}>
+          <div class={styles.schoolName}>报名缴费</div>
+          <div class={styles.shareType}>
+            请截图下方二维码
+            <span>登录支付宝扫码支付</span>
+          </div>
+
+          <div class={styles.qrcodeSection}>
+            <OQrcode text={props.url} logoSize={'small'} size={'100%'} />
+          </div>
+
+          <div class={styles.memo}>请在30分钟内扫码支付</div>
+        </div>
+
+        <div class={[styles.shareContaienr, styles.tips]}>
+          <div class={styles.tipsTitle}>使用说明:</div>
+          <div class={styles.tipsContent}>
+            1.打开{props.pay_channel === 'wx_pub' ? '微信' : '支付宝'}扫一扫
+            <br />
+            2.选择相册中的二维码
+            <br />
+            3.请在30分钟内扫码支付
+          </div>
+        </div>
+      </div>
+    )
+  }
+})

+ 0 - 3
src/student/my-orchestra/index.tsx

@@ -136,9 +136,6 @@ export default defineComponent({
                 {state.selectOrchestra.status === 'AUTH' && (
                   <span style={{ color: 'red' }}>申请退团中</span>
                 )}
-                {/* {state.selectOrchestra.status === 'OUTOF_ORCHESTRA' && (
-                  <span style={{ color: '#666' }}>已退团</span>
-                )} */}
               </>
             )
           }}

+ 2 - 0
src/views/coursewarePlay/index.module.less

@@ -2,6 +2,7 @@
   width: 100vw;
   height: 100vh;
   background-color: #000;
+  overflow: hidden;
 }
 .coursewarePlay {
   position: relative;
@@ -28,6 +29,7 @@
   align-items: center;
   justify-content: space-between;
   background: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent);
+  transition: transform 0.5s;
 }
 .backBtn {
   color: #fff;

+ 15 - 18
src/views/coursewarePlay/index.tsx

@@ -158,7 +158,8 @@ export default defineComponent({
           }
         )
         if (res?.data) {
-          data.isCourse = res.data.status === 'ING' ? true : false
+          data.isCourse =
+            res.data.status === 'ING' && state.platformType == 'TEACHER' ? true : false
         }
       } catch (e) {
         console.log(e)
@@ -596,11 +597,6 @@ export default defineComponent({
                               <div>{m.name}</div>
                             </div>
                           </div>
-                          {/* <Transition name="bottom">
-                            {activeData.model && (
-                              
-                            )}
-                          </Transition> */}
                         </>
                       ) : m.type === 'IMG' ? (
                         <img src={m.content} />
@@ -620,18 +616,19 @@ export default defineComponent({
             })}
           </Swipe>
 
-          <Transition name="top">
-            {activeData.model && (
-              <div id="coursePlayHeader" class={styles.headerContainer} ref={headeRef}>
-                <div class={styles.backBtn} onClick={() => goback()}>
-                  <Icon name={iconBack} />
-                  返回
-                </div>
-                <div class={styles.menu}>{popupData.tabName}</div>
-                {data.isCourse && <PlayRecordTime list={data.itemList} />}
-              </div>
-            )}
-          </Transition>
+          <div
+            style={{ transform: activeData.model ? '' : 'translateY(-100%)' }}
+            id="coursePlayHeader"
+            class={styles.headerContainer}
+            ref={headeRef}
+          >
+            <div class={styles.backBtn} onClick={() => goback()}>
+              <Icon name={iconBack} />
+              返回
+            </div>
+            <div class={styles.menu}>{popupData.tabName}</div>
+            {data.isCourse && <PlayRecordTime list={data.itemList} />}
+          </div>
 
           <Transition name="right">
             {activeData.model && (

BIN
src/views/follow-account/images/bg.png


BIN
src/views/follow-account/images/bottom_bg.png


BIN
src/views/follow-account/images/btn.png


BIN
src/views/follow-account/images/content1.png


BIN
src/views/follow-account/images/content2.png


BIN
src/views/follow-account/images/icon_small.png


BIN
src/views/follow-account/images/qrcode.jpg


BIN
src/views/follow-account/images/top_bg.png


+ 43 - 0
src/views/follow-account/index.module.less

@@ -0,0 +1,43 @@
+.followAccount {
+  position: relative;
+  min-height: 100vh;
+  background: url('./images/top_bg.png') no-repeat top center,
+    url('./images/bottom_bg.png') no-repeat bottom center,
+    url('./images/bg.png') repeat center center;
+  background-color: #5cbd75;
+  background-size: 100%;
+  padding: 443px 20px 0;
+  overflow: hidden;
+
+  &::before {
+    content: ' ';
+    position: absolute;
+    width: 50px;
+    height: 47px;
+    background: url('./images/icon_small.png') no-repeat center center;
+    background-size: contain;
+    left: 0;
+    top: 640px;
+    z-index: 1;
+  }
+
+  .content2 {
+    padding: 30px 0;
+  }
+
+  .saveQrcode {
+    background: url('./images/btn.png') no-repeat center center;
+    background-size: contain;
+    width: 300px;
+    height: 50px;
+    margin: 0 auto;
+    margin-bottom: 70px;
+  }
+
+  .followQrcode {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: -1;
+  }
+}

+ 87 - 0
src/views/follow-account/index.tsx

@@ -0,0 +1,87 @@
+import {
+  closeToast,
+  Image,
+  showFailToast,
+  showLoadingToast,
+  showSuccessToast,
+  showToast
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+import content1 from './images/content1.png'
+import content2 from './images/content2.png'
+import qrcode from './images/qrcode.jpg'
+import html2canvas from 'html2canvas'
+import { promisefiyPostMessage, postMessage } from '@/helpers/native-message'
+
+export default defineComponent({
+  name: 'follow-account',
+  setup() {
+    const imgs = reactive({
+      saveLoading: false,
+      image: null as any,
+      shareLoading: false
+    })
+    const onSaveImg = async () => {
+      // 判断是否在保存中...
+      if (imgs.saveLoading) {
+        return
+      }
+      imgs.saveLoading = true
+      // 判断是否已经生成图片
+      if (imgs.image) {
+        saveImg()
+      } 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
+            saveImg()
+          })
+          .catch(() => {
+            closeToast()
+            imgs.saveLoading = false
+          })
+      }
+    }
+
+    const saveImg = async () => {
+      showLoadingToast({ message: '图片生成中...', forbidClick: true })
+      setTimeout(() => {
+        imgs.saveLoading = false
+      }, 100)
+      const res = await promisefiyPostMessage({
+        api: 'savePicture',
+        content: {
+          base64: imgs.image
+        }
+      })
+      if (res?.content?.status === 'success') {
+        showSuccessToast('保存成功')
+      } else {
+        showFailToast('保存失败')
+      }
+    }
+
+    onMounted(() => {
+      postMessage({ api: 'setBarStatus', content: { status: 0 } })
+    })
+    return () => (
+      <div class={styles.followAccount}>
+        <Image src={content1} class={styles.content1} />
+        <Image src={content2} class={styles.content2} />
+
+        <div class={styles.saveQrcode} onClick={onSaveImg}></div>
+
+        <div id="preview-container" class={styles.followQrcode}>
+          <Image src={qrcode} />
+        </div>
+      </div>
+    )
+  }
+})

+ 84 - 13
src/views/mine-orchestra/index.tsx

@@ -3,7 +3,7 @@ import OSticky from '@/components/o-sticky'
 import request from '@/helpers/request'
 import { state } from '@/state'
 import { Cell, CellGroup, Picker, Popup, Tab, Tabs } from 'vant'
-import { defineComponent, onMounted, reactive, ref } from 'vue'
+import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue'
 import styles from './index.module.less'
 import iconOrchestra from './images/icon-or.png'
 import MyClass from './my-class'
@@ -11,11 +11,14 @@ import OEmpty from '@/components/o-empty'
 import OFullRefresh from '@/components/o-full-refresh'
 import OrchestraDeeds from './orchestra-deeds'
 import MyPhoto from './my-photo'
+import { useRoute, useRouter } from 'vue-router'
 
 export default defineComponent({
   name: 'my-orchestra',
   setup(props, ctx) {
-    const tabActive = ref('乐团相册')
+    const route = useRoute()
+    const router = useRouter()
+    const tabActive = ref<'course' | 'photo' | 'deeds'>((route.query as any)?.tab || 'course')
     const data = reactive({
       orchestraList: [] as any[],
       loading: true
@@ -24,6 +27,25 @@ export default defineComponent({
       orchestra: {} as any,
       orchestraStatus: false
     })
+    /** 学生获取我的乐团 */
+    const getStudentOrchestras = () => {
+      data.loading = true
+      request.post(`${state.platformApi}/orchestra/studentOrchestra`).then((res: any) => {
+        if (Array.isArray(res?.data)) {
+          data.orchestraList = res.data.map((n: any) => {
+            return {
+              ...n,
+              name: n.name || n.orchestraName || '',
+              id: n.id || n.orchestraId || ''
+            }
+          })
+          modelData.orchestra = data.orchestraList[0] || {}
+        }
+      })
+      setTimeout(() => {
+        data.loading = false
+      }, 300)
+    }
     const getOrchestras = async () => {
       data.loading = true
       try {
@@ -37,8 +59,15 @@ export default defineComponent({
       } catch {}
       data.loading = false
     }
+    const getData = () => {
+      getStudentOrchestras()
+      // if (state.platformType === 'STUDENT') {
+      // } else {
+      //   getOrchestras()
+      // }
+    }
     onMounted(() => {
-      getOrchestras()
+      getData()
     })
 
     return () => (
@@ -48,13 +77,45 @@ export default defineComponent({
             document.documentElement.style.setProperty('--header-height', height + 'px')
           }}
         >
-          <OHeader title="我的乐团" />
+          <OHeader
+            title="我的乐团"
+            v-slots={{
+              right: () => (
+                <>
+                  {state.platformType == 'STUDENT' && (
+                    <>
+                      {(modelData.orchestra?.status === 'REGISTER' ||
+                        modelData.orchestra?.status === 'LEARNING') && (
+                        <span
+                          onClick={() => {
+                            router.push({
+                              path: '/apply-withdrawal',
+                              query: {
+                                id: modelData.orchestra?.orchestraId
+                              }
+                            })
+                          }}
+                        >
+                          申请退团
+                        </span>
+                      )}
+                      {modelData.orchestra?.status === 'AUTH' && (
+                        <span style={{ color: 'red' }}>申请退团中</span>
+                      )}
+                    </>
+                  )}
+                </>
+              )
+            }}
+          />
         </OSticky>
         <OFullRefresh
           v-model:modelValue={data.loading}
           onRefresh={() => {
             data.orchestraList = []
-            getOrchestras()
+            nextTick(() => {
+              getData()
+            })
           }}
           style="min-height: calc(100vh - var(--van-nav-bar-height) - var(--header-height))"
         >
@@ -71,21 +132,31 @@ export default defineComponent({
               }}
             </Cell>
           </CellGroup>
-          {!!data.orchestraList.length && (
-            <Tabs v-model:active={tabActive.value} class={styles.tabs} lazyRender={true} background="transparent" animated swipeable>
-              <Tab name="我的班级" title="我的班级">
+          {!data.loading && !!data.orchestraList.length && (
+            <Tabs
+              v-model:active={tabActive.value}
+              class={styles.tabs}
+              lazyRender={true}
+              background="transparent"
+              animated
+              swipeable
+            >
+              <Tab name="course" title="我的班级">
                 <div class={styles.content}>
-                  <MyClass orchestraId={modelData.orchestra?.id || ''} />
+                  <MyClass
+                    list={modelData.orchestra?.classGroupIdList || []}
+                    orchestraId={modelData.orchestra?.id || ''}
+                  />
                 </div>
               </Tab>
-              <Tab name="乐团相册" title="乐团相册">
+              <Tab name="photo" title="乐团相册">
                 <div class={styles.content}>
-                    <MyPhoto orchestraId={modelData.orchestra?.id || ''} />
+                  <MyPhoto orchestraId={modelData.orchestra?.id || ''} />
                 </div>
               </Tab>
-              <Tab name="乐团事迹" title="乐团事迹">
+              <Tab name="deeds" title="乐团事迹">
                 <div class={styles.content}>
-                    <OrchestraDeeds orchestraId={modelData.orchestra?.id || ''} />
+                  <OrchestraDeeds orchestraId={modelData.orchestra?.id || ''} />
                 </div>
               </Tab>
             </Tabs>

+ 52 - 61
src/views/mine-orchestra/my-class/index.tsx

@@ -11,13 +11,17 @@ import { openDefaultWebView } from '../../../state'
 export default defineComponent({
   name: 'my-orchestra',
   props: {
+    list: {
+      type: Object,
+      default: () => []
+    },
     orchestraId: {
       type: String,
       default: ''
     }
   },
   setup(props) {
-    console.log('🚀 ~ props', props)
+    console.log("🚀 ~ props", props.list)
     const onMessage = async (item: any) => {
       console.log(item)
       postMessage({
@@ -36,7 +40,7 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      classList: [] as any[],
+      classList: props.list as any[],
       loading: false,
       finished: false
     })
@@ -68,67 +72,54 @@ export default defineComponent({
       } catch {}
       data.loading = false
     }
-    onMounted(() => {
-      getClassList()
-    })
     return () => (
       <div class={styles.myClass}>
-        <List
-          v-model:loading={data.loading}
-          finishedText="没有更多数据"
-          finished={data.finished}
-          onLoad={getClassList}
-          immediateCheck={false}
-        >
-          {Array.isArray(data.classList) &&
-            data.classList.map((item: any) => (
-              <div class={styles.itemDiv} onClick={() => openClassDetail(item)}>
-                <Cell center label={item.orchestraName}>
-                  {{
-                    icon: () => (
-                      <Image
-                        src={item.teacherAvatar || iconTeacher}
-                        class={styles.iconImg}
-                        fit="cover"
-                      />
-                    ),
-                    title: () => (
-                      <div class={styles.content}>
-                        <div class={['van-ellipsis', styles.teacherName]}>{item.teacherName}</div>
-                        <div class={styles.tag}>
-                          {item.name}
-                        </div>
-                      </div>
-                    ),
-                    value: () => (
-                      <Image
-                        class={styles.messageImg}
-                        src={iconMessage}
-                        onClick={(e: Event) => {
-                          e.stopPropagation()
-                          onMessage(item)
-                        }}
-                      />
-                    )
-                  }}
-                </Cell>
-                <Grid border={false} columnNum={3} class={styles.grid}>
-                  <GridItem>
-                    <p class={styles.title}>{item.preStudentNum || 0}</p>
-                    <p class={styles.name}>学生人数</p>
-                  </GridItem>
-                  <GridItem>
-                    <p class={[styles.title]}>{item.courseNum || 0}</p>
-                    <p class={styles.name}>剩余课时</p>
-                  </GridItem>
-                  <GridItem>
-                    <p class={styles.title}>{item.courseScheduleNum || 0}</p>
-                    <p class={styles.name}>总课时</p>
-                  </GridItem>
-                </Grid>
-              </div>
-            ))}
-        </List>
+        {Array.isArray(data.classList) &&
+          data.classList.map((item: any) => (
+            <div class={styles.itemDiv} onClick={() => openClassDetail(item)}>
+              <Cell center label={item.orchestraName}>
+                {{
+                  icon: () => (
+                    <Image
+                      src={item.teacherAvatar || iconTeacher}
+                      class={styles.iconImg}
+                      fit="cover"
+                    />
+                  ),
+                  title: () => (
+                    <div class={styles.content}>
+                      <div class={['van-ellipsis', styles.teacherName]}>{item.teacherName}</div>
+                      <div class={styles.tag}>{item.classGroupName}</div>
+                    </div>
+                  ),
+                  value: () => (
+                    <Image
+                      class={styles.messageImg}
+                      src={iconMessage}
+                      onClick={(e: Event) => {
+                        e.stopPropagation()
+                        onMessage(item)
+                      }}
+                    />
+                  )
+                }}
+              </Cell>
+              <Grid border={false} columnNum={3} class={styles.grid}>
+                <GridItem>
+                  <p class={styles.title}>{item.preStudentNum || 0}</p>
+                  <p class={styles.name}>学生人数</p>
+                </GridItem>
+                <GridItem>
+                  <p class={[styles.title]}>{item.courseNum || 0}</p>
+                  <p class={styles.name}>剩余课时</p>
+                </GridItem>
+                <GridItem>
+                  <p class={styles.title}>{item.courseScheduleNum || 0}</p>
+                  <p class={styles.name}>总课时</p>
+                </GridItem>
+              </Grid>
+            </div>
+          ))}
       </div>
     )
   }

+ 15 - 12
src/views/mine-orchestra/photo-list/detail.tsx

@@ -2,7 +2,7 @@ import OEmpty from '@/components/o-empty'
 import OHeader from '@/components/o-header'
 import request from '@/helpers/request'
 import { state } from '@/state'
-import { Grid, GridItem, Image, List, showImagePreview } from 'vant'
+import { Grid, GridItem, Image, List, Loading, showImagePreview } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'
 import styles from './index.module.less'
@@ -18,7 +18,7 @@ export default defineComponent({
   },
   setup(props) {
     const route = useRoute()
-    console.log("🚀 ~ route", route)
+    console.log('🚀 ~ route', route)
     const data = reactive({
       loading: false,
       finished: false,
@@ -70,7 +70,7 @@ export default defineComponent({
     return () => (
       <div>
         <OSticky>
-            <OHeader title={(route.query.name as string) || '我的乐团'} />
+          <OHeader title={(route.query.name as string) || '我的乐团'} />
         </OSticky>
         <div class={styles.phoneDetail}>
           {!data.loading && !!data.list.length && (
@@ -81,17 +81,20 @@ export default defineComponent({
               onLoad={getList}
               immediateCheck={false}
             >
-              <Grid columnNum={3}>
+              <Grid class={styles.detailGrid} columnNum={3} border={false} gutter={3}>
                 {data.list.map((item: any, index: number) => (
                   <GridItem onClick={() => onShowImage(index)}>
-                    {item.fileUrl ? (
-                      <Image class={styles.gridImg} style={{height: 'calc(100vw / 3)'}} src={item.fileUrl} fit="cover" />
-                    ) : (
-                      <div class={styles.gridImg}>
-                        <Image src={iconImage} fit="cover" />
-                      </div>
-                    )}
-
+                    <Image
+                      class={styles.gridImg}
+                      style={{ width: '100%', height: 'calc(100vw / 3)' }}
+                      src={item.fileUrl}
+                      errorIcon={iconImage}
+                      fit="cover"
+                    >
+                      {{
+                        loading: () => <Loading type="spinner" />,
+                      }}
+                    </Image>
                   </GridItem>
                 ))}
               </Grid>

+ 9 - 2
src/views/mine-orchestra/photo-list/index.module.less

@@ -26,11 +26,18 @@
     .gridName{
       font-size: 16px;
       color:#333;
-      padding: 6px 0 4px 0;
+      padding: 8px 0 4px 0;
     }
     .gridDes {
       color: #777;
       font-size: 12px;
     }
   }
-  
+  
+  .detailGrid{
+    :global{
+      .van-grid-item__content{
+        padding: 0;
+      }
+    }
+  }

+ 15 - 16
src/views/mine-orchestra/photo-list/index.tsx

@@ -2,7 +2,7 @@ import OEmpty from '@/components/o-empty'
 import OHeader from '@/components/o-header'
 import request from '@/helpers/request'
 import { state } from '@/state'
-import { Grid, GridItem, Image, List, showImagePreview } from 'vant'
+import { Grid, GridItem, Image, List, Loading, showImagePreview } from 'vant'
 import { defineComponent, onMounted, reactive } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import styles from './index.module.less'
@@ -19,7 +19,7 @@ export default defineComponent({
   setup(props) {
     const route = useRoute()
     const router = useRouter()
-    console.log("🚀 ~ route", route)
+    console.log('🚀 ~ route', route)
     const data = reactive({
       loading: false,
       finished: false,
@@ -72,7 +72,7 @@ export default defineComponent({
     return () => (
       <div>
         <OSticky>
-            <OHeader title={(route.query.name as string) || '我的乐团'} />
+          <OHeader title={(route.query.name as string) || '我的乐团'} />
         </OSticky>
         <div class={styles.phoneDetail}>
           {!data.loading && !!data.list.length && (
@@ -85,21 +85,20 @@ export default defineComponent({
             >
               <div class={styles.photoWrap}>
                 {data.list.map((item: any, index: number) => (
-                  <div class={styles.photoItem} onClick={() => {
-                    router.push({
+                  <div
+                    class={styles.photoItem}
+                    onClick={() => {
+                      router.push({
                         path: '/photo-list-detail',
-                        query:{
-                            orchestraPhotoAlbumId: item.id
+                        query: {
+                          orchestraPhotoAlbumId: item.id
                         }
-                    })
-                  }}>
-                    {item.coverUrl ? (
-                      <Image class={styles.gridImg} src={item.coverUrl} fit="cover" />
-                    ) : (
-                      <div class={styles.gridImg}>
-                        <Image src={iconImage} fit="cover" />
-                      </div>
-                    )}
+                      })
+                    }}
+                  >
+                    <Image class={styles.gridImg} src={item.coverUrl} fit="cover">
+                      {{ loading: () => <Loading type="spinner" /> }}
+                    </Image>
 
                     <div class={styles.gridName}>{item.name || ''}</div>
                     <div class={styles.gridDes}>{item.photoCount || 0}张</div>