Browse Source

添加曲谱页面

wolyshaw 3 years ago
parent
commit
3148e97cdf

+ 5 - 1
.eslintrc.js

@@ -11,7 +11,11 @@ module.exports = {
     '@vue/prettier/@typescript-eslint'
   ],
   rules: {
-    '@typescript-eslint/no-explicit-any': ['off']
+    '@typescript-eslint/no-explicit-any': ['off'],
+    "prettier/prettier": ["off", {
+      "singleQuote": true,
+      "semi": false
+    }]
   },
   parserOptions: {
     ecmaVersion: 2020

+ 3 - 2
.prettierrc.js

@@ -2,7 +2,8 @@ module.exports = {
   bracketSpacing: true,
   jsxBracketSameLine: true,
   singleQuote: true,
+  semi: false,
   arrowParens: 'avoid',
   trailingComma: 'none',
-  endOfLine: 'lf'
-};
+  endOfLine: 'lf',
+}

+ 4 - 0
src/components/col-area/index.module.less

@@ -0,0 +1,4 @@
+.col-area{
+  background-color: var(--white);
+  border-radius: 20px;
+}

+ 4 - 1
src/components/col-area/index.tsx

@@ -1,6 +1,9 @@
 import { defineComponent } from 'vue'
+import styles from './index.module.less'
 
 export default defineComponent({
   name: 'ColArea',
-
+  setup(props, { slots }) {
+    return () => <div class={styles['col-area']}>{slots?.default?.()}</div>
+  }
 })

+ 49 - 44
src/components/col-field/index.tsx

@@ -1,44 +1,49 @@
-import { Button, Col, Icon, Row } from "vant";
-import { defineComponent } from "vue";
-import styles from './index.module.less';
-
-export default defineComponent({
-  name: 'col-field',
-  props: {
-    required: {
-      type: Boolean,
-      default: false
-    },
-    title: {
-      type: String,
-      required: true
-    },
-    border: {
-      type: Boolean,
-      default: true
-    },
-    iconName: {
-      type: String
-    }
-  },
-  render() {
-    return (
-      <Row class={styles['col-field']}>
-        <Col span={24} class={styles.formTitle}>
-          <div class={styles['col-left']}>
-            <div class={styles['col-icon']}>
-              {this.$slots.icon ? this.$slots.icon() : this.iconName ? <Icon name={this.iconName} size="24" /> : null}
-            </div>
-            {this.required ? <i class={styles.required}>*</i> : null}{this.title}
-          </div>
-          <div class={styles['col-right']}>
-            {this.$slots.right && this.$slots.right()}
-          </div>
-        </Col>
-        <Col span={24} class={this.border ? 'van-hairline--bottom' : null}>
-          {this.$slots.default && this.$slots.default()}
-        </Col>
-      </Row>
-    )
-  }
-})
+import { Button, Col, Icon, Row } from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'col-field',
+  props: {
+    required: {
+      type: Boolean,
+      default: false
+    },
+    title: {
+      type: String,
+      required: true
+    },
+    border: {
+      type: Boolean,
+      default: true
+    },
+    iconName: {
+      type: String
+    }
+  },
+  render() {
+    return (
+      <Row class={styles['col-field']}>
+        <Col span={24} class={styles.formTitle}>
+          <div class={styles['col-left']}>
+            <div class={styles['col-icon']}>
+              {this.$slots.icon ? (
+                this.$slots.icon()
+              ) : this.iconName ? (
+                <Icon name={this.iconName} size="24" />
+              ) : null}
+            </div>
+            {this.required ? <i class={styles.required}>*</i> : null}
+            {this.title}
+          </div>
+          <div class={styles['col-right']}>
+            {this.$slots.right && this.$slots.right()}
+          </div>
+        </Col>
+        <Col span={24} class={this.border ? 'van-hairline--bottom' : null}>
+          {this.$slots.default && this.$slots.default()}
+        </Col>
+      </Row>
+    )
+  }
+})

+ 6 - 0
src/constant/music.ts

@@ -0,0 +1,6 @@
+/** 曲谱审核状态 */
+export const auditStatus = {
+  0: '待审核',
+  1: '通过',
+  2: '未通过'
+}

+ 12 - 5
src/router/routes-teacher.ts

