Browse Source

更新组件

lex-xin 3 years ago
parent
commit
d62e22f3ee

+ 3 - 1
README.md

@@ -37,7 +37,9 @@ See [Configuration Reference](https://vitejs.dev/config/).
 ```
 /src/student -- 学生端页面目录
 /src/teacher -- 老师端页面目录
-/src/views 两端共用页面,但每个端的路由都需要单独配置
+/src/views 两端共用页面,路由最好配置到 routes-common 文件中
+
+/src/views/module -- 公用组件
 ```
 
 ### Rem Unit (default)

+ 11 - 0
package-lock.json

@@ -2077,6 +2077,12 @@
       "integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==",
       "dev": true
     },
+    "@types/numeral": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/@types/numeral/-/numeral-2.0.2.tgz",
+      "integrity": "sha512-A8F30k2gYJ/6e07spSCPpkuZu79LCnkPTvqmIWQzNGcrzwFKpVOydG41lNt5wZXjSI149qjyzC2L1+F2PD/NUA==",
+      "dev": true
+    },
     "@types/through": {
       "version": "0.0.30",
       "resolved": "https://registry.npmmirror.com/@types/through/-/through-0.0.30.tgz",
@@ -5477,6 +5483,11 @@
         }
       }
     },
+    "numeral": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmmirror.com/numeral/-/numeral-2.0.6.tgz",
+      "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA=="
+    },
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",

+ 2 - 0
package.json

@@ -27,6 +27,7 @@
     "loaders.css": "^0.1.2",
     "mitt": "^3.0.0",
     "normalize.css": "^8.0.1",
+    "numeral": "^2.0.6",
     "query-string": "^7.1.1",
     "umi-request": "^1.4.0",
     "vant": "^3.3.7",
@@ -38,6 +39,7 @@
     "@babel/core": "^7.16.5",
     "@babel/preset-env": "^7.16.5",
     "@types/node": "^16.11.14",
+    "@types/numeral": "^2.0.2",
     "@typescript-eslint/eslint-plugin": "^5.7.0",
     "@typescript-eslint/parser": "^5.7.0",
     "@vitejs/plugin-legacy": "^1.7.1",

BIN
public/favicon - 副本.ico


BIN
public/favicon.ico


+ 9 - 4
src/components/col-protocol/index.module.less

