瀏覽代碼

Merge branch 'hqyDevNewVersion' of http://git.dayaedu.com/liushengqiang/music-score into feature-tianyong-newVersion

TIANYONG 1 年之前
父節點
當前提交
0a7cba5e97
共有 25 個文件被更改,包括 608 次插入262 次删除
  1. 30 0
      package-lock.json
  2. 1 0
      package.json
  3. 68 0
      src/helpers/oss-file-upload.ts
  4. 二進制
      src/page-instrument/component/the-music-list/icon_menu.png
  5. 二進制
      src/page-instrument/component/the-music-list/imgs/bg.png
  6. 二進制
      src/page-instrument/component/the-music-list/imgs/huo.png
  7. 0 0
      src/page-instrument/component/the-music-list/imgs/icon-music-vip.png
  8. 二進制
      src/page-instrument/component/the-music-list/imgs/qtqm.png
  9. 二進制
      src/page-instrument/component/the-music-list/imgs/qtqmAct.png
  10. 二進制
      src/page-instrument/component/the-music-list/imgs/searImg.png
  11. 二進制
      src/page-instrument/component/the-music-list/imgs/zjlx.png
  12. 二進制
      src/page-instrument/component/the-music-list/imgs/zjlxAct.png
  13. 172 101
      src/page-instrument/component/the-music-list/index.module.less
  14. 11 9
      src/page-instrument/component/the-music-list/index.tsx
  15. 23 2
      src/page-instrument/component/the-music-list/list.tsx
  16. 186 101
      src/page-instrument/custom-plugins/helper-model/recommendation/index.module.less
  17. 85 40
      src/page-instrument/custom-plugins/helper-model/recommendation/index.tsx
  18. 二進制
      src/page-instrument/header-top/image/photo.png
  19. 二進制
      src/page-instrument/header-top/image/qx.png
  20. 二進制
      src/page-instrument/header-top/image/recommendationName.png
  21. 二進制
      src/page-instrument/header-top/image/tj.png
  22. 7 2
      src/page-instrument/header-top/index.tsx
  23. 21 3
      src/page-instrument/header-top/settting/index.tsx
  24. 2 2
      src/page-instrument/view-detail/index.tsx
  25. 2 2
      vite.config.ts

+ 30 - 0
package-lock.json

@@ -12,6 +12,7 @@
         "@varlet/ui": "^2.9.5",
         "clean-deep": "^3.4.0",
         "consola": "^2.15.3",
+        "cos-js-sdk-v5": "^1.4.20",
         "dayjs": "^1.11.7",
         "eventemitter3": "^5.0.0",
         "hammerjs": "^2.0.8",
@@ -2752,6 +2753,14 @@
       "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz",
       "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ=="
     },
+    "node_modules/@xmldom/xmldom": {
+      "version": "0.8.10",
+      "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+      "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/acorn": {
       "version": "8.8.2",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -3210,6 +3219,14 @@
         "url": "https://opencollective.com/core-js"
       }
     },
+    "node_modules/cos-js-sdk-v5": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmmirror.com/cos-js-sdk-v5/-/cos-js-sdk-v5-1.8.1.tgz",
+      "integrity": "sha512-crsdrcDSRJqdniG61JiQCEA4FIUMuvqNohRCIONrHGd23xvykZs8uySLHmvAKDieAYRT+P72F/Ng7kjycW2b1w==",
+      "dependencies": {
+        "@xmldom/xmldom": "^0.8.6"
+      }
+    },
     "node_modules/css-line-break": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
@@ -7549,6 +7566,11 @@
       "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz",
       "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ=="
     },
+    "@xmldom/xmldom": {
+      "version": "0.8.10",
+      "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+      "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="
+    },
     "acorn": {
       "version": "8.8.2",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -7897,6 +7919,14 @@
         "browserslist": "^4.21.5"
       }
     },
+    "cos-js-sdk-v5": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmmirror.com/cos-js-sdk-v5/-/cos-js-sdk-v5-1.8.1.tgz",
+      "integrity": "sha512-crsdrcDSRJqdniG61JiQCEA4FIUMuvqNohRCIONrHGd23xvykZs8uySLHmvAKDieAYRT+P72F/Ng7kjycW2b1w==",
+      "requires": {
+        "@xmldom/xmldom": "^0.8.6"
+      }
+    },
     "css-line-break": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "@varlet/ui": "^2.9.5",
     "clean-deep": "^3.4.0",
     "consola": "^2.15.3",
+    "cos-js-sdk-v5": "^1.4.20",
     "dayjs": "^1.11.7",
     "eventemitter3": "^5.0.0",
     "hammerjs": "^2.0.8",

+ 68 - 0
src/helpers/oss-file-upload.ts