@@ -1,9 +1,9 @@
-import Auth from '@/teacher/layout/auth';
-import { router, rootRouter } from './routes-common';
+import Auth from '@/teacher/layout/auth'
+import { router, rootRouter } from './routes-common'
 
 type metaType = {
-  isRegister: boolean;
-};
+  isRegister: boolean
+}
 
 export default [
   {
@@ -40,6 +40,13 @@ export default [
         }
       },
       {
+        path: '/music-list',
+        component: () => import('@/teacher/music/list/switch'),
+        meta: {
+          title: '曲谱列表'
+        }
+      },
+      {
         path: 'openLive',
         name: 'openLive',
         component: () => import('@/teacher/open-live/index'),
@@ -74,4 +81,4 @@ export default [
       platform: 'TEACHER'
     }
   }
-];
+]

+ 6 - 0
src/styles/index.less

@@ -77,6 +77,12 @@
   // --van-border-radius-max: 999px;
 
   --col-background-color: #F6F8F9;
+
+  --white: #fff;
+
+  --tips-color: #999;
+  --strong--color: #FF4E19;
+  --box-shadow-color: rgba(0, 0, 0, 0.05);
 }
 
 * {

+ 84 - 84
src/teacher/layout/auth.tsx

@@ -1,84 +1,84 @@
-import { defineComponent } from "vue";
-import styles from './auth.module.less';
-import { state, setLogin } from '@/state';
-import { browser, setAuth } from "@/helpers/utils";
-import { postMessage } from "@/helpers/native-message";
-import { RouterView } from "vue-router";
-import { Button, Icon } from "vant";
-import request from "@/helpers/request";
-
-export default defineComponent({
-  name: "Auth",
-  data() {
-    return {
-      loading: false as boolean,
-    }
-  },
-  computed: {
-    isNeedView() {
-      return state.user.status === 'login' || this.$route.path === '/login';
-    }
-  },
-  mounted() {
-    this.setAuth();
-  },
-  methods: {
-    async setAuth() {
-      const { query } = this.$route
-      const token = query.userInfo || query.Authorization
-      if (token) {
-        setAuth(token)
-      }
-      if (this.loading) {
-        return
-      }
-      if ((state.user.status === 'init' || state.user.status === 'error')) {
-        this.loading = true
-        try {
-          let res = await request.get('/api-teacher/Teacher/queryUserInfo', {
-            requestType: "form",
-            initRequest: true // 初始化接口
-          })
-          // console.log(res)
-          setLogin(res.data)
-        } catch (e: any) {
-          // console.log(e)
-        }
-        this.loading = false
-      }
-      if (state.user.status === 'logout') {
-        if (browser().isApp) {
-          postMessage({ api: 'login' })
-        } else {
-          try {
-            let route = this.$route
-            let query = {
-              returnUrl: this.$route.path,
-              ...this.$route.query,
-            } as any;
-            if (route.meta.isRegister) {
-              query.isRegister = route.meta.isRegister
-            }
-            this.$router.replace({
-              path: '/login',
-              query: query
-            })
-          } catch (error) { }
-        }
-      }
-    }
-  },
-  render() {
-    return (
-      <>
-        {state.user.status === 'error' ? <div class={styles.error}>
-          <div class={styles.info}>
-            <Icon name="clear" size="36" color="#ee0a24" />
-            <span>加载失败,请重新尝试</span>
-          </div>
-          <Button type="primary" round onClick={this.setAuth}>重新加载</Button>
-        </div> : this.isNeedView ? <RouterView></RouterView> : null}
-      </>
-    )
-  }
-})
+import { defineComponent } from "vue";
+import styles from './auth.module.less';
+import { state, setLogin } from '@/state';
+import { browser, setAuth } from "@/helpers/utils";
+import { postMessage } from "@/helpers/native-message";
+import { RouterView } from "vue-router";
+import { Button, Icon } from "vant";
+import request from "@/helpers/request";
+
+export default defineComponent({
+  name: "Auth",
+  data() {
+    return {
+      loading: false as boolean,
+    }
+  },
+  computed: {
+    isNeedView() {
+      return state.user.status === 'login' || this.$route.path === '/login';
+    }
+  },
+  mounted() {
+    this.setAuth();
+  },
+  methods: {
+    async setAuth() {
+      const { query } = this.$route
+      const token = query.userInfo || query.Authorization
+      if (token) {
+        setAuth(token)
+      }
+      if (this.loading) {
+        return
+      }
+      if ((state.user.status === 'init' || state.user.status === 'error')) {
+        this.loading = true
+        try {
+          let res = await request.get('/api-teacher/teacher/queryUserInfo', {
+            requestType: "form",
+            initRequest: true // 初始化接口
+          })
+          // console.log(res)
+          setLogin(res.data)
+        } catch (e: any) {
+          // console.log(e)
+        }
+        this.loading = false
+      }
+      if (state.user.status === 'logout') {
+        if (browser().isApp) {
+          postMessage({ api: 'login' })
+        } else {
+          try {
+            let route = this.$route
+            let query = {
+              returnUrl: this.$route.path,
+              ...this.$route.query,
+            } as any;
+            if (route.meta.isRegister) {
+              query.isRegister = route.meta.isRegister
+            }
+            this.$router.replace({
+              path: '/login',
+              query: query
+            })
+          } catch (error) { }
+        }
+      }
+    }
+  },
+  render() {
+    return (
+      <>
+        {state.user.status === 'error' ? <div class={styles.error}>
+          <div class={styles.info}>
+            <Icon name="clear" size="36" color="#ee0a24" />
+            <span>加载失败,请重新尝试</span>
+          </div>
+          <Button type="primary" round onClick={this.setAuth}>重新加载</Button>
+        </div> : this.isNeedView ? <RouterView></RouterView> : null}
+      </>
+    )
+  }
+})

+ 173 - 172
src/teacher/layout/login.tsx

@@ -1,172 +1,173 @@
-import { defineComponent } from "vue";
-import { CellGroup, Field, Button, CountDown, Row, Col, Toast } from "vant";
-import ImgCode from "@/components/col-img-code";
-import { checkPhone } from "@/helpers/validate";
-import request from "@/helpers/request";
-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: 'SMS' as loginType,
-      username: '',
-      password: '',
-      smsCode: '',
-      countDownStatus: true, // 是否发送验证码
-      countDownTime: 1000 * 120, // 倒计时时间
-      countDownRef: null as any, // 倒计时实例
-      imgCodeStatus: false,
-    }
-  },
-  computed: {
-    codeDisable() {
-      let status = true;
-      if (this.loginType === 'PWD') {
-        this.username && this.password && (status = false);
-      } else {
-        this.username && this.smsCode && (status = false);
-      }
-      return status;
-    },
-  },
-  mounted() {
-    removeAuth();
-    this.directNext();
-  },
-  methods: {
-    directNext() {
-      if (state.user.status === "login" || state.user.status === "error") {
-        const { returnUrl, isRegister, ...rest } = this.$route.query;
-        this.$router.replace({
-          path: returnUrl as any,
-          query: {
-            ...rest,
-          },
-        });
-      }
-    },
-    async onLogin() {
-      try {
-        let res: any;
-        if (this.loginType === 'PWD') {
-          res = await request.post('/api-auth/usernameLogin', {
-            requestType: "form",
-            data: {
-              username: this.username,
-              password: this.password,
-              clientId: 'teacher',
-              clientSecret: 'teacher'
-            }
-          });
-        } else {
-          res = await request.post('/api-auth/smsLogin', {
-            requestType: "form",
-            data: {
-              clientId: 'teacher',
-              clientSecret: 'teacher',
-              phone: this.username,
-              smsCode: this.smsCode,
-              channel: 'H5'
-            }
-          });
-        }
-
-        const { authentication } = res.data;
-        setAuth(authentication.token_type + " " + authentication.access_token);
-
-        let userCash = await request.get('/api-teacher/Teacher/queryUserInfo', {
-          initRequest: true // 初始化接口
-        })
-        setLogin(userCash.data)
-
-        this.directNext();
-      } catch {
-
-      }
-    },
-    async onSendCode() { // 发送验证码
-      if(!checkPhone(this.username)) {
-        return Toast('请输入正确的手机号码');
-      }
-      this.imgCodeStatus = true
-    },
-    onCodeSend() {
-      this.countDownStatus = false;
-      this.countDownRef.start();
-    },
-    onFinished() {
-      this.countDownStatus = true;
-      this.countDownRef.reset();
-    },
-    onChange() {
-      if (this.loginType === 'PWD') {
-        this.loginType = 'SMS'
-      } else if (this.loginType === 'SMS') {
-        this.loginType = 'PWD'
-      }
-    },
-  },
-  render() {
-    return (
-      <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 class={styles.margin34}>
-          <Button round block type="primary" disabled={this.codeDisable} onClick={this.onLogin}>
-            提交
-          </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>
-    )
-  }
-})
+import { defineComponent } from "vue";
+import { CellGroup, Field, Button, CountDown, Row, Col, Toast } from "vant";
+import ImgCode from "@/components/col-img-code";
+import { checkPhone } from "@/helpers/validate";
+import request from "@/helpers/request";
+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: 'SMS' as loginType,
+      username: '',
+      password: '',
+      smsCode: '',
+      countDownStatus: true, // 是否发送验证码
+      countDownTime: 1000 * 120, // 倒计时时间
+      countDownRef: null as any, // 倒计时实例
+      imgCodeStatus: false,
+    }
+  },
+  computed: {
+    codeDisable() {
+      let status = true;
+      if (this.loginType === 'PWD') {
+        this.username && this.password && (status = false);
+      } else {
+        this.username && this.smsCode && (status = false);
+      }
+      return status;
+    },
+  },
+  mounted() {
+    console.log('q22313')
+    removeAuth();
+    this.directNext();
+  },
+  methods: {
+    directNext() {
+      if (state.user.status === "login" || state.user.status === "error") {
+        const { returnUrl, isRegister, ...rest } = this.$route.query;
+        this.$router.replace({
+          path: returnUrl as any,
+          query: {
+            ...rest,
+          },
+        });
+      }
+    },
+    async onLogin() {
+      try {
+        let res: any;
+        if (this.loginType === 'PWD') {
+          res = await request.post('/api-auth/usernameLogin', {
+            requestType: "form",
+            data: {
+              username: this.username,
+              password: this.password,
+              clientId: 'teacher',
+              clientSecret: 'teacher'
+            }
+          });
+        } else {
+          res = await request.post('/api-auth/smsLogin', {
+            requestType: "form",
+            data: {
+              clientId: 'teacher',
+              clientSecret: 'teacher',
+              phone: this.username,
+              smsCode: this.smsCode,
+              channel: 'H5'
+            }
+          });
+        }
+
+        const { authentication } = res.data;
+        setAuth(authentication.token_type + " " + authentication.access_token);
+
+        let userCash = await request.get('/api-teacher/teacher/queryUserInfo', {
+          initRequest: true // 初始化接口
+        })
+        setLogin(userCash.data)
+
+        this.directNext();
+      } catch {
+
+      }
+    },
+    async onSendCode() { // 发送验证码
+      if(!checkPhone(this.username)) {
+        return Toast('请输入正确的手机号码');
+      }
+      this.imgCodeStatus = true
+    },
+    onCodeSend() {
+      this.countDownStatus = false;
+      this.countDownRef.start();
+    },
+    onFinished() {
+      this.countDownStatus = true;
+      this.countDownRef.reset();
+    },
+    onChange() {
+      if (this.loginType === 'PWD') {
+        this.loginType = 'SMS'
+      } else if (this.loginType === 'SMS') {
+        this.loginType = 'PWD'
+      }
+    },
+  },
+  render() {
+    return (
+      <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 class={styles.margin34}>
+          <Button round block type="primary" disabled={this.codeDisable} onClick={this.onLogin}>
+            提交
+          </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>
+    )
+  }
+})

+ 14 - 14
src/teacher/main.ts

@@ -1,15 +1,15 @@
-import { createApp } from 'vue';
-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 { createApp } from 'vue'
+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';
+import 'normalize.css'
 
-import '../styles/index.less';
+import '../styles/index.less'
 
-const app = createApp(App);
+const app = createApp(App)
 
 // 将selects全局混入当前vue实例中
 // import activeButtonIcon from '@/common/images/icon_check.png';
@@ -23,9 +23,9 @@ const app = createApp(App);
 //   }
 // });
 
-dayjs.locale('zh-ch');
-app.config.globalProperties.$dayjs = dayjs;
-app.config.globalProperties.$filters = vueFilter;
-app.use(router);
+dayjs.locale('zh-ch')
+app.config.globalProperties.$dayjs = dayjs
+app.config.globalProperties.$filters = vueFilter
+app.use(router)
 
-app.mount('#app');
+app.mount('#app')

+ 4 - 0
src/teacher/music/list/index.module.less

@@ -0,0 +1,4 @@
+.list-contaner {
+  display: flex;
+  flex-direction: column;
+}

+ 68 - 0
src/teacher/music/list/index.tsx

@@ -0,0 +1,68 @@
+import { defineComponent } from 'vue'
+import { Button, List } from 'vant'
+import request from '@/helpers/request'
+import MusicListItem from './item'
+import { MusicType } from './item.d'
+import styles from './index.module.less'
+
+export type AuditStatus = 0 | 1 | 2
+
+/** 曲谱列表 */
+export default defineComponent({
+  name: 'MusicList',
+  props: {
+    auditStatus: {
+      type: Number as () => AuditStatus,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      list: [] as MusicType[],
+      loading: false,
+      error: false,
+      finished: false,
+      page: 1
+    }
+  },
+  methods: {
+    async FetchList() {
+      this.loading = true
+      try {
+        const res = await request.post('/api-web/music/sheet/list', {
+          data: {
+            auditStatus: this.auditStatus
+          }
+        })
+        if (res.data.length) {
+          this.list = this.list.concat(res.data)
+        }
+      } catch (error) {
+        this.error = true
+      }
+      this.loading = false
+    },
+    /** 前往上传曲谱页 */
+    toUpload() {
+      this.$router.push({
+        path: '/music-upload'
+      })
+    }
+  },
+  render() {
+    return (
+      <div class={styles['list-contaner']}>
+        <Button onClick={this.toUpload}>上传曲谱</Button>
+        <List
+          loading={this.loading}
+          error={this.error}
+          finished={this.finished}
+          onLoad={this.FetchList}>
+          {this.list.map(item => (
+            <MusicListItem data={item} />
+          ))}
+        </List>
+      </div>
+    )
+  }
+})

