Просмотр исходного кода

Merge branch 'feature-tianyong' into ponline

TIANYONG 4 месяцев назад
Родитель
Сommit
fa2cc837ae
65 измененных файлов с 3069 добавлено и 1404 удалено
  1. 13 5
      src/components/col-header/index.tsx
  2. 3 3
      src/components/col-search/index.module.less
  3. 12 5
      src/components/col-upload/index.tsx
  4. 12 8
      src/helpers/request.ts
  5. 32 0
      src/helpers/utils.ts
  6. 1 1
      src/router/routes-common.ts
  7. 1 1
      src/router/routes-tenant.ts
  8. 4 1
      src/shims-vue.d.ts
  9. 2 1
      src/state.ts
  10. 1 1
      src/student/down-load/index.module.less
  11. 5 3
      src/student/member-center/member-record.tsx
  12. 3 2
      src/student/share-active/track-review-activity/index.tsx
  13. 3 2
      src/student/share-active/track-review-activity/track-song.tsx
  14. 3 2
      src/teacher/share-page/share-music-sheet/index.tsx
  15. 3 2
      src/tenant/exercise-record/modals/detail-item.tsx
  16. 3 1
      src/tenant/music/music-detail/new-index.tsx
  17. 4 2
      src/tenant/music/music.ts
  18. 6 0
      src/views/article-center/help-center-detail.module.less
  19. 2 1
      src/views/article-center/help-center-detail.tsx
  20. 18 8
      src/views/article-center/help-center.tsx
  21. 1 1
      src/views/creation/api.ts
  22. 143 0
      src/views/creation/audioVisualDraw.ts
  23. 14 3
      src/views/creation/edit/index.module.less
  24. 88 38
      src/views/creation/edit/index.tsx
  25. BIN
      src/views/creation/images/Landscape.png
  26. BIN
      src/views/creation/images/audioBg.png
  27. BIN
      src/views/creation/images/back.png
  28. BIN
      src/views/creation/images/back1.png
  29. BIN
      src/views/creation/images/bg.png
  30. BIN
      src/views/creation/images/btn.png
  31. BIN
      src/views/creation/images/edit.png
  32. BIN
      src/views/creation/images/icon-delete.png
  33. BIN
      src/views/creation/images/icon-download.png
  34. BIN
      src/views/creation/images/icon-share.png
  35. BIN
      src/views/creation/images/icon-zan.png
  36. BIN
      src/views/creation/images/logo.png
  37. BIN
      src/views/creation/images/logo1.png
  38. BIN
      src/views/creation/images/midPlay.png
  39. BIN
      src/views/creation/images/music_bg.png
  40. BIN
      src/views/creation/images/pause1.png
  41. BIN
      src/views/creation/images/pause2.png
  42. BIN
      src/views/creation/images/play.png
  43. BIN
      src/views/creation/images/play1.png
  44. BIN
      src/views/creation/images/play2.png
  45. BIN
      src/views/creation/images/svip_icon.png
  46. BIN
      src/views/creation/images/ty.png
  47. BIN
      src/views/creation/images/upward.png
  48. BIN
      src/views/creation/images/videoBg.png
  49. BIN
      src/views/creation/images/vip_icon.png
  50. BIN
      src/views/creation/images/wx_bg.png
  51. 647 256
      src/views/creation/index-share.tsx
  52. 955 461
      src/views/creation/index.module.less
  53. 569 264
      src/views/creation/index.tsx
  54. 19 0
      src/views/creation/loading.tsx
  55. BIN
      src/views/creation/share-model/images/audioLabel.png
  56. BIN
      src/views/creation/share-model/images/share-bg.png
  57. BIN
      src/views/creation/share-model/images/videoLabel.png
  58. 21 5
      src/views/creation/share-model/index.module.less
  59. 9 1
      src/views/creation/share-model/index.tsx
  60. 12 0
      src/views/creation/text-ellipsis/index.module.less
  61. 99 0
      src/views/creation/text-ellipsis/index.tsx
  62. 34 5
      src/views/music/music-detail/index.tsx
  63. 4 2
      src/views/music/music.ts
  64. 6 2
      src/views/music/personal/collection.tsx
  65. 317 317
      yarn.lock

+ 13 - 5
src/components/col-header/index.tsx

@@ -52,9 +52,14 @@ export default defineComponent({
     },
     hideHeader: {
       type: Boolean,
+      default: false
+    },
+    leftClickDefault: {
+      type: Boolean,
       default: true
     }
   },