@@ -0,0 +1,68 @@
+import request from "../utils/request"
+import COS from "cos-js-sdk-v5"
+
+const tencentBucket = "daya-online-1303457149"
+const ossType = "tencent"
+
+export async function fileUpload(fileName:string,file:Blob) {
+   const { data } = await getUploadSign(fileName)
+   return await onOnlyFileUpload(data.signature, {
+      fileName,
+      file
+   })
+}
+
+const getUploadSign = async (fileName:string) => {
+   const fileUrl = "yjl/" + fileName
+   return request.post("/open/getUploadSign", {
+      data: {
+         postData: {
+            key: fileUrl
+         },
+         pluginName: ossType,
+         bucketName: tencentBucket,
+         filename: fileUrl
+      },
+      requestType: "json",
+      params: { pluginName: ossType }
+   })
+}
+
+const onOnlyFileUpload = async (signature: string, params: { fileName: string; file: Blob }) => {
+   let file = ""
+   let errorObj: any = null
+   const cos = new COS({
+      Domain: "https://oss.dayaedu.com",
+      Protocol: "https",
+      getAuthorization: async (options, callback: any) => {
+         callback({ Authorization: signature })
+      }
+   })
+   await cos
+      .uploadFile({
+         Bucket: tencentBucket /* 填写自己的 bucket,必须字段 */,
+         Region: "ap-nanjing" /* 存储桶所在地域,必须字段 */,
+         Key: `yjl/${params.fileName}`,
+         /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */
+         Body: params.file, // 上传文件对象
+         SliceSize: 1024 * 1024 * 500 /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */,
+         onProgress: function (progressData) {
+            // onProgress({ percent: Math.ceil((progressData.percent || 0) * 100) })
+         }
+      })
+      .then((res: any) => {
+         if (res.Location?.indexOf("http") >= 0) {
+            file = res.Location
+         } else {
+            file = "https://" + res.Location
+         }
+      })
+      .catch((error: any) => {
+         errorObj = error
+      })
+   if (file) {
+      return file
+   } else {
+      throw new Error(errorObj)
+   }
+}

二進制
src/page-instrument/component/the-music-list/icon_menu.png


二進制
src/page-instrument/component/the-music-list/imgs/bg.png


二進制
src/page-instrument/component/the-music-list/imgs/huo.png


+ 0 - 0
src/page-instrument/component/the-music-list/icon-music-vip.png → src/page-instrument/component/the-music-list/imgs/icon-music-vip.png


二進制
src/page-instrument/component/the-music-list/imgs/qtqm.png


二進制
src/page-instrument/component/the-music-list/imgs/qtqmAct.png


二進制
src/page-instrument/component/the-music-list/imgs/searImg.png


二進制
src/page-instrument/component/the-music-list/imgs/zjlx.png


二進制
src/page-instrument/component/the-music-list/imgs/zjlxAct.png


+ 172 - 101
src/page-instrument/component/the-music-list/index.module.less