+ 40 - 0
src/teacher/music/list/item.d.ts

@@ -0,0 +1,40 @@
+export type AudioType = 'MP3' | 'MP3_METRONOME' | 'MIDI'
+
+export type Background = {
+  musicSubject: string
+  audioFileUrl: string
+  sortNumber: number
+}
+
+export type ChargeType = 0 | 1 | 2
+
+export type MusicType = {
+  /** 曲谱名称 */
+  musicSheetName: string
+  /** 声部 */
+  musicSubject: string
+  /** 作者 */
+  composer: string
+  /** 标签 */
+  musicTag: string
+  /** 曲目类型 */
+  audioType: AudioType
+  /** 曲谱地址 */
+  musicSheetUrl: string
+  /** 曲谱审核状态 */
+  auditStatus: number
+  /** 曲谱id */
+  id: string
+  /** 曲谱类型 */
+  musicSheetType: number
+  /** 背景伴奏 */
+  background?: Background[]
+  /** 收费类型 */
+  chargeType: number
+  /** 收费价格 */
+  musicPrice: number
+  /** 音频文件地址 */
+  audioFileUrl: string
+  /** XML文件地址 */
+  xmlFileUrl: string
+}

+ 16 - 0
src/teacher/music/list/item.tsx

@@ -0,0 +1,16 @@
+import { defineComponent } from 'vue'
+import { MusicType } from './item.d'
+
+export default defineComponent({
+  name: 'MusicListItem',
+  props: {
+    data: {
+      type: Object as () => MusicType | null,
+      default: () => null
+    }
+  },
+  render() {
+    if (!this.data) return null
+    return <div></div>
+  }
+})

