Browse Source

Merge branch 'iteration-orchestra-new' into online

lex 1 year ago
parent
commit
c0ebef0e33

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

@@ -54,6 +54,14 @@ const noLoginRouter = [
     meta: {
       title: ''
     }
+  },
+  {
+    path: '/previewGoodsApply',
+    name: 'previewGoodsApply',
+    component: () => import('@/student/music-group/pre-goods-apply/preview-index'),
+    meta: {
+      title: '乐团报名'
+    }
   }
 ]
 

BIN
src/student/music-group/pre-goods-apply/images/icon-free.png


BIN
src/student/music-group/pre-goods-apply/images/title-2.png


BIN
src/student/music-group/pre-goods-apply/images/title-3.png


BIN
src/student/music-group/pre-goods-apply/images/title-5.png


+ 48 - 21
src/student/music-group/pre-goods-apply/index.module.less

@@ -70,30 +70,24 @@
   padding-top: 22px;
   overflow: visible;
 
-  &.self,
-  &.groupBuy {
+  &.self {
     margin-top: 12px;
     padding-top: 0px;
 
-    &::before {
-      content: ' ';
-      position: absolute;
-      right: 24%;
-      top: -6px;
-      display: inline-block;
-      width: 21px;
-      height: 21px;
-      background: #FFFFFF;
-      border-radius: 3px 0px 0px 0px;
-      transform: rotate(45deg);
-    }
+    // &::before {
+    //   content: ' ';
+    //   position: absolute;
+    //   right: 24%;
+    //   top: -6px;
+    //   display: inline-block;
+    //   width: 21px;
+    //   height: 21px;
+    //   background: #FFFFFF;
+    //   border-radius: 3px 0px 0px 0px;
+    //   transform: rotate(45deg);
+    // }
   }
 
-  &.groupBuy {
-    &::before {
-      left: 23%;
-    }
-  }
 
   .title {
     position: absolute;
@@ -131,6 +125,13 @@
     background-size: contain;
   }
 
+  .titleIntrumentTool {
+    width: 235px;
+    margin-left: -118px;
+    background: url('./images/title-5.png') no-repeat center;
+    background-size: contain;
+  }
+
   :global {
     .van-cell {
       padding: 18px 12px;
@@ -159,6 +160,26 @@
   .radioSectionTag {
     min-height: 28px;
     flex: 1;
+    font-weight: 600;
+    padding: 5px 0px 7px !important;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+    line-height: 22px !important;
+
+    .radioTip {
+      font-weight: 400;
+      padding-top: 4px;
+      font-size: 11px;
+      color: #987D6E;
+      line-height: 16px;
+    }
+
+    &.active {
+      .radioTip {
+        color: #54260D;
+      }
+    }
   }
 
   .radioSection {
@@ -171,9 +192,12 @@
     border-radius: 6px;
     line-height: 1;
     padding: 5px 10px 3.5px;
-    font-weight: 400;
+    font-weight: 500;
     font-size: 16px;
 
+
+
+
     .radioItem {
       position: absolute;
       top: 0;
@@ -196,7 +220,9 @@
 }
 
 .tipsContainer {
-  padding: 14px 12px 10px 43px;
+  // padding: 14px 12px 10px 43px;
+  padding: 14px 12px 10px 12px;
+  font-size: 14px;
 
   .line {
     font-size: 14px;
@@ -334,6 +360,7 @@
   .goodsTitle {
     display: flex;
     align-items: center;
+    flex-wrap: wrap;
     font-size: 16px;
     font-weight: 600;
     color: #131415;

+ 20 - 19
src/student/music-group/pre-goods-apply/index.tsx

@@ -64,7 +64,7 @@ export default defineComponent({
         { text: '九年级', value: 9 }
       ], // 年级数组列表
       classList: classList,
-      subjectList: [] as any, // 选声部列表
+      subjectList: [] as any, // 选声部列表
       instrumentsInspectionDescribe: '', // 配置信息
       inspectPopupStatus: false, // 查看说明
       gradeStatus: false,
@@ -102,7 +102,7 @@ export default defineComponent({
       currentClass: '', // 班级
       currentClassTxt: null, // 年级编号
       registerSubjectId: '',
-      registerSubjectTxt: null, // 所在选声部
+      registerSubjectTxt: null, // 所在选声部
       parentName: null,
       groupBuyType: '' as any,
       phone: null as any,
@@ -147,7 +147,7 @@ export default defineComponent({
       }
     }
 
-    // 获取选声部信息
+    // 获取选声部信息
     const getSubjects = async () => {
       try {
         const subjects = await request.post(
@@ -593,21 +593,21 @@ export default defineComponent({
             />
             <Field
               required
-              label="选声部"
+              label="选声部"
               inputAlign="right"
               readonly
               isLink
               clickable={false}
-              placeholder="请选择选声部"
+              placeholder="请选择选声部"
               v-model={forms.registerSubjectTxt}
               onClick={() => {
                 if (state.subjectList.length <= 0) {
-                  showToast('暂无报名选声部')
+                  showToast('暂无报名选声部')
                   return
                 }
                 state.subjectStatus = true
               }}
-              rules={[{ required: true, message: '请选择选声部' }]}
+              rules={[{ required: true, message: '请选择选声部' }]}
             />
           </CellGroup>
 
@@ -637,8 +637,8 @@ export default defineComponent({
           <CellGroup class={styles.applyCellGroup} border={false}>
             <div class={[styles.title, styles.titleTips]}></div>
 
-            <div class={styles.tipsContainer}>
-              <p class={styles.line}>
+            <div class={styles.tipsContainer} v-html={state.registerInfo.joinNotice}>
+              {/* <p class={styles.line}>
                 <i class={[styles.num, styles.numOne]}></i>
                 为保障乐团训练质量,开训前,家长务必准备好①乐器和②管乐AI学练工具,准备方式不限;
               </p>
@@ -654,7 +654,7 @@ export default defineComponent({
                   3、如期间或期满不再训练,家长归还乐器即可,
                   <span style="color: #F67146">无需额外支付</span>乐器费用。
                 </p>
-              </p>
+              </p> */}
             </div>
           </CellGroup>
 
@@ -662,9 +662,9 @@ export default defineComponent({
             <div class={[styles.title, styles.titleTool]}></div>
             <Field
               required
-              label="请选择训练工具的准备方:"
+              label="请选择训练工具的准备方:"
               labelAlign="top"
-              rules={[{ required: true, message: '请选择训练工具的准备方' }]}
+              rules={[{ required: true, message: '请选择训练工具的准备方' }]}
             >
               {{
                 input: () => (
@@ -684,12 +684,13 @@ export default defineComponent({
                         disabled={forms.registerSubjectId ? false : true}
                         onClick={() => {
                           if (!forms.registerSubjectId) {
-                            showToast('请选择选声部')
+                            showToast('请选择选声部')
                             return
                           }
                         }}
                       ></Radio>
-                      参与团购
+                      统一团购
+                      <p class={styles.radioTip}>团购AI工具,乐器免费提供</p>
                     </Tag>
                     <Tag
                       size="large"
@@ -700,7 +701,8 @@ export default defineComponent({
                         forms.groupBuyType === 'SELF' ? styles.active : ''
                       ]}
                     >
-                      <Radio class={styles.radioItem} name={'SELF'}></Radio>自行准备
+                      <Radio class={styles.radioItem} name={'SELF'}></Radio>单独准备
+                      <p class={styles.radioTip}>AI工具和乐器自行准备</p>
                     </Tag>
                   </RadioGroup>
                 )
@@ -711,6 +713,7 @@ export default defineComponent({
           {forms.groupBuyType === 'GROUP_BUY' && (
             <>
               <CellGroup class={[styles.applyCellGroup, styles.groupBuy]} border={false}>
+                <div class={[styles.title, styles.titleIntrumentTool]}></div>
                 <Cell border={false}>
                   {{
                     icon: () => <Image src={state.vipYearInfo.goodsUrl} class={styles.goodsImg} />,
@@ -965,7 +968,7 @@ export default defineComponent({
             }}
           />
         </Popup>
-        {/* 选声部 */}
+        {/* 选声部 */}
         <Popup
           v-model:show={state.subjectStatus}
           position="bottom"
@@ -980,17 +983,15 @@ export default defineComponent({
               const selectedOption = val.selectedOptions[0]
               forms.registerSubjectId = selectedOption.value
               forms.registerSubjectTxt = selectedOption.text
-              console.log(selectedOption, 'selected')
               state.subjectStatus = false
 
               // 更新商品信息
               await registerGoods()
-              forms.groupBuyType = 'GROUP_BUY'
             }}
           />
         </Popup>
 
-        {/* 选声部 */}
+        {/* 选声部 */}
         <Popup v-model:show={state.inspectPopupStatus} round closeable class={styles.inspectPopup}>
           <InspectModal describe={state.instrumentsInspectionDescribe} />
         </Popup>

+ 347 - 0
src/student/music-group/pre-goods-apply/preview-index.tsx

@@ -0,0 +1,347 @@
+import { defineComponent, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
+import styles from './index.module.less'
+import headTitle from './images/header-title.png'
+import headPhone from './images/header-phone.png'
+import headBg from './images/header-bg.png'
+import { Button, CellGroup, Field, Form, Radio, RadioGroup, Tag, showToast } from 'vant'
+import { useRoute, useRouter } from 'vue-router'
+
+// 乐团交付,乐团停止或关闭,有新的交付团;则不允许报名
+const classList: any = []
+for (let i = 1; i <= 40; i++) {
+  classList.push({ text: i + '班', value: i })
+}
+
+export default defineComponent({
+  name: 'pre-goods-apply',
+  setup() {
+    const route = useRoute()
+
+    // 获取是否已经看过训练工具图片
+    const state = reactive({
+      code: '' as any, // 微信授权code码
+      detail: {} as any, // 学员详情
+      toolImgStatus: false,
+      currentGrade: [
+        { text: '一年级', value: 1 },
+        { text: '二年级', value: 2 },
+        { text: '三年级', value: 3 },
+        { text: '四年级', value: 4 },
+        { text: '五年级', value: 5 },
+        { text: '六年级', value: 6 },
+        { text: '七年级', value: 7 },
+        { text: '八年级', value: 8 },
+        { text: '九年级', value: 9 }
+      ], // 年级数组列表
+      classList: classList,
+      subjectList: [] as any, // 选报声部列表
+      instrumentsInspectionDescribe: '', // 配置信息
+      inspectPopupStatus: false, // 查看说明
+      gradeStatus: false,
+      classStatus: false,
+      subjectStatus: false,
+      registerInfo: {} as any, // 乐团信息
+      goodsInfo: {} as any, // 商品
+      textBookInfo: {} as any, // 教材
+      inspectInfo: {} as any, // 乐器检查
+      vipYearInfo: {} as any, // 学练工具
+      inspectStatus: true,
+      // 是否开启微信登录(测试使用)默认为false
+      testIsWeixin: false,
+      details: [] as any, //
+      pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
+      nameReg: /^[\u4E00-\u9FA5]+$/,
+      paymentType: '',
+      musicPaymentType: '', // 乐团中对应支付方式
+      studentReadStatus: false, // 学生在读
+      dialogStatus: false,
+      dialogMessage: '',
+      dialogOrchestraStatus: false, // 是否为不同的乐团
+      dialogConfig: {} as any,
+      orderInfo: {
+        needPrice: 0,
+        originalPrice: 0
+      },
+      submitStatus: false
+    })
+    const forms = reactive({
+      username: null,
+      sex: null as any,
+      currentGrade: null,
+      currentGradeTxt: null, // 年级编号
+      currentClass: '', // 班级
+      currentClassTxt: null, // 年级编号
+      registerSubjectId: '',
+      registerSubjectTxt: null, // 所在选报声部
+      parentName: null,
+      groupBuyType: '' as any,
+      phone: null as any,
+      learningTools: null,
+      instrumentsBrand: null
+    })
+
+    const validator = (val: any) => {
+      // 校验函数返回 true 表示校验通过,false 表示不通过
+      return state.nameReg.test(val) && val.length >= 2 && val.length <= 15
+    }
+
+    const message = (value: any) => {
+      if (!value) {
+        return '请填写学员真实姓名'
+      } else if (!state.nameReg.test(value)) {
+        return '学员姓名必须为中文'
+      } else if (value.length < 2 || value.length > 15) {
+        return '学员姓名必须为2~15个字'
+      } else {
+        return ''
+      }
+    }
+
+    // 乐团报名
+    const onSubmit = async () => {
+      //
+    }
+
+    const messageContent = ref('')
+    const orchestraName = ref(route.query.orchestraName || '') // 乐团名称
+    const getMessage = (ev: any) => {
+      if (ev.data.api === 'payment-notes') {
+        messageContent.value = ev.data.message || ''
+        // document.body
+      }
+    }
+
+    onMounted(() => {
+      nextTick(() => {
+        // 是否加载完成
+        window.parent &&
+          window.parent.postMessage(
+            {
+              api: 'onLoad',
+              status: true
+            },
+            '*'
+          )
+      })
+
+      window.addEventListener('message', getMessage)
+    })
+
+    onUnmounted(() => {
+      window.removeEventListener('message', getMessage)
+    })
+    return () => (
+      <div class={styles.goodsApply}>
+        <img src={headBg} class={styles.headBg} />
+        <div class={styles.goodsHeader}>
+          <div class={styles.orchestraTitle}>
+            <img class={styles.headTitle} src={headTitle} />
+            <p class={[styles.name, 'van-multi-ellipsis--l3']}>{orchestraName.value}</p>
+          </div>
+          <img src={headPhone} class={styles.headPhone} />
+        </div>
+        <Form
+          validateFirst
+          errorMessageAlign="right"
+          scrollToError={true}
+          onSubmit={onSubmit}
+          onFailed={(e: any) => {
+            // 获取第一个校验错误的元素
+            nextTick(() => {
+              const isError = document.getElementsByClassName('van-field__error-message')
+              // 滚动到错误元素对应位置
+              isError[0]?.scrollIntoView({
+                block: 'center',
+                behavior: 'smooth'
+              })
+            })
+          }}
+          ref="form"
+          class={styles.form}
+        >
+          <CellGroup class={styles.applyCellGroup} border={false} style={{ display: 'none' }}>
+            <div class={[styles.title, styles.titleApply]}></div>
+            <Field
+              required
+              label="学员信息"
+              placeholder="请填写学员真实姓名"
+              inputAlign="right"
+              v-model={forms.username}
+              maxlength={15}
+              rules={[{ validator, message }]}
+            />
+            <Field
+              required
+              label="性别"
+              inputAlign="right"
+              rules={[{ required: true, message: '请选择性别' }]}
+            >
+              {{
+                input: () => (
+                  <RadioGroup v-model={forms.sex}>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      class={[styles.radioSection, forms.sex === 1 ? styles.active : '']}
+                    >
+                      <Radio class={styles.radioItem} name={1}></Radio>
+                      男生
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      class={[styles.radioSection, forms.sex === 0 ? styles.active : '']}
+                    >
+                      <Radio class={styles.radioItem} name={0}></Radio>女生
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+            <Field
+              required
+              label="年级"
+              inputAlign="right"
+              readonly
+              isLink
+              clickable={false}
+              placeholder="请选择年级"
+              v-model={forms.currentGradeTxt}
+              onClick={() => (state.gradeStatus = true)}
+              rules={[{ required: true, message: '请选择年级' }]}
+            />
+            <Field
+              required
+              label="班级"
+              inputAlign="right"
+              readonly
+              isLink
+              clickable={false}
+              placeholder="请选择班级"
+              v-model={forms.currentClassTxt}
+              onClick={() => (state.classStatus = true)}
+              rules={[{ required: true, message: '请选择班级' }]}
+            />
+            <Field
+              required
+              label="选报声部"
+              inputAlign="right"
+              readonly
+              isLink
+              clickable={false}
+              placeholder="请选择选报声部"
+              v-model={forms.registerSubjectTxt}
+              onClick={() => {
+                if (state.subjectList.length <= 0) {
+                  showToast('暂无报名选报声部')
+                  return
+                }
+                state.subjectStatus = true
+              }}
+              rules={[{ required: true, message: '请选择选报声部' }]}
+            />
+          </CellGroup>
+
+          <CellGroup class={styles.applyCellGroup} border={false}>
+            <div class={[styles.title, styles.titleParent]}></div>
+            <Field
+              required
+              label="家长姓名"
+              inputAlign="right"
+              placeholder="请填写家长真实姓名"
+              v-model={forms.parentName}
+              maxlength={15}
+              // rules={[{ required: true, message: '请填写家长真实姓名' }]}
+            />
+            <Field
+              required
+              label="手机号"
+              inputAlign="right"
+              placeholder="请输入手机号"
+              v-model={forms.phone}
+              maxlength={11}
+              type="tel"
+              // rules={[{ pattern: state.pattern, message: '输入监护人手机号码有误' }]}
+            />
+          </CellGroup>
+
+          <CellGroup class={styles.applyCellGroup} border={false}>
+            <div class={[styles.title, styles.titleTips]}></div>
+
+            <div class={styles.tipsContainer} v-html={messageContent.value}>
+              {/* <p class={styles.line}>
+                <i class={[styles.num, styles.numOne]}></i>
+                为保障乐团训练质量,开训前,家长务必准备好①乐器和②管乐AI学练工具,准备方式不限;
+              </p>
+              <p class={styles.line}>
+                <i class={[styles.num, styles.numTwo]}></i>
+                为了降低家长投入压力,可参与项目支持方提供的AI学练工具团购,政策如下:
+                <p class={[styles.child]}>
+                  1、支持方<span style="color: #F67146">免费</span>
+                  提供一支全新乐器供学生训练(可带回家) ;<br />
+                  2、乐器提供时间为一年,如期满继续训练,乐器将
+                  <span style="color: #F67146">赠送</span>至学生以作鼓励;
+                  <br />
+                  3、如期间或期满不再训练,家长归还乐器即可,
+                  <span style="color: #F67146">无需额外支付</span>乐器费用。
+                </p>
+              </p> */}
+            </div>
+          </CellGroup>
+
+          <CellGroup class={styles.applyCellGroup} border={false}>
+            <div class={[styles.title, styles.titleTool]}></div>
+            <Field
+              required
+              label="请选择训练工具的准备方式:"
+              labelAlign="top"
+              rules={[{ required: true, message: '请选择训练工具的准备方式' }]}
+            >
+              {{
+                input: () => (
+                  <RadioGroup v-model={forms.groupBuyType} class={styles.toolRadioGroup}>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      class={[
+                        styles.radioSectionTag,
+                        styles.radioSection,
+                        forms.groupBuyType === 'GROUP_BUY' ? styles.active : ''
+                      ]}
+                    >
+                      <Radio
+                        class={styles.radioItem}
+                        name={'GROUP_BUY'}
+                        disabled={true}
+                        onClick={() => {
+                          // if (!forms.registerSubjectId) {
+                          //   showToast('请选择选报声部')
+                          //   return
+                          // }
+                        }}
+                      ></Radio>
+                      统一团购
+                      <p class={styles.radioTip}>团购AI工具,乐器免费提供</p>
+                    </Tag>
+                    <Tag
+                      size="large"
+                      type="primary"
+                      class={[
+                        styles.radioSectionTag,
+                        styles.radioSection,
+                        forms.groupBuyType === 'SELF' ? styles.active : ''
+                      ]}
+                    >
+                      <Radio class={styles.radioItem} name={'SELF'} disabled></Radio>自行准备
+                      <p class={styles.radioTip}>AI工具和乐器自行准备</p>
+                    </Tag>
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+          </CellGroup>
+        </Form>
+      </div>
+    )
+  }
+})

+ 1 - 0
src/student/pre-register-active/compontent-show/video-show.tsx

@@ -161,6 +161,7 @@ export default defineComponent({
           </div>
         </div>
         <div class={styles.videoCount}>
+          <div class={styles.videoTitle}></div>
           <div class={styles.videoCountContent}>
             {forms.videoDetails.map((item: any) => (
               <span

BIN
src/student/pre-register-active/images/video-path-title.png


+ 41 - 12
src/student/pre-register-active/video.module.less

@@ -102,19 +102,39 @@
 }
 
 .videoCount {
+  // position: relative;
+  // margin-top: 5px;
+  // background: url('./images/video-count.png') no-repeat center;
+  // background-size: contain;
+  // min-height: 82px;
+  // box-sizing: content-box;
+  // padding: 60px 36px 0;
   position: relative;
-  margin-top: 5px;
-  background: url('./images/video-count.png') no-repeat center;
-  background-size: contain;
-  min-height: 82px;
-  box-sizing: content-box;
-  padding: 60px 36px 0;
+  margin: 8px 14px 12px;
+  // background: url('./images/flow-path-bg.png') no-repeat center;
+  // background-size: contain;
+  background: linear-gradient(180deg, #BFF4FF 0%, #80D3E1 100%);
+  box-shadow: 0px 2px 4px 0px rgba(23, 89, 202, 0.92), inset 0px -9px 6px 0px #64BDFF, inset 0px 3px 4px 0px #FFFFFF;
+  border-radius: 25px;
+  padding: 12px 10px 11px;
+
+  .videoTitle {
+    display: block;
+    position: absolute;
+    top: -6px;
+    left: 50%;
+    margin-left: -93px;
+    width: 186px;
+    height: 32px;
+    background: url('./images/video-path-title.png') no-repeat center;
+    background-size: contain;
+  }
 
   &::before,
   &::after {
     content: ' ';
     position: absolute;
-    top: -27px;
+    top: -33px;
     width: 11px;
     height: 44px;
     background: url('./images/icon-connect.png') no-repeat center;
@@ -131,8 +151,15 @@
 
 
   .videoCountContent {
-    overflow-x: auto;
-    white-space: nowrap;
+    padding: 31px 20px 14px;
+    font-size: 14px;
+    color: #2D1A18;
+    line-height: 26px;
+
+    background: linear-gradient(180deg, #FFFFFA 0%, rgba(255, 255, 253, 0.87) 90%, rgba(255, 255, 255, 0.52) 100%);
+    box-shadow: 0px 1px 6px 0px #D9EFF8;
+    border-radius: 18px;
+    border: 5px solid #139CF1;
 
     span {
       font-size: 13px;
@@ -142,6 +169,8 @@
       border-radius: 14px;
       padding: 4px 9px;
       display: inline-block;
+      margin-right: 8px;
+      margin-bottom: 6px;
 
       &.active {
         font-weight: 600;
@@ -149,9 +178,9 @@
         background: #198CFE;
       }
 
-      &+span {
-        margin-left: 8px;
-      }
+      // &+span {
+      //   margin-left: 8px;
+      // }
     }
 
     &::-webkit-scrollbar {

+ 8 - 3
src/student/pre-register-active/video.tsx

@@ -361,6 +361,11 @@ export default defineComponent({
             window.location.origin +
             window.location.pathname +
             `/#/preApply?id=${forms.orchestraId}`
+        } else if (forms.orchestraRegisterType === 'GROUP_BUY') {
+          window.location.href =
+            window.location.origin +
+            window.location.pathname +
+            `/#/preGoodsApply?id=${forms.orchestraId}`
         } else {
           window.location.href =
             window.location.origin +
@@ -502,6 +507,7 @@ export default defineComponent({
           </div>
         </div>
         <div class={styles.videoCount}>
+          <div class={styles.videoTitle}></div>
           <div class={styles.videoCountContent}>
             {forms.videoDetails.map((item: any) => (
               <span
@@ -533,9 +539,8 @@ export default defineComponent({
               注:乐团于下学期正式开始训练,训练时间下学期开学前另行通知,训练时间会与学校其他社团错开,家长无需担心时间冲突问题。
             </p> */}
             <div v-html={forms.parentConferencesNotes}></div>
-            {forms.orchestraRegisterType !== 'GROUP_BUY' && (
-              <Button class={styles.submitBtn} onClick={onSubmit}></Button>
-            )}
+
+            <Button class={styles.submitBtn} onClick={onSubmit}></Button>
           </div>
         </div>
       </div>