lex-xin 3 years ago
parent
commit
52060708d0

+ 10 - 0
src/components/ColHeader/index.module.less

@@ -0,0 +1,10 @@
+.colHeader {
+  &.green {
+    background-color: var(--van-primary);
+    :global {
+      .van-nav-bar__title, .van-icon {
+        color: #fff;
+      }
+    }
+  }
+}

+ 97 - 0
src/components/ColHeader/index.tsx

@@ -0,0 +1,97 @@
+import { postMessage } from "@/helpers/native-message";
+import { NavBar } from "vant";
+import { defineComponent } from "vue";
+import styles from './index.module.less'
+
+type backIconColor = 'black' | 'white';
+type backgroundType = 'white' | 'green';
+
+export default defineComponent({
+  name: "col-header",
+  props: {
+    title: String,
+    isBack: {
+      type: Boolean,
+      default: false
+    },
+    isFixed: {
+      type: Boolean,
+      default: true
+    },
+    styleName: {
+      type: Object,
+      default: () => ({})
+    },
+    titleClass: String,
+    background: {
+      type: String,
+      default: 'white' as backgroundType
+    },
+    rightText: String,
+    onClickRight: {
+      type: Function,
+      default: () => { }
+    }
+  },
+  data() {
+    return {
+      headerTitle: null as any,
+      navBarHeight: 0, // 顶部导航栏高度
+      titleHeight: 44, // 顶部导航高度(默认44px)
+    }
+  },
+  mounted() {
+    this.headerTitle = this.title || this.$route.meta.title;
+    this.navBarInit();
+  },
+  methods: {
+    navBarInit() {
+      // 设置是否显示导航栏 0 显示 1 不显示
+      postMessage({ api: 'setBarStatus', content: { status: 0 } })
+      // 设置返回按钮颜色
+      postMessage({ api: 'backIconChange', content: { iconStyle: 'black' as backIconColor } })
+
+      let sNavHeight = sessionStorage.getItem('navHeight')
+      let sTitleHeight = sessionStorage.getItem('titleHeight')
+      if (sNavHeight && sTitleHeight) {
+        this.navBarHeight = Number(sNavHeight)
+      } else {
+        postMessage({ api: 'getNavHeight' }, (res) => {
+          const { content } = res as any
+          const dpi = content.dpi || 2
+          if (content.navHeight) {
+            const navHeight = content.navHeight / dpi
+            sessionStorage.setItem('navHeight', String(navHeight))
+            this.navBarHeight = navHeight
+          }
+          if (content.titleHeight) { // 导航栏的高度
+            const titleHeight = content.titleHeight / dpi
+            sessionStorage.setItem('titleHeight', String(titleHeight))
+            this.titleHeight = titleHeight
+          }
+        })
+      }
+    },
+    onClickLeft() {
+      this.$router.back();
+    },
+    clickRight() {
+      this.onClickRight && this.onClickRight();
+    }
+  },
+  render() {
+    return (
+      <>
+        <NavBar title={this.headerTitle}
+          style={{ paddingTop: `${this.navBarHeight}px`, height: this.titleHeight + 'px', lineHeight: this.titleHeight + 'px' }}
+          class={[this.background === 'green' ? styles.green : null, styles.colHeader]}
+          left-arrow={this.isBack}
+          rightText={this.rightText}
+          fixed={this.isFixed}
+          onClick-right={this.clickRight}
+          onClick-left={this.onClickLeft}></NavBar>
+          { this.$slots.default ? this.$slots.default() : null }
+      </>
+    )
+  }
+})

+ 1 - 1
src/components/imgCode/index.module.less

@@ -25,7 +25,7 @@
 
   .field {
     background: #F4F4F4;
-    padding: 10px 12px;
+    padding: 10px 12px !important;
   }
 }
 

+ 5 - 3
src/components/imgCode/index.tsx

@@ -10,7 +10,8 @@ export default defineComponent({
     phone: [String, Number],
     onClose: {
       type: Function,
-      default: () => {},
+      // (...args: any[]) => any) | undefined
+      default: () => {}
     },
     onSendCode: {
       type: Function,
@@ -48,13 +49,13 @@ export default defineComponent({
           if((this as any).code.length < 4) {
               return
           }
-          await request('/api-student/code/verifyLoginImage', {
+          await request.post('/api-student/code/verifyLoginImage', {
             data: {
               phone: this.phone,
               code: this.code
             }
           })
-          await request('/api-student/code/sendSms', {
+          await request.post('/api-student/code/sendSms', {
             data: {
               mobile: this.phone
             }
@@ -69,6 +70,7 @@ export default defineComponent({
   },
   render() {
     return (
+      // @ts-ignore
       <Popup show={this.showStatus} class={styles.imgCodePopup} closeOnClickOverlay={false} onClose={this.onClose} closeable closeIcon="close">
         <div class={styles.imgCode}>
           <p class={styles.codeTitle}>输入图形验证码</p>

+ 5 - 0
src/helpers/helpState.ts

@@ -0,0 +1,5 @@
+import { reactive } from 'vue';
+
+export const state = reactive({
+  loadingCount: 0 as number // 加载次数
+})

+ 8 - 5
src/helpers/request.ts

@@ -1,10 +1,9 @@
 import { extend } from 'umi-request';
-import { Toast } from 'vant';
 import cleanDeep from 'clean-deep';
-import { browser } from '@/helpers/utils';
-import { setLogout, setLoginError } from '@/student/state'
+import { browser, openLoading, closeLoading } from '@/helpers/utils';
+import { setLogout, setLoginError } from '@/state';
 import { postMessage } from './native-message';
-import { getAuth } from './storage';
+import { Toast } from 'vant';
 
 export interface SearchInitParams {
   rows?: string | number;
@@ -32,6 +31,7 @@ let initRequest = false;
 
 request.interceptors.request.use(
   (url, options: any) => {
+    openLoading();
     initRequest = options.initRequest || false;
     const Authorization = sessionStorage.getItem('Authorization') || '';
     const authHeaders: any = {};
@@ -55,13 +55,16 @@ request.interceptors.request.use(
           ...authHeaders
         }
       }
-    }
+    };
   },
   { global: false }
 );
 
 request.interceptors.response.use(
   async res => {
+    setTimeout(() => {
+      closeLoading();
+    }, 100);
     if (res.status > 299 || res.status < 200) {
       const msg = '服务器错误,状态码' + res.status;
       Toast(msg);

+ 31 - 0
src/helpers/utils.ts

@@ -1,4 +1,6 @@
 import { sessionStorage as storage } from 'js-storage';
+import { Toast } from 'vant';
+import { state as helpState } from './helpState';
 
 export const browser = () => {
   const u = navigator.userAgent;
@@ -52,3 +54,32 @@ export const setAuth = (token: any) => {
 export const getAuth = () => {
   storage.get('Authorization');
 };
+
+/**
+ * 开始加载
+ */
+export const openLoading = () => {
+  if (helpState.loadingCount === 0) {
+    helpState.loadingCount++;
+    Toast.loading({
+      message: '加载中...',
+      forbidClick: true,
+      loadingType: 'spinner',
+      duration: 0
+    });
+  }
+};
+
+/**
+ * 关闭加载
+ */
+export const closeLoading = () => {
+  console.log(helpState.loadingCount, +new Date());
+  if (helpState.loadingCount <= 0) return;
+  setTimeout(() => {
+    helpState.loadingCount--;
+    if (helpState.loadingCount === 0) {
+      Toast.clear();
+    }
+  }, 200);
+};

+ 6 - 0
src/helpers/validate.ts

@@ -1,3 +1,4 @@
+import { phoneRule } from './rules';
 // 学生地址
 export function vaildStudentUrl() {
   const url = window.location.href;
@@ -17,3 +18,8 @@ export function vaildStudentUrl() {
   }
   return returnUrl;
 }
+
+export function checkPhone(phone: string) {
+  const phoneRule = /^1[3456789]\d{9}$/;
+  return phoneRule.test(phone);
+}

+ 5 - 0
src/router/index-student.ts

@@ -5,4 +5,9 @@ const router: Router = createRouter({
   routes
 });
 
+router.beforeEach((to, from, next) => {
+  document.title = (to.meta.title || '酷乐秀') as any;
+  next();
+});
+
 export default router;

+ 2 - 3
src/router/index-teacher.ts

@@ -1,8 +1,7 @@
 import { createRouter, createWebHashHistory, Router } from 'vue-router';
-
+import routes from './routes-teacher';
 const router: Router = createRouter({
   history: createWebHashHistory(),
-  routes: []
+  routes
 });
-
 export default router;

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

@@ -21,6 +21,14 @@ export default [
         path: '/home',
         name: 'home',
         component: () => import('@/student/home/index')
+      },
+      {
+        path: '/practiceClass',
+        name: 'practiceClass',
+        component: () => import('@/student/practiceClass/index'),
+        meta: {
+          title: '陪练课'
+        }
       }
     ]
   },

+ 0 - 0
src/student/state.ts → src/state.ts


+ 0 - 5
src/student/layout/api.ts

@@ -1,5 +0,0 @@
-import request from '@/helpers/request';
-
-export const getUserInfo = () => {
-  return request.post('/api-auth/usernameLogin');
-}

+ 1 - 1
src/student/layout/auth.tsx

@@ -1,6 +1,6 @@
 import { defineComponent } from "vue";
 import styles from './auth.module.less';
-import { state, setLogin } from '../state';
+import { state, setLogin } from '@/state';
 import { browser, setAuth } from "@/helpers/utils";
 import { postMessage } from "@/helpers/native-message";
 import { RouterView } from "vue-router";

+ 29 - 0
src/student/layout/login.module.less

@@ -2,6 +2,7 @@
   min-height: 100vh;
   background: url('./images/top_bg.png') no-repeat top center, url('./images/bottom_bg.png') no-repeat bottom center;
   background-color: #fff;
+  background-size: contain;
 
   .loginTitle {
     padding-top: 100px;
@@ -11,4 +12,32 @@
     line-height: 37px;
     font-weight: 500;
   }
+
+  .codeText {
+    color: var(--van-primary);
+  }
+
+  .margin34 {
+    margin: 0 34px;
+  }
+
+  .formTitle {
+    font-size: 18px;
+    color: #000;
+    font-weight: 500;
+  }
+
+  :global {
+    .van-cell-group {
+      margin-bottom: 35px;
+    }
+    .van-field {
+      padding-left: 0;
+      padding-right: 0;
+    }
+    .van-button + .van-button {
+      margin-top: 20px;
+      color: #000 !important;
+    }
+  }
 }

+ 56 - 42
src/student/layout/login.tsx

@@ -1,8 +1,9 @@
 import { defineComponent } from "vue";
-import { CellGroup, Field, Button, CountDown } from "vant";
-import ImgCode from "@/components/imgCode";
+import { CellGroup, Field, Button, CountDown, Row, Col, Toast } from "vant";
+import ImgCode from "@/components/ImgCode";
+import { checkPhone } from "@/helpers/validate";
 import request from "@/helpers/request";
-import { setLogin, state } from "@/student/state";
+import { setLogin, state } from "@/state";
 import { removeAuth, setAuth } from "@/helpers/utils";
 import styles from "./login.module.less";
 
@@ -51,7 +52,7 @@ export default defineComponent({
     async onLogin() {
       try {
         let res: any;
-        if(this.loginType === 'PWD') {
+        if (this.loginType === 'PWD') {
           res = await request.post('/api-auth/usernameLogin', {
             data: {
               username: this.username,
@@ -81,14 +82,14 @@ export default defineComponent({
         setLogin(userCash.data)
 
         this.directNext();
-      } catch{
+      } catch {
 
       }
     },
     async onSendCode() { // 发送验证码
-      // if(!checkPhone(this.phoneNumber)) {
-      //     return
-      // }
+      if(!checkPhone(this.username)) {
+        return Toast('请输入正确的手机号码');
+      }
       this.imgCodeStatus = true
     },
     onCodeSend() {
@@ -100,9 +101,9 @@ export default defineComponent({
       this.countDownRef.reset();
     },
     onChange() {
-      if(this.loginType === 'PWD') {
+      if (this.loginType === 'PWD') {
         this.loginType = 'SMS'
-      } else if(this.loginType === 'SMS') {
+      } else if (this.loginType === 'SMS') {
         this.loginType = 'PWD'
       }
     },
@@ -111,45 +112,58 @@ export default defineComponent({
     return (
       <div class={styles.login}>
         <div class={styles.loginTitle}>您好,<br /> 欢迎使用酷乐秀</div>
-        <CellGroup inset>
-          <Field
-            v-model={this.username}
-            name="手机号"
-            label="手机号"
-            placeholder="手机号"
-            type="tel"
-            maxlength={11}
-          />
-          { this.loginType === 'PWD' ? <Field
-            v-model={this.password}
-            type="password"
-            name="密码"
-            label="密码"
-            placeholder="密码"
-          /> : <Field
-            v-model={this.smsCode}
-            name="验证码"
-            label="验证码"
-            placeholder="验证码"
-            type="tel"
-            maxlength={6}
-            // @ts-ignore
-            vSlots={{
-              button: () => (
-                this.countDownStatus ? <Button size="small" round type="primary" onClick={this.onSendCode}>发送验证码</Button> :  <CountDown ref={this.countDownRef} auto-start="false" time={this.countDownTime} onFinish={this.onFinished} format="ss秒" />
-              )
-            }}
-          /> }
+        <CellGroup class={styles.margin34} border={false}>
+          <Row style={{ marginBottom: '16px' }}>
+            <Col span={24} class={styles.formTitle}>手机号</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.username}
+                name="手机号"
+                placeholder="请输入您的手机号"
+                type="tel"
+                maxlength={11}
+              />
+            </Col>
+          </Row>
+
+          {this.loginType === 'PWD' ? <Row>
+            <Col span={24} class={styles.formTitle}>密码</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.password}
+                type="password"
+                name="密码"
+                placeholder="请输入密码"
+              />
+            </Col>
+          </Row> : <Row>
+            <Col span={24} class={styles.formTitle}>密码</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.smsCode}
+                name="验证码"
+                placeholder="请输入验证码"
+                type="tel"
+                maxlength={6}
+                // @ts-ignore
+                vSlots={{
+                  button: () => (
+                    this.countDownStatus ? <span class={styles.codeText} onClick={this.onSendCode}>获取验证码</span> : <CountDown ref={this.countDownRef} auto-start={false} time={this.countDownTime} onFinish={this.onFinished} format="ss秒" />
+                  )
+                }}
+              />
+            </Col>
+          </Row>}
 
         </CellGroup>
-        <div style="margin: 16px;">
+        <div class={styles.margin34}>
           <Button round block type="primary" disabled={this.codeDisable} onClick={this.onLogin}>
             提交
           </Button>
-          <Button plain onClick={this.onChange}>{ this.loginType === 'PWD' ? '验证码登录' : '密码登录' }</Button>
+          <Button block round color="#F5F7FB" onClick={this.onChange}>{this.loginType === 'PWD' ? '验证码登录' : '密码登录'}</Button>
         </div>
 
-        { this.imgCodeStatus ? <ImgCode v-model:value={this.imgCodeStatus} phone={this.username} onClose={() => { this.imgCodeStatus = false }} onSendCode={this.onCodeSend} /> : null }
+        {this.imgCodeStatus ? <ImgCode v-model:value={this.imgCodeStatus} phone={this.username} onClose={() => { this.imgCodeStatus = false }} onSendCode={this.onCodeSend} /> : null}
       </div>
     )
   }

+ 0 - 0
src/student/practiceClass/index.module.less


+ 19 - 0
src/student/practiceClass/index.tsx

@@ -0,0 +1,19 @@
+import { defineComponent } from "vue";
+import styles from './index.module.less';
+import ColHeader from '@/components/ColHeader';
+import { Sticky } from "vant";
+
+export default defineComponent({
+  name: "practiceClass",
+  render() {
+    return (
+      <>
+        <Sticky>
+          <ColHeader title="陪练课" isFixed={false} isBack background="green">
+            显示
+          </ColHeader>
+        </Sticky>
+      </>
+    )
+  }
+})

+ 2 - 7
src/teacher/App.vue

@@ -1,16 +1,11 @@
 <template>
-  <!-- <img alt="Vue logo" src="./common/assets/logo.png" /> -->
-  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
+  <router-view></router-view>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import HelloWorld from '@components/HelloWorld.vue';
 
 export default defineComponent({
-  name: 'App',
-  components: {
-    HelloWorld
-  }
+  name: 'App'
 });
 </script>

+ 0 - 5
src/teacher/layout/api.ts

@@ -1,5 +0,0 @@
-import request from '@/helpers/request';
-
-export const getUserInfo = () => {
-  return request.post('/api-auth/usernameLogin');
-}

+ 2 - 3
src/teacher/layout/auth.tsx

@@ -1,6 +1,6 @@
 import { defineComponent } from "vue";
 import styles from './auth.module.less';
-import { state, setLogin } from '../../student/state';
+import { state, setLogin } from '@/state';
 import { browser, setAuth } from "@/helpers/utils";
 import { postMessage } from "@/helpers/native-message";
 import { RouterView } from "vue-router";
@@ -32,11 +32,10 @@ export default defineComponent({
       if (this.loading) {
         return
       }
-      console.log(state)
       if ((state.user.status === 'init' || state.user.status === 'error')) {
         this.loading = true
         try {
-          let res = await request.post('/api-student/userCashAccount/get', {
+          let res = await request.get('/api-student/userCashAccount/get', {
             initRequest: true // 初始化接口
           })
           // console.log(res)

BIN
src/teacher/layout/images/bottom_bg.png


BIN
src/teacher/layout/images/top_bg.png


+ 43 - 0
src/teacher/layout/login.module.less

@@ -0,0 +1,43 @@
+.login {
+  min-height: 100vh;
+  background: url('./images/top_bg.png') no-repeat top center, url('./images/bottom_bg.png') no-repeat bottom center;
+  background-color: #fff;
+  background-size: contain;
+
+  .loginTitle {
+    padding-top: 100px;
+    font-size: 26px;
+    padding-left: 35px;
+    padding-bottom: 70px;
+    line-height: 37px;
+    font-weight: 500;
+  }
+
+  .codeText {
+    color: var(--van-primary);
+  }
+
+  .margin34 {
+    margin: 0 34px;
+  }
+
+  .formTitle {
+    font-size: 18px;
+    color: #000;
+    font-weight: 500;
+  }
+
+  :global {
+    .van-cell-group {
+      margin-bottom: 35px;
+    }
+    .van-field {
+      padding-left: 0;
+      padding-right: 0;
+    }
+    .van-button + .van-button {
+      margin-top: 20px;
+      color: #000 !important;
+    }
+  }
+}

+ 66 - 41
src/teacher/layout/login.tsx

@@ -1,21 +1,25 @@
 import { defineComponent } from "vue";
-import { CellGroup, Field, Button, CountDown } from "vant";
+import { CellGroup, Field, Button, CountDown, Row, Col, Toast } from "vant";
+import ImgCode from "@/components/ImgCode";
+import { checkPhone } from "@/helpers/validate";
 import request from "@/helpers/request";
-import { setLogin, state } from "@/student/state";
+import { setLogin, state } from "@/state";
 import { removeAuth, setAuth } from "@/helpers/utils";
+import styles from "./login.module.less";
 
 type loginType = 'PWD' | 'SMS';
 export default defineComponent({
   name: 'login',
   data() {
     return {
-      loginType: 'PWD' as loginType,
+      loginType: 'SMS' as loginType,
       username: '',
       password: '',
       smsCode: '',
       countDownStatus: true, // 是否发送验证码
       countDownTime: 1000 * 120, // 倒计时时间
       countDownRef: null as any, // 倒计时实例
+      imgCodeStatus: false,
     }
   },
   computed: {
@@ -26,7 +30,6 @@ export default defineComponent({
       } else {
         this.username && this.smsCode && (status = false);
       }
-      console.log(status, this.loginType)
       return status;
     },
   },
@@ -49,7 +52,7 @@ export default defineComponent({
     async onLogin() {
       try {
         let res: any;
-        if(this.loginType === 'PWD') {
+        if (this.loginType === 'PWD') {
           res = await request.post('/api-auth/usernameLogin', {
             data: {
               username: this.username,
@@ -79,10 +82,16 @@ export default defineComponent({
         setLogin(userCash.data)
 
         this.directNext();
-      } catch{
+      } catch {
 
       }
     },
+    async onSendCode() { // 发送验证码
+      if(!checkPhone(this.username)) {
+        return Toast('请输入正确的手机号码');
+      }
+      this.imgCodeStatus = true
+    },
     onCodeSend() {
       this.countDownStatus = false;
       this.countDownRef.start();
@@ -92,53 +101,69 @@ export default defineComponent({
       this.countDownRef.reset();
     },
     onChange() {
-      if(this.loginType === 'PWD') {
+      if (this.loginType === 'PWD') {
         this.loginType = 'SMS'
-      } else if(this.loginType === 'SMS') {
+      } else if (this.loginType === 'SMS') {
         this.loginType = 'PWD'
       }
-    }
+    },
   },
   render() {
     return (
-      <div class="login">
-        <CellGroup inset>
-          <Field
-            v-model={this.username}
-            name="手机号"
-            label="手机号"
-            placeholder="手机号"
-            type="tel"
-            maxlength={11}
-          />
-          { this.loginType === 'PWD' ? <Field
-            v-model={this.password}
-            type="password"
-            name="密码"
-            label="密码"
-            placeholder="密码"
-          /> : <Field
-            v-model={this.smsCode}
-            name="验证码"
-            label="验证码"
-            placeholder="验证码"
-            type="tel"
-            maxlength={6}
-            // @ts-ignore
-            vSlots={{
-              button: () => (
-                this.countDownStatus ? <Button size="small" round type="primary" onClick={this.onCodeSend}>发送验证码</Button> :  <CountDown ref={this.countDownRef} auto-start="false" time={this.countDownTime} onFinish={this.onFinished} format="ss秒" />
-              )
-            }}
-          /> }
+      <div class={styles.login}>
+        <div class={styles.loginTitle}>您好,<br /> 欢迎使用酷乐秀</div>
+        <CellGroup class={styles.margin34} border={false}>
+          <Row style={{ marginBottom: '16px' }}>
+            <Col span={24} class={styles.formTitle}>手机号</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.username}
+                name="手机号"
+                placeholder="请输入您的手机号"
+                type="tel"
+                maxlength={11}
+              />
+            </Col>
+          </Row>
+
+          {this.loginType === 'PWD' ? <Row>
+            <Col span={24} class={styles.formTitle}>密码</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.password}
+                type="password"
+                name="密码"
+                placeholder="请输入密码"
+              />
+            </Col>
+          </Row> : <Row>
+            <Col span={24} class={styles.formTitle}>密码</Col>
+            <Col span={24} class="van-hairline--bottom">
+              <Field
+                v-model={this.smsCode}
+                name="验证码"
+                placeholder="请输入验证码"
+                type="tel"
+                maxlength={6}
+                // @ts-ignore
+                vSlots={{
+                  button: () => (
+                    this.countDownStatus ? <span class={styles.codeText} onClick={this.onSendCode}>获取验证码</span> : <CountDown ref={this.countDownRef} auto-start={false} time={this.countDownTime} onFinish={this.onFinished} format="ss秒" />
+                  )
+                }}
+              />
+            </Col>
+          </Row>}
 
         </CellGroup>
-        <div style="margin: 16px;">
+        <div class={styles.margin34}>
           <Button round block type="primary" disabled={this.codeDisable} onClick={this.onLogin}>
             提交
           </Button>
-          <Button plain onClick={this.onChange}>{ this.loginType === 'PWD' ? '验证码登录' : '密码登录' }</Button>
+          <Button block round color="#F5F7FB" onClick={this.onChange}>{this.loginType === 'PWD' ? '验证码登录' : '密码登录'}</Button>
         </div>
+
+        {this.imgCodeStatus ? <ImgCode v-model:value={this.imgCodeStatus} phone={this.username} onClose={() => { this.imgCodeStatus = false }} onSendCode={this.onCodeSend} /> : null}
       </div>
     )
   }