+ 25 - 0
src/teacher/music/list/switch.tsx

@@ -0,0 +1,25 @@
+import { defineComponent } from 'vue'
+import { Tabs, Tab } from 'vant'
+import MusicList from './index'
+
+/** 曲谱列表 包含分类切换 */
+export default defineComponent({
+  name: 'MusicListSwitch',
+  render() {
+    return (
+      <div>
+        <Tabs>
+          <Tab title="已上架">
+            <MusicList auditStatus={0} />
+          </Tab>
+          <Tab title="审核中">
+            <MusicList auditStatus={1} />
+          </Tab>
+          <Tab title="审核失败">
+            <MusicList auditStatus={2} />
+          </Tab>
+        </Tabs>
+      </div>
+    )
+  }
+})

+ 27 - 0
src/teacher/music/upload/index.module.less

@@ -1,4 +1,31 @@
 .container{
   background-color: var(--col-background-color);
   min-height: 100vh;
+  margin: 14px;
+  .area{
+    padding: 20px;
+    margin-bottom: 12px;
+  }
+}
+
+.clear-px{
+  padding-left: 0;
+  padding-right: 0;
+}
+
+.rule{
+  font-size: 14px;
+  line-height: 27px;
+  color: var(--tips-color);
+  margin-bottom: 20px;
+  >p>span{
+    color: var(--strong--color);
+    font-weight: bold;
+  }
+}
+
+.button-area{
+  padding: 10px 14px;
+  background-color: var(--white);
+  box-shadow: 0 0 10px var(--box-shadow-color);
 }

+ 62 - 8
src/teacher/music/upload/index.tsx

@@ -1,19 +1,73 @@
 import { defineComponent } from 'vue'
-import { Field } from 'vant'
+import { Button, Field, Sticky } from 'vant'
+import ColArea from '@/components/col-area'
+import { MusicType } from 'src/teacher/music/list/item.d'
 import ColField from '@/components/col-field'
 import styles from './index.module.less'
 
 export default defineComponent({
   name: 'MusicUpload',
+  data() {
+    return {
+      musicSheetName: ''
+    }
+  },
   render() {
     return (
-      <div class={styles.container}>
-        <ColField
-          title="曲目名称"
-        >
-          <Field placeholder="请输入曲目名称"/>
-        </ColField>
-      </div>
+      <>
+        <div class={styles.container}>
+          <ColArea class={styles.area}>
+            <ColField required title="曲目名称">
+              <Field class={styles['clear-px']} placeholder="请输入曲目名称" />
+            </ColField>
+            <ColField required title="作曲人">
+              <Field
+                class={styles['clear-px']}
+                placeholder="请输入作曲人姓名"
+              />
+            </ColField>
+          </ColArea>
+          <ColArea class={styles.area}>
+            <ColField required title="曲目标签">
+              <Field class={styles['clear-px']} placeholder="请输入曲目名称" />
+            </ColField>
+          </ColArea>
+          <ColArea class={styles.area}>
+            <ColField required title="默认速度">
+              <Field class={styles['clear-px']} placeholder="请输入默认速度" />
+            </ColField>
+          </ColArea>
+          <ColArea class={styles.area}>
+            <ColField required title="默认速度">
+              <Field class={styles['clear-px']} placeholder="请输入默认速度" />
+            </ColField>
+          </ColArea>
+          <ColArea class={styles.area}>
+            <ColField required title="默认速度">
+              <Field class={styles['clear-px']} placeholder="请输入默认速度" />
+            </ColField>
+          </ColArea>
+          <ColArea class={styles.area}>
+            <ColField required title="收费价格">
+              <Field class={styles['clear-px']} placeholder="请输入收费价格" />
+            </ColField>
+          </ColArea>
+          <div class={styles.rule}>
+            <p>扣除手续费后该曲目预计收入为:</p>
+            <p>
+              单课时:<span>5.8</span>元/人
+            </p>
+            <p>您的乐谱收入将在学员购买后结算到您的账户中</p>
+          </div>
+        </div>
+        <Sticky offsetBottom={0} position="bottom">
+          <div class={styles['button-area']}>
+            <Button type="primary" block round>
+              确认
+            </Button>
+          </div>
+        </Sticky>
+      </>
     )
   }
 })

+ 15 - 11
vite.config.ts

@@ -1,18 +1,18 @@
-import { defineConfig } from 'vite';
-import vue from '@vitejs/plugin-vue';
-import styleImport from 'vite-plugin-style-import';
-import vueJsx from '@vitejs/plugin-vue-jsx';
-import legacy from '@vitejs/plugin-legacy';
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import styleImport from 'vite-plugin-style-import'
+import vueJsx from '@vitejs/plugin-vue-jsx'
+import legacy from '@vitejs/plugin-legacy'
 // eslint-disable-next-line @typescript-eslint/no-var-requires
-const path = require('path');
+const path = require('path')
 
 function resolve(dir: string) {
-  return path.join(__dirname, dir);
+  return path.join(__dirname, dir)
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
 // const proxyUrl = 'https://mstutest.dayaedu.com/';
-const proxyUrl = 'http://dev.colexiu.com/';
+const proxyUrl = 'http://dev.colexiu.com/'
 export default defineConfig({
   base: './',
   plugins: [
@@ -61,15 +61,19 @@ export default defineConfig({
       '/api-web': {
         target: proxyUrl,
         changeOrigin: true
+      },
+      '/music': {
+        target: proxyUrl,
+        changeOrigin: true
       }
     }
   },
   build: {
     rollupOptions: {
       input: {
-        index: path.resolve(__dirname, 'index.html'),
-        about: path.resolve(__dirname, 'teacher.html')
+        index: resolve('index.html'),
+        teacher: resolve('teacher.html')
       }
     }
   }
-});
+})