+  emits: ['leftClick'],
   watch: {
     backIconColor() {
       // 设置返回按钮颜色
@@ -125,14 +130,17 @@ export default defineComponent({
       !browser().isApp && callBack && callBack()
     },
     onClickLeft() {
+      this.$emit('leftClick', null)
       postMessage({
         api: 'setStatusBarTextColor',
         content: { statusBarTextColor: false }
       })
-      if (browser().isApp) {
-        postMessage({ api: 'goBack' })
-      } else {
-        this.$router.back()
+      if(this.leftClickDefault) {
+        if (browser().isApp) {
+          postMessage({ api: 'goBack' })
+        } else {
+          this.$router.back()
+        }
       }
     },
     clickRight() {
@@ -141,7 +149,7 @@ export default defineComponent({
   },
   render() {
     // 只有app里面才显示头部
-    return browser().isApp || !this.hideHeader ? (
+    return !this.hideHeader ? (
       <div>
         {this.$slots.content ? (
           <div

+ 3 - 3
src/components/col-search/index.module.less

@@ -40,7 +40,7 @@
     }
 
     .van-field__control {
-      font-size: 14px;
+      font-size: 15px;
     }
   }
 
@@ -111,11 +111,11 @@
     width: 56px;
     height: 28px;
     padding: 0;
-    font-size: 14px;
+    font-size: 15px;
     font-weight: 500;
     --van-button-mini-height: 28px;
     --van-font-size-xs: 14px;
-    line-height: 1;
+    line-height: 28px;
 
     &.searchTenantBtn {
       background: linear-gradient( 270deg, #FF436A 0%, #FF6D8B 100%);

+ 12 - 5
src/components/col-upload/index.tsx

@@ -54,6 +54,10 @@ export default defineComponent({
     disabled: {
       type: Boolean,
       default: false
+    },
+    hasDeviceAuth: {
+      type: Boolean,
+      default: true
     }
   },
   methods: {
@@ -192,11 +196,14 @@ export default defineComponent({
                 {this.tips && <p class={styles.uploaderText}>{this.tips}</p>}
               </div>
             )}
-            <ColCropper
-              disabled={this.disabled}
-              option={this.options}
-              getFile={this.getFile}
-            />
+            {
+              this.hasDeviceAuth && 
+              <ColCropper
+                disabled={this.disabled }
+                option={this.options}
+                getFile={this.getFile}
+              />              
+            }
           </div>
         ) : this.native ? (
           <div

+ 12 - 8
src/helpers/request.ts

@@ -36,14 +36,18 @@ let hideErrorMessage = false // 是否隐藏报错信息
 request.interceptors.request.use(
   (url, options: any) => {
     hideErrorMessage = options.hideErrorMessage
-    if (!options.hideLoading) {
-      clearTimeout(toast)
-      Toast.loading({
-        message: '加载中...',
-        forbidClick: true,
-        loadingType: 'spinner',
-        duration: 0
-      })
+    // 作品页面不需要默认的加载loading,使用作品页面自己的加载loading
+    const isCreationPage = window.location.href.includes('creation') || window.location.href.includes('shareCreation')
+    if (!isCreationPage) {
+      if (!options.hideLoading) {
+        clearTimeout(toast)
+        Toast.loading({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        })
+      }
     }
 
     initRequest = options.initRequest || false

+ 32 - 0
src/helpers/utils.ts

@@ -7,6 +7,33 @@ import qs from 'query-string'
 export const browser = () => {
   const u = navigator.userAgent
   //   app = navigator.appVersion;
+  const isAndroid = /(?:Android)/.test(u);
+  const isFireFox = /(?:Firefox)/.test(u);
+  function isIpadFun() {
+    const ua = window.navigator.userAgent;
+    let IsIPad = false;
+    if (/ipad/i.test(ua)) {
+      IsIPad = true;
+    }
+    // iPad from IOS13
+    const macApp = ua.match(/Macintosh/i) != null;
+    if (macApp) {
+      // need to distinguish between Macbook and iPad
+      const canvas = document.createElement('canvas');
+      if (canvas != null) {
+        const context: any =
+          canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+        if (context) {
+          const info = context.getExtension('WEBGL_debug_renderer_info');
+          if (info) {
+            const renderer = context.getParameter(info.UNMASKED_RENDERER_WEBGL);
+            if (renderer.indexOf('Apple') != -1) IsIPad = true;
+          }
+        }
+      }
+    }
+    return IsIPad;
+  }
 
   let instance: any
   if (u.indexOf('ORCHESTRASTUDENT') > -1) {
@@ -34,6 +61,11 @@ export const browser = () => {
     //   u.indexOf('COLEXIUAPPA') > -1 ||
     //   u.indexOf('ORCHESTRASTUDENT') > -1 ||
     //   u.indexOf('Adr') > -1,
+    isTablet:
+      /(?:iPad|PlayBook)/.test(u) ||
+      (isAndroid && !/(?:Mobile)/.test(u)) ||
+      (isFireFox && /(?:Tablet)/.test(u)) ||
+      isIpadFun(),    
     isTeacher: u.indexOf('COLEXIUTEACHER') > -1,
     isStudent: u.indexOf('COLEXIUSTUDENT') > -1,
     isOrchestraStudent: u.indexOf('ORCHESTRASTUDENT') > -1, // 判断是否是管乐团学生端

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

@@ -263,7 +263,7 @@ export const router = [
     path: '/creation-edit',
     component: () => import('@/views/creation/edit/index'),
     meta: {
-      title: '作品详情'
+      title: '编辑'
     }
   }
 ]

+ 1 - 1
src/router/routes-tenant.ts

@@ -288,7 +288,7 @@ export default [
         path: '/creation-edit',
         component: () => import('@/views/creation/edit/index'),
         meta: {
-          title: '作品详情'
+          title: '编辑'
         }
       }
     ]

+ 4 - 1
src/shims-vue.d.ts

@@ -15,6 +15,9 @@ declare module '@vue/runtime-core' {
 
 declare module 'vue' {
   interface CSSProperties {
-    '--navBarHeight'?: string
+    '--navBarHeight'?: string;
+    '--barheight'?: string;
+    '--creationHeight'?: string;
+    '--staffBoxHeight'?: string;
   }
 }

+ 2 - 1
src/state.ts

@@ -25,7 +25,8 @@ export const state = reactive({
   version: '', // 版本号 例如: 1.0.0
   ossUploadUrl: 'https://ks3-cn-beijing.ksyuncs.com/',
   musicCertStatus: false as boolean, // 是否音乐认证
-  openLiveStatus: false as boolean // 是否开通直播
+  openLiveStatus: false as boolean, // 是否开通直播
+  helpItemTitle: '' as any, // 帮助详情title
 })
 
 // 预览上传到oss的地址

+ 1 - 1
src/student/down-load/index.module.less

@@ -11,7 +11,7 @@
   width: 104px;
   height: 127px;
   margin: 0 auto;
-
+  box-sizing: content-box;
   img {
     width: inherit;
     height: inherit;

+ 5 - 3
src/student/member-center/member-record.tsx

@@ -199,13 +199,15 @@ export default defineComponent({
                   border={false}
                   onClick={() => {
                     const behaviorId = +new Date()
-                    //dev.colexiu.com/accompany/colexiu-report.html?id=817&behaviorId=165699355934918269&Authorization=bearer%20aea0b4c1-423c-4466-902a-17dc7ac8938a#/
+                    // 酷乐秀云教练的部署目录
+                    const musicScorePath = "/klx-music-score/";
+                    //https://dev.colexiu.com/klx-music-score/#/evaluat-report?id=6856&musicRenderType=staff&systemType=student&Authorization=bearer%2043d42470-e968-4efe-a17a-b859a350cbff
                     postMessage({
                       api: 'openAccompanyWebView',
                       content: {
                         url:
-                          location.origin +
-                          '/accompany/colexiu-report.html?id=' +
+                          location.origin + musicScorePath + '#/' +
+                          'evaluat-report?id=' +
                           item.id +
                           '&behaviorId=' +
                           behaviorId,

+ 3 - 2
src/student/share-active/track-review-activity/index.tsx

@@ -296,12 +296,13 @@ export default defineComponent({
           return
         }
         const browserInfo = browser()
+        const musicScorePath = "/klx-music-score/";
         const url = qs.stringifyUrl({
-          url: location.origin + '/accompany',
+          url: location.origin + musicScorePath,
           query: {
             id: selectMusic.musicSheetId,
             behaviorId: this.behaviorId,
-            client: browserInfo.isStudent ? 'student' : 'teacher',
+            systemType: browserInfo.isStudent ? 'student' : 'teacher',
             setting: JSON.stringify({
               mode: 'EVALUATING',
               resets: ['SPEED'],

+ 3 - 2
src/student/share-active/track-review-activity/track-song.tsx

@@ -103,12 +103,13 @@ export default defineComponent({
     onOpenMusic(item: any) {
       try {
         const browserInfo = browser()
+        const musicScorePath = "/klx-music-score/";
         const url = qs.stringifyUrl({
-          url: location.origin + '/accompany',
+          url: location.origin + musicScorePath,
           query: {
             id: item.musicSheetId,
             behaviorId: this.behaviorId,
-            client: browserInfo.isTeacher ? 'teacher' : 'student',
+            systemType: browserInfo.isTeacher ? 'teacher' : 'student',
             setting: JSON.stringify({
               mode: 'EVALUATING',
               resets: ['SPEED'],

+ 3 - 2
src/teacher/share-page/share-music-sheet/index.tsx

@@ -55,8 +55,9 @@ export default defineComponent({
     onDetail() {
       const behaviorId = getRandomKey()
       const browserInfo = browser()
+      const musicScorePath = "/klx-music-score/";
       const url = qs.stringifyUrl({
-        url: location.origin + '/accompany',
+        url: location.origin + musicScorePath,
         query: {
           id: this.id,
           recomUserId:
@@ -66,7 +67,7 @@ export default defineComponent({
               : this.recomUserId,
           activityId: this.activityId,
           discounts: this.discounts,
-          client: browserInfo.isStudent ? 'student' : 'teacher',
+          systemType: browserInfo.isStudent ? 'student' : 'teacher',
           behaviorId
         }
       })

+ 3 - 2
src/tenant/exercise-record/modals/detail-item.tsx

@@ -59,12 +59,13 @@ export default defineComponent({
     }
     const gotoDetail = () => {
       const behaviorId = +new Date()
+      const musicScorePath = "/klx-music-score/";
       postMessage({
         api: 'openAccompanyWebView',
         content: {
           url:
-            location.origin +
-            '/accompany/colexiu-report.html?id=' +
+            location.origin + musicScorePath + '#/' +
+            'evaluat-report?id=' +
             props.item.id +
             '&behaviorId=' +
             behaviorId,

+ 3 - 1
src/tenant/music/music-detail/new-index.tsx

@@ -1013,9 +1013,11 @@ export default defineComponent({
                         // const index = staffData.tempPartList.findIndex(
                         //   (i: any) => i.track === item?.track
                         // )
+                        // 新版云教练的谱面类型使用musicRenderType字段
+                        const musicRenderType = staff.radio === 'staff' ? 'staff' : staff.radio === 'first' ? 'firstTone' :  staff.radio === 'fixed' ? 'fixedTone' : '';                        
                         musicBuy(musicDetail.value, () => {}, {
                           'part-index': item?.xmlValue || 0,
-                          sett: staff.radio,
+                          musicRenderType,
                           albumId: route.query.tenantAlbumId || '', // 专辑编号
                           // 1:忽略系统节拍器
                           ignoreSysMetronome:

+ 4 - 2
src/tenant/music/music.ts

@@ -13,12 +13,14 @@ export const getRandomKey = () => {
 
 export const musicBuy = (item: any, callBack?: any, moreQuery = {}) => {
   const behaviorId = localStorage.getItem('behaviorId') || ''
+  // 酷乐秀云教练的部署目录
+  const musicScorePath = "/klx-music-score/";
   const url = qs.stringifyUrl({
-    url: location.origin + '/accompany',
+    url: location.origin + musicScorePath,
     query: {
       id: item.id,
       behaviorId,
-      client: browserInfo.isStudent ? 'student' : 'teacher',
+      systemType: browserInfo.isStudent ? 'student' : 'teacher',
       ...moreQuery
     }
   })

+ 6 - 0
src/views/article-center/help-center-detail.module.less

@@ -43,6 +43,12 @@
     padding-top: 12px;
     margin-bottom: 10px;
   }
+  :global {
+    .van-nav-bar__title {
+      margin-top: 2px;
+      margin-left: 40px;
+    }
+  }
 }
 
 .titleInfo {

+ 2 - 1
src/views/article-center/help-center-detail.tsx

@@ -5,6 +5,7 @@ import dayjs from 'dayjs'
 import { ImagePreview, NavBar } from 'vant'
 import { defineComponent } from 'vue'
 import styles from './help-center-detail.module.less'
+import { state } from '@/state'
 
 export default defineComponent({
   name: 'help-center-detail',
@@ -69,7 +70,7 @@ export default defineComponent({
       <div class={styles['help-center-detail']}>
         {this.catalogType === 'ANALYSIS' ? (
           <NavBar
-            title={this.documentTitle}
+            title={state.helpItemTitle || this.documentTitle}
             left-arrow
             fixed
             onClick-left={() => {

+ 18 - 8
src/views/article-center/help-center.tsx

@@ -32,13 +32,15 @@ export default defineComponent({
         status: 1,
         // STUDENT:学生 TEACHER:老师 ANALYSIS:智能陪练
         catalogType:
+          query.platformType === 'ANALYSIS' ? "ANALYSIS" : 
           query.platformType ||
           (state.projectType === 'tenant' && state.platformType === 'STUDENT')
             ? 'TENANT_STUDENT'
             : state.platformType,
         page: 1,
         rows: 20
-      }
+      },
+      hideTitle: query?.hideTitle == '1' ? true : false, // 嵌入云教练需要隐藏标题栏
     }
   },
   mounted() {
@@ -83,6 +85,10 @@ export default defineComponent({
       this.getList()
     },
     onDetail(item: any) {
+      // 云教练嵌入的
+      if (this.$route?.query?.hideTitle == '1') {
+        state.helpItemTitle = item.title || '';
+      }
       this.$router.push({
         path: 'helpCenterDetail',
         query: {
@@ -95,13 +101,17 @@ export default defineComponent({
   render() {
     return (
       <div>
-        <Sticky offsetTop={0} position="top" class={'mb12'}>
-          <ColHeader isFixed={false} title={this.pageTitle} border={false} />
-          <ColSearch
-            type={state.projectType === 'tenant' ? 'tenant' : 'person'}
-            onSearch={this.onSearch}
-          />
-        </Sticky>
+        {
+          <Sticky offsetTop={0} position="top" class={'mb12'}>
+            {
+              !this.hideTitle && <ColHeader isFixed={false} title={this.pageTitle} border={false} />
+            }
+            <ColSearch
+              type={state.projectType === 'tenant' ? 'tenant' : 'person'}
+              onSearch={this.onSearch}
+            />
+          </Sticky>          
+        }
         {this.dataShow ? (
           <List
             v-model:loading={this.loading}

+ 1 - 1
src/views/creation/api.ts

@@ -6,7 +6,7 @@ const apiFix =
 
 /** 详情 */
 export const api_userMusicDetail = (params: any): Promise<any> => {
-  return request.get(apiFix + `/userMusic/detail/${params}`)
+  return request.get(apiFix + `/userMusic/detail/${params}`, { hideLoading: true })
 }
 
 /** 开放详情 */

+ 143 - 0
src/views/creation/audioVisualDraw.ts

@@ -0,0 +1,143 @@
+    /**
+     * 音频可视化
+     * @param audioDom
+     * @param canvasDom
+     * @param fftSize  2的幂数,最小为32
+     * 注意   由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+     */
+    export default function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
+      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
+      // canvas
+      const canvasCtx = canvasDom.getContext("2d")!
+      let { width, height } = canvasDom.getBoundingClientRect()
+      // 向上取整,当with为小数或者小于当前dom时候,切换app之后 会出现黑边
+      width = Math.ceil(width)
+      height = Math.ceil(height)
+      canvasDom.width = width
+      canvasDom.height = height
+      // audio
+      //const audioCtx = new AudioContext()
+      //const source = audioCtx.createMediaElementSource(audioDom)
+      //const analyser = audioCtx.createAnalyser()
+      //analyser.fftSize = fftSize
+      //source?.connect(analyser)
+      //analyser.connect(audioCtx.destination)
+      //const dataArray = new Uint8Array(fftSize / 2)
+      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
+        if (!ctx) return
+        const w = canvWidth
+        const h = canvHeight
+        fillCanvasBackground(ctx, w, h, canvFillColor)
+          // 可视化
+        const dataLen = data.length
+        let step = (w / 2 - lineGap * dataLen) / dataLen
+        step < 1 && (step = 1)
+        const midX = w / 2
+        const midY = h / 2
+        let xLeft = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          // 中间加间隙
+          if (i === 0) {
+            xLeft -= lineGap / 2
+          }
+          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
+          xLeft -= step + lineGap
+        }
+        let xRight = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          if (i === 0) {
+            xRight += lineGap / 2
+          }
+          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xRight, midY, step, barHeight)
+          xRight += step + lineGap
+        }
+      }
+      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
+        ctx.clearRect(0, 0, w, h)
+        ctx.fillStyle = colors
+        ctx.fillRect(0, 0, w, h)
+      }
+      const requestAnimationFrameFun = () => {
+        // requestAnimationFrame(() => {
+        //   //analyser?.getByteFrequencyData(dataArray)
+        //   draw(generateMixedData(48), canvasCtx, {
+        //     lineGap: 2,
+        //     canvWidth: width,
+        //     canvHeight: height,
+        //     canvFillColor: "transparent",
+        //     lineColor: "rgba(255, 255, 255, 0.7)"
+        //   })
+        //   if (!isPause) {
+        //     requestAnimationFrameFun()
+        //   }
+        // })
+        const _time = setInterval(() => {
+            if (isPause) {
+              clearInterval(_time)
+              return
+            }
+            //analyser?.getByteFrequencyData(dataArray)
+            draw(generateMixedData(48), canvasCtx, {
+              lineGap: 2,
+              canvWidth: width,
+              canvHeight: height,
+              canvFillColor: "transparent",
+              lineColor: "rgba(255, 255, 255, 0.7)"
+            })
+        }, 300);
+      }
+      let isPause = true
+      const playVisualDraw = () => {
+        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        isPause = false
+        requestAnimationFrameFun()
+      }
+      const pauseVisualDraw = () => {
+        isPause = true
+        requestAnimationFrame(()=>{
+          canvasCtx.clearRect(0, 0, width, height);
+        })
+        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        // source?.disconnect()
+        // analyser?.disconnect()
+      }
+      return {
+        playVisualDraw,
+        pauseVisualDraw
+      }
+    }
+
+export function generateMixedData(size: number) {
+  const dataArray = new Uint8Array(size);
+  const baseNoiseAmplitude = 30;
+  const minFrequency = 0.01;
+  const maxFrequency = 0.2;
+  const minAmplitude = 50;
+  const maxAmplitude = 150;
+
+  let lastAmplitude = maxAmplitude;  // 初始振幅设置为最大值
+  let lastFrequency = minFrequency + Math.random() * (maxFrequency - minFrequency);
+
+  for (let i = 0; i < size; i++) {
+      const decayFactor = 1 - (i / size);  // 使振幅随时间递减
+      const amplitude = lastAmplitude * decayFactor + (Math.random() - 0.5) * 10;
+      const frequency = lastFrequency + (Math.random() - 0.5) * 0.01;
+      const wave = amplitude * (0.5 + 0.5 * Math.sin(frequency * i));
+      const noise = Math.floor(Math.random() * baseNoiseAmplitude) - baseNoiseAmplitude / 2;
+      dataArray[i] = Math.min(255, Math.max(0, Math.floor(wave + noise)));
+      lastAmplitude += (amplitude - lastAmplitude) * 0.05;
+      lastFrequency += (frequency - lastFrequency) * 0.05;
+  }
+
+  return dataArray;
+}

+ 14 - 3
src/views/creation/edit/index.module.less

@@ -1,8 +1,12 @@
+// 平板
+.creationTablet .sectionVideo .videoBg {
+  height: 314px;
+}
 .sectionVideo {
   position: relative;
   line-height: 0;
   overflow: visible !important;
-  margin-bottom: 24px !important;
+  margin-bottom: 12px !important;
 
   .videoBg {
     width: 100%;
@@ -14,8 +18,8 @@
   .btnGroup {
     position: absolute;
     left: 50%;
-    bottom: -12px;
-    background: linear-gradient(180deg, rgba(128, 158, 200, 0.59) 0%, rgba(58, 101, 162, 0.59) 100%);
+    bottom: 12px;
+    background: linear-gradient(180deg, rgba(128, 177, 200, 0.59) 0%, rgba(58, 152, 162, 0.59) 100%);
     border-radius: 15px;
     height: 30px;
     // transform: translate(-50%);
@@ -208,4 +212,11 @@
   margin: 32px 24px 12px;
   font-weight: 500;
   font-size: 16px;
+  :global {
+    .van-button__content {
+      .van-button__text {
+        font-size: 16px;
+      }
+    }
+  }
 }

+ 88 - 38
src/views/creation/edit/index.tsx

@@ -1,17 +1,19 @@
 import MHeader from '@/components/col-header'
 import MSticky from '@/components/col-sticky'
-import { defineComponent, onMounted, reactive } from 'vue'
+import { defineComponent, onMounted, reactive, onBeforeUnmount } from 'vue'
 import styles from './index.module.less'
 import { Button, Field } from 'vant'
 import MUploader from '@/components/col-upload'
 import { api_userMusicDetail, api_userMusicSave } from '../api'
 import { useRoute, useRouter } from 'vue-router'
-import videoBg from '../images/video-bg.png'
+import videoBg from '../images/videoBg.png'
 import { postMessage } from '@/helpers/native-message'
+import { browser } from '@/helpers/utils'
 
 export default defineComponent({
   name: 'creation-edit',
   setup() {
+    const { isTablet, ios, iPhone } = browser()
     const route = useRoute()
     const router = useRouter()
     const state = reactive({
@@ -20,7 +22,9 @@ export default defineComponent({
       playType: '',
       desc: '',
       videoImg: '', // 视频封面
-      img: ''
+      img: '',
+      needCheckDevice: (ios || iPhone) ? true : false,
+      hasDeviceAuth: false, // 有设备相机权限
     })
 
     const onSubmit = async () => {
@@ -47,7 +51,39 @@ export default defineComponent({
         //
       }
     }
-
+    // 初始化获取是否已经授权
+    const initDeviceAuth = () => {
+      postMessage(
+        {
+          api: 'checkDeviceCamera',
+          content: {
+            hideAlert: true
+          }
+        },
+        res => {
+          if (res?.content.status) {
+            state.hasDeviceAuth = true
+          }
+        }
+      )
+    }
+    // 校验是否已经授权
+    const checkDeviceAuth = () => {
+      console.log('校验app',state.needCheckDevice)
+      if (state.needCheckDevice) {
+        postMessage({ api: 'checkDeviceCamera' }, res => {
+          const { content } = res as any
+          if (content?.status) {
+            state.hasDeviceAuth = true
+          } else {
+            // 没有权限不能获取图片
+            state.hasDeviceAuth = false
+          }
+        })
+      } else {
+        state.hasDeviceAuth = true
+      }
+    }
     // 截图
     const onCropper = () => {
       postMessage(
@@ -64,8 +100,16 @@ export default defineComponent({
         }
       )
     }
-
+    // 设置导航栏颜色
+    function setStatusBarTextColor(isWhite: boolean) {
+      postMessage({
+        api: 'setStatusBarTextColor',
+        content: { statusBarTextColor: isWhite }
+      });
+    }
     onMounted(async () => {
+      initDeviceAuth();
+      setStatusBarTextColor(false);
       try {
         const { data } = await api_userMusicDetail(state.id)
         state.musicDetail = data
@@ -82,28 +126,52 @@ export default defineComponent({
         //
       }
     })
+    onBeforeUnmount(() => {
+      setStatusBarTextColor(true);
+    });
     return () => (
-      <div>
+      <div class={isTablet ? styles.creationTablet : ''}>
         <MSticky position="top">
-          <MHeader border={false} />
+          <MHeader background={'#F1F1F1'} border={false} />
         </MSticky>
+        <div class={[styles.section, styles.sectionFile]}>
+          <div class={styles.uploadImg} onClick={checkDeviceAuth}>
+            <MUploader
+              class={styles.muploader}
+              // native
+              cropper
+              tips={''}
+              deletable={false}
+              hasDeviceAuth={state.hasDeviceAuth}
+              v-model:modelValue={state.img}
+            />
+            {/* <div class={styles.tip}>选封面</div> */}
+          </div>
+          <div class={styles.musicDetail}>
+            <p class={styles.musicName}>{state.musicDetail.musicSheetName}</p>
+            <p class={styles.username}>{state.musicDetail.username}</p>
+          </div>
+        </div>        
         {state.playType === 'Video' && (
           <div class={[styles.section, styles.sectionVideo]}>
             <img src={state.videoImg || videoBg} class={styles.videoBg} />
             <div class={styles.btnGroup}>
-              <MUploader
-                class={styles.btnImg}
-                cropper
-                tips=""
-                deletable={false}
-                onUploadChange={img => {
-                  console.log(img, 'img')
-                  state.videoImg = img
-                }}
-                options={{
-                  fixedNumber: [16, 9]
-                }}
-              />
+              <div onClick={checkDeviceAuth}>
+                <MUploader
+                  class={styles.btnImg}
+                  cropper
+                  tips=""
+                  deletable={false}
+                  hasDeviceAuth={state.hasDeviceAuth}
+                  onUploadChange={img => {
+                    console.log(img, 'img')
+                    state.videoImg = img
+                  }}
+                  options={{
+                    fixedNumber: [16, 9]
+                  }}
+                />
+              </div>
               <div class={styles.btnCropper} onClick={onCropper}>
                 视频截取封面
               </div>
@@ -123,24 +191,6 @@ export default defineComponent({
           />
         </div>
 
-        <div class={[styles.section, styles.sectionFile]}>
-          <div class={styles.uploadImg}>
-            <MUploader
-              class={styles.muploader}
-              // native
-              cropper
-              tips={''}
-              deletable={false}
-              v-model:modelValue={state.img}
-            />
-            {/* <div class={styles.tip}>选封面</div> */}
-          </div>
-          <div class={styles.musicDetail}>
-            <p class={styles.musicName}>{state.musicDetail.musicSheetName}</p>
-            <p class={styles.username}>{state.musicDetail.username}</p>
-          </div>
-        </div>
-
         <div class={styles.btnGroup}>
           <Button type="primary" round block color="#2DC7AA" onClick={onSubmit}>
             {state.musicDetail.type === 'FORMAL' ? '保存' : '发布'}

BIN
src/views/creation/images/Landscape.png


BIN
src/views/creation/images/audioBg.png


BIN
src/views/creation/images/back.png


BIN
src/views/creation/images/back1.png


BIN
src/views/creation/images/bg.png


BIN
src/views/creation/images/btn.png


BIN
src/views/creation/images/edit.png


BIN
src/views/creation/images/icon-delete.png


BIN
src/views/creation/images/icon-download.png


BIN
src/views/creation/images/icon-share.png


BIN
src/views/creation/images/icon-zan.png


BIN
src/views/creation/images/logo.png


BIN
src/views/creation/images/logo1.png


BIN
src/views/creation/images/midPlay.png


BIN
src/views/creation/images/music_bg.png


BIN
src/views/creation/images/pause1.png


BIN
src/views/creation/images/pause2.png


BIN
src/views/creation/images/play.png


BIN
src/views/creation/images/play1.png


BIN
src/views/creation/images/play2.png


BIN
src/views/creation/images/svip_icon.png


BIN
src/views/creation/images/ty.png


BIN
src/views/creation/images/upward.png


BIN
src/views/creation/images/videoBg.png


BIN
src/views/creation/images/vip_icon.png


BIN
src/views/creation/images/wx_bg.png


Разница между файлами не показана из-за своего большого размера
+ 647 - 256
src/views/creation/index-share.tsx


+ 955 - 461
src/views/creation/index.module.less

@@ -1,493 +1,604 @@
-.playSection {
-  min-height: 175px;
-
-  :global {
-    .vjs-poster {
-      background-size: cover;
-    }
-
-
-    .video-js .vjs-progress-control:hover .vjs-progress-holder {
-      font-size: inherit !important;
-      outline: none;
+* {
+  box-sizing: border-box;
+}
+.creationBg{
+  position: fixed;
+  z-index: -1;
+  width: 100%;
+  height: 100%;
+  min-height: 100vh;
+  top: 0;
+  left: 0;
+  background: url("./images/bg.png") no-repeat;
+  background-size: 100% 100%;
+}
+.creation{
+  :global{
+    .van-nav-bar .van-icon{
+      color: #ffffff;
     }
-
-    .video-js .vjs-slider:focus {
-      box-shadow: none !important;
-      text-shadow: none !important;
-      outline: none;
+  }
+  &.isScreenScroll,&.isShareScreenScroll{
+    :global{
+      .van-nav-bar .van-icon{
+        color: #333333;
+      }
     }
   }
 }
-
-@keyframes rotateImg {
-  100% {
-    transform: rotate(360deg);
-  }
+.singer{
+  text-align: center;
+  font-weight: 400;
+  font-size: 14px;
+  color: rgba(255,255,255,0.7);
+  line-height: 20px;
+  margin-bottom: 14vh;
 }
 
-.audioSection {
+.playSection{
+  height: 210px;
   position: relative;
-  background: url('./images/audio-banner-bg.png') no-repeat top center;
-  background-size: cover;
-  height: 175px;
-
-  .audioContainer {
+  &::after{
     position: absolute;
-    top: 0;
-    left: 50%;
-    width: 196px;
-    height: 35px;
-    transform: translate(-50%, 60px);
-
-    .waveActive,
-    .waveDefault {
-      width: 100%;
-      height: 100%;
-    }
-
-    .waveDefault {
-      position: absolute;
-      top: 0;
-      left: 0;
-      background: url('./images/wave-1.png')no-repeat center left;
-      background-size: cover;
-    }
-
-    .waveActive {
-      position: absolute;
-      top: 0;
-      left: 0;
-      z-index: 1;
-      background: url('./images/wave-2.png')no-repeat center left;
-      background-size: cover;
-    }
+    content: "";
+    width: 100%;
+    height: 40px;
+    bottom: -40px;
+    left: 0;
+    pointer-events: none;
   }
-
-
-  .audioBox {
-    position: absolute;
-    left: 50%;
-    transform: translate(-50%, 50%);
-    z-index: 2;
-    width: 74px;
-    height: 75px;
-    background: url('./images/audio-bg.png') no-repeat center;
-    background-size: contain;
-
-    // &::after {
-    //   content: '';
-    //   width: 134px;
-    //   height: 73px;
-    //   position: absolute;
-    //   left: 50%;
-    //   transform: translate(-50%, 50%);
-    //   background: url('./images/audio-shadow.png') no-repeat center;
-    //   background-size: contain;
-    //   z-index: -1;
-    // }
-    .audioPan {
-      position: absolute;
-      left: 8px;
-      top: 6px;
-      z-index: 8;
-      width: 59px;
-      height: 60px;
-      background: url('./images/audio-pan.png') no-repeat center;
-      background-size: contain;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-
-      animation: rotateImg 6s linear infinite;
-
-      &.imgRotate {
-        animation-play-state: paused;
+  :global {
+      .plyr {
+          width: 100%;
+          height: 100%;
+          z-index: initial;
+          .plyr__controls{
+              background: initial;
+              padding: 0 12px 2px;
+              opacity: 1 !important;
+              transform: translateY(0) !important;
+              pointer-events: initial !important;
+              .plyr__controls__item.plyr__progress__container{
+                  input[type=range]{
+                      color: #ffffff;
+                      height: 10px;
+                  }
+                  input[type="range"]::-webkit-slider-runnable-track {
+                      height: 2px;
+                  }
+                  input[type="range"]::-webkit-slider-thumb {
+                      width: 6px;
+                      height: 6px;
+                      margin-top: -2px;
+                      box-shadow: initial;
+                  }
+                  .plyr__progress__buffer{
+                      height: 2px;
+                      color: rgba(255, 255, 255, 0.7);
+                      background-color: rgba(0, 0, 0, 0.1);
+                      margin-top: -1px;
+                  }
+              }
+              .plyr__controls__item.plyr__time{
+                display: none;
+              }
+              .plyr__controls__item.plyr__control{
+                display: none;
+              }
+          }
       }
-    }
-
-    .audioImg {
-      width: 32px;
-      height: 32px;
-      border-radius: 50%;
+  }
+  .videoBox{
+    width: 100%;
+    height: 100%;
+  }
+  .audioBox{
+      width: 100%;
+      height: 100%;
+      background: url("./images/audioBg.png") no-repeat;
+      background-size: 100% 100%;
+      position: relative;
       overflow: hidden;
-    }
-
-    .audioPoint {
-      position: absolute;
-      z-index: 9;
-      left: 50%;
-      top: 50%;
-      transform: translate(-50%, -50%);
-      width: 8px;
-      height: 8px;
-      background: url('./images/audio-point.png') no-repeat center;
-      background-size: contain;
-    }
+      .audioBga {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, -60%);
+        width: 100%;
+        height: 82%;
+      }
 
-    .audioZhen {
-      position: absolute;
-      z-index: 9;
-      right: -4px;
-      top: -33px;
-      width: 26px;
-      height: 87px;
-      background: url('./images/audio-zhen.png') no-repeat center;
-      background-size: contain;
-      transition: transform .5s ease-in-out;
+      .audioBga1 {
+          position: absolute;
+          left: 0;
+          top: 16px;
+          width: 94px;
+      }
 
-      &.active {
-        transform: rotate(92deg) translate3d(0, 0, 3px);
-        transition: transform .5s ease-in-out;
+      .audioBga2 {
+          width: 192px;
+          position: absolute;
+          right: -24px;
+          top: 0;
       }
-    }
-  }
+      :global {
+          .plyr {
+              position: absolute;
+              height: initial;
+              left: 0;
+              bottom: 0;
+              z-index: 2;
+          }
+      }
+      .audioVisualizer{
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%,-50%);
+          width: 280px;
+          height: 55px;
+      }
+      .tyBg {
+        width: 139px;
+        height: 74px;
+        position: absolute;
+        z-index: 1;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, calc(-50% + 28px));
+     }
+     .audioBoxBg {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        transform: translate(-50%, -50%);
+        z-index: 2;
+        width: 74px;
+        height: 75px;
+        background: url("./images/audio-bg.png") no-repeat center;
+        background-size: 100% 100%;
+
+        .audioPan {
+           position: absolute;
+           left: 50%;
+           top: 50%;
+           transform: translate(-50%, -50%);
+           z-index: 8;
+           width: 59px;
+           height: 60px;
+           background: url("./images/audio-pan.png") no-repeat center;
+           background-size: 100% 100%;
+           display: flex;
+           align-items: center;
+           justify-content: center;
+
+           animation: rotateImg 6s linear infinite;
+
+           &.imgRotate {
+              animation-play-state: paused;
+           }
+        }
 
-}
+        .audioImg {
+           width: 32px;
+           height: 32px;
+           border-radius: 50%;
+        }
 
-.controls {
-  position: absolute;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  height: 44px;
-  display: flex;
-  flex-direction: column;
-  justify-content: space-between;
-  flex-direction: row;
-  transition: all 0.5s;
-  padding: 0 12px;
+        .audioPoint {
+           position: absolute;
+           z-index: 9;
+           left: 50%;
+           top: 50%;
+           transform: translate(-50%, -50%);
+           width: 8px;
+           height: 8px;
+           background: url("./images/audio-point.png") no-repeat center;
+           background-size: contain;
+        }
 
-  &>div {
-    display: flex;
-    align-items: center;
+        .audioZhen {
+           position: absolute;
+           z-index: 9;
+           right: -4px;
+           top: -33px;
+           width: 26px;
+           height: 87px;
+           background: url("./images/audio-zhen.png") no-repeat center;
+           background-size: contain;
+           transition: transform 0.5s ease-in-out;
+
+           &.active {
+              transform: rotate(92deg) translate3d(0, 0, 3px);
+              transition: transform 0.5s ease-in-out;
+           }
+        }
+     }      
   }
-
-  &.hide {
-    transform: translateY(100%);
+  .playLarge{
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    width: 48px;
+    height: 48px;
+    background: url("./images/midPlay.png") no-repeat;
+    background-size: 100% 100%;
+    z-index: 12;
+    display: none;
+    &.playIngShow{
+      display: initial;
+    }
   }
-
-
-
-  .actionBtn {
-    line-height: 0;
-    margin-right: 4px;
-
-    img {
-      width: 14px;
-      height: 14px;
-      margin-bottom: -2px;
+  .mediaTimeCon{
+    display: none;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, .3);
+  }
+  &.mediaTimeShow{
+    .mediaTimeCon{
+      display: block;
     }
   }
-
-  .time {
+  .mediaTime{
+    position: absolute;
+    left: 50%;
+    transform: translateX(-50%);
+    bottom: 95px;
     display: flex;
-    justify-content: space-between;
-    flex: 1;
-    min-width: 86px;
-    font-size: 12px;
-    color: #131415;
+    font-weight: 500;
+    font-size: 16px;
+    color: #B8E8FF;
     line-height: 20px;
-
-    span {
-      font-size: 12px;
-      padding: 0 1px;
+    z-index: 10;
+    text-shadow: 0px 1px 1px rgba(0,0,0,0.5);
+    & div:first-child{
+      width: 50px;
+      text-align: right;
+    }
+    .note{
+      margin: 0 4px;
+    }
+    .duration{
+      color: #fff;
     }
   }
-
-  .slider {
+  .landscapeScreen{
+    width: 32px;
+    height: 32px;
+    position: absolute;
+    background: url("./images/Landscape.png") no-repeat;
+    background-size: 26px 26px;
+    background-position: center center;
+    right: 7px;
+    top: 7px;
+    z-index: 15;
+  }
+  .staffBoxCon{
+    position: absolute;
     width: 100%;
-    margin: 0 12px;
-    --van-slider-bar-height: 4px;
-    --van-slider-button-width: 13px !important;
-    --van-slider-button-height: 13px !important;
-    --van-slider-inactive-background: #fff;
-    --van-slider-inactive-background-color: #fff;
-    --van-slider-active-background: #2DC7AA !important;
-
-    :global {
-
-      .van-loading {
-        width: 100%;
-        height: 100%;
-      }
-
+    height: 100%;
+    left: 0;
+    top: 0;
+    z-index: 1;
+    overflow: hidden;
+    visibility: hidden;
+    &.staffBoxShow{
+      visibility: initial;
     }
   }
-
-}
-
-.userSection {
-  padding: 15px 12px !important;
-  background-color: transparent !important;
-
-  .userLogoSection {
-    width: 44px;
-    height: 44px;
-    border: 1px solid #FFFFFF;
-    margin-right: 10px;
-    border-radius: 50%;
-    flex-shrink: 0;
-    position: relative;
-
-    .showMemeber {
+  .staffBox{
+    width: 100%;
+    height: calc(var(--staffBoxHeight) + 12px);
+    position: absolute;
+    bottom: 0;
+    padding-bottom: 12px;
+    .staff{
+      width: 100%;
+      height: 100%;
+      padding-left: 10px;
+    }
+    .mask{
       position: absolute;
-      bottom: 1px;
-      right: -3px;
-      width: 18px;
-      height: 18px;
+      z-index: 6;
+      width: 100%;
+      height: 100%;
     }
-
-    &.userVip {
-      border: 1px solid #F0AF88;
-
-      .showMemeber {
-        background: url('./images/icon-vip.png') no-repeat center;
-        background-size: contain;
+    &.staffBoxBg {
+      .staff{
+        background-color: rgba(255, 255, 255, 0.7) !important;
       }
     }
-
-    &.userSVip {
-
-      border: 1px solid #F0AF88;
-
-      .showMemeber {
-        background: url('./images/icon-svip.png') no-repeat center;
-        background-size: contain;
+  }
+  &.isLandscapeScreen2 {
+    :global {
+      .plyr {
+        .plyr__controls{
+          .plyr__controls__item.plyr__progress__container {
+            input[type="range"] {
+               color: #01c1b5 !important;
+            }
+            .plyr__progress__buffer {
+               color: rgba(1, 193, 181, 0.8);
+               background-color: #fff;
+            }
+         }
+        }
       }
-
     }
   }
+}
 
-  .userLogo {
-    width: 44px;
-    height: 44px;
-    border-radius: 50%;
-    overflow: hidden;
-  }
+.musicSection {
+  width: 100%;
+  min-height: calc(var(--creationHeight, 100vh) - var(--barheight) - 20px - 14vh - 210px - 55px - 80px);
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-end;
+  padding: 10px 12px 0;
 
-  .userInfo {
-    .name {
+  .avatarInfoBox{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .avatar{
       display: flex;
       align-items: center;
-      font-size: 16px;
-      font-weight: 500;
-      color: #333333;
-      line-height: 22px;
-
-      span {
-        display: inline-block;
-        white-space: nowrap;
+      .avatarImg {
+        position: relative;
+      }
+      .userLogo{
+        width: 44px;
+        height: 44px;
+        border: 2px solid #FFFFFF;
+        margin-right: 10px;
+        border-radius: 50%;
         overflow: hidden;
-        text-overflow: ellipsis;
-        max-width: 100px;
+        &.vipLogo {
+          border: 2px solid #FADA9B;
+        }
+        &.svipLogo {
+          border: 2px solid #F0AF88;
+        }
+      }
+      .vipIcon {
+        position: absolute;
+        bottom: -6px;
+        left: 2px;
+        z-index: 1;
+        width: 40px;
+        height: 18px;
+      }
+      .infoCon{
+        .info{
+          display: flex;
+          align-items: center;
+          .userName{
+            font-weight: 500;
+            font-size: 16px;
+            color: #FFFFFF;
+            line-height: 22px;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            max-width: 160px;
+          }
+          .iconMember{
+            margin-left: 6px;
+            width: 14px;
+            height: 14px;
+          }
+        }
+        .sub{
+          margin-top: 2px;
+          font-weight: 400;
+          font-size: 12px;
+          color: #FFFFFF;
+          line-height: 17px;
+        }
       }
     }
-
-    .sub {
-      padding-top: 2px;
-      font-size: 12px;
-      color: #777777;
-      line-height: 17px;
-    }
-
-    .iconMember {
-      margin-left: 6px;
-      width: 14px;
-      height: 14px;
-    }
-  }
-
-  .zan {
-    background: #FFFFFF;
-    border-radius: 13px;
-    font-size: 14px;
-    color: #777777;
-    line-height: 20px;
-    padding: 4px 9px 3px;
-    display: inline-flex;
-    align-items: center;
-
-    &.zanActive {
-      background: #F7EEEE;
-      color: #FF6A6A;
-    }
-
-    .iconZan {
-      width: 18px;
-      height: 18px;
-      margin-right: 2px;
-    }
-  }
-}
-
-.musicSection {
-  margin: 0 13px 12px;
-  padding: 14px 12px;
-  background: #FFFFFF;
-  border-radius: 10px;
-
-  .musicName {
-    font-size: 15px;
-    font-weight: 500;
-    color: #333333;
-    line-height: 21px;
-    // display: flex;
-    // align-items: center;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    max-width: 230px;
-
-    .musicTag {
-      margin-right: 6px;
-      padding: 1px 6px;
-      font-size: 12px;
-      color: #FF7B31;
-      line-height: 17px;
-      background: rgba(255, 166, 115, 0.07);
-      border-radius: 9px;
-      border: 1px solid #FFBF9A;
+    .linkes{
+      display: flex;
+      align-items: center;
+      border-radius: 13px;
+      padding: 4px 8px 3px;
+      background-color: rgba(255,255,255,.12);
       font-weight: 400;
-      vertical-align: text-bottom;
-      display: inline-block;
+      font-size: 14px;
+      color: #FFFFFF;
+      .iconZan{
+        width: 18px;
+        height: 18px;
+        margin-right: 2px;
+      }
     }
   }
-
-  .musicDesc {
-    padding-top: 8px;
+  .textEllipsis{
+    margin-top: 10px;
+    font-weight: 400;
     font-size: 14px;
-    color: #777777;
+    color: #FFFFFF;
     line-height: 20px;
+    :global{
+      .van-text-ellipsis__action{
+        color: #5CCEFF;
+        font-weight: 500;
+        margin-left: 2px;
+        &:active{
+          opacity: 1;
+        }
+      }
+    }
   }
 }
 
 .likeSection {
-  margin: 0 13px 12px;
-  background: #FFFFFF;
+  margin: 20px 12px;
+  background: rgba(255,255,255,.09);
   border-radius: 10px;
-  padding: 10px 12px;
-
+  padding: 12px 12px 0 12px;
+  overflow: hidden;
   .likeTitle {
     display: flex;
     align-items: center;
     font-size: 17px;
     font-weight: 600;
-    color: #333333;
+    color: #ffffff;
     line-height: 24px;
-    padding-bottom: 8px;
-
     &::before {
       display: inline-block;
       content: '';
       width: 4px;
       height: 14px;
       border-radius: 2px;
-      background: linear-gradient(to bottom, #59E5D5, #2DC7AA);
+      background: #2dc7aa;
       margin-right: 6px;
     }
   }
-}
-
-.likeItem {
-  padding: 16px 0;
+  .likeItem {
+    padding: 13px 0 16px;
+    background-color: initial;
+    border-bottom: 1px solid rgba(242,242,242,0.12);
+    &.likeItemLast{
+      border-bottom: none;
+    }
+    .userLogo {
+      border-radius: 50%;
+      overflow: hidden;
+      width: 42px;
+      height: 42px;
+      margin-right: 7px;
+    }
 
-  .userLogo {
-    border-radius: 50%;
-    overflow: hidden;
-    width: 42px;
-    height: 42px;
-    margin-right: 7px;
-  }
+    .userInfo {
+      .name {
+        font-size: 16px;
+        font-weight: 500;
+        color: #ffffff;
+        line-height: 22px;
+      }
 
-  .userInfo {
-    .name {
-      font-size: 16px;
-      font-weight: 500;
-      color: #333333;
-      line-height: 22px;
+      .sub {
+        padding-top: 2px;
+        font-size: 13px;
+        color: #ffffff;
+        line-height: 18px;
+      }
     }
 
-    .sub {
-      padding-top: 2px;
+    .time {
+      font-weight: 400;
       font-size: 13px;
-      color: #777777;
+      color: #FFFFFF;
       line-height: 18px;
     }
   }
-
-  .time {
-    font-size: 13px;
-    color: #777777;
-    line-height: 18px;
+  .mEmpty{
+    padding: 0;
+  }
+  .btnImg{
+    display: flex;
+    justify-content: center;
+    margin-top: 3px;
+    margin-bottom: 12px;
+    &>img{
+      width: 88px;
+      height: 31px;
+      &:active{
+        opacity: 0.8;
+      }
+    }
+  }
+  :global {
+    .van-empty__description {
+      color: #fff;
+    }
+    .van-cell {
+      padding-left: 0;
+      padding-right: 0;
+    }
   }
 }
 
-
+.upward{
+  padding-top: 12px;
+  display: flex;
+  justify-content: center;
+  height: 55px;
+  background: linear-gradient(180deg, rgba(42, 78, 85, 0) 0%, rgba(43, 78, 85, 0.7) 19%, #2b4e55 100%);
+  > img{
+    width: 19px;
+    height: 15px;
+  }
+}
 .bottomSection {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  background-color: #fff;
-  padding: 15px 12px;
-
+  padding: 0 12px 0 20px;
+  width: 100%;
+  height: 80px;
+  background: #1F1F1F;
+  box-shadow: 0px -1px 10px 0px rgba(0,0,0,0.05);
   .bottomShare {
     display: flex;
     align-items: center;
-
     p {
-      padding: 0 15px;
-      text-align: center;
-      line-height: 0;
-
-      &:first-child {
-        padding-left: 5px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      margin-right: 28px;
+      &:last-child{
+        margin-right: 0;
       }
     }
-
     img {
       width: 18px;
       height: 18px;
     }
-
     span {
-      padding-top: 8px;
+      margin-top: 8px;
+      font-weight: 400;
       font-size: 12px;
-      color: #333333;
+      color: #ffffff;
       line-height: 17px;
-      display: block;
     }
   }
 
   .btnEdit {
-    font-size: 14px;
-    font-weight: 500;
-    background: #2DC7AA;
-    color: #FFFFFF;
-    line-height: 22px;
-    min-width: 80px;
+    width: 80px;
     height: 30px;
-    border: none;
   }
 }
 
 .popupContainer {
   width: 80%;
-
-
-  .popupContent {
-    padding: 29px 0 25px;
+  max-width: 350px;
+  .popupTit {
+    margin-top: 20px;
     text-align: center;
+    font-weight: 600;
     font-size: 18px;
-    font-weight: 500;
-    color: #333333;
+    color: #131415;
     line-height: 25px;
   }
-
+  .popupContent {
+    margin: 20px 0;
+    font-weight: 400;
+    font-size: 16px;
+    color: #777777;
+    line-height: 26px;
+    text-align: center;
+  }
   .popupBtnGroup {
     text-align: center;
-    margin-bottom: 22px;
-
+    margin-bottom: 20px;
     :global {
       .van-button {
         height: 40px;
@@ -495,117 +606,500 @@
         font-weight: 400 !important;
         line-height: 22px;
         min-width: 122px;
-
         &:last-child {
-          margin-left: 10px;
-          background: #2DC7AA;
-          border: none;
+           margin-left: 15px;
+           background: #2dc7aa;
+           border: none;
         }
-      }
+     }
     }
   }
 }
-
-.cellGroup {
+// 分享样式
+.playSection.notLoaded{
+  :global{
+    .plyr .plyr__controls {
+      display: none;
+    }
+  }
+}
+.logoDownload{
   display: flex;
-  flex-wrap: wrap;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 13px;
+  position: relative;
+  &::after{
+    content: "";
+    position: absolute;
+    bottom: 0;
+    left: 13px;
+    width: calc(100% - 26px);
+    height: 1px;
+    background-color: rgba(255, 255, 255, 0.3) ;
+  }
+  .logoImg{
+    width: 107px;
+    height: 30px;
+  }
+  .logTit{
+    font-weight: 400;
+    font-size: 14px;
+    color: #FFFFFF;
+    line-height: 22px;
+    padding: 2px 10px;
+    border-radius: 20px;
+    background: #2DC7AA;
+  }
 }
-
-.cell {
-  // display: flex;
-  // flex-direction: column;
-  width: 96px;
-  margin-right: 18px;
-  margin-bottom: 18px;
-
-  &:nth-child(3n + 3) {
-    margin-right: 0;
+.isShareScreenScroll{
+  .logoDownload{
+    background-color: #ffffff;
+    .logTit{
+      background: #2dc7aa;
+      border: none;
+      padding: 3px 11px;
+    }
   }
-
-  .cellImg {
+}
+.singerBox{
+  height: 20vh;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-end;
+  .musicSheetName{
+    width: 200px;
+    margin: 0 auto 10px;
+    :global{
+      .van-notice-bar{
+          padding: 0;
+          height: 28px;
+          font-weight: 600;
+          font-size: 20px;
+          color: #FFFFFF;
+          line-height: 28px;
+          .van-notice-bar__content{
+            min-width: 100%;
+            text-align: center;
+          }
+      }
+    }
+  }
+  .singerName{
+    text-align: center;
+    font-weight: 400;
+    font-size: 14px;
+    color: rgba(255,255,255,0.7);
+    line-height: 20px;
+    margin-bottom: 10px;
+  }
+}
+.musicShareSection{
+  min-height: calc(var(--creationHeight, 100vh) - var(--barheight) - 20vh - 210px - 55px);
+}
+.likeShareItem{
+  background-color: initial !important;
+  padding: 0;
+  margin-top: 25px;
+  &:first-child{
+    margin-top: 15px;
+  }
+  &.likeShareItemLast{
+    padding-bottom: 20px;
+  }
+  .audioImgBox{
     position: relative;
-
-    &::before {
-      content: '';
+    width: 51px;
+    height: 51px;
+    margin-right: 14px;
+    .audioPan{
       position: absolute;
+      width: 100%;
+      height: 100%;
       right: -6px;
-      top: 3px;
-      z-index: 8;
-      width: 84px;
-      height: 84px;
-      background: url('./images/audio-pan.png') no-repeat center;
-      background-size: contain;
-      display: flex;
-      align-items: center;
-      justify-content: center;
+      top: 0;
     }
-
-    .iconZan {
+    .muploader{
+      position: relative;
+      z-index: 1;
+      width: 100%;
+      height: 100%;
+      border-radius: 8.5px;
+    }
+    .imgLabel{
       position: absolute;
-      bottom: 4px;
-      left: 4px;
+      right: 0;
+      top: 0;
+      width: 28px;
+      height: 14px;
       z-index: 10;
-      padding: 3px;
-      background: rgba(67, 67, 67, 0.3);
-      border-radius: 8px;
-      backdrop-filter: blur(4px);
-
-      font-size: 9px;
-      font-weight: 500;
+    }
+  }
+  .userInfo{
+    .musicSheetName{
+      font-weight: 600;
+      font-size: 16px;
       color: #FFFFFF;
-      line-height: 13px;
+      line-height: 22px;
+      width: 200px;
+    }
+    .usernameCon{
       display: flex;
       align-items: center;
-
-      &::before {
-        content: '';
-        display: inline-block;
-        width: 12px;
-        height: 12px;
-        background: url('./images/icon-z.png') no-repeat center;
-        background-size: contain;
+      margin-top: 4px;
+      .likeNum{
+        display: flex;
+        align-items: center;
+        border-radius: 3px;
+        background-color: rgba(255,255,255,.22);
+        padding: 1px 2px;
+        img{
+          width: 14px;
+          height: 15px;
+        }
+        span{
+          font-weight: 400;
+          font-size: 10px;
+          color: #FFFFFF;
+          line-height: 1;
+          margin-left: 2px;
+        }
+      }
+      .username{
+        max-width: 160px;
+        margin-left: 4px;
+        font-weight: 400;
+        font-size: 13px;
+        color: #DEDEDE;
+        //line-height: 13px;
       }
     }
   }
+  :global{
+    .van-cell__value{
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+    }
+  }
+  .playImg{
+    width: 20px;
+    height: 20px;
+  }
+}
+.isEmpty{
+  height: calc(var(--creationHeight, 100vh) - var(--barheight));
+  display: flex;
+  align-items: center;
+}
 
-  .cellImage {
-    position: relative;
-    width: 88px;
-    height: 88px;
-    border-radius: 12px;
-    z-index: 9;
-
-    :global {
-      img {
-        border-radius: 12px;
+// 平板样式
+.creation{
+  &.creationTablet{
+    .playSection{
+      height: 340px;
+      .audioBox {
+        .audioBga{
+          width: 80%;
+          height: 62%;
+        }
+      }
+    }
+    .musicSection{
+      min-height: calc(var(--creationHeight, 100vh) - var(--barheight) - 20px - 14vh - 340px - 55px - 80px);
+    }
+    .musicShareSection{
+      min-height: calc(var(--creationHeight, 100vh) - var(--barheight) - 20vh - 340px - 55px);
+    }
+    .wxpopup{
+      img{
+        width: 54%;
+        margin-right: 18px;
       }
     }
   }
+}
 
-  .cellTitle {
-    font-size: 13px;
-    color: #131415;
-    line-height: 18px;
-    margin: 8px 0 6px;
+@keyframes rotate {
+  from {
+      transform: rotate(0deg);
   }
+  to {
+      transform: rotate(360deg);
+  }
+}
+.loadingPop {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  z-index: 9999999;
+  background: rgba(0, 0, 0, .5);
+  .loadingCssBox{
+      width: 27px;
+      height: 27px;
+      display: flex;
+      justify-content: space-between;
+      flex-wrap: wrap;
+      align-content: space-between;
+      margin-bottom: 24px;
+      animation: rotate 1.5s linear infinite;
+      .loadingCssItem{
+          width: 11px;
+          height: 11px;
+          border-radius: 50%;
+          background: #11ffd4;
+          opacity: 0.5;
+          &:nth-child(2){
+              opacity:1;
+          }
+      }
+  }
+  .loadingTip {
+      font-size: 14px;
+      color: #fff;
+  }
+}
 
-  .users {
-    display: flex;
-    align-items: center;
+.wxpopup {
+  width: 100%;
+  height: 100%;
+  min-height: 100vh;
+  position: fixed;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 9999;
+  text-align: right;
 
-    .userImg {
-      width: 20px;
-      height: 20px;
-      border-radius: 50%;
-      overflow: hidden;
-      margin-right: 4px;
-      flex-shrink: 0;
-    }
+  img {
+    width: 88%;
+    margin-right: 6%;
+  }
+}
 
-    .name {
-      font-size: 12px;
-      color: #402424;
-      line-height: 14px;
+// :global{
+//   .dialogMusicClass.van-dialog{
+//     width: 300px;
+//     .van-dialog__message{
+//       font-weight: 500;
+//       line-height: 24px;
+//     }
+//   }
+// }
+
+// 横屏样式
+.creation.creationTablet{
+  .playSection.isLandscapeScreen{
+    position: relative;
+    .audioBox {
+      .audioBga{
+        width: 72%;
+        height: 56%;
+      }
+    }
+  }
+}
+.playSection.isLandscapeScreen{
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  width: 100%;
+  height: 100%;
+  min-height: 100vh;
+  z-index: 1000;
+  &::before {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 115px;
+    content: "";
+    background: linear-gradient(0, rgba(255, 255, 255, 0) 0%, rgba(3, 3, 3, 0.2) 45%, rgba(0, 0, 0, 0.7) 100%);
+    z-index: 2;
+  }
+  .landscapeScreen{
+    display: none;
+  }
+  .audioBox{
+    .audioBoxBg,.audioVisualizer{
+       transform: translate(-50%, -50%) scale(1.4);
+    }
+    .tyBg{
+       transform: translate(-50%, calc(-50% + 39px)) scale(1.4);
+    }
+  }  
+  :global {
+    .plyr{
+      .plyr__controls{
+        padding: 0 20px 20px;
+        .plyr__controls__item.plyr__control{
+          display: block;
+          padding: 0;
+          width: 18px;
+          height: 18px;
+          &:hover{
+              background: initial;
+          }
+          .icon--pressed{
+              width: 100%;
+              height: 100%;
+              background: url("./images/pause1.png") no-repeat;
+              background-size: 100% 100%;
+              use{
+                  display: none;
+              }
+          }
+          .icon--not-pressed{
+              width: 100%;
+              height: 100%;
+              background: url("./images/play1.png") no-repeat;
+              background-size: 100% 100%;
+              use{
+                  display: none;
+              }
+          }
+        }
+        .plyr__controls__item.plyr__progress__container{
+          margin-left: 9px;
+          input[type=range]{
+              color: #ffffff;
+              height: 20px;
+          }
+          input[type="range"]::-webkit-slider-runnable-track {
+              height: 4px;
+          }
+          input[type="range"]::-webkit-slider-thumb {
+              width: 12px;
+              height: 12px;
+              margin-top: -4px;
+              box-shadow: initial;
+              background: #ffffff;
+          }
+          .plyr__progress__buffer{
+              height: 4px;
+              color: rgba(255, 255, 255, 0.7);
+              background-color: #fff;
+              margin-top: -2px;
+          }
+        }
+        .plyr__controls__item.plyr__time{
+            font-weight: 500;
+            font-size: 14px;
+            color: #FFFFFF;
+            display: initial;
+            &.plyr__time--current{
+                margin-left: 9px;
+            }
+        }
+      }
+    }
+  }
+  .backBox{
+    position: absolute;
+    left: 20px;
+    top: 20px;
+    display: flex;
+    z-index: 999;
+    .backImg{
+      width: 21px;
+      height: 21px;
     }
+    .musicDetail{
+      margin-left: 10px;
+      .musicSheetName{
+        width: 300px;
+        //margin-top: 4px;
+        :global{
+          .van-notice-bar{
+              padding: 0;
+              height: 20px;
+              font-weight: 600;
+              font-size: 18px;
+              color: #FFFFFF;
+              line-height: 20px;
+          }
+        }
+      }
+      .username{
+        margin-top: 2px;
+        font-weight: 400;
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.7);
+        line-height: 18px
+      }
+    }
+    .adMusicDetail {
+      :global{
+        .van-notice-bar{
+            color: #131415 !important;
+        }
+      }
+      .username {
+        color: #333333;
+      }
+    }
+  }
+  .staffBox{
+    height: calc(var(--staffBoxHeight) + 44px);
+    padding-bottom: 44px;
+    .staff{
+      padding-left: 20px;
+    }
+    &.staffBoxBg {
+      .staff{
+        background-color: rgba(255, 255, 255, 0.7) !important;
+      }
+    }
+  }
+  &.isLandscapeScreen2 {
+    &::before {
+      background: transparent;
+    }
+    :global {
+      .plyr{
+        .plyr__controls{
+          .plyr__controls__item.plyr__control{
+            .icon--pressed{
+                width: 100%;
+                height: 100%;
+                background: url("./images/pause2.png") no-repeat;
+                background-size: 100% 100%;
+            }
+            .icon--not-pressed{
+              width: 100%;
+              height: 100%;
+              background: url("./images/play2.png") no-repeat;
+              background-size: 100% 100%;
+            }
+          }
+          .plyr__controls__item.plyr__progress__container{
+            input[type="range"]::-webkit-slider-thumb {
+               background-color: #2DC7AA;
+            }
+          }
+         .plyr__controls__item.plyr__time {
+            font-weight: 500;
+            font-size: 14px;
+            color: #131415;
+            display: initial;
+            &.plyr__time--current {
+              margin-left: 9px;
+            }
+          }
+        }
+      }
+    }  
   }
 }

Разница между файлами не показана из-за своего большого размера
+ 569 - 264
src/views/creation/index.tsx


+ 19 - 0
src/views/creation/loading.tsx

@@ -0,0 +1,19 @@
+import { defineComponent } from 'vue';
+import styles from './index.module.less';
+
+export default defineComponent({
+  name: 'loading',
+  setup() {
+    return () => (
+      <div class={[styles.loadingPop]}>
+        <div class={styles.loadingCssBox}>
+          <div class={styles.loadingCssItem}></div>
+          <div class={styles.loadingCssItem}></div>
+          <div class={styles.loadingCssItem}></div>
+          <div class={styles.loadingCssItem}></div>
+        </div>
+        <div class={styles.loadingTip}>资源加载中...</div>
+      </div>
+    );
+  }
+});

BIN
src/views/creation/share-model/images/audioLabel.png


BIN
src/views/creation/share-model/images/share-bg.png


BIN
src/views/creation/share-model/images/videoLabel.png


+ 21 - 5
src/views/creation/share-model/index.module.less

@@ -51,7 +51,7 @@
     width: 56px;
     height: 56px;
     object-fit: cover;
-    border-radius: 6px;
+    border-radius: 9px;
   }
 
   .uploadImg {
@@ -68,7 +68,14 @@
       width: 56px;
       height: 56px;
     }
-
+    .imgLabel{
+      position: absolute;
+      right: 0;
+      top: 0;
+      width: 28px;
+      height: 14px;
+      z-index: 10;
+    }
 
   }
 
@@ -135,7 +142,11 @@
     margin-left: 10px;
     padding-left: 9px;
     border-left: 1px dashed #D8D8D8;
-
+    font-weight: 500;
+    font-size: 12px;
+    color: #01C1B5;
+    line-height: 18px;
+    padding-top: 5px;
     .tip {
       font-size: 12px;
       color: #777777;
@@ -145,7 +156,7 @@
     .iconLogo {
       width: 68px;
       height: 21px;
-      margin: 12px 0 4px;
+      margin: 5px 0 0;
     }
 
     .downTip {
@@ -168,9 +179,14 @@
     position: absolute;
     top: 12px;
     right: 12px;
-    font-size: 16px;
+    font-size: 20px;
     color: #999999;
   }
+  :global {
+    .van-grid {
+      justify-content: space-around;
+    }
+  }
 }
 
 .share__header {

+ 9 - 1
src/views/creation/share-model/index.tsx

@@ -11,6 +11,8 @@ import shareBg from './images/share-bg.png'
 import audioPan from '../images/audio-pan.png'
 import smallLogo from '@common/images/icon_logo.png'
 import musicBg from './images/music-bg.png'
+import audioLabel from './images/audioLabel.png';
+import videoLabel from './images/videoLabel.png';
 import QRCode from 'qrcode'
 import { promisefiyPostMessage } from '@/helpers/native-message'
 import html2canvas from 'html2canvas'
@@ -21,6 +23,10 @@ export default defineComponent({
     musicDetail: {
       type: Object,
       default: () => {}
+    },
+    playType:{
+      type: String,
+      default: ''
     }
   },
   emits: ['close'],
@@ -205,6 +211,7 @@ export default defineComponent({
                 class={styles.muploader}
                 crossorigin="anonymous"
               />
+              <img class={styles.imgLabel} src={props.playType === "Audio" ? audioLabel : videoLabel} />
             </div>
             <div class={styles.musicDetail}>
               <p class={[styles.musicName, 'van-ellipsis']}>
@@ -222,8 +229,9 @@ export default defineComponent({
               <img src={smallLogo} class={styles.qrcodeLogo} />
             </div>
             <div class={styles.qrtips}>
+              <div>温馨提示:</div>
               <p class={styles.tip}>
-                温馨提示:保存图片到相册或长按识别二维码进入查看喔
+                保存图片到相册后,请在微信里扫码查看
               </p>
               <img src={iconLogo} class={styles.iconLogo} />
               {/* <p class={styles.downTip}>扫码下载音乐数字课堂App</p> */}

+ 12 - 0
src/views/creation/text-ellipsis/index.module.less

@@ -0,0 +1,12 @@
+.ellipsis {
+  line-height: 0.2rem;
+  &.vis {
+     visibility: hidden;
+  }
+  .ellipsisAct {
+     cursor: pointer;
+     color: #2CDCBB;
+     font-weight: 500;
+     margin-left: 2px;
+  }
+}

+ 99 - 0
src/views/creation/text-ellipsis/index.tsx

@@ -0,0 +1,99 @@
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+    name: "TextEllipsis",
+    data() {
+       return {
+          ellipsisData: {
+             oversize: false,
+             computedReady: false, // 先隐形计算,计算好后,再根据配置显示
+             expanded: false,
+             key: 0
+          }
+       }
+    },
+    props: {
+       text: {
+          type: String
+       },
+       lines: {
+          type: Number,
+          default: 2 // 默认显示的行数
+       }
+    },
+    watch: {
+       text() {
+          // 强制刷新组件
+          this.ellipsisData.key++
+          this.ellipsisData.expanded = false
+          this.computeText()
+       }
+    },
+    created() {
+       this.computeText()
+    },
+    methods: {
+       getStyle(el, styleName) {
+          if (!el) return ""
+          if (styleName === "float") {
+             styleName = "cssFloat"
+          }
+          try {
+             const style = el.style[styleName]
+             if (style) return style
+             const computed = document.defaultView?.getComputedStyle(el, "")
+             return computed ? computed[styleName] : ""
+          } catch {
+             return el.style[styleName]
+          }
+       },
+       computeText() {
+          this.ellipsisData.oversize = false
+          this.ellipsisData.computedReady = false
+          this.$nextTick(() => {
+             let text: any = this.text
+             let height = 0
+             const lines = this.lines
+             const ellipsisDom: any = this.$refs.ellipsisDom
+             const textDom: any = this.$refs.textDom
+             if (this.ellipsisData.expanded) {
+                textDom.innerText = this.text
+                this.ellipsisData.oversize = true
+                this.ellipsisData.computedReady = true
+                return
+             }
+             if (!height && lines) {
+                const lineHeight = parseInt(this.getStyle(ellipsisDom, "lineHeight"))
+                height = lineHeight * lines
+             }
+             if (ellipsisDom.offsetHeight > height) {
+                this.ellipsisData.oversize = true
+                this.$nextTick(() => {
+                   while (ellipsisDom.offsetHeight > height) {
+                      if (ellipsisDom.offsetHeight > height * 3) {
+                         textDom.innerText = text = text.substring(0, Math.floor(text.length / 2))
+                      } else {
+                         textDom.innerText = text = text.substring(0, text.length - 1)
+                      }
+                   }
+                })
+             }
+             this.ellipsisData.computedReady = true
+          })
+       },
+       handleExpand() {
+          this.ellipsisData.expanded = !this.ellipsisData.expanded
+          this.computeText()
+       }
+    },
+    render() {
+        return (
+            <div ref="ellipsisDom" class={[styles.ellipsis, !this.ellipsisData.computedReady && styles.vis]} key={this.ellipsisData.key}>
+                <span ref="textDom">{ this.text }</span>
+                {this.ellipsisData.oversize && !this.ellipsisData.expanded && <span>...</span>}
+                {this.ellipsisData.oversize && <span class={styles.ellipsisAct} onClick={this.handleExpand}>{ this.ellipsisData.expanded ? "收起" : "展开" }</span>}
+            </div>
+        )
+    }
+})

+ 34 - 5
src/views/music/music-detail/index.tsx

@@ -188,7 +188,11 @@ export default defineComponent({
       loading.value = true
       isError.value = false
       try {
-        const res = await request.get(`/music/sheet/detail/${route.query.id}`, {
+        let apiUrl = route.query.tenantAlbumId ? `/music/sheet/detail/${route.query.id}?tenantAlbumId=${route.query.tenantAlbumId}` : `/music/sheet/detail/${route.query.id}`
+        if (route.query.providerType) {
+          apiUrl += route.query.tenantAlbumId ? `&providerType=${route.query.providerType}` : `?providerType=${route.query.providerType}`
+        }
+        const res = await request.get(apiUrl, {
           prefix:
             state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
         })
@@ -329,8 +333,23 @@ export default defineComponent({
     })
 
     const toggleFavorite = async () => {
+      /**
+       * 酷乐秀老师端 收藏曲目 music/sheet/favorite/id?providerType=?? 添加参数
+       * @ApiModelProperty("曲目评测来源 TENANT 机构 PLATFORM 平台")
+       * private String providerType;
+       * 表示收藏的是机构曲目,还是平台曲目,
+       */
+      let apiUrl = '', providerType = ''
+      if (browser().isTeacher) {
+        providerType = route.query.tenantAlbumId || route.query.providerType == 'TENANT' ? 'TENANT' : 'PLATFORM'
+      }
+      apiUrl = `/music/sheet/favorite/${musicDetail.value?.id}`
       try {
-        await request.post('/music/sheet/favorite/' + musicDetail.value?.id, {
+        await request.post(apiUrl, {
+          requestType: 'form',
+          data: {
+            providerType
+          },
           prefix:
             state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
         })
@@ -1146,10 +1165,20 @@ export default defineComponent({
                         // const index = staffData.tempPartList.findIndex(
                         //   (i: any) => i.track === item?.track
                         // )
-                        musicBuy(musicDetail.value, () => {}, {
+                        // 新版云教练的谱面类型使用musicRenderType字段
+                        const musicRenderType = staff.radio === 'staff' ? 'staff' : staff.radio === 'first' ? 'firstTone' :  staff.radio === 'fixed' ? 'fixedTone' : '';
+                        let extraParam: any = {
                           'part-index': item?.xmlValue || 0,
-                          sett: staff.radio
-                        })
+                          musicRenderType,
+                        }
+                        // 有专辑id
+                        if (route.query.tenantAlbumId) {
+                          extraParam.albumId = route.query.tenantAlbumId
+                        } else if (browser().isTeacher && route.query.providerType == 'TENANT') {
+                           // 机构老师端
+                          extraParam.albumId = 1
+                        }
+                        musicBuy(musicDetail.value, () => {}, extraParam)
                       }, 500)
 
                       throttleFn()

+ 4 - 2
src/views/music/music.ts

@@ -13,12 +13,14 @@ export const getRandomKey = () => {
 
 export const musicBuy = (item: any, callBack?: any, moreQuery = {}) => {
   const behaviorId = localStorage.getItem('behaviorId') || ''
+  // 酷乐秀云教练的部署目录
+  const musicScorePath = "/klx-music-score/";
   const url = qs.stringifyUrl({
-    url: location.origin + '/accompany',
+    url: location.origin + musicScorePath,
     query: {
       id: item.id,
       behaviorId,
-      client: browserInfo.isStudent ? 'student' : 'teacher',
+      systemType: browserInfo.isStudent ? 'student' : 'teacher',
       ...moreQuery
     }
   })

+ 6 - 2
src/views/music/personal/collection.tsx

@@ -72,16 +72,20 @@ export default defineComponent({
             <Song
               list={rows.value}
               onDetail={(item: any) => {
-                const url =
+                let url =
                   location.origin +
                   location.pathname +
                   '#/music-detail?id=' +
                   item.id
+                if (item.favoriteProviderType) {
+                  url += `&providerType=${item.favoriteProviderType}`
+                }  
                 openDefaultWebView(url, () => {
                   router.push({
                     path: '/music-detail',
                     query: {
-                      id: item.id
+                      id: item.id,
+                      providerType: item.favoriteProviderType
                     }
                   })
                 })

Разница между файлами не показана из-за своего большого размера
+ 317 - 317
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов