lex 11 місяців тому
батько
коміт
46762c5845

+ 56 - 11
src/views/activation-code/activation-register/index.tsx

@@ -125,7 +125,7 @@ export default defineComponent({
     const forms = reactive({
       schoolId: null as any,
       schoolAreaId: null, // 学校区域编号
-      activationCode: route.query.code as any, // 互通码
+      activationCode: null as any, // 互通码
       paymentType: '', // 支付类型
       paymentChannel: '',
       multi_user_limit: 1, // 限制注册学生数量
@@ -145,6 +145,7 @@ export default defineComponent({
       schoolStatus: false,
       schoolPopupShow: false,
       schoolLoading: false,
+      schoolPopupIndex: [] as any,
       schoolAreaList: [] as any,
       provinceCode: null,
       cityCode: null,
@@ -652,6 +653,7 @@ export default defineComponent({
         const { data } = await request.post('/edu-app/open/schoolArea/list', {
           data: {
             name,
+            testFlag: true,
             provinceCode: forms.provinceCode,
             cityCode: forms.cityCode,
             regionCode: forms.regionCode
@@ -663,7 +665,35 @@ export default defineComponent({
       }
       forms.schoolLoading = false;
     };
+
+    // 格式化互通码
+    const maskMiddleDigits = (str: string) => {
+      if (!str) {
+        return '';
+      }
+      let numPart = str.match(/\d+/); // 提取数字部分
+      if (numPart) {
+        let start = str.indexOf(numPart[0]); // 数字部分的起始索引
+        let end = start + numPart[0].length; // 数字部分的结束索引
+        let maskedStr =
+          str.substring(0, start) +
+          '*'.repeat(numPart[0].length) +
+          str.substring(end);
+        return maskedStr;
+      }
+      return str;
+    };
+
     onMounted(async () => {
+      try {
+        const code: any = route.query.code;
+        if (code) {
+          forms.activationCode = window.atob(code);
+        }
+      } catch {
+        //
+      }
+
       getAreaList();
       try {
         // 获取支付类型
@@ -854,6 +884,9 @@ export default defineComponent({
                   }
 
                   forms.schoolStatus = true;
+                  if (forms.schoolAreaId) {
+                    forms.schoolPopupIndex = [forms.schoolAreaId];
+                  }
                   // forms.gradeStatus = true;
                   // forms.gradePopupIndex = [studentInfo.extra.currentGradeNum];
                 }}
@@ -902,15 +935,27 @@ export default defineComponent({
                 }}
               />
 
-              <Field
-                clearable={false}
-                required
-                inputAlign="right"
-                label="互通码"
-                placeholder="请选择互通码"
-                readonly={route.query.code ? true : false}
-                v-model={forms.activationCode}
-              />
+              {/* maskMiddleDigits */}
+              {route.query.code ? (
+                <Field
+                  clearable={false}
+                  required
+                  inputAlign="right"
+                  label="互通码"
+                  readonly={route.query.code ? true : false}
+                  modelValue={maskMiddleDigits(forms.activationCode)}
+                />
+              ) : (
+                <Field
+                  clearable={false}
+                  required
+                  inputAlign="right"
+                  label="互通码"
+                  placeholder="请选择互通码"
+                  autocomplete="off"
+                  v-model={forms.activationCode}
+                />
+              )}
             </Form>
           </div>
 
@@ -965,7 +1010,7 @@ export default defineComponent({
             <div>
               <Picker
                 showToolbar
-                // v-model={forms.gradePopupIndex}
+                v-model={forms.schoolPopupIndex}
                 columns={forms.schoolAreaList}
                 loading={forms.schoolLoading}
                 columnsFieldNames={{

+ 19 - 4
src/views/activation-code/index.tsx

@@ -3,11 +3,19 @@ import { defineComponent, reactive } from 'vue';
 import styles from './index.module.less';
 import MSticky from '@/components/m-sticky';
 import MHeader from '@/components/m-header';
+import { postMessage } from '@/helpers/native-message'
 import { useRouter } from 'vue-router';
 import { Button, Field, Popup, showToast } from 'vant';
 import iconKey from './images/icon-key.png';
 import CodeDialog from './modal/code-dialog';
 import request from '@/helpers/request';
+import dayjs from 'dayjs';
+
+const vipGiftPeriodType = {
+  DAY: '天',
+  MONTH: '个月',
+  YEAR: '年'
+} as any;
 
 export default defineComponent({
   name: 'activationCode',
@@ -18,7 +26,8 @@ export default defineComponent({
       reslutPopupType: '',
       resultPopupContent: '',
       loading: false,
-      activeCodeRecordCode: null as any
+      activeCodeRecordCode: null as any,
+      successInfo: {} as any
     });
 
     const onSubmit = async () => {
@@ -49,7 +58,7 @@ export default defineComponent({
         } else {
           state.showPopup = true;
           state.reslutPopupType = 'ACTIVATED';
-          state.resultPopupContent = res.message;
+          state.successInfo = res.data;
         }
       } catch {}
       state.loading = false;
@@ -162,8 +171,14 @@ export default defineComponent({
             }}>
             {state.reslutPopupType === 'ACTIVATED' && (
               <p>
-                您已成功激活一年乐器AI学练工具,有效期
-                <span style={{ color: '#2B85FF' }}>2024-07-17</span>
+                您已成功激活{state.successInfo?.times}
+                {vipGiftPeriodType[state.successInfo?.type]}
+                乐器AI学练工具,有效期
+                <span style={{ color: '#2B85FF' }}>
+                  {dayjs(state.successInfo.membershipEndTime).format(
+                    'YYYY-MM-DD'
+                  )}
+                </span>
               </p>
             )}
 

+ 34 - 17
src/views/activation-code/instrument-registration/index.tsx

@@ -11,6 +11,7 @@ export default defineComponent({
   setup() {
     const router = useRouter();
     const state = reactive({
+      progressRate: 0,
       statusShow: false,
       mobile: '',
       loading: false
@@ -32,20 +33,32 @@ export default defineComponent({
           }
         );
 
-        if (res.code !== 200) {
-          state.statusShow = true;
-        } else {
-          router.push({
-            path: '/activationRegistrationDetail',
-            query: {
-              mobile: state.mobile
-            }
-          });
-        }
+        animation(res);
       } catch {
         //
+        state.loading = false;
       }
-      state.loading = false;
+    };
+
+    const animation = (item: any) => {
+      const timer = setInterval(() => {
+        if (state.progressRate >= 100) {
+          clearInterval(timer);
+          if (item.code !== 200) {
+            state.statusShow = true;
+          } else {
+            router.push({
+              path: '/activationRegistrationDetail',
+              query: {
+                mobile: state.mobile
+              }
+            });
+          }
+          state.loading = false;
+        } else {
+          state.progressRate += 4;
+        }
+      }, 80);
     };
 
     return () => (
@@ -57,6 +70,8 @@ export default defineComponent({
               leftIcon={iconKey}
               v-model={state.mobile}
               autocomplete="off"
+              maxlength={11}
+              type="tel"
               placeholder="请输入【音乐数字课堂】激活成功时的手机号"
             />
 
@@ -72,12 +87,14 @@ export default defineComponent({
                   {state.loading ? '请稍后······' : '多子女需多次核验'}
                 </span>
               </Button>
-              <Progress
-                showPivot={false}
-                strokeWidth={4}
-                percentage={30}
-                class={styles.progress}
-              />
+              {state.loading && (
+                <Progress
+                  showPivot={false}
+                  strokeWidth={4}
+                  v-model:percentage={state.progressRate}
+                  class={styles.progress}
+                />
+              )}
             </div>
           </div>
         </div>

+ 90 - 62
src/views/activation-code/record.tsx

@@ -1,25 +1,75 @@
 import { browser } from '@/helpers/utils';
-import { defineComponent, reactive } from 'vue';
+import { defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import MSticky from '@/components/m-sticky';
 import MHeader from '@/components/m-header';
 import { useRouter } from 'vue-router';
+import { postMessage } from '@/helpers/native-message';
 import MSearch from '@/components/m-search';
 import { Calendar, List } from 'vant';
 import dayjs from 'dayjs';
 import isBetween from 'dayjs/plugin/isBetween';
+import request from '@/helpers/request';
+import MEmpty from '@/components/m-empty';
 dayjs.extend(isBetween);
 
+const vipGiftPeriodType = {
+  DAY: '天',
+  MONTH: '个月',
+  YEAR: '年'
+} as any;
+
 export default defineComponent({
   name: 'activationCode',
   setup() {
     const router = useRouter();
     const state = reactive({
-      showPopoverTime: false
+      showPopoverTime: false,
+      background: 'transparent',
+      loading: false,
+      finished: false,
+      list: [] as any
     });
+
     const forms = reactive({
-      startTime: dayjs().subtract(1, 'months').format('YYYYMMDD'),
-      endTime: dayjs().format('YYYY-MM-DD')
+      page: 1,
+      rows: 20,
+      code: null as any,
+      activateStartTime: dayjs().subtract(1, 'months').format('YYYY-MM-DD'),
+      activateEndTime: dayjs().format('YYYY-MM-DD')
+    });
+
+    const getList = async () => {
+      state.loading = true;
+      try {
+        const params = {
+          ...forms
+        };
+
+        if (forms.activateEndTime && forms.activateStartTime) {
+          params.activateEndTime = forms.activateEndTime + ' 23:59:59';
+          params.activateStartTime = forms.activateStartTime + ' 00:00:00';
+        }
+        const res = await request.post('/edu-app/activationCodeRecord/page', {
+          data: params
+        });
+        if (res.code === 200 && Array.isArray(res?.data?.rows)) {
+          state.list = [...state.list, ...res.data.rows];
+          state.finished = !res.data.next;
+          forms.page = res.data.current + 1;
+          // state.listState.dataShow = state.list.length > 0;
+        } else {
+          state.finished = true;
+        }
+      } catch (error) {
+        // console.log('🚀 ~ error:', error);
+        state.finished = true;
+      }
+      state.loading = false;
+    };
+
+    onMounted(() => {
+      getList();
     });
     return () => (
       <div
@@ -61,7 +111,11 @@ export default defineComponent({
               <MSearch
                 inputBackground="white"
                 shape="round"
-                onSearch={(val: any) => {}}
+                placeholder="请输入互通码"
+                onSearch={(val: any) => {
+                  forms.code = val;
+                  getList();
+                }}
               />
 
               <div class={styles.prodSection}>
@@ -74,7 +128,8 @@ export default defineComponent({
                   onClick={() => {
                     state.showPopoverTime = true;
                   }}>
-                  {dayjs(forms.startTime).format('YYYY-MM-DD')}至{forms.endTime}
+                  {dayjs(forms.activateStartTime).format('YYYY-MM-DD')}至
+                  {forms.activateEndTime}
                 </div>
               </div>
             </div>
@@ -82,61 +137,34 @@ export default defineComponent({
         </MSticky>
 
         <div class={styles.sectionList}>
-          <div class={styles.sectionItem}>
-            <div class={styles.itemTitle}>乐器AI学练工具1年</div>
-            <div class={styles.itemCode}>SZKT765649LsRB</div>
-            <div class={styles.itemTime}>
-              激活时间:<span>2024-07-12</span>
-            </div>
-          </div>
-        </div>
-
-        {/* <List
-          loading={state.loading}
-          finished={state.finished}
-          finishedText=" "
-          onLoad={getMusicList}
-          immediateCheck={false}>
-          {state.musics.length > 0 && (
-            <div class={styles.musicList}>
-              {state.musics.map((item: any) => (
-                <Cell
-                  class={styles.musicItem}
-                  border={false}
-                  center
-                  onClick={() => onDetail(item)}>
-                  {{
-                    icon: () => (
-                      <div class={styles.musicImg}>
-                        <i
-                          class={[
-                            styles.iconType,
-                            styles[item.paymentType]
-                          ]}></i>
-                        <Image class={styles.musicImg} src={item.titleImg} />
-                      </div>
-                    ),
-                    title: () => (
-                      <div class={styles.musicContnet}>
-                        <h2>{item.musicSheetName}</h2>
-                        {item.composer && <p>{item.composer}</p>}
-                      </div>
-                    ),
-                    'right-icon': () => (
-                      <Image class={styles.musicPlayIcon} src={iconPlayer} />
-                    )
-                  }}
-                </Cell>
+          <List
+            loading={state.loading}
+            finished={state.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}>
+            {state.list.length > 0 &&
+              state.list.map((item: any) => (
+                <div class={styles.sectionItem}>
+                  <div class={styles.itemTitle}>
+                    乐器AI学练工具{item.times}
+                    {vipGiftPeriodType[item.type]}
+                  </div>
+                  <div class={styles.itemCode}>{item.code}</div>
+                  <div class={styles.itemTime}>
+                    激活时间:
+                    <span>{dayjs(item.activateTime).format('YYYY-MM-DD')}</span>
+                  </div>
+                </div>
               ))}
+          </List>
+
+          {!state.loading && state.list.length === 0 && (
+            <div style={{ height: '100%' }}>
+              <MEmpty description="暂无激活记录~" />
             </div>
           )}
-        </List> */}
-
-        {/* {!state.loading && state.musics.length === 0 && (
-          <div class={styles.emptyGroup}>
-            <MEmpty description="暂无曲谱" />
-          </div>
-        )} */}
+        </div>
 
         <Calendar
           v-model:show={state.showPopoverTime}
@@ -146,15 +174,15 @@ export default defineComponent({
           title="周期选择"
           minDate={new Date('2023-02-27')}
           defaultDate={[
-            dayjs(forms.startTime).toDate(),
-            dayjs(forms.endTime).toDate()
+            dayjs(forms.activateStartTime).toDate(),
+            dayjs(forms.activateEndTime).toDate()
           ]}
           style={{
             height: '70%'
           }}
           onConfirm={(item: any) => {
-            forms.startTime = dayjs(item[0]).format('YYYYMMDD');
-            forms.endTime = dayjs(item[1]).format('YYYY-MM-DD');
+            forms.activateStartTime = dayjs(item[0]).format('YYYY-MM-DD');
+            forms.activateEndTime = dayjs(item[1]).format('YYYY-MM-DD');
             state.showPopoverTime = false;
           }}
         />

+ 10 - 2
src/views/school-register/index.module.less

@@ -17,6 +17,12 @@
     height: 26Px;
     margin: 8px auto 0;
   }
+
+  :global {
+    .van-picker__loading {
+      top: calc(var(--van-picker-toolbar-height) + 15px + var(--van-search-input-height)) !important;
+    }
+  }
 }
 
 .title {
@@ -210,11 +216,13 @@
     }
   }
 }
+
 .sendBtn {
   width: 100Px;
 }
-.sendBtn:global(.van-button--disabled){
-  &::before{
+
+.sendBtn:global(.van-button--disabled) {
+  &::before {
     left: -5%;
     top: -15%;
     width: 110%;

+ 119 - 20
src/views/school-register/index.tsx

@@ -1,7 +1,16 @@
 import { defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from './index.module.less';
 import MHeader from '@/components/m-header';
-import { Area, Button, CellGroup, Field, Form, Popup, showToast } from 'vant';
+import {
+  Area,
+  Button,
+  CellGroup,
+  Field,
+  Form,
+  Picker,
+  Popup,
+  showToast
+} from 'vant';
 import icon_school from './images/icon_school.png';
 import icon_person from './images/icon_person.png';
 import icon_submit from './images/icon_submit.png';
@@ -17,6 +26,8 @@ import {
 import { useRoute } from 'vue-router';
 import MImgCode from '@/components/m-img-code';
 import { browser } from '@/helpers/utils';
+import request from '@/helpers/request';
+import MSearch from '@/components/m-search';
 
 export default defineComponent({
   name: 'SchoolRegister',
@@ -49,6 +60,7 @@ export default defineComponent({
     };
     const forms = reactive({
       id: '',
+      schoolAreaId: null as any,
       name: '', // 学校名称
       regionCode: '', // 所属区域
       cityCode: '', // 所属城市
@@ -79,6 +91,13 @@ export default defineComponent({
 
       inputFouce: 0
     });
+    const state = reactive({
+      schoolLoading: false,
+      schoolPopupIndex: [] as any,
+      schoolAreaList: [] as any,
+      schoolStatus: false,
+      schoolPopupShow: false
+    });
     const formateArea = (area: any[]) => {
       const province_list: { [_: string]: string } = {};
       const city_list: { [_: string]: string } = {};
@@ -136,6 +155,24 @@ export default defineComponent({
       }, 1000);
     };
     const formRef = ref();
+    const getSchoolAreaList = async (name?: string) => {
+      state.schoolLoading = true;
+      try {
+        const { data } = await request.post('/edu-app/open/schoolArea/list', {
+          data: {
+            name,
+            testFlag: true,
+            provinceCode: forms.provinceCode,
+            cityCode: forms.cityCode,
+            regionCode: forms.regionCode
+          }
+        });
+        state.schoolAreaList = data;
+      } catch {
+        //
+      }
+      state.schoolLoading = false;
+    };
     const handleSubmit = () => {
       forms.name = forms.name.trim();
       formRef.value
@@ -181,6 +218,27 @@ export default defineComponent({
               <Form ref={formRef}>
                 <CellGroup class={styles.group}>
                   <img src={icon_school} class={styles.icon} />
+
+                  <Field
+                    isLink
+                    border
+                    name="cityName"
+                    label="所属城市"
+                    placeholder="请选择"
+                    readonly
+                    inputAlign="right"
+                    v-model={data.cityName}
+                    onClick={() => {
+                      if (browserInfo.ios && data.inputFouce < 2) {
+                        data.inputFouce++;
+                        setTimeout(() => {
+                          data.showArea = true;
+                        }, 400);
+                      } else {
+                        data.showArea = true;
+                      }
+                    }}
+                    rules={[{ required: true, message: '请选择' }]}></Field>
                   <Field
                     border
                     name="name"
@@ -188,7 +246,9 @@ export default defineComponent({
                     rows="1"
                     autosize
                     // type="textarea"
-                    placeholder="请输入学校全称"
+                    isLink
+                    readonly
+                    placeholder="请选择学校全称"
                     inputAlign="right"
                     v-model={forms.name}
                     onUpdate:modelValue={(val: string) => {
@@ -206,27 +266,17 @@ export default defineComponent({
                     onFocus={() => {
                       data.inputFouce++;
                     }}
-                  />
-                  <Field
-                    isLink
-                    border
-                    name="cityName"
-                    label="所属城市"
-                    placeholder="请选择"
-                    readonly
-                    inputAlign="right"
-                    v-model={data.cityName}
                     onClick={() => {
-                      if (browserInfo.ios && data.inputFouce < 2) {
-                        data.inputFouce++;
-                        setTimeout(() => {
-                          data.showArea = true;
-                        }, 700);
-                      } else {
-                        data.showArea = true;
+                      if (!data.cityName) {
+                        showToast('请选择城市');
+                        return;
+                      }
+                      state.schoolStatus = true;
+                      if (forms.schoolAreaId) {
+                        state.schoolPopupIndex = [forms.schoolAreaId];
                       }
                     }}
-                    rules={[{ required: true, message: '请选择' }]}></Field>
+                  />
                   <Field center border name="schoolNature" label="办学性质">
                     {{
                       input: () => (
@@ -497,10 +547,59 @@ export default defineComponent({
                       .map((item: any) => item.text)
                       .join('-');
                     data.showArea = false;
+
+                    getSchoolAreaList();
                   }}
                 />
               </Popup>
 
+              {/* 互通学校 */}
+              <Popup
+                v-model:show={state.schoolStatus}
+                position="bottom"
+                // round
+                safeAreaInsetBottom
+                lazyRender={false}
+                class={'popupBottomSearch'}
+                onOpen={() => {
+                  state.schoolPopupShow = true;
+                }}
+                onClosed={() => {
+                  state.schoolPopupShow = false;
+                }}>
+                {state.schoolPopupShow && (
+                  <div>
+                    <Picker
+                      showToolbar
+                      v-model={state.schoolPopupIndex}
+                      columns={state.schoolAreaList}
+                      loading={state.schoolLoading}
+                      columnsFieldNames={{
+                        text: 'name',
+                        value: 'id'
+                      }}
+                      onCancel={() => (state.schoolStatus = false)}
+                      onConfirm={(val: any) => {
+                        const selectedOption = val.selectedOptions[0];
+                        forms.schoolAreaId = selectedOption.id;
+                        forms.name = selectedOption.name;
+                        state.schoolStatus = false;
+                      }}>
+                      {{
+                        'columns-top': (
+                          <MSearch
+                            placeholder="请输入学校名称"
+                            onSearch={(val: any) => {
+                              getSchoolAreaList(val);
+                            }}
+                          />
+                        )
+                      }}
+                    </Picker>
+                  </div>
+                )}
+              </Popup>
+
               <Popup
                 class="popup-custom van-scale"
                 transition="van-scale"