Jelajahi Sumber

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

skyblued 2 tahun lalu
induk
melakukan
58503fb0f0

+ 7 - 0
src/components/o-qrcode/index.module.less

@@ -15,5 +15,12 @@
     width: 40px !important;
     height: 40px !important;
     border-radius: 4px;
+
+    &.small {
+      margin-left: -10px;
+      margin-top: -10px;
+      width: 20px !important;
+      height: 20px !important;
+    }
   }
 }

+ 9 - 3
src/components/o-qrcode/index.tsx

@@ -1,4 +1,4 @@
-import { defineComponent, onMounted, ref, watch } from 'vue'
+import { defineComponent, nextTick, onMounted, ref, watch } from 'vue'
 import logo from '@common/images/logo.png'
 import QRCode from 'qrcode'
 import styles from './index.module.less'
@@ -12,6 +12,10 @@ export default defineComponent({
     size: {
       type: String,
       default: '200px'
+    },
+    logoSize: {
+      type: String,
+      default: 'default'
     }
   },
   setup(props) {
@@ -37,12 +41,14 @@ export default defineComponent({
       }
     )
     onMounted(() => {
-      init()
+      nextTick(() => {
+        init()
+      })
     })
     return () => (
       <div class={styles.qrcode} style={{ width: props.size, height: props.size }}>
         <canvas ref={canvas} class={styles.qrcodeCanvas}></canvas>
-        <img src={logo} class={styles.qrcodeLogo} />
+        <img src={logo} class={[styles.qrcodeLogo, props.logoSize === 'small' && styles.small]} />
       </div>
     )
   }

+ 1 - 1
src/components/o-upload/index.tsx

@@ -183,7 +183,7 @@ export default defineComponent({
     useCustomFieldValue(() => this.modelValue)
 
     return (
-      <div class={styles['uploader-section']}>
+      <div class={[styles['uploader-section'], 'oUpload']}>
         {this.modelValue && this.deletable ? (
           <Icon name="cross" onClick={this.onClose} class={styles['img-close']} />
         ) : null}

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

@@ -142,6 +142,14 @@ export default [
         }
       },
       {
+        path: '/save-share-image',
+        name: 'save-share-image',
+        component: () => import('@/school/save-share-image/index'),
+        meta: {
+          title: '注册'
+        }
+      },
+      {
         path: '/orchestra-information',
         name: 'orchestra-information',
         component: () => import('@/school/orchestra/orchestra-information'),

+ 26 - 2
src/school/companion-teacher/companion-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; */
@@ -123,7 +123,7 @@ span {
   line-height: 22px;
   text-shadow: 0px 1px 5px #ff5e20;
   display: flex;
-  align-items: center;
+  align-items: flex-start;
 }
 
 .tips img {
@@ -286,3 +286,27 @@ span {
     line-height: 21px;
   }
 }
+
+.fieldGroup {
+  display: flex;
+  align-items: flex-start;
+  margin: 0 13px;
+  padding: 14px 0;
+
+  :global {
+    .van-field {
+      padding: 0;
+    }
+
+    .van-field + .van-field {
+      margin-left: 12px;
+    }
+    .oUpload {
+      margin-top: 0;
+      height: 114px;
+    }
+  }
+}
+.fieldTitle {
+  color: #fff !important;
+}

+ 42 - 37
src/school/companion-teacher/companion-teacher-register.tsx

@@ -426,7 +426,7 @@ export default defineComponent({
             ></Field>
             <div class={styles.phoneTips}>
               <Icon name="warning" size="16" />
-              提示:手机号将成为您管乐团伴学指导端登录账号
+              提示:手机号将成为您管乐团伴学指导端登录账号
             </div>
             <Field
               label="真实姓名"
@@ -486,42 +486,47 @@ export default defineComponent({
               }}
             </Field>
 
-            <Field
-              label="身份证照片正面"
-              v-model={state.forms.idcardFrontImg}
-              readonly
-              name="idcardFrontImg"
-              rules={[{ required: true, message: '请上传身份证正面', trigger: 'onChange' }]}
-              placeholder="请上传身份证正面"
-            >
-              {{
-                input: () => (
-                  <OUpload
-                    style={{ width: '100%' }}
-                    tips="上传身份证正面"
-                    v-model:modelValue={state.forms.idcardFrontImg}
-                  />
-                )
-              }}
-            </Field>
-            <Field
-              label="身份证照片反面"
-              v-model={state.forms.idcardBackImg}
-              readonly
-              name="idcardBackImg"
-              rules={[{ required: true, message: '请上传身份证反面', trigger: 'onChange' }]}
-              placeholder="请上传身份证反面"
-            >
-              {{
-                input: () => (
-                  <OUpload
-                    style={{ width: '100%' }}
-                    tips="上传身份证反面"
-                    v-model:modelValue={state.forms.idcardBackImg}
-                  />
-                )
-              }}
-            </Field>
+            <div class={[styles.fieldGroup, 'van-hairline--bottom']}>
+              <Field
+                label="身份证照片正面"
+                v-model={state.forms.idcardFrontImg}
+                readonly
+                border={false}
+                name="idcardFrontImg"
+                rules={[{ required: true, message: '请上传身份证正面', trigger: 'onChange' }]}
+                placeholder="请上传身份证正面"
+              >
+                {{
+                  input: () => (
+                    <OUpload
+                      style={{ width: '100%' }}
+                      tips="上传身份证正面"
+                      v-model:modelValue={state.forms.idcardFrontImg}
+                    />
+                  )
+                }}
+              </Field>
+              <Field
+                label={'上传身份证反面'}
+                labelClass={styles.fieldTitle}
+                v-model={state.forms.idcardBackImg}
+                readonly
+                border={false}
+                name="idcardBackImg"
+                rules={[{ required: true, message: '请上传身份证反面', trigger: 'onChange' }]}
+                placeholder="请上传身份证反面"
+              >
+                {{
+                  input: () => (
+                    <OUpload
+                      style={{ width: '100%' }}
+                      tips="上传身份证反面"
+                      v-model:modelValue={state.forms.idcardBackImg}
+                    />
+                  )
+                }}
+              </Field>
+            </div>
 
             <Field
               label="学历"

TEMPAT SAMPAH
src/school/companion-teacher/images/banner1.png


+ 8 - 201
src/school/companion-teacher/index.tsx

@@ -47,10 +47,6 @@ export default defineComponent({
       showMessage: false,
       showPopover: false,
       oPopover: false,
-      showQrcode: false,
-      schoolName: null,
-      schoolId: null,
-      url: null as any,
       subjectList: [{ text: '全部声部', value: 'ALL' }] as any,
       list: [] as any,
       listState: {
@@ -69,8 +65,7 @@ export default defineComponent({
         page: 1,
         rows: 20
       },
-      selectItem: {} as any,
-      paramValue: '2'
+      selectItem: {} as any
     })
 
     const getSubjects = async () => {
@@ -94,25 +89,6 @@ export default defineComponent({
       }
     }
 
-    // 获取当前用户所在的学校
-    const getDetail = async (id: string | number) => {
-      try {
-        const res = await request.get('/api-school/schoolStaff/detail/' + id)
-        form.schoolName = res.data.schoolName
-        form.schoolId = res.data.schoolId
-        form.url =
-          location.origin +
-          '/orchestra-school/#/companion-teacher-register?id=' +
-          res.data.schoolId +
-          '&name=' +
-          res.data.schoolName +
-          '&t=' +
-          +new Date()
-      } catch {
-        //
-      }
-    }
-
     const getList = async () => {
       try {
         const res = await request.post('/api-school/teacher/page', {
@@ -171,125 +147,9 @@ export default defineComponent({
       onSearch()
     }
 
-    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 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 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('保存成功')
-        form.showQrcode = false
-      } else {
-        showFailToast('保存失败')
-      }
-    }
-
     onMounted(async () => {
-      getDetail(state.user.data.id)
       getSubjects()
       getList()
-
-      try {
-        const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
-          requestType: 'form',
-          params: {
-            paramName: 'qr_code_expire_hours'
-          }
-        })
-        form.paramValue = data.paramValue
-      } catch {
-        //
-      }
     })
     return () => (
       <>
@@ -306,15 +166,12 @@ export default defineComponent({
                   name="plus"
                   size={19}
                   onClick={() => {
-                    form.url =
-                      location.origin +
-                      '/orchestra-school/#/companion-teacher-register?id=' +
-                      form.schoolId +
-                      '&name=' +
-                      form.schoolName +
-                      '&t=' +
-                      +new Date()
-                    form.showQrcode = true
+                    router.push({
+                      path: 'save-share-image',
+                      query: {
+                        type: 'teacher'
+                      }
+                    })
                   }}
                 />
               )
@@ -362,7 +219,7 @@ export default defineComponent({
             >
               {form.list.map((item: any) => (
                 <CellGroup inset style={{ marginBottom: '12px' }} onClick={() => onDetail(item)}>
-                  <Cell center isLink class={styles.manageCell}>
+                  <Cell center isLink class={styles.manageCell} clickable={false}>
                     {{
                       icon: () => (
                         <Image
@@ -430,56 +287,6 @@ export default defineComponent({
         )}
 
         <Popup
-          v-model:show={form.showQrcode}
-          position="bottom"
-          style={{ background: 'transparent' }}
-        >
-          <div class={styles.codeContainer}>
-            <div class={styles.codeImg} id="preview-container">
-              <div class={styles.codeContent}>
-                <h2 class={[styles.codeTitle, 'van-ellipsis']}>{form.schoolName}</h2>
-                <div class={styles.codeName}>邀请您成为乐团伴学指导</div>
-
-                <div class={styles.codeQr}>
-                  <OQrcode text={form.url} size={'100%'} />
-                </div>
-                <div style={{ textAlign: 'center' }}>
-                  <span class={styles.codeBtnText}>扫描上方二维码完成资料填写</span>
-                </div>
-                <div class={styles.codeTips}>二维码将在{form.paramValue}小时后失效,请及时登记</div>
-              </div>
-            </div>
-            <div class={styles.codeBottom}>
-              <Icon
-                name="cross"
-                size={22}
-                class={styles.close}
-                color="#666"
-                onClick={() => (form.showQrcode = false)}
-              />
-
-              <h3 class={styles.title}>
-                <i></i>分享方式
-              </h3>
-              <Grid columnNum={2} border={false}>
-                <GridItem onClick={onSaveImg}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconSaveImage} />,
-                    text: () => <div class={styles.shareText}>保存图片</div>
-                  }}
-                </GridItem>
-                <GridItem onClick={onShare}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconWechat} />,
-                    text: () => <div class={styles.shareText}>微信</div>
-                  }}
-                </GridItem>
-              </Grid>
-            </div>
-          </div>
-        </Popup>
-
-        <Popup
           v-model:show={form.showMessage}
           position="bottom"
           style={{ background: 'transparent' }}

+ 6 - 190
src/school/manage-teacher/index.tsx

@@ -37,10 +37,6 @@ export default defineComponent({
     const router = useRouter()
     const form = reactive({
       oPopover: false,
-      showQrcode: false,
-      schoolName: null,
-      schoolId: null,
-      url: null as any,
       list: [] as any,
       listState: {
         dataShow: true, // 判断是否有数据
@@ -60,26 +56,6 @@ export default defineComponent({
       paramValue: '2'
     })
 
-    // 获取当前用户所在的学校
-    const getDetail = async (id: string | number) => {
-      try {
-        const res = await request.get('/api-school/schoolStaff/detail/' + id)
-        console.log(res, 'res')
-        form.schoolName = res.data.schoolName
-        form.schoolId = res.data.schoolId
-        form.url =
-          location.origin +
-          '/orchestra-school/#/manage-teacher-register?id=' +
-          res.data.schoolId +
-          '&name=' +
-          res.data.schoolName +
-          '&t=' +
-          +new Date()
-      } catch {
-        //
-      }
-    }
-
     const getList = async () => {
       try {
         if (form.isClick) return
@@ -128,113 +104,7 @@ export default defineComponent({
       })
     }
 
-    const imgs = reactive({
-      saveLoading: false,
-      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) {
-        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('保存成功')
-        form.showQrcode = false
-      } else {
-        showFailToast('保存失败')
-      }
-    }
-
     onMounted(async () => {
-      // console.log(state.user.data.id, '1212')
-      getDetail(state.user.data.id)
-
       getList()
 
       try {
@@ -264,15 +134,12 @@ export default defineComponent({
                   name="plus"
                   size={19}
                   onClick={() => {
-                    form.url =
-                      location.origin +
-                      '/orchestra-school/#/manage-teacher-register?id=' +
-                      form.schoolId +
-                      '&name=' +
-                      form.schoolName +
-                      '&t=' +
-                      +new Date()
-                    form.showQrcode = true
+                    router.push({
+                      path: 'save-share-image',
+                      query: {
+                        type: 'manage'
+                      }
+                    })
                   }}
                 />
               )
@@ -342,57 +209,6 @@ export default defineComponent({
           <OEmpty btnStatus={false} tips="暂无管理老师" />
         )}
 
-        <Popup
-          v-model:show={form.showQrcode}
-          position="bottom"
-          style={{ background: 'transparent' }}
-          // safeAreaInsetBottom={true}
-        >
-          <div class={styles.codeContainer}>
-            <div class={styles.codeImg} id="preview-container">
-              <div class={styles.codeContent}>
-                <h2 class={[styles.codeTitle, 'van-ellipsis']}>{form.schoolName}</h2>
-                <div class={styles.codeName}>邀请您成为乐团管理老师</div>
-
-                <div class={styles.codeQr}>
-                  <OQrcode text={form.url} size={'100%'} />
-                </div>
-                <div style={{ textAlign: 'center' }}>
-                  <span class={styles.codeBtnText}>扫描上方二维码完成资料填写</span>
-                </div>
-                <div class={styles.codeTips}>二维码将在{form.paramValue}小时后失效,请及时登记</div>
-              </div>
-            </div>
-            <div class={styles.codeBottom}>
-              <Icon
-                name="cross"
-                size={22}
-                class={styles.close}
-                color="#666"
-                onClick={() => (form.showQrcode = false)}
-              />
-
-              <h3 class={styles.title}>
-                <i></i>分享方式
-              </h3>
-              <Grid columnNum={2} border={false}>
-                <GridItem onClick={onSaveImg}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconSaveImage} />,
-                    text: () => <div class={styles.shareText}>保存图片</div>
-                  }}
-                </GridItem>
-                <GridItem onClick={onShare}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconWechat} />,
-                    text: () => <div class={styles.shareText}>微信</div>
-                  }}
-                </GridItem>
-              </Grid>
-            </div>
-          </div>
-        </Popup>
-
         {/* <van-action-sheet v-model:show="show" :actions="actions" @select="onSelect" /> */}
 
         <ActionSheet

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

@@ -287,3 +287,27 @@ span {
     line-height: 21px;
   }
 }
+
+.fieldGroup {
+  display: flex;
+  align-items: flex-start;
+  margin: 0 13px;
+  padding: 14px 0;
+
+  :global {
+    .van-field {
+      padding: 0;
+    }
+
+    .van-field + .van-field {
+      margin-left: 12px;
+    }
+    .oUpload {
+      margin-top: 0;
+      height: 114px;
+    }
+  }
+}
+.fieldTitle {
+  color: #fff !important;
+}

+ 41 - 36
src/school/manage-teacher/manage-teacher-register.tsx

@@ -317,42 +317,47 @@ export default defineComponent({
               placeholder="请输入身份证号码"
             ></Field>
 
-            <Field
-              label="身份证照片正面"
-              v-model={state.forms.idcardFrontImg}
-              readonly
-              name="idcardFrontImg"
-              rules={[{ required: true, message: '请上传身份证正面', trigger: 'onChange' }]}
-              placeholder="请上传身份证正面"
-            >
-              {{
-                input: () => (
-                  <OUpload
-                    style={{ width: '100%' }}
-                    tips="上传身份证正面"
-                    v-model:modelValue={state.forms.idcardFrontImg}
-                  />
-                )
-              }}
-            </Field>
-            <Field
-              label="身份证照片反面"
-              v-model={state.forms.idcardBackImg}
-              readonly
-              name="idcardBackImg"
-              rules={[{ required: true, message: '请上传身份证反面', trigger: 'onChange' }]}
-              placeholder="请上传身份证反面"
-            >
-              {{
-                input: () => (
-                  <OUpload
-                    style={{ width: '100%' }}
-                    tips="上传身份证反面"
-                    v-model:modelValue={state.forms.idcardBackImg}
-                  />
-                )
-              }}
-            </Field>
+            <div class={[styles.fieldGroup, 'van-hairline--bottom']}>
+              <Field
+                label="身份证照片正面"
+                v-model={state.forms.idcardFrontImg}
+                readonly
+                border={false}
+                name="idcardFrontImg"
+                rules={[{ required: true, message: '请上传身份证正面', trigger: 'onChange' }]}
+                placeholder="请上传身份证正面"
+              >
+                {{
+                  input: () => (
+                    <OUpload
+                      style={{ width: '100%' }}
+                      tips="上传身份证正面"
+                      v-model:modelValue={state.forms.idcardFrontImg}
+                    />
+                  )
+                }}
+              </Field>
+              <Field
+                label={'上传身份证反面'}
+                labelClass={styles.fieldTitle}
+                v-model={state.forms.idcardBackImg}
+                readonly
+                border={false}
+                name="idcardBackImg"
+                rules={[{ required: true, message: '请上传身份证反面', trigger: 'onChange' }]}
+                placeholder="请上传身份证反面"
+              >
+                {{
+                  input: () => (
+                    <OUpload
+                      style={{ width: '100%' }}
+                      tips="上传身份证反面"
+                      v-model:modelValue={state.forms.idcardBackImg}
+                    />
+                  )
+                }}
+              </Field>
+            </div>
 
             <Field label="性别" name="gender" rules={[{ required: true, message: '请选择性别' }]}>
               {{

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

@@ -22,7 +22,7 @@ import iconSaveImage from '../images/icon-save-image.png'
 import iconWechat from '../images/icon-wechat.png'
 import OQrcode from '@/components/o-qrcode'
 import request from '@/helpers/request'
-import { useRoute } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import { CountUp } from 'countup.js'
 import OEmpty from '@/components/o-empty'
 import dayjs from 'dayjs'
@@ -41,6 +41,7 @@ export default defineComponent({
     const startTime = computed(() => props.termTimes.start)
     const endTime = computed(() => props.termTimes.end)
     const route = useRoute()
+    const router = useRouter()
     const state = reactive({
       timeShow: false,
       currentData: [dayjs().year() + ''],
@@ -53,8 +54,6 @@ export default defineComponent({
       oPopover: false,
       check: [],
       checkboxRefs: [] as any,
-      showQrcode: false,
-      qrcodeUrl: '',
       isLoading: false,
       list: [] as any,
       listState: {
@@ -197,109 +196,6 @@ export default defineComponent({
       })
     }
 
-    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 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 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('保存成功')
-        state.showQrcode = false
-      } else {
-        showFailToast('保存失败')
-      }
-    }
-
     onMounted(() => {
       getDetails()
       getStatistics()
@@ -408,9 +304,13 @@ export default defineComponent({
                 block
                 type="primary"
                 onClick={() => {
-                  state.showQrcode = true
-                  state.qrcodeUrl =
-                    window.location.origin + '/orchestra-student/#/preApply?id=' + route.query.id
+                  router.push({
+                    path: 'save-share-image',
+                    query: {
+                      type: 'orchestra',
+                      id: route.query.id
+                    }
+                  })
                 }}
               >
                 报名二维码
@@ -419,57 +319,6 @@ export default defineComponent({
           </OSticky>
         )}
 
-        <Popup
-          v-model:show={state.showQrcode}
-          position="bottom"
-          style={{ background: 'transparent' }}
-          // safeAreaInsetBottom={true}
-        >
-          <div class={styles.codeContainer}>
-            <div class={styles.codeImg} id="preview-container">
-              <div class={styles.codeContent}>
-                <h2 class={styles.codeTitle}>乐团报名</h2>
-                <div class={[styles.codeName, 'van-ellipsis']}>{state.orchestraInfo.name}</div>
-
-                <div class={styles.codeQr}>
-                  <OQrcode text={state.qrcodeUrl} size={'400'} />
-                </div>
-                <div style={{ textAlign: 'center' }}>
-                  <span class={styles.codeBtnText}>扫描上方二维码完成资料填写</span>
-                </div>
-                {/* <div class={styles.codeTips}>二维码将在两小时后失效,请及时登记</div> */}
-              </div>
-            </div>
-            <div class={styles.codeBottom}>
-              <Icon
-                name="cross"
-                size={22}
-                class={styles.close}
-                color="#666"
-                onClick={() => (state.showQrcode = false)}
-              />
-
-              <h3 class={styles.title}>
-                <i></i>分享方式
-              </h3>
-              <Grid columnNum={2} border={false}>
-                <GridItem onClick={onSaveImg}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconSaveImage} />,
-                    text: () => <div class={styles.shareText}>保存图片</div>
-                  }}
-                </GridItem>
-                <GridItem onClick={onShare}>
-                  {{
-                    icon: () => <Image class={styles.shareImg} src={iconWechat} />,
-                    text: () => <div class={styles.shareText}>微信</div>
-                  }}
-                </GridItem>
-              </Grid>
-            </div>
-          </div>
-        </Popup>
-
         <Popup v-model:show={state.timeShow} position="bottom" round>
           <DatePicker
             v-model={state.currentData}

TEMPAT SAMPAH
src/school/save-share-image/images/icon-image.png


TEMPAT SAMPAH
src/school/save-share-image/images/icon-qrcode-bg.png


TEMPAT SAMPAH
src/school/save-share-image/images/icon-weichat.png


TEMPAT SAMPAH
src/school/save-share-image/images/manage-top_bg.png


TEMPAT SAMPAH
src/school/save-share-image/images/orchestra-top_bg.png


TEMPAT SAMPAH
src/school/save-share-image/images/teacher-top_bg.png


+ 141 - 0
src/school/save-share-image/index.module.less

@@ -0,0 +1,141 @@
+.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;
+    }
+  }
+
+  .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: 130px;
+    height: 130px;
+    background: url('./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;
+    }
+  }
+}
+
+.btnGroup {
+  margin: 0 22px;
+  display: flex;
+  align-items: center;
+  margin-top: 30px;
+  margin-bottom: 20px;
+  .icon {
+    font-size: 38px;
+    margin-left: -6px;
+  }
+  .btn {
+    background: rgba(255, 255, 255, 0.4);
+    border-radius: 39px;
+    border: 1px solid #ff6e00;
+    font-size: 16px;
+    color: #ffffff;
+    line-height: 22px;
+    & + .btn {
+      margin-left: 13px;
+    }
+
+    :global {
+      .van-button__text {
+        display: flex;
+        align-items: center;
+      }
+    }
+  }
+}

+ 331 - 0
src/school/save-share-image/index.tsx

@@ -0,0 +1,331 @@
+import request from '@/helpers/request'
+import {
+  Button,
+  closeToast,
+  Icon,
+  Image,
+  showFailToast,
+  showLoadingToast,
+  showSuccessToast,
+  showToast
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import styles from './index.module.less'
+import { postMessage, promisefiyPostMessage } from '@/helpers/native-message'
+import html2canvas from 'html2canvas'
+import { state as baseState } from '@/state'
+import OQrcode from '@/components/o-qrcode'
+import iconImage from './images/icon-image.png'
+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'
+
+export default defineComponent({
+  name: 'save-share-image',
+  setup() {
+    const route = useRoute()
+    const state = reactive({
+      type: route.query.type as any,
+      paramValue: 2,
+      schoolName: '',
+      schoolId: '',
+      url: null as any,
+      schoolLogo: '',
+      loading: false
+    })
+
+    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 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 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('保存失败')
+      }
+    }
+
+    // 获取当前用户所在的学校
+    const getDetail = async () => {
+      try {
+        const schoolId = (baseState.user.data.schoolInfos || [])
+          .map((item) => {
+            return item.id
+          })
+          .join(',')
+
+        const res = await request.get(`/api-school/school/detail/${schoolId}`, {})
+
+        state.schoolName = res.data.name
+        state.schoolId = res.data.id
+        state.schoolLogo = res.data.logo + '@base@tag=imgScale&w=570?t=' + +new Date()
+        // 生成二维码
+        if (state.type === 'teacher') {
+          state.url =
+            location.origin +
+            '/orchestra-school/#/companion-teacher-register?id=' +
+            res.data.id +
+            '&name=' +
+            res.data.name +
+            '&t=' +
+            +new Date()
+        } else if (state.type === 'manage') {
+          state.url =
+            location.origin +
+            '/orchestra-school/#/manage-teacher-register?id=' +
+            res.data.id +
+            '&name=' +
+            res.data.name +
+            '&t=' +
+            +new Date()
+        }
+      } catch {
+        //
+      }
+    }
+
+    // 获取当前用户所在的学校
+    const getOrchestraDetail = async () => {
+      try {
+        const res = await request.get('/api-school/orchestra/detail/' + route.query.id)
+        state.schoolName = res.data.name
+        state.schoolId = res.data.id
+        state.schoolLogo = res.data.schoolLogo + '@base@tag=imgScale&w=570?t=' + +new Date()
+        // 生成二维码
+
+        state.url = window.location.origin + '/orchestra-student/#/preApply?id=' + route.query.id
+      } catch {
+        //
+      }
+    }
+
+    onMounted(async () => {
+      if (state.type === 'teacher') {
+        document.title = '乐团伴学指导注册'
+      } else if (state.type === 'manage') {
+        document.title = '乐团管理老师注册'
+      } else if (state.type === 'orchestra') {
+        document.title = '乐团报名'
+      }
+      try {
+        const { data } = await request.get('/api-school/open/paramConfig/queryByParamName', {
+          requestType: 'form',
+          params: {
+            paramName: 'qr_code_expire_hours'
+          }
+        })
+        state.paramValue = data.paramValue
+      } catch {
+        //
+      }
+
+      if (state.type === 'orchestra') {
+        getOrchestraDetail()
+      } else {
+        getDetail()
+      }
+    })
+    return () => (
+      <div class={[styles.saveShareImage]}>
+        {state.type === 'teacher' && <Image src={teacherTopBg} class={styles.topImage} />}
+        {state.type === 'manage' && <Image src={manageTopBg} class={styles.topImage} />}
+        {state.type === 'orchestra' && <Image src={orchestraTopBg} class={styles.topImage} />}
+        <div
+          class={[styles.shareContaienr, state.type === 'orchestra' && styles.orchestraContainer]}
+        >
+          {state.type !== 'orchestra' ? (
+            <>
+              <img
+                class={[styles.schoolLogo]}
+                src={state.schoolLogo}
+                crossorigin="anonymous"
+                style={{
+                  objectFit: 'cover'
+                }}
+              />
+              <div class={styles.schoolName}>{state.schoolName}</div>
+              <div class={styles.shareType}>
+                邀请您成为
+                <span>
+                  {state.type === 'teacher' && '乐团伴学指导'}
+                  {state.type === 'manage' && '乐团管理老师'}
+                </span>
+              </div>
+            </>
+          ) : (
+            <>
+              <div class={styles.schoolName}>乐团报名</div>
+              <div class={styles.shareType}>{state.schoolName}</div>
+            </>
+          )}
+
+          <div class={styles.qrcodeSection}>
+            <OQrcode text={state.url} logoSize={'small'} size={'100%'} />
+          </div>
+
+          <div class={styles.memo}>扫描上方二维码完成资料填写</div>
+          {state.type !== 'orchestra' && (
+            <div class={styles.endTime}>
+              二维码将在<span>{state.paramValue}小时后</span>失效,请及时登记
+            </div>
+          )}
+        </div>
+
+        <div class={styles.btnGroup}>
+          <Button class={styles.btn} round block onClick={onSaveImg}>
+            <Icon name={iconImage} class={styles.icon} />
+            保存图片
+          </Button>
+          <Button class={styles.btn} round block onClick={onShare}>
+            <Icon name={iconWeichat} class={styles.icon} />
+            分享到微信
+          </Button>
+        </div>
+
+        {!state.loading && (
+          <div class={[styles.saveShareImage, styles.previewSection]} id="preview-container">
+            {state.type === 'teacher' && <Image src={teacherTopBg} class={styles.topImage} />}
+            {state.type === 'manage' && <Image src={manageTopBg} class={styles.topImage} />}
+            {state.type === 'orchestra' && <Image src={orchestraTopBg} class={styles.topImage} />}
+            <div
+              class={[
+                styles.shareContaienr,
+                state.type === 'orchestra' && styles.orchestraContainer
+              ]}
+            >
+              {state.type !== 'orchestra' ? (
+                <>
+                  <img
+                    class={[styles.schoolLogo]}
+                    src={state.schoolLogo}
+                    crossorigin="anonymous"
+                    style={{
+                      objectFit: 'cover'
+                    }}
+                  />
+                  <div class={styles.schoolName}>{state.schoolName}</div>
+                  <div class={styles.shareType}>
+                    邀请您成为
+                    <span>
+                      {state.type === 'teacher' && '乐团伴学指导'}
+                      {state.type === 'manage' && '乐团管理老师'}
+                    </span>
+                  </div>
+                </>
+              ) : (
+                <>
+                  <div class={styles.schoolName}>乐团报名</div>
+                  <div class={styles.shareType}>{state.schoolName}</div>
+                </>
+              )}
+
+              <div class={styles.qrcodeSection}>
+                <OQrcode text={state.url} logoSize={'small'} size={'100%'} />
+              </div>
+
+              <div class={styles.memo}>扫描上方二维码完成资料填写</div>
+              {state.type !== 'orchestra' && (
+                <div class={styles.endTime}>
+                  二维码将在<span>{state.paramValue}小时后</span>失效,请及时登记
+                </div>
+              )}
+            </div>
+          </div>
+        )}
+      </div>
+    )
+  }
+})