@@ -1,91 +1,145 @@
-.fixedBtn {
-    position: fixed;
-    top: 50%;
-    right: 0;
-    transform: translateY(-50%);
-    width: 22px;
-    height: 42px;
-    background: rgba(0, 0, 0, 0.24);
-    border-radius: 9px 0px 0px 9px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-
-    &:active {
-        opacity: .8;
-    }
-
-    &>img {
-        width: 12px;
-        height: 14px;
-    }
+.popup{
+    background:initial;
 }
-
 .tabs {
     height: 100vh;
-    width: 50vw;
-
+    width: 320px;
+    padding: 10px 0;
     :global {
-        .van-tabs {
+        .van-tabs{
             height: 100%;
-        }
-
-        .van-tabs__wrap {
-            height: 44px;
-            --van-tab-text-color: #777;
-
-            .van-tab {
-                z-index: 2;
+            .van-tabs__wrap{
+                display: flex;
+                justify-content: right;
+                height: 30px;
+                .van-tabs__nav--line{
+                    padding-bottom: 0;
+                    background-color: initial;
+                    .van-tab{
+                        flex: initial;
+                        .van-tab__text{
+                            display: none;
+                        }
+                        &:nth-child(1){
+                            width: 100px;
+                            height: 30px;
+                            background: url("./imgs/qtqm.png") no-repeat;
+                            background-size: 100% 100%;
+                            &.van-tab--active{
+                                background: url("./imgs/qtqmAct.png") no-repeat;
+                                background-size: 100% 100%;
+                            }
+                        }                   
+                        &:nth-child(2){
+                            margin-left: 24px;
+                            margin-right: 34px;
+                            width: 100px;
+                            height: 30px;
+                            background: url("./imgs/zjlx.png") no-repeat;
+                            background-size: 100% 100%;
+                            &.van-tab--active{
+                                background: url("./imgs/zjlxAct.png") no-repeat;
+                                background-size: 100% 100%;
+                            }
+                        }
+                    }
+                }
+                .van-tabs__line{
+                    display: none;
+                }
+            }
+            .van-tabs__content{
+                height: calc(100% - 30px);
+                background: url("./imgs/bg.png") no-repeat;
+                background-size: 100% 100%;
+                .van-tab__panel{
+                    height: 100%;
+                }
             }
         }
+    }
+}
 
-        .van-tabs__content {
-            height: calc(100% - 44px);
-            overflow: hidden;
+.wrap {
+    height: 100%;
+    padding: 18px 16px 12px 46px;
+    .searchBox{
+        display: flex;
+        align-items: center;
+        height: 34px;
+        background: #F8F9FC;
+        border-radius: 18px;
+        padding: 0 4px 0 12px;
+        border: 1px solid transparent;
+        &.isFocus{
+            border-color: #1CACF1;
         }
-
-        .van-tab__panel {
-            height: 100%;
-            overflow-x: hidden;
-            overflow-y: auto;
+        >img{
+            flex-shrink: 0;
+            width: 14px;
+            height: 14px;
         }
-
-        .van-tab--active::after {
-            content: '';
-            position: absolute;
-            bottom: 0;
-            left: 50%;
-            transform: translateX(-50%);
-            width: var(--van-tabs-bottom-bar-width);
-            height: var(--van-tabs-bottom-bar-height);
-            background: var(--van-tabs-bottom-bar-color);
-            border-radius: var(--van-tabs-bottom-bar-height);
+        :global{
+            .van-field{
+                margin: 0 6px;
+                flex-grow: 1;
+                padding: 0;
+                line-height: initial;
+                background: initial;
+                &::after{
+                    display: none;
+                }
+                .van-field__control{
+                    font-weight: 400;
+                    font-size: 13px;
+                    color: #131415;
+                    &::placeholder{
+                        color: #AAAAAA;
+                    }
+                }
+            }
         }
-
-        .van-tabs__line {
-            transition-duration: 0s !important;
-            display: none;
+        .searchBtn{
+            flex-shrink: 0;
+            width: 54px;
+            height: 26px; 
+            line-height: 26px;
+            text-align: center;
+            background: linear-gradient(to right,#5BECFF,#259CFE);
+            border-radius: 18px;
+            font-weight: 500;
+            font-size: 13px;
+            color: #FFFFFF;
+            cursor: pointer;
+            &:active{
+                opacity: 0.8;
+            }
+        }
+    }
+    :global{
+        .van-list{
+            margin-top: 10px;
+            height: calc(100% - 44px);
+            overflow-y: auto;
         }
     }
-}
-
-.wrap {
-    padding: 4px 12px;
 }
 
 .item {
     display: flex;
     align-items: center;
-    // height: 41px;
-    // border-radius: 7px;
-    font-size: 13px;
-    font-family: PingFangSC-Regular, PingFang SC;
-    font-weight: 400;
-    color: #333333;
-    line-height: 18px;
-    padding: 12px 12px;
-    // margin: 10px 0;
-
+    background: #FFFFFF;
+    border-radius: 16px;
+    padding: 6px;
+    margin-bottom: 8px;
+    &.itemActive {
+        background: linear-gradient( 180deg, #FFFFFF 0%, #BFE1FF 100%);
+        box-shadow: 0px 2px 4px 0px #499FE4;
+        border: 3px solid #FFFFFF;
+        .content .name{
+            color: #2EAAFE;
+        }
+    }
     .titleImg {
         width: 51px;
         height: 51px;
@@ -94,40 +148,58 @@
         overflow: hidden;
         position: relative;
         flex-shrink: 0;
-    }
-
-    .iconType {
-        position: absolute;
-        width: 28px;
-        height: 14px;
-        right: 0;
-        top: 0;
-        z-index: 9;
-        border-top-right-radius: 8px !important;
-
-        // &.FREE {
-        //   background: url('../co-ai/image/icon-music-default.png') no-repeat center;
-        //   background-size: contain;
-        // }
-
-        &.VIP {
-            background: url('./icon-music-vip.png') no-repeat center;
-            background-size: contain;
+        .iconType {
+            position: absolute;
+            width: 28px;
+            height: 14px;
+            right: 0;
+            top: 0;
+            z-index: 9;
+            border-top-right-radius: 8px !important;
+            &.VIP {
+                background: url('./imgs/icon-music-vip.png') no-repeat center;
+                background-size: contain;
+            }
         }
     }
-
-    .author {
-        padding-top: 8px;
-        font-size: 13px;
-        color: #777777;
-        line-height: 1;
+    .content{
+        .name{
+            font-weight: 600;
+            font-size: 16px;
+            color: #333333;
+        }
+        .detail{
+            display: flex;
+            align-items: center;
+            margin-top: 8px;
+            .usedNum{
+                display: flex;
+                align-items: center;
+                padding: 3px 5px;
+                height: 17px;
+                background: #FFF8F7;
+                border-radius: 4px;
+                border: 1px solid #FFC5C5;
+                >img{
+                    width: 8px;
+                    height: 11px;
+                }
+                >div{
+                    margin-left: 3px;
+                    font-weight: 400;
+                    font-size: 12px;
+                    color: #FF6A6A
+                }
+            }
+            .author {
+                margin-left: 6px;
+                font-weight: 400;
+                font-size: 13px;
+                color: rgba(0,0,0,0.5);
+            }
+        }
     }
 }
-
-.itemActive {
-    background: #ECF9FF;
-}
-
 .noData {
     display: flex;
     justify-content: center;
@@ -135,5 +207,4 @@
     height: 100%;
     font-size: 14px;
     color: #999999;
-    height: 70vh;
 }

+ 11 - 9
src/page-instrument/component/the-music-list/index.tsx

@@ -1,21 +1,23 @@
-import { defineComponent, reactive } from "vue";
+import { computed, defineComponent, ref } from "vue";
 import styles from "./index.module.less";
-import icon_menu from "./icon_menu.png";
 import { Popup, Tab, Tabs } from "vant";
 import List from "./list";
+import { followData } from "/src/view/follow-practice";
+import state, {IPlatform} from "/src/state";
+import { evaluatingData } from "/src/view/evaluating";
+import { getQuery } from "/src/utils/queryString";
 
+const query: any = getQuery();
+export const isMusicList = computed(()=>{
+	return !(state.playState == "play" || followData.start || evaluatingData.startBegin || query.workRecord || query.modelType || state.platform === IPlatform.PC || query.isCbs)
+})
+export const musicListShow = ref(false)
 export default defineComponent({
 	name: "TheMusicList",
 	setup() {
-		const data = reactive({
-			show: false,
-		});
 		return () => (
 			<>
-				<div class={styles.fixedBtn} onClick={() => (data.show = true)}>
-					<img src={icon_menu} />
-				</div>
-				<Popup position="right" v-model:show={data.show} round>
+				<Popup class={styles.popup} position="left" v-model:show={musicListShow.value} round overlay-style={{background:'rgba(0, 0, 0, 0.3)'}}>
 					<div class={styles.tabs}>
 						<Tabs>
 							<Tab title="其他曲谱">

+ 23 - 2
src/page-instrument/component/the-music-list/list.tsx

@@ -2,9 +2,11 @@ import { defineComponent, onMounted, reactive, watch } from "vue";
 import styles from "./index.module.less";
 import { api_musicSheetPage } from "../../api";
 import state, { togglePlay } from "/src/state";
-import { List, Image } from "vant";
+import { List, Image, Field } from "vant";
 import { postMessage } from "/src/utils/native-message";
 import qs from "query-string";
+import searImg from "./imgs/searImg.png"
+import huoimg from "./imgs/huo.png"
 
 export default defineComponent({
   name: "TheMusicList-list",
@@ -16,6 +18,7 @@ export default defineComponent({
   },
   setup(props) {
     const forms = reactive({
+      name: "",
       page: 1,
       rows: 20,
       musicSheetCategoriesId: state.bizMusicCategoryId,
@@ -23,6 +26,7 @@ export default defineComponent({
       excludeMusicId: props.recentFlag ? null : state.examSongId,
     });
     const data = reactive({
+      isFocus: false,
       list: [] as any[],
       finished: false,
       loading: false,
@@ -46,6 +50,15 @@ export default defineComponent({
 
       data.loading = false;
     };
+    function handleQuery(){
+      forms.page = 1
+      forms.rows = 20
+      data.list = []
+      data.finished =false
+      data.loading = false
+      data.hasNext = true
+      getList()
+    }
     watch(
       () => props.recentFlag,
       () => {
@@ -78,6 +91,11 @@ export default defineComponent({
     };
     return () => (
       <div class={styles.wrap}>
+        <div class={[styles.searchBox,data.isFocus && styles.isFocus]}>
+          <img src={searImg} />
+          <Field placeholder="请输入曲目名称" v-model={forms.name} autocomplete="off" onFocus={()=>{ data.isFocus = true }} onBlur={()=>{ data.isFocus = false }} />
+          <div class={styles.searchBtn} onClick={handleQuery}>搜索</div>
+        </div>
         <List
           loading={data.loading}
           finished={data.finished}
@@ -96,7 +114,10 @@ export default defineComponent({
                 </div>
                 <div class={styles.content}>
                   <p class={styles.name}>{item.musicSheetName}</p>
-                  {item.composer && <p class={styles.author}>{item.composer}</p>}
+                  <div class={styles.detail}>
+                    {item.usedNum && <div class={styles.usedNum}><img src={huoimg}/><div>{item.usedNum}</div></div>}
+                    {item.composer && <p class={styles.author}>{item.composer}</p>}
+                  </div>
                 </div>
               </div>
             );

+ 186 - 101
src/page-instrument/custom-plugins/helper-model/recommendation/index.module.less

@@ -1,112 +1,197 @@
-
-.closeBtn {
-    position: absolute;
-    right: -34px;
-    top: -6px;
-    width: 24px;
-    height: 24px;
-    border-radius: 50%;
-    background-color: #fff;
-    overflow: hidden;
-    padding: 6px;
-
-    img {
-        width: 100%;
-        height: 100%;
-        display: block;
-    }
-
-    &:active {
-        opacity: .8;
-    }
-}
-
-.content {
-    position: relative;
-    border-radius: 8px;
-    width: 300px;
-    // height: 90vh;
-    max-height: 370px;
-    background-color: #fff;
-    --van-tabs-line-height: 42px;
-    overflow: hidden;
-    :global {
-        .van-tabs__wrap{
-            border-bottom: 1Px solid #F0F0F0;
+.recommendation{
+    .head{
+        background: url("/src/page-instrument/header-top/image/headImg.png") no-repeat;
+        background-size: 100% 100%;
+        width: 372px;
+        height: 57px;
+        position: relative;
+        .headTit{
+            position: absolute;
+            bottom: 8px;
+            left: 50%;
+            transform: translateX(-50%);
+            width: 76px;
+            height: 20px;
+        }        
+        .closeImg{
+            position: absolute;
+            top: 0;
+            right: -38px;
+            width: 32px;
+            height: 32px;
+            cursor: pointer;
         }
-        .van-tabs__content {
-            max-height: calc(90vh - var(--van-tabs-line-height));
+    }
+    .content{
+        width: 354px;
+        height: 284px;
+        background: #B0D8FF;
+        box-shadow: 0px 4px 0px 0px #7AAEE0;
+        border-radius: 0px 0px 24px 24px;
+        margin: 0 auto;
+        padding: 10px;
+        .conBox{
+            width: 100%;
+            height: 100%;
+            background: #EAF2FB;
+            border-radius: 12px;
             overflow-y: auto;
-
+            padding: 10px;
             &::-webkit-scrollbar {
                 width: 0;
                 display: none;
             }
-        }
-        .van-field{
-            font-size: 12Px;
-            line-height: 16Px;
-        }
-        .van-field__value{
-            background-color: #F8F8F8;
-            padding: 9px;
-        }
-    }
-    &.pcContent {
-        :global {
-            .van-field{
-                font-size: 16Px;
-                line-height: 20Px;
+            .dropdownMenu{
+                width: 138px;
+                position: relative;
+                :global{
+                    .van-dropdown-menu__bar{
+                        height: 30px;
+                        background: #FFFFFF;
+                        border-radius: 15px;
+                        .van-dropdown-menu__item{
+                            padding: 0 12px;
+                        }
+                        .van-dropdown-menu__title{
+                            --van-gray-4: #AAAAAA;
+                            font-weight: 500;
+                            font-size: 14px;
+                            color: #AAAAAA;
+                            padding: 0 10px 0 0;
+                            &::after{
+                                right: 0;
+                                opacity: initial;
+                            }
+                        }
+                    }
+                    .recommendationDropdownItem{
+                        top: 112px !important;
+                        left: 24px;
+                        width: 152px;
+                        .van-dropdown-item__content{
+                            max-height:162px;
+                            padding: 0 10px;
+                            background: #FFFFFF;
+                            box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.1);
+                            border-radius: 12px;
+                            .van-cell{
+                                margin-top: 6px;
+                                padding: 0;
+                                font-weight: 400;
+                                font-size: 13px;
+                                color: #777777;
+                                line-height: 32px;
+                                text-align: center;
+                                &::after{
+                                    border: none;
+                                }
+                                &:last-child{
+                                    margin-bottom: 6px;
+                                }
+                                &.van-dropdown-item__option--active{
+                                    background: #F2FAFF;
+                                    border-radius: 8px;
+                                    color: #1CACF1;
+                                }
+                                .van-cell__value{
+                                    display: none;
+                                }
+                            }
+                        }
+                    }
+                }
+                &.currItem{
+                    :global{
+                        .van-dropdown-menu__bar  .van-dropdown-menu__title{
+                            color: #1CACF1;
+                            --van-gray-4:#1CACF1;
+                        }
+                    }
+                }
             }
-            .van-cell__title {
-                font-size: 18Px;
+            .field{
+                margin-top: 10px;
+                height: 80px;
+                background: #FFFFFF;
+                border-radius: 12px;
+                padding: 10px;
+                :global{
+                    .van-field__control{
+                        font-weight: 500;
+                        font-size: 14px;
+                        color: #131415;
+                        &::placeholder {
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #AAAAAA;
+                        }
+                    }
+                }
+            }
+            .uploader{
+                margin-top: 10px;
+                display: block;
+                :global{
+                    .van-uploader__preview{
+                        margin: 0 8px 0 0;
+                        .van-uploader__preview-image{
+                            width: 56px;
+                            height: 56px;
+                            border-radius: 6px;
+                        }
+                        .van-uploader__preview-delete--shadow{
+                            width: 14px;
+                            height: 14px;
+                            border-radius: 50%;
+                            right: 3px;
+                            top: 3px;
+                            background:rgba(0,0,0,0.4);
+                            display: flex;
+                            justify-content: center;
+                            align-items: center;
+                            .van-uploader__preview-delete-icon{
+                                transform:initial;
+                                position:initial;
+                                font-size: 12px;
+                            }
+                        }
+                    }
+                }
+                .uploaderbox{
+                    width: 56px;
+                    height: 56px;
+                    background: #FFFFFF;
+                    border-radius: 6px;
+                    border: 1px dashed #D9D9D9;
+                    display: flex;
+                    flex-direction: column;
+                    justify-content: center;
+                    align-items: center;
+                    .img{
+                        width: 22px;
+                        height: 22px;
+                        margin-bottom: 2px;
+                    }
+                    >div{
+                        font-weight: 400;
+                        font-size: 10px;
+                        color: #777777;
+                    }
+                }
+            }
+            .btnCon{
+                margin-top: 16px;
+                display: flex;
+                justify-content: center;
+                .img{
+                    cursor: pointer;
+                    width: 118px;
+                    height: 39px;
+                    &:first-child{
+                        margin-right: 20px;
+                    }
+                }
             }
-        }
-    }
-}
-
-.tags {
-    display: flex;
-    text-align: center;
-    flex-wrap: wrap;
-    padding: 0 var(--van-cell-horizontal-padding) var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);
-    >span {
-        margin: 3px 12px 3px 0;
-        border-radius: 3PX;
-        display: block;
-        width: 30%;
-        font-size: 12PX;
-        padding: 6PX 0;
-        background-color: #F8F8F8;
-        color: #999999;
-        border: 1PX solid #F8F8F8;
-        &:nth-child(3n+3) {
-            margin-right: 0px;
-        }
-        &.active {
-            color: var(--van-primary-color);
-            border-color: var(--van-primary-color);
-            background-color: #ECF9FF;
-            pointer-events: none;
-        }
-    }
-    &.pcTags {
-        >span {
-            font-size: 15PX;
-        }
-    }
-}
-.btn{
-    display: block;
-    height: 36px;
-    font-size: 13px;
-    margin: 0 auto;
-}
-
-.pcContent {
-    .tags {
-        >span {
-            font-size: 16PX;
         }
     }
 }

+ 85 - 40
src/page-instrument/custom-plugins/helper-model/recommendation/index.tsx

@@ -1,29 +1,33 @@
-import { defineComponent, reactive, ref, onMounted } from "vue";
+import { defineComponent, reactive, ref, onMounted, computed } from "vue";
 import styles from "./index.module.less";
-import iconClose from "../icons/close2.svg";
-import { Button, Cell, Field, Tab, Tabs, showToast } from "vant";
-import iconSubmit from "../icons/icon-submit.svg";
+import { Button, Cell, Field, Tab, Tabs, showToast, DropdownMenu, DropdownItem, Uploader } from "vant";
 import { sysSuggestionAdd, getSuggestionList } from "/src/page-instrument/api";
 import { storeData } from "/src/store";
 import state, { IPlatform } from "/src/state";
+import { headImg } from "/src/page-instrument/header-top/image";
+import { fileUpload } from "/src/helpers/oss-file-upload"
 
 export default defineComponent({
 	name: "recommendation",
 	emits: ["close"],
 	setup(props, { emit }) {
-		const suggestionTypeList = ref([] as any);
-		const tags = ["识别不准", "无法评测", "不出评测结果", "曲谱不一致", "指法错误", "其他"];
+		const suggestionTypeList = ref<any[]>([]);
 		const recommenData = reactive({
-			loading: false,
-			active: "识别不准",
 			message: "",
-			suggestId: null,
+			suggestId: "",
 		});
+		const fileList = ref<any[]>([])  // 上传列表
 		// 获取建议类别
 		const getTypeList = async () => {
 			try {
-				const res = await getSuggestionList({ rows: 9999, page: 1 });
-				suggestionTypeList.value = res.data.rows || [];
+				const res = await getSuggestionList({ rows: 9999, page: 1, useClient: "SMART_PRACTICE" });
+				const data = res.data.rows || [];
+				suggestionTypeList.value = data.map((item:any) => {
+					return {
+						text: item.name,
+						value: item.id
+					}
+				})
 			} catch (e) {
 				//
 			}
@@ -32,65 +36,106 @@ export default defineComponent({
 		/** 提交意见反馈 */
 		const handleSubmit = async () => {
 			if (!recommenData.message || !recommenData.suggestId) {
-				const desc = !recommenData.suggestId ? '请先选择问题类型' : '请先填写意见反馈'
+				const desc = !recommenData.suggestId ? '请先选择反馈类型' : '请先填写意见反馈'
 				showToast({
 					message: desc,
 					position: "top",
 				});
 				return;
 			}
-			recommenData.loading = true;
 			try {
+				const attachmentUrlsArr = fileList.value.reduce((arr,item)=>{
+					item.url && arr.push(item.url)
+					return arr
+				},[])
 				await sysSuggestionAdd({
 					content: recommenData.message,
 					type: "SMART_PRACTICE",
 					suggestionTypeId: recommenData.suggestId,
-					mobileNo: storeData.user?.phone
+					mobileNo: storeData.user?.phone,
+					attachmentUrls: attachmentUrlsArr.join(",")
 				});
 				showToast({
 					message: "意见反馈已提交",
 					position: "top",
 				});
 				emit("close");
-				recommenData.suggestId = null
+				recommenData.suggestId = ""
 				recommenData.message = ''
+				fileList.value = []
 			} catch (error) {}
-			recommenData.loading = false;
+		};
+		const currItem = computed(()=>{
+			const currItem = suggestionTypeList.value.find((item:any)=>{
+				return item.value === recommenData.suggestId
+			})
+			return currItem
+		})
+		/* 文件上传 */
+		const afterRead = (file:any[]|Record<string,any>) => {
+			let files:any[] = []
+			if(Array.isArray(file)){
+				files = file.map(item =>{
+							item.status = 'uploading';
+							item.message = '上传中...';
+							item.key = new Date().getTime() + item.file.name
+							return item
+						})
+			} else {
+				file.status = 'uploading';
+				file.message = '上传中...';
+				file.key = new Date().getTime() + file.file.name
+				files.push(file)
+			}
+			files.map(async item=>{
+				try {
+					const url = await fileUpload(item.key,item.file)
+					item.status = ""
+					item.url = url
+				}catch{
+					item.status = "failed"
+					item.message = "上传失败"
+				}
+			})
+		};
+		const maxSize = 5
+		const onOversize = () => {
+			showToast(`文件大小不能超过 ${maxSize}M`);
 		};
 		onMounted(() => {
 			getTypeList();
 		});
 		return () => (
-			<div class={[styles.content, state.platform === IPlatform.PC && styles.pcContent]}>
-				{ state.platform === IPlatform.PC && <div class={'top_drag'}></div> }
-				<Tabs lineHeight={0} color="#1A1A1A">
-					<Tab title="意见反馈">
-						<Cell border={false} title="请选择问题类型" />
-						<div class={styles.tags}>
-							{suggestionTypeList.value.map((item: any) => (
-								<span
-									class={[styles.tag, recommenData.suggestId === item.id && styles.active]}
-									onClick={() => (recommenData.suggestId = item.id)}
-								>
-									{item.name}
-								</span>
-							))}
-						</div>
+			<div class={[styles.recommendation]}>
+				<div class={styles.head}>
+					<img class={styles.headTit} src={headImg("recommendationName.png")} />
+					<img class={styles.closeImg} src={headImg("closeImg.png")} onClick={()=>{ emit("close") }} />
+				</div>
+				<div class={styles.content}>
+                    <div class={styles.conBox}>
+						<DropdownMenu class={[styles.dropdownMenu, currItem.value && styles.currItem]} overlay={false}>
+							<DropdownItem class={['recommendationDropdownItem']} title={ currItem.value?currItem.value.name:"请选择反馈类型"} v-model={recommenData.suggestId} options={suggestionTypeList.value}/>
+						</DropdownMenu>
 						<Field
+							class={styles.field}
 							v-model={recommenData.message}
-							rows="2"
-							autosize={{ maxHeight: 44 }}
 							border={false}
 							type="textarea"
 							maxlength={200}
-							placeholder="请详细描述您遇到的问题,以便我们尽快为您解决!"
-							show-word-limit
+							placeholder="请详细描述您遇到的问题,以便我们尽快为您解决"
 						/>
-						<Cell>
-							<img class={styles.btn} src={iconSubmit} onClick={handleSubmit} />
-						</Cell>
-					</Tab>
-				</Tabs>
+						<Uploader accept=".jpg,jpeg,.png" class={styles.uploader} max-size={maxSize * 1024 * 1024} onOversize={onOversize} v-model={fileList.value} after-read={afterRead} multiple max-count={4}>
+							<div class={styles.uploaderbox}>
+								<img class={styles.img} src={headImg("photo.png")}></img>
+								<div>上传图片</div>
+							</div>
+						</Uploader>
+						<div class={styles.btnCon}>
+							<img class={styles.img} src={headImg("qx.png")} onClick={()=>{ emit("close") }}></img>
+							<img class={styles.img} src={headImg("tj.png")} onClick={handleSubmit}></img>
+						</div>
+                    </div>  
+                </div>
 			</div>
 		);
 	},

二進制
src/page-instrument/header-top/image/photo.png


二進制
src/page-instrument/header-top/image/qx.png


二進制
src/page-instrument/header-top/image/recommendationName.png


二進制
src/page-instrument/header-top/image/tj.png


+ 7 - 2
src/page-instrument/header-top/index.tsx

@@ -30,6 +30,7 @@ import Dragbom from "/src/view/plugins/useDrag/dragbom";
 import { getGuidance, setGuidance } from "../custom-plugins/guide-page/api";
 import ModeView from "./modeView"
 import { smoothAnimationState } from "../view-detail/smoothAnimation"
+import { isMusicList, musicListShow } from "../component/the-music-list";
 
 /** 头部数据和方法 */
 export const headTopData = reactive({
@@ -504,13 +505,17 @@ export default defineComponent({
             <img src={iconBack} class={['headTopBackBtn', styles.img, !headTopData.showBack && styles.hidenBack]} onClick={handleBack} />
             {
               state.modeType === "practise" && smoothAnimationState.isShow.value ? 
-                <div class={styles.title}>
+                <div class={styles.title} onClick={()=>{
+                  isMusicList.value && (musicListShow.value = true)
+                }}>
                   <NoticeBar
                     text={state.examSongName}
                     background="none"
                   />
               </div> :
-              <img src={listImg} class={[styles.img]} />
+              <img src={listImg} class={[styles.img]} onClick={()=>{
+                  isMusicList.value && (musicListShow.value = true)
+              }} />
             }
           </div>
           {/* 模式切换 */}

+ 21 - 3
src/page-instrument/header-top/settting/index.tsx

@@ -1,14 +1,19 @@
-import { defineComponent } from "vue";
+import { defineComponent, reactive } from "vue";
 import styles from "./index.module.less"
 import { headImg } from "../image";
 import { headTopData } from "../index"
-import { Switch, showToast, Field } from "vant";
+import { Switch, showToast, Field, Popup } from "vant";
 import state from "/src/state"
 import { smoothAnimationState} from "/src/page-instrument/view-detail/smoothAnimation"
+import Recommendation from "../../custom-plugins/helper-model/recommendation";
 
 export default defineComponent({
 	name: "settting",
 	setup() {
+        const helperData = reactive({
+			screenModelShow: false, // 投屏帮助
+			recommendationShow: false, // 建议
+		});
         // 加减评测频率
 		const operateHz = (type: number) => {
 			const minFrequency = state.baseFrequency - 10, maxFrequency = state.baseFrequency + 10
@@ -84,10 +89,23 @@ export default defineComponent({
                         </div>
                         <div class={styles.cellBtnBox}>
                             <img  src={headImg("tpbz.png")} />
-                            <img  src={headImg("yjfk.png")} />
+                            <img  src={headImg("yjfk.png")} onClick={() => (helperData.recommendationShow = true)} />
                         </div>
                     </div>  
                 </div>
+                <Popup
+					v-model:show={helperData.recommendationShow}
+					class="popup-custom van-scale center-closeBtn recommenBoxClass_drag"
+					transition="van-scale"
+					teleport="body"
+                    overlay-style={{background:'rgba(0, 0, 0, 0.3)'}}
+				>
+                    <Recommendation
+                        onClose={() => {
+                            helperData.recommendationShow = false;
+                        }}
+                    />
+				</Popup>
 			</div>
 		);
 	},

+ 2 - 2
src/page-instrument/view-detail/index.tsx

@@ -23,7 +23,7 @@ import FollowPractice, { followData } from "/src/view/follow-practice";
 import FollowModel from "../follow-model";
 import RecordingTime from "../custom-plugins/recording-time";
 import WorkIndex from "../custom-plugins/work-index";
-import TheMusicList from "../component/the-music-list";
+import TheMusicList, { isMusicList } from "../component/the-music-list";
 import { storeData } from "/src/store";
 import ViewFigner from "../view-figner";
 import { recalculateNoteData } from "/src/view/selection";
@@ -522,7 +522,7 @@ export default defineComponent({
             {/* 作业 */}
             {query.workRecord && <WorkIndex />}
             {/* 曲谱列表 */}
-            {state.playState == "play" || followData.start || evaluatingData.startBegin || query.workRecord || query.modelType || state.platform === IPlatform.PC || query.isCbs ? null : <TheMusicList />}
+            {isMusicList.value && <TheMusicList />}
           </>
         )}
         <Popup

+ 2 - 2
vite.config.ts

@@ -76,9 +76,9 @@ export default defineConfig({
         // target: "https://kt.colexiu.com",
         // target: "https://test.lexiaoya.cn",
         // target: "https://kt.colexiu.com",
-        target: "https://test.resource.colexiu.com", // 内容平台开发环境,内容平台开发,需在url链接上加上isCbs=true
+        //target: "https://test.resource.colexiu.com", // 内容平台开发环境,内容平台开发,需在url链接上加上isCbs=true
         //target: "https://dev.resource.colexiu.com",
-        // target: "https://dev.kt.colexiu.com",
+        target: "https://dev.kt.colexiu.com",
         //target: "https://mec.colexiu.com",
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/instrument/, ""),