@@ -1,6 +1,6 @@
 .colProtocol {
-  display: flex;
-  align-items: center;
+  // display: flex;
+  // align-items: center;
   font-size: 12px;
   padding: 15px 14px;
   color: #999;
@@ -16,11 +16,16 @@
     border: transparent;
   }
   :global {
+    .van-checkbox {
+      display: inline-block;
+      align-items: inherit;
+      overflow: inherit;
+    }
     .van-checkbox__icon {
       height: 15px;
       line-height: 15px;
-      display: flex;
-      align-items: center;
+      display: inline-block;
+      vertical-align: sub;
     }
     .van-checkbox__label {
       line-height: 15px;

+ 3 - 3
src/components/col-protocol/index.tsx

@@ -7,7 +7,7 @@ import inactiveButtonIcon from '@common/images/icon_checkbox_default.png';
 export default defineComponent({
   name: 'protocol',
   props: {
-    value: {
+    modelValue: {
       type: Boolean,
       default: false
     }
@@ -21,7 +21,7 @@ export default defineComponent({
     }
   },
   mounted() {
-    this.checked = this.value;
+    this.checked = this.modelValue;
     window.addEventListener('hashchange', this.onHash, false)
   },
   unmounted() {
@@ -29,7 +29,7 @@ export default defineComponent({
   },
   watch: {
     checked(val) {
-      this.$emit('update:value', val)
+      this.$emit('update:modelValue', val)
     }
   },
   methods: {

+ 7 - 0
src/helpers/vueFilter.ts

@@ -0,0 +1,7 @@
+import numeral from 'numeral';
+
+export default {
+  moneyFormat(value: number) {
+    return numeral(value).format('0,0.00');
+  }
+};

+ 18 - 1
src/router/routes-common.ts

@@ -1,5 +1,22 @@
 // 需要登录的路由
-export const router = [];
+export const router = [
+  {
+    path: '/videoDetail',
+    name: 'videoDetail',
+    component: () => import('@/views/video-detail/index'),
+    meta: {
+      title: '视频课'
+    }
+  },
+  {
+    path: '/orderDetail',
+    name: 'orderDetail',
+    component: () => import('@/views/order-detail/index'),
+    meta: {
+      title: '订单详情'
+    }
+  }
+];
 
 // 不需要登录的路由
 export const rootRouter = [];

+ 10 - 2
src/router/routes-student.ts

@@ -10,6 +10,7 @@ export default [
     path: '/',
     component: Auth,
     children: [
+      ...router,
       {
         path: '/login',
         name: 'login',
@@ -29,8 +30,15 @@ export default [
         component: () => import('@/student/practice-class/index'),
         meta: {
           title: '陪练课'
-        },
-        ...router
+        }
+      },
+      {
+        path: '/memberCenter',
+        name: 'memberCenter',
+        component: () => import('@/student/member-center/index'),
+        meta: {
+          title: '会员中心'
+        }
       }
     ]
   },

+ 3 - 0
src/router/routes-teacher.ts

@@ -1,4 +1,5 @@
 import Auth from '@/teacher/layout/auth';
+import { router, rootRouter } from './routes-common';
 
 type metaType = {
   isRegister: boolean;
@@ -9,6 +10,7 @@ export default [
     path: '/',
     component: Auth,
     children: [
+      ...router,
       {
         path: '/login',
         name: 'login',
@@ -48,6 +50,7 @@ export default [
       }
     ]
   },
+  ...rootRouter,
   {
     path: '/:pathMatch(.*)*',
     component: () => import('@/views/404'),

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

@@ -35,7 +35,7 @@ export default defineComponent({
       if ((state.user.status === 'init' || state.user.status === 'error')) {
         this.loading = true
         try {
-          let res = await request.get('/api-student/userCashAccount/get', {
+          let res = await request.get('/api-auth/api/queryUserInfo', {
             initRequest: true // 初始化接口
           })
           // console.log(res)

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

@@ -76,7 +76,7 @@ export default defineComponent({
         const { authentication } = res.data;
         setAuth(authentication.token_type + " " + authentication.access_token);
 
-        let userCash = await request.get('/api-student/userCashAccount/get', {
+        let userCash = await request.get('/api-auth/api/queryUserInfo', {
           initRequest: true // 初始化接口
         })
         setLogin(userCash.data)

+ 2 - 0
src/student/main.ts

@@ -7,11 +7,13 @@ import router from '../router/index-student';
 import 'normalize.css';
 
 import '../styles/index.less';
+import vueFilter from '@/helpers/vueFilter';
 
 const app = createApp(App);
 
 dayjs.locale('zh-ch');
 app.config.globalProperties.$dayjs = dayjs;
+app.config.globalProperties.$filters = vueFilter;
 app.use(router);
 
 app.mount('#app');

BIN
src/student/member-center/images/1.png


BIN
src/student/member-center/images/2.png


BIN
src/student/member-center/images/3.png


BIN
src/student/member-center/images/4.png


BIN
src/student/member-center/images/5.png


BIN
src/student/member-center/images/6.png


BIN
src/student/member-center/images/7.png


BIN
src/student/member-center/images/8.png


BIN
src/student/member-center/images/member_bg.png


BIN
src/student/member-center/images/tip_bg.png


+ 122 - 0
src/student/member-center/index.module.less

@@ -0,0 +1,122 @@
+.member-center {
+  background-color: #FFE5CC;
+  min-height: 100vh;
+  position: relative;
+
+  :global {
+    .van-nav-bar {
+      background-color: transparent;
+    }
+  }
+
+  .member_container {
+    padding: 10px 14px 0;
+    .title {
+      display: flex;
+      align-items: center;
+      font-size: 16px;
+      line-height: 28px;
+      font-weight: 500;
+      color: #333333;
+      &::before {
+        content: " ";
+        width: 4px;
+        height: 17px;
+        background: #01c1b5;
+        display: inline-block;
+        margin-right: 7px;
+        border-radius: 8px;
+      }
+    }
+  }
+  .level {
+    width: 18px;
+    height: 16px;
+  }
+  .userMember {
+    background: url("./images/member_bg.png") no-repeat center #534754;
+    background-size: cover;
+    width: auto;
+    border-radius: 10px;
+    padding: 20px 12px 30px;
+    .userImg {
+      width: 46px;
+      height: 46px;
+      border-radius: 50%;
+      margin-right: 12px;
+    }
+    .userInfo {
+      display: flex;
+      align-items: center;
+      color: #fff;
+      padding-bottom: 5px;
+      .name {
+        font-size: 18px;
+        padding-right: 5px;
+      }
+      .phone {
+        font-size: 14px;
+      }
+    }
+    .timeRemaining {
+      margin-top: 0;
+      font-size: 14px;
+      color: #c0c0c0;
+      .remaining {
+        color: #f7b500;
+        padding: 0 5px;
+      }
+    }
+    .member_time {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+  }
+
+  .memberContainer {
+    height: calc(100vh - 196px);
+    overflow-y: auto;
+    background-color: #fff;
+    border-radius: 18px 18px 0px 0px;
+    position: relative;
+    margin-top: -15px;
+    padding: 0 14px;
+    z-index: 99;
+  }
+
+
+  .btnGroup {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 100;
+    background-color: #fff;
+    display: flex;
+    align-items: center;
+    padding: 12px 16px;
+    justify-content: space-between;
+    border-top: 1px solid #F0F0F0;
+      .btn {
+        padding: 0 22px;
+        color: #7A3104 !important;
+      }
+
+    .priceSection {
+      display: flex;
+      align-items: center;
+      font-size: 16px;
+      color: #1A1A1A;
+      .price {
+        font-size: 18px;
+        font-weight: bold;
+        color: #FF3535;
+
+        .priceUnit {
+          font-size: 14px;
+        }
+      }
+    }
+  }
+}

+ 50 - 0
src/student/member-center/index.tsx

@@ -0,0 +1,50 @@
+import ColHeader from "@/components/col-header";
+import { Button, Cell, Image } from "vant";
+import { defineComponent } from "vue";
+import styles from './index.module.less';
+
+import iconTeacher from '@common/images/icon_teacher.png';
+import ColProtocol from "@/components/col-protocol";
+
+export default defineComponent({
+  name: 'MemberCenter',
+  data() {
+    return {
+      agreeStatus: false,
+    }
+  },
+  render() {
+    return (
+      <div class={styles['member-center']}>
+        <ColHeader isFixed={false} />
+        <div class={styles.member_container}>
+          <Cell class={styles.userMember} labelClass={styles.timeRemaining} v-slots={{
+            icon: () => (<Image class={styles.userImg} src={iconTeacher} fit="cover" />),
+            title: () => (<div class={styles.userInfo}>
+              <span class={styles.name}>李小明</span>
+              <Image class={styles.level} src="https://daya.ks3-cn-beijing.ksyun.com/202107/ScSTL1D.png" />
+              <span class={styles.phone} v-html="(15907121013)"></span>
+            </div>),
+            label: () => (<div class={styles.member_time}>
+              {true ? <div> 会员权益有效期剩余<span class={styles.remaining}>200</span>天</div> :<div>亲,您还不是会员哟</div>}
+            </div>)
+          }}></Cell>
+        </div>
+
+        <div class={styles.memberContainer}>
+          <ColProtocol v-model={this.agreeStatus} style={{ paddingLeft: 0, paddingRight: 0 }} />
+        </div>
+        <div class={styles.btnGroup}>
+          <div class={styles.priceSection}>
+            支付金额:
+            <div class={styles.price}>
+              <span class={styles.priceUnit}>¥</span>
+              <span class={styles.priceNum}>{(this as any).$filters.moneyFormat(99)}</span>
+            </div>
+          </div>
+          <Button color="linear-gradient(220deg, #DFA164 0%, #FAC87E 100%)" round class={styles.btn}>立即支付</Button>
+        </div>
+      </div>
+    )
+  }
+})

+ 4 - 0
src/styles/index.less

@@ -92,4 +92,8 @@
 
 body {
   background-color: #F6F8F9;
+}
+
+.mb12 {
+  margin-bottom: 12px;
 }

+ 2 - 0
src/teacher/main.ts

@@ -3,6 +3,7 @@ import App from './App.vue';
 import dayjs from 'dayjs';
 import 'dayjs/locale/zh-cn';
 import router from '../router/index-teacher';
+import vueFilter from '@/helpers/vueFilter';
 
 import 'normalize.css';
 
@@ -24,6 +25,7 @@ const app = createApp(App);
 
 dayjs.locale('zh-ch');
 app.config.globalProperties.$dayjs = dayjs;
+app.config.globalProperties.$filters = vueFilter;
 app.use(router);
 
 app.mount('#app');

+ 2 - 2
src/teacher/teacher-cert/index.tsx

@@ -76,7 +76,7 @@ export default defineComponent({
       if(!teacherState.teacherCert.subjectId) {
         Toast('请选择教授科目')
         return
-      } 
+      }
       teacherState.active = 3;
     },
     async onSubmit() {
@@ -102,7 +102,7 @@ export default defineComponent({
             <>
               <CertOne />
               <div class={styles.btnGroup}>
-                <ColProtocol v-model:value={this.agreeStatus} style={{ paddingLeft: 0, paddingRight: 0 }} />
+                <ColProtocol v-model={this.agreeStatus} style={{ paddingLeft: 0, paddingRight: 0 }} />
                 <Button block round onClick={this.next} type="primary" text="下一步" />
               </div>
             </>

+ 49 - 0
src/views/module/user-detail/index.module.less

@@ -0,0 +1,49 @@
+.userInfo {
+  border-radius: 12px;
+  overflow: hidden;
+
+  .avatar {
+    width: 24px;
+    height: 24px;
+    border-radius: 50%;
+    overflow: hidden;
+  }
+  .name {
+    padding-left: 8px;
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 22px;
+  }
+
+  .info {
+    font-size: 12px;
+    font-weight: 400;
+    color: #6A6A6A;
+    line-height: 17px;
+  }
+  .price {
+    display: flex;
+    align-items: center;
+    .number {
+      padding-right: 12px;
+      color: #FA6400;
+      font-size: 18px;
+    }
+    .priceText {
+      font-size: 12px;
+    }
+  }
+  :global {
+    .van-cell {
+      padding: 14px;
+    }
+    .van-cell__title, .van-cell__value {
+      display: flex;
+      align-items: center;
+    }
+    .van-cell__value {
+      justify-content: flex-end;
+    }
+  }
+}

+ 44 - 0
src/views/module/user-detail/index.tsx

@@ -0,0 +1,44 @@
+import { userInfo } from "os";
+import { Cell, CellGroup, Image, Tag } from "vant";
+import { defineComponent } from "vue";
+import styles from "./index.module.less";
+
+/**
+ * @description: 视频详情
+ * @param {type}
+ */
+interface UserType {
+  headUrl: string;
+  username: string;
+  startTime: string;
+  price: number;
+  classNum: number;
+}
+
+export default defineComponent({
+  name: "user-detail",
+  props: {
+    userInfo: Object as () => UserType
+  },
+  render() {
+    return (
+      <CellGroup class={styles.userInfo}>
+        <Cell v-slots={{
+          icon: () => <Image class={styles.avatar} src="https://daya.ks3-cn-beijing.ksyun.com/202201/SvB6tqR.png" />,
+          title: () => (<div class={styles.name}>张星</div>),
+          value: () => (<div class={styles.info}>开课时间:2月28日 19:30</div>),
+        }}></Cell>
+        <Cell v-slots={{
+          title: () => (<div class={styles.price}>
+            <div class={styles.number}>
+              <span class={styles.priceText}>¥</span>
+              <span class={styles.priceNum}>99</span>
+            </div>
+            <Tag color="#FFF1DE" textColor="#FF9300">12课时</Tag>
+          </div>),
+          value: () => (<div class={styles.info}>已购 6 人</div>),
+        }}></Cell>
+      </CellGroup>
+    )
+  }
+})

+ 36 - 0
src/views/order-detail/index.module.less

@@ -0,0 +1,36 @@
+.order-detail {
+  position: relative;
+  padding: 14px 14px 0;
+  .btnGroup {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background-color: #fff;
+    display: flex;
+    align-items: center;
+    padding: 12px 16px;
+    justify-content: space-between;
+    :global {
+      .van-button {
+        padding: 0 18px;
+      }
+    }
+
+    .priceSection {
+      display: flex;
+      align-items: center;
+      font-size: 16px;
+      color: #1A1A1A;
+      .price {
+        font-size: 18px;
+        font-weight: bold;
+        color: #FF3535;
+
+        .priceUnit {
+          font-size: 14px;
+        }
+      }
+    }
+  }
+}

+ 36 - 0
src/views/order-detail/index.tsx

@@ -0,0 +1,36 @@
+import ColProtocol from "@/components/col-protocol";
+import { Button, Sticky } from "vant";
+import { defineComponent } from "vue";
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: "order-detail",
+  data() {
+    return {
+      agreeStatus: false
+    }
+  },
+  methods: {
+    onSubmit() {
+      console.log("submit");
+    }
+  },
+  render() {
+    return (
+      <div class={styles['order-detail']}>
+
+        <ColProtocol v-model={this.agreeStatus} style={{ paddingLeft: 0, paddingRight: 0 }} />
+        <div class={styles.btnGroup}>
+          <div class={styles.priceSection}>
+            支付金额:
+            <div class={styles.price}>
+              <span class={styles.priceUnit}>¥</span>
+              <span class={styles.priceNum}>{ (this as any).$filters.moneyFormat(99) }</span>
+            </div>
+          </div>
+          <Button type="primary" round class={styles.btn} onClick={this.onSubmit}>立即支付</Button>
+        </div>
+      </div>
+    )
+  }
+})

+ 10 - 0
src/views/video-detail/index.module.less

@@ -0,0 +1,10 @@
+.video-detail {
+  padding: 12px;
+  .banner {
+    width: 100%;
+    height: 145px;
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+}

+ 25 - 0
src/views/video-detail/index.tsx

@@ -0,0 +1,25 @@
+import { defineComponent } from "vue";
+import { Cell, CellGroup, Icon, Image } from "vant";
+import styles from './index.module.less';
+
+import UserDetail from "../module/user-detail";
+
+export default defineComponent({
+  name: "VideoDetail",
+  render() {
+    return (
+      <div class={styles['video-detail']}>
+        <Image class={[styles.banner, 'mb12']} src="https://daya.ks3-cn-beijing.ksyun.com/202201/SvB6tqR.png" fit="cover" />
+
+        <UserDetail class='mb12' />
+
+        <CellGroup>
+          <Cell v-slots={{
+            icon: () => (<Icon name="close" size="22" />),
+            title: () => (<div class={styles.name}>张星</div>),
+          }}></Cell>
+      </CellGroup>
+      </div>
+    )
+  }
+})