浏览代码

评测记录和分享

liushengqiang 1 年之前
父节点
当前提交
1791a665d5
共有 37 个文件被更改,包括 1367 次插入5 次删除
  1. 二进制
      public/share-orchestra-evaluating/icons/avatar.png
  2. 二进制
      public/share-orchestra-evaluating/icons/dot.png
  3. 二进制
      public/share-orchestra-evaluating/icons/header.png
  4. 二进制
      public/share-orchestra-evaluating/icons/logo.png
  5. 二进制
      public/share-orchestra-evaluating/icons/qrcode.png
  6. 二进制
      public/share-orchestra-evaluating/icons/tag.png
  7. 二进制
      public/share-orchestra-evaluating/icons/videobg.png
  8. 272 0
      public/share-orchestra-evaluating/index.css
  9. 111 0
      public/share-orchestra-evaluating/index.html
  10. 10 0
      public/share-orchestra-evaluating/index.js
  11. 45 0
      report-share.html
  12. 19 0
      src/components/the-video/index.module.less
  13. 32 0
      src/components/the-video/index.tsx
  14. 1 1
      src/page-orchestra/evaluat-model/evaluat-share/index.tsx
  15. 2 2
      src/page-orchestra/header-top/index.module.less
  16. 57 0
      src/report-share/orchestra-share/App.tsx
  17. 14 0
      src/report-share/orchestra-share/again.svg
  18. 23 0
      src/report-share/orchestra-share/api.ts
  19. 53 0
      src/report-share/orchestra-share/button-normal.svg
  20. 15 0
      src/report-share/orchestra-share/explain.svg
  21. 134 0
      src/report-share/orchestra-share/index.module.less
  22. 210 0
      src/report-share/orchestra-share/index.tsx
  23. 23 0
      src/report-share/orchestra-share/main.ts
  24. 21 0
      src/report-share/orchestra-share/note.tsx
  25. 15 0
      src/report-share/orchestra-share/replay.svg
  26. 24 0
      src/report-share/orchestra-share/router.ts
  27. 9 0
      src/report-share/orchestra-share/share-top/image/arrow.svg
  28. 二进制
      src/report-share/orchestra-share/share-top/image/icon-back.png
  29. 二进制
      src/report-share/orchestra-share/share-top/image/icon-huifang.png
  30. 二进制
      src/report-share/orchestra-share/share-top/image/icon-shiyi.png
  31. 112 0
      src/report-share/orchestra-share/share-top/index.module.less
  32. 92 0
      src/report-share/orchestra-share/share-top/index.tsx
  33. 25 0
      src/report-share/orchestra-share/share-top/title/index.module.less
  34. 37 0
      src/report-share/orchestra-share/share-top/title/index.tsx
  35. 9 0
      src/report-share/orchestra-share/theme.css
  36. 二进制
      src/report-share/orchestra-share/videobg.png
  37. 2 2
      src/view/evaluating/index.tsx

二进制
public/share-orchestra-evaluating/icons/avatar.png


二进制
public/share-orchestra-evaluating/icons/dot.png


二进制
public/share-orchestra-evaluating/icons/header.png


二进制
public/share-orchestra-evaluating/icons/logo.png


二进制
public/share-orchestra-evaluating/icons/qrcode.png


二进制
public/share-orchestra-evaluating/icons/tag.png


二进制
public/share-orchestra-evaluating/icons/videobg.png


+ 272 - 0
public/share-orchestra-evaluating/index.css

@@ -0,0 +1,272 @@
+html, body{
+  margin: 0;
+  background: #ff8057;
+  min-height: 100vh;
+  background-image: url('./icons/header.png');
+  background-size: contain;
+  background-position: top center;
+  background-repeat: no-repeat;
+  font-family: PingFangSC-Regular, PingFang SC;
+  overflow-x: hidden;
+}
+
+:root{
+  --plyr-color-main: #ff8057;
+  --plyr-font-size-base: 30px;
+  --plyr-control-icon-size: 36px;
+  --plyr-range-thumb-height: 26px;
+  --plyr-control-spacing: 20px;
+  --plyr-font-size-small: 26px;
+  --plyr-video-background: transparent;
+}
+
+body{
+  padding-top: 1.80rem;
+  box-sizing: border-box;
+  padding-bottom: 0.10rem;
+}
+
+.content{
+  box-sizing: border-box;
+  width: 95%;
+  background-color: #fff;
+  border-radius: 0.10rem;
+  padding: 0.22rem 0.24rem;
+  margin: 0 2.5%;
+  position: relative;
+  overflow: hidden;
+  /* border: none;
+  box-shadow: none; */
+}
+
+.content .tag{
+  position: absolute;
+  top: -0.01rem;
+  right: 0.23rem;
+  width: 0.13rem;
+  height: 0.22rem;
+  background: url('./icons/tag.png') no-repeat center;
+  background-size: contain;
+}
+
+.content .userinfo{
+  display: flex;
+}
+
+.content .userinfo > img {
+  display: block;
+  width: 0.60rem;
+  height: 0.60rem;
+  margin-right: 0.15rem;
+  border-radius: 50%;
+}
+
+.content .userinfo .cont {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.content .userinfo .cont > p {
+  color: rgba(80, 80, 80, 1);
+  font-size: 0.14rem;
+  margin: 0;
+}
+
+.content .userinfo .cont > .name{
+  font-size: 0.18rem;
+  color: rgba(26, 26, 26, 1);
+}
+
+.content div.desc {
+  color: rgba(128, 128, 128, 1);
+  font-size: 0.14rem;
+  line-height: 1.5;
+  position: relative;
+  margin: 0;
+  margin-top: 0.20rem;
+  margin-left: 0.20rem;
+}
+
+.content div.desc::before {
+  content: "";
+  background: url('./icons/dot.png') no-repeat center;
+  background-size: contain;
+  display: block;
+  width: 0.06rem;
+  height: 0.06rem;
+  margin-right: 0.10rem;
+  position: absolute;
+  top: 0.06rem;
+  left: -0.14rem;
+}
+
+.content .tit{
+  font-size: 0.16rem;
+  color: #000;
+}
+
+.content .info{
+  font-size: 0.14rem;
+  color: #808080;
+}
+
+.video-container{
+  border-radius: 0.20rem;
+  border: 0.04rem solid #F3F3F3;
+  overflow: hidden;
+  margin-top: 0.17rem;
+}
+
+.video{
+  max-width: 100%;
+  width: 0.289rem;
+  margian: 0 auto;
+  display: block;
+}
+
+.plyr__control--overlaid{
+  background-color: rgba(0, 0, 0, .5)!important;
+}
+
+.plyr--stopped.plyr__poster-enabled .plyr__poster{
+  background-color: #fff!important;
+  background-size: 70%;
+}
+
+.line{
+  margin-top: 0.21rem;
+  width: 3.00rem;
+  height: 0.02rem;
+  border-top: 0.03rem dotted #ff8057;
+  position: relative;
+}
+
+.line::after,
+.line::before{
+  content: "";
+  display: block;
+  position: absolute;
+  width: 0.23rem;
+  height: 0.23rem;
+  border-radius: 100%;
+  background-color: #ff8057;
+  z-index: 2;
+}
+
+.line::after{
+  right: -0.46rem;
+  top: -0.12rem;
+}
+
+.line::before{
+  left: -0.38rem;
+  top: -0.12rem;
+}
+
+.app{
+  margin-top: 0.18rem;
+  display: flex;
+  justify-content: space-between;
+}
+
+.app-info {
+  padding: 0.10rem 0;
+  display: flex;
+  flex: 1;
+  flex-direction: column;
+  justify-content: space-around;
+}
+
+.app-title{
+  color: rgba(80, 80, 80, 1);
+  font-size: 0.18rem;
+  font-weight: bold;
+}
+
+.app-desc{
+  font-size: 0.16rem;
+  color: rgba(80, 80, 80, 1);
+}
+
+.app-desc > span{
+  color: #ff8057;
+  font-weight: bold;
+}
+
+.app-subtitle{
+  font-size: 0.12rem;
+  color: #fff;
+  background: #ff8057;
+  height: 0.20rem;
+  line-height: 0.20rem;
+  border-radius: 0.10rem;
+  padding-left: 0.05rem;
+  display: inline-block;
+  width: 1.70rem;
+  font-weight: bold;
+}
+
+.app > .img{
+  width: 0.96rem;
+  height: 0.96rem;
+  position: relative;
+  display: flex;
+}
+.app > .img #qrcode{
+  width: 100%;
+  height: 100%;
+}
+.app > .img .logo{
+  position: absolute;
+  top: .36rem;
+  left: .36rem;
+  width: .24rem;
+  height: .24rem;
+  border-radius: .04rem;
+}
+
+.video,
+.plyr__video-wrapper,
+.plyr,
+.plyr__poster,
+.plyr__video-wrapper{
+  border-radius: 0.20rem;
+  overflow: hidden;
+}
+
+.fraction{
+  display: flex;
+  margin: 0.10rem 0;
+  margin-left: 0.20rem;
+}
+
+.fraction .item{
+  display: flex;
+  color: #ff8057;
+  font-size: 0.10rem;
+  font-weight: bold;
+}
+
+.fraction .item .view{
+  flex: 1;
+  height: 0.16rem;
+  width: 1.37rem;
+  background: #F5F4F2;
+  border-radius: 0.04rem;
+  margin: 0 0.06rem;
+  position: relative;
+}
+
+.fraction .item .view>span{
+  display: block;
+  flex: 1;
+  height: 0.16rem;
+  width: 0%;
+  border-radius: 0.04rem;
+  background: linear-gradient(90deg, #FF9E7F 0%, #ff8057 100%);
+  position: absolute;
+  top: 0;
+  left: 0;
+}

+ 111 - 0
public/share-orchestra-evaluating/index.html

@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta name="description" content="酷乐秀APP,器乐学习的不二选择">
+  <title>酷乐秀</title>
+  <link rel="stylesheet" href="index.css">
+  <script src="../helpers/rem-fit.min.js"></script>
+  <script src="../helpers/qs.min.js"></script>
+  <script src="../helpers/html2canvas.js"></script>
+  <script src="../helpers/qrcode.js"></script>
+  <script>
+    var remFit = new RemFit(3.75,true)
+    remFit.init()
+    window.addEventListener('resize', function () {
+      remFit.init()
+    })
+    var parseSearch = Qs.parse(window.location.search, { ignoreQueryPrefix: true })
+  </script>
+  <!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/plyr@3.6.8/dist/plyr.css"> -->
+</head>
+<body>
+  <div class="content">
+    <div class="tag"></div>
+    <div class="userinfo">
+      <img id="avatar" crossOrigin="anonymous"/>
+      <div class="cont">
+        <p class="name" id="name"></p>
+        <p class="sub" id="subjectName"></p>
+      </div>
+    </div>
+    <div class="desc">
+      <div class="tit">我用小酷Ai智能评测获得了<span id="score"></span>分!</div>
+      <div class="info" id="examSongName"></div>
+    </div>
+    <div class="fraction" style="display: none;">
+      <div class="item" id="intonation">
+        <div class="decs">音准</div>
+        <div class="view"><span id="intonation-view"></span></div>
+        <div class="val" id="intonation-val"></div>
+      </div>
+    </div>
+    <div class="fraction" style="display: none;">
+      <div class="item" id="cadence">
+        <div class="decs">节奏</div>
+        <div class="view"><span id="cadence-view"></span></div>
+        <div class="val" id="cadence-val"></div>
+      </div>
+    </div>
+    <div class="fraction" style="display: none;">
+      <div class="item" id="integrity">
+        <div class="decs">节奏</div>
+        <div class="view"><span id="integrity-view"></span></div>
+        <div class="val" id="integrity-val"></div>
+      </div>
+    </div>
+    <div class="line"></div>
+    <div class="app">
+      <div class="app-info">
+        <div class="app-title">酷乐秀</div>
+        <div class="app-desc">器乐学习的<span>不二选择</span></div>
+        <div class="app-subtitle">小酷Ai见证你的成长!</div>
+      </div>
+      <div class="img">
+        <img id="qrcode" src="./icons/qrcode.png"/>
+        <img class="logo" src="./icons/logo.png"/>
+      </div>
+    </div>
+  </div>
+  <script>
+    document.getElementById('avatar').src = (decodeURIComponent(parseSearch.avatar) || './icons/avatar.png') + '?v=' + parseInt(Math.random() * 10000000)
+    document.getElementById('name').innerText = parseSearch.name || ''
+    document.getElementById('subjectName').innerText = parseSearch.subjectName || ''
+    document.getElementById('examSongName').innerText = parseSearch.examSongName || ''
+    document.getElementById('score').innerText = parseSearch.score || ''
+    if (parseSearch.intonation) {
+      document.getElementById('intonation').parentElement.style.display = 'flex'
+      document.getElementById('intonation-val').innerText = parseSearch.intonation || ''
+      document.getElementById('intonation-view').style.width = parseSearch.intonation + '%' || ''
+    }
+    if (parseSearch.cadence) {
+      document.getElementById('cadence').parentElement.style.display = 'flex'
+      document.getElementById('cadence-val').innerText = parseSearch.cadence || ''
+      document.getElementById('cadence-view').style.width = parseSearch.cadence + '%' || ''
+    }
+    if (parseSearch.integrity) {
+      document.getElementById('integrity').parentElement.style.display = 'flex'
+      document.getElementById('integrity-val').innerText = parseSearch.integrity || ''
+      document.getElementById('integrity-view').style.width = parseSearch.integrity + '%' || ''
+    }
+
+    window.addEventListener('load', function () {
+      QRCode.toDataURL(location.origin + '/accompany/colexiu-report-share.html?id=' + (parseSearch.id || '') + '&musicId=' + (parseSearch.musicId || '') + '&client=web', { errorCorrectionLevel: 'H', width: 192 }, function (err, val) {
+        console.log(val)
+        document.getElementById('qrcode').setAttribute('src', val)
+        html2canvas(document.body)
+        .then((canvas) => canvas.toDataURL())
+        .then(res => {
+          // console.log(res)
+          if (window.setPng) {
+            window.setPng(res)
+          }
+        })
+      })
+    })
+  </script>
+  <!-- <script src="./index.js"></script> -->
+</body>
+</html>

+ 10 - 0
public/share-orchestra-evaluating/index.js

@@ -0,0 +1,10 @@
+;(function() {
+  new Plyr(document.querySelector('.video'), {
+    controls: ['play-large', 'play', 'progress', 'current-time', 'airplay', 'fullscreen',],
+    fullscreen: {
+      enabled: true,
+      fallback: true,
+      iosNative: true,
+    }
+  })
+})()

+ 45 - 0
report-share.html

@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8" />
+  <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
+  <meta name="viewport"
+    content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
+  <title>管乐团云教练</title>
+  <!-- <link rel="icon" href="/favicon.ico" /> -->
+  <script src="/flexible.js" charset="UTF-8"></script>
+  <script src="/helpers/lottie.min.js" charset="UTF-8"></script>
+  <style>
+    #loading {
+      position: fixed;
+      z-index: 100;
+      top: 50%;
+      left: 50%;
+      width: 100Px;
+      height: 100Px;
+      transform: translate(-50%, -50%);
+      pointer-events: none;
+      transition: opacity .3s;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="app"></div>
+  <div id="loading"></div>
+  <script>
+    lottie.loadAnimation({
+      container: document.getElementById('loading'),
+      renderer: 'svg',
+      width: '30px',
+      height: '30px',
+      loop: true,
+      autoplay: true,
+      path: './loading.json'
+    });
+  </script>
+  <script type="module" src="/src/report-share/orchestra-share/main.ts"></script>
+</body>
+
+</html>

+ 19 - 0
src/components/the-video/index.module.less

@@ -0,0 +1,19 @@
+.wrap{
+    position: relative;
+    background-color: #fff;
+    border-radius: 14px;
+    width: 50vw;
+    min-height: 40vh;
+    overflow: hidden;
+}
+.video{
+    display: block;
+    width: 100%;
+}
+.playBtn{
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 48px;
+}

+ 32 - 0
src/components/the-video/index.tsx

@@ -0,0 +1,32 @@
+import { defineComponent, reactive, ref } from "vue";
+import styles from "./index.module.less";
+import { Icon } from "vant";
+export default defineComponent({
+	name: "the-video",
+    props:{
+        src: {
+            type: String,
+            default: ''
+        }
+    },
+	setup(props) {
+        const videoRef = ref()
+		const videoData = reactive({
+			play: false,
+		});
+        const toggle = () => {
+            videoData.play = !videoData.play
+            if (videoData.play) {
+                videoRef.value?.play()
+            } else {
+                videoRef.value?.pause()
+            }
+        }
+		return () => (
+			<div class={styles.wrap}>
+				<video ref={videoRef} preload="auto" controls class={styles.video} src={props.src}></video>
+				{/* <div class={styles.playBtn} onClick={toggle}>{videoData.play ? <Icon name="pause-circle" /> : <Icon name="play-circle" />}</div> */}
+			</div>
+		);
+	},
+});

+ 1 - 1
src/page-orchestra/evaluat-model/evaluat-share/index.tsx

@@ -28,7 +28,7 @@ export default defineComponent({
 				data.integrity = evaluatingData.resultData?.integrity;
 			}
 			// src.value = `${location.origin}/accompany/share-evaluating/index.html?${qs.stringify(data)}`;
-			src.value = `${location.origin}/share-colexiu-evaluating/index.html?${qs.stringify(data)}`;
+			src.value = `${location.origin}${location.pathname}share-orchestra-evaluating/index.html?${qs.stringify(data)}`;
 		};
 		const shareLoaded = (evt: Event) => {
 			const el = evt.target as HTMLIFrameElement;

+ 2 - 2
src/page-orchestra/header-top/index.module.less

@@ -17,8 +17,8 @@
 
     img {
         display: block;
-        width: 24px;
-        height: 24px;
+        width: 32px;
+        height: 32px;
     }
 }
 

+ 57 - 0
src/report-share/orchestra-share/App.tsx

@@ -0,0 +1,57 @@
+import request from "umi-request";
+import { computed, defineComponent, onBeforeMount, onMounted } from "vue";
+import { RouterView } from "vue-router";
+import { employeeQueryUserInfo, studentQueryUserInfo, teacherQueryUserInfo } from "./api";
+import { getQuery } from "/src/utils/queryString";
+import { setUserInfo, storeData } from "/src/store";
+import { getRandomKey, setBehaviorId, setToken } from "/src/utils";
+import { promisefiyPostMessage } from "/src/utils/native-message";
+import TheError from "/src/components/The-error";
+
+export default defineComponent({
+	name: "App",
+	setup() {
+		const query: any = getQuery();
+		/** 获取用户信息 */
+		const getUserInfo = async () => {
+			// const a = await request.get(`/student/queryUserInfo`)
+			// console.log(a)
+			if (storeData.platformType === "WEB") {
+				return await employeeQueryUserInfo();
+			} else if (storeData.platformType === "TEACHER") {
+				return await teacherQueryUserInfo();
+			}
+			return await studentQueryUserInfo();
+		};
+		const setUser = async () => {
+			const res = await getUserInfo();
+			const student = res?.data || {};
+			setUserInfo(student);
+			// console.log("🚀 ~ res:", student);
+		};
+		onBeforeMount(async () => {
+			if (query.Authorization) {
+				setToken(query.Authorization);
+			} else {
+				// 获取token
+				const res = await promisefiyPostMessage({ api: "getToken" });
+				const content = res?.content;
+				if (content?.accessToken) {
+					setToken(content.tokenType + " " + content.accessToken);
+				}
+				console.log(content.tokenType + " " + content.accessToken);
+			}
+			setUser();
+			setBehaviorId(getRandomKey());
+		});
+		onMounted(() => {
+			const _loading = document.getElementById("loading");
+			_loading && document.body.removeChild(_loading);
+		});
+
+		const inited = computed(() => {
+			return storeData.status === "login";
+		});
+		return () => <>{storeData.status === "error" ? <TheError /> : inited.value ? <RouterView /> : null}</>;
+	},
+});

+ 14 - 0
src/report-share/orchestra-share/again.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="33px" height="33px" viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>button-normal备份</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="评测报告(节奏)" transform="translate(-741.000000, -13.000000)">
+            <g id="button-normal备份" transform="translate(741.000000, 13.000000)">
+                <rect id="button-normal" fill="#DEFFF9" x="0" y="0" width="33" height="33" rx="16.5"></rect>
+                <g id="编组" transform="translate(17.074156, 16.223239) rotate(-330.000000) translate(-17.074156, -16.223239) translate(9.574156, 7.973239)" fill="#2DC7AA" fill-rule="nonzero">
+                    <path d="M12.4993338,9.16618465 C12.4993338,9.35039905 12.4888969,9.53461345 12.4680233,9.71477918 C12.1904034,12.1581504 10.0717254,14.0569757 7.50008869,14.0569757 C4.73850152,14.0569757 2.5008436,11.8666463 2.5008436,9.16618465 C2.5008436,6.46572301 4.73850152,4.27741788 7.50008869,4.27741788 L7.50008869,6.11146454 L8.01566845,6.11146454 L11.6622994,3.05472011 L8.01566845,0 L7.50008869,0 L7.50008869,1.83404666 C4.46714375,1.83202233 1.73269236,3.61950931 0.572116057,6.36045764 C-0.590547623,9.10140596 0.0523615522,12.2553184 2.19608795,14.3525285 C4.33146487,16.4477143 7.56479709,17.0772822 10.370219,15.9416308 C13.000302,14.8748067 14.7724769,12.4537032 14.9791263,9.70668184 C14.9937379,9.5265161 15,9.34635038 15,9.16416032 L12.4993338,9.16416032 L12.4993338,9.16618465 Z" id="路径"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 23 - 0
src/report-share/orchestra-share/api.ts

@@ -0,0 +1,23 @@
+import request from "/src/utils/request";
+
+/** 获取学生信息 */
+export const studentQueryUserInfo = async () => {
+	return await request.get(`/user/getUserInfo`);
+};
+/** 获取老师信息 */
+export const teacherQueryUserInfo = () => {
+	return request.get(`/user/getUserInfo`);
+};
+/** 后台用户信息 */
+export const employeeQueryUserInfo = () => {
+	return request.get(`/user/getUserInfo`);
+};
+
+/** 获取曲谱信息 */
+export const sysMusicScoreAccompanimentQueryPage = (sysMusicScoreId: string) => {
+	return request.get("/musicSheet/detail/" + sysMusicScoreId);
+};
+/** 获取曲谱信息 */
+export const musicPracticeRecordGetLastEvaluationMusicalNotesPlayStats = (recordId: string) => {
+	return request.get("/musicPracticeRecord/getLastEvaluationMusicalNotesPlayStats", { params: { recordId } });
+};

+ 53 - 0
src/report-share/orchestra-share/button-normal.svg

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="126px" height="44px" viewBox="0 0 126 44" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>button-normal备份</title>
+    <defs>
+        <linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
+            <stop stop-color="#55F1CC" offset="0%"></stop>
+            <stop stop-color="#2DC7AA" offset="100%"></stop>
+        </linearGradient>
+        <rect id="path-2" x="0" y="0" width="126" height="41.592233" rx="20.7961165"></rect>
+        <filter x="-0.8%" y="-2.4%" width="101.6%" height="109.6%" filterUnits="objectBoundingBox" id="filter-3">
+            <feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feColorMatrix values="0 0 0 0 0.140022123   0 0 0 0 0.741724871   0 0 0 0 0.628417211  0 0 0 1 0" type="matrix" in="shadowOffsetOuter1"></feColorMatrix>
+        </filter>
+        <filter x="-1.6%" y="-4.8%" width="103.2%" height="114.4%" filterUnits="objectBoundingBox" id="filter-4">
+            <feGaussianBlur stdDeviation="1.5" in="SourceAlpha" result="shadowBlurInner1"></feGaussianBlur>
+            <feOffset dx="0" dy="1" in="shadowBlurInner1" result="shadowOffsetInner1"></feOffset>
+            <feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite>
+            <feColorMatrix values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.5 0" type="matrix" in="shadowInnerInner1"></feColorMatrix>
+        </filter>
+        <text id="text-5" font-family="STYuanti-SC-Bold, Yuanti SC" font-size="16" font-weight="bold" letter-spacing="0.914285714" fill="#FFFFFF">
+            <tspan x="39.1714286" y="25.5728155">查看回放</tspan>
+        </text>
+        <filter x="-2.6%" y="-4.5%" width="105.2%" height="118.2%" filterUnits="objectBoundingBox" id="filter-6">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0.161975631   0 0 0 0 0.702658833   0 0 0 0 0.594522193  0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="修改" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="评测报告" transform="translate(-343.000000, -282.000000)">
+            <g id="button-normal备份" transform="translate(343.000000, 282.000000)">
+                <g id="button-normal">
+                    <use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
+                    <use fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                </g>
+                <path d="M6.7918406,10.2536943 C9.41739329,16.8742088 12.7423351,20.184466 16.7666662,20.184466 C22.6640326,20.184466 99.6033159,20.184466 107.847557,20.184466 C113.343718,20.184466 117.705547,16.6376269 120.933045,9.54394855 C122.638541,16.3640284 123.3389,20.8519096 123.034122,23.0075923 C122.835918,24.4094822 121.398519,27.068378 118.721925,30.9842797 C115.553786,35.6193184 110.30151,38.3912624 104.687181,38.3912624 L20.3588579,38.3912624 C10.6413433,38.3912333 2.76374114,30.5136312 2.76374114,20.7961165 C2.76374114,20.7961165 2.76374114,20.7961165 2.76374114,20.7961165 C2.76374114,16.5579484 4.10644096,13.0438076 6.7918406,10.2536943 Z" id="矩形" fill="#29BD9D" opacity="0.499798729"></path>
+                <g id="编组-6" opacity="0.85" transform="translate(9.427979, 12.591438) rotate(-5.000000) translate(-9.427979, -12.591438) translate(1.807238, 3.717203)" fill="#FFFFFF">
+                    <ellipse id="椭圆形" opacity="0.882866269" transform="translate(9.202471, 6.069205) rotate(44.000000) translate(-9.202471, -6.069205) " cx="9.20247081" cy="6.06920508" rx="3.66990291" ry="4.89320388"></ellipse>
+                    <ellipse id="椭圆形备份-3" opacity="0.882866269" transform="translate(3.884379, 13.848995) rotate(44.000000) translate(-3.884379, -13.848995) " cx="3.8843788" cy="13.8489954" rx="2.44660194" ry="3.05825243"></ellipse>
+                </g>
+                <g id="查看回放" fill="#FFFFFF" fill-opacity="1">
+                    <use filter="url(#filter-6)" xlink:href="#text-5"></use>
+                    <use xlink:href="#text-5"></use>
+                </g>
+                <g id="编组" transform="translate(27.112905, 20.771792) rotate(-330.000000) translate(-27.112905, -20.771792) translate(20.071803, 12.787633)" fill="#FFFFFF" fill-rule="nonzero">
+                    <path d="M11.7312795,8.87082159 C11.7312795,9.04910003 11.721484,9.22737847 11.7018929,9.4017387 C11.4413321,11.7663769 9.45284187,13.6040162 7.03922611,13.6040162 C4.44733189,13.6040162 2.34717272,11.484266 2.34717272,8.87082159 C2.34717272,6.25737725 4.44733189,4.13958614 7.03922611,4.13958614 L7.03922611,5.91453409 L7.52312472,5.91453409 L10.9456789,2.9562875 L7.52312472,1.42108547e-14 L7.03922611,1.42108547e-14 L7.03922611,1.77494795 C4.1926484,1.77298886 1.62622254,3.50287744 0.536960888,6.15550386 C-0.554259878,8.80813028 0.0491440596,11.8604139 2.06114358,13.8900453 C4.06530667,15.9177176 7.09995833,16.5269989 9.7329937,15.4279417 C12.2014644,14.3954941 13.8647434,12.052406 14.0586947,9.39390228 C14.0724084,9.21954205 14.0782857,9.04518183 14.0782857,8.8688625 L11.7312795,8.8688625 L11.7312795,8.87082159 Z" id="路径"></path>
+                    <path d="M12.9067417,10.1697074 C13.555205,10.1697074 14.0822039,9.64270847 14.0822039,8.99424512 C14.0822039,8.34578178 13.555205,7.81878291 12.9067417,7.81878291 C12.2582784,7.81878291 11.7312795,8.3457818 11.7312795,8.99424512 C11.7312795,9.64270845 12.2582784,10.1697074 12.9067417,10.1697074 Z" id="路径"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 15 - 0
src/report-share/orchestra-share/explain.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="33px" height="33px" viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>button-normal备份 2</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="评测报告(节奏)" transform="translate(-690.000000, -13.000000)">
+            <g id="button-normal备份-2" transform="translate(690.000000, 13.000000)">
+                <rect id="button-normal" fill="#FFEFE5" x="0" y="0" width="33" height="33" rx="16.5"></rect>
+                <g id="编组" transform="translate(7.000000, 7.000000)" fill="#FF8800" fill-rule="nonzero" stroke="#FF8800">
+                    <path d="M9.5,0 C4.25322823,0 0,4.25324263 0,9.5 C0,14.7467574 4.25324678,19 9.5,19 C14.7467532,19 19,14.7467574 19,9.5 C19,4.25324263 14.7467347,0 9.5,0 Z M9.49999096,17.5000093 C5.08224075,17.5000093 1.50001028,13.9181622 1.50001028,9.50000928 C1.50001028,5.08182021 5.08222266,1.50000928 9.49999096,1.50000928 C13.9185552,1.50000928 17.4999897,5.08182019 17.4999897,9.50000928 C17.4999897,13.9181622 13.9185552,17.5000093 9.49999096,17.5000093 Z" id="形状"></path>
+                    <path d="M9.60242663,4.40820056 C8.69574736,4.40820056 7.97469307,4.6677898 7.4389318,5.18715088 C6.90315395,5.69822914 6.63526502,6.415299 6.63526502,7.33837705 L8.04487302,7.33837705 C8.04487302,6.81089915 8.14788552,6.40699959 8.35389392,6.12666179 C8.58443543,5.78879242 8.97191911,5.61974983 9.51601299,5.61974983 C9.94462863,5.61974983 10.2743981,5.73539395 10.5053048,5.96591863 C10.7358463,6.21324134 10.8512913,6.53471105 10.8512913,6.9303112 C10.8512913,7.24366409 10.739996,7.53608583 10.5173721,7.8081242 L10.3691112,7.9813165 C9.56127805,8.69838636 9.0790813,9.22189715 8.9224877,9.55148369 C8.75761128,9.87295341 8.67534734,10.2768696 8.67534736,10.763033 L8.67534736,10.9362087 L10.0970393,10.9362087 L10.0970393,10.763033 C10.0970393,10.4745617 10.1589364,10.2066731 10.2826809,9.95935037 C10.3977774,9.72050967 10.5626538,9.51431889 10.7769782,9.34134239 C11.3538881,8.83856355 11.7085558,8.51294411 11.8402179,8.36446749 C12.1450891,7.96075053 12.2978816,7.45383858 12.2978816,6.84373165 C12.2978816,6.08551327 12.050791,5.49202176 11.5561285,5.06338994 C11.0697654,4.62665788 10.4185259,4.40820056 9.60242663,4.40820056 Z M8.69988046,12.8015559 C8.51877034,12.9747482 8.42784181,13.1971561 8.42784181,13.4692111 C8.42784181,13.7412494 8.51877034,13.9638565 8.69988046,14.1368496 C8.8979878,14.3183413 9.1243464,14.4088879 9.38018456,14.4088879 C9.6522066,14.4088879 9.87859838,14.3223084 10.0600737,14.1493153 C10.2494998,13.976123 10.3445946,13.7495489 10.3445946,13.4692111 C10.3445946,13.2056547 10.2536329,12.9830477 10.0725228,12.8015559 C9.89104754,12.6285628 9.66015745,12.5419667 9.38018456,12.5419667 C9.11606357,12.5419667 8.88967177,12.6285628 8.69988046,12.8015559 Z" id="形状"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 134 - 0
src/report-share/orchestra-share/index.module.less

@@ -0,0 +1,134 @@
+.skeleton {
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100vw;
+  height: 100vh;
+  padding: 20px 30px;
+  background-color: #fff;
+  z-index: 10;
+  --van-skeleton-paragraph-height: .8rem;
+}
+
+.detail {
+  width: 100vw;
+  height: 100vh;
+  overflow: hidden;
+  --header-height: 62px;
+  background: var(--container-background);
+
+  .headHeight {
+    position: fixed;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: var(--header-height);
+    transition: margin .3s;
+    z-index: 10;
+
+    &.headHide {
+      margin-top: calc(0Px - var(--header-height));
+    }
+  }
+
+  .container {
+    position: relative;
+    height: 100vh;
+    margin: 0 10px;
+    border-radius: 10px;
+    padding-top: calc(var(--header-height) + 20px);
+    overflow-x: hidden;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar {
+      width: 0;
+      display: none;
+    }
+
+    :global {
+      #musicAndSelection {
+        overflow: auto;
+      }
+    }
+  }
+}
+
+.shareBox {
+  background-color: rgba(248, 242, 232, 1);
+
+  :global {
+
+    #cursorImg-0 {
+      display: none !important;
+    }
+
+    #selectionBox {
+      pointer-events: none;
+    }
+  }
+}
+
+.demos {
+  position: fixed;
+  top: var(--header-height);
+  right: 10px;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  padding: 6px 10px;
+  border-radius: 20px;
+  background-color: #E2F6F1;
+  z-index: 1;
+
+  &>div {
+    display: flex;
+    align-items: center;
+    margin-right: 6px;
+
+    &>span {
+      margin-left: 4px;
+    }
+  }
+}
+
+.right {
+  path {
+    fill: #01C1B5;
+    stroke: #01C1B5;
+  }
+}
+
+.wrong {
+  path {
+    fill: #FF4444;
+    stroke: #FF4444;
+  }
+}
+
+.notPlay {
+  path {
+    fill: #000;
+    stroke: #000;
+  }
+}
+
+.cadence_wrong {
+  path {
+    fill: #067DD7;
+    stroke: #067DD7;
+  }
+}
+
+.intonation_wrong {
+  path {
+    fill: #FFAB25;
+    stroke: #FFAB25;
+  }
+}
+
+.integrity_wrong {
+  path {
+    fill: #CC75FF;
+    stroke: #CC75FF;
+  }
+}

+ 210 - 0
src/report-share/orchestra-share/index.tsx

@@ -0,0 +1,210 @@
+import { Skeleton } from "vant";
+import { defineComponent, onBeforeMount, onBeforeUnmount, onMounted, reactive, Transition } from "vue";
+import { formateTimes } from "../../helpers/formateMusic";
+import state, { isRhythmicExercises } from "../../state";
+import { setGlobalData } from "../../utils";
+import MusicScore, { resetMusicScore } from "../../view/music-score";
+import styles from "./index.module.less";
+import { api_cloudLoading, api_setStatusBarVisibility, isSpecialShapedScreen } from "/src/helpers/communication";
+import { getQuery } from "/src/utils/queryString";
+import { mappingVoicePart, subjectFingering } from "/src/view/fingering/fingering-config";
+import { musicPracticeRecordGetLastEvaluationMusicalNotesPlayStats, sysMusicScoreAccompanimentQueryPage } from "./api";
+import ShareTop from "./share-top";
+import Note from "./note";
+import { addMeasureScore } from "/src/view/evaluating";
+
+const colorsClass: any = {
+	RIGHT: styles.right,
+	WRONG: styles.wrong,
+	NOT_PLAY: styles.notPlay,
+	CADENCE_WRONG: styles.cadence_wrong,
+	INTONATION_WRONG: styles.intonation_wrong,
+	INTEGRITY_WRONG: styles.integrity_wrong,
+};
+
+export default defineComponent({
+	name: "music-list",
+	setup() {
+		const query: any = getQuery();
+		const scoreData: any = reactive({
+			videoFilePath: "", // 回放视频路径
+			cadence: 0,
+			integrity: 0,
+			intonation: 0,
+			score: 0,
+			heardLevel: "",
+		});
+
+		const detailData = reactive({
+			isLoading: true,
+			paddingLeft: "",
+			headerHide: false,
+			musicalNotesPlayStats: [] as any[],
+			userMeasureScore: {} as any,
+		});
+		const getAPPData = async () => {
+			const screenData = await isSpecialShapedScreen();
+			if (screenData?.content) {
+				// console.log("🚀 ~ screenData:", screenData.content);
+				const { isSpecialShapedScreen, notchHeight } = screenData.content;
+				if (isSpecialShapedScreen) {
+					detailData.paddingLeft = 25 + "px";
+				}
+			}
+		};
+		onBeforeMount(() => {
+			getAPPData();
+			api_setStatusBarVisibility();
+		});
+		// console.log(route.params, query)
+		/** 获取曲谱数据 */
+		const getMusicInfo = (res: any) => {
+			const index = state.partIndex;
+			const musicInfo = {
+				...res.data,
+				...res.data.background[index],
+			};
+			// console.log("🚀 ~ musicInfo:", musicInfo);
+			setState(musicInfo, index);
+			setCustom();
+			detailData.isLoading = false;
+		};
+
+		const setState = (data: any, index: number) => {
+			// console.log("🚀 ~ data:", data)
+			state.scrollContainer = "scrollContainer";
+			state.detailId = data.id;
+			state.xmlUrl = data.xmlFileUrl;
+			state.partIndex = index;
+			state.subjectId = data.musicSubject;
+			state.categoriesId = data.categoriesId;
+			state.categoriesName = data.musicTagNames;
+			state.enableEvaluation = data.canEvaluate ? true : false;
+			state.examSongId = data.id + "";
+			state.examSongName = data.musicSheetName;
+			// 解析扩展字段
+			if (data.extConfigJson) {
+				try {
+					state.extConfigJson = JSON.parse(data.extConfigJson as string);
+				} catch (error) {
+					console.error("解析扩展字段错误:", error);
+				}
+			}
+			state.isOpenMetronome = data.mp3Type === "MP3_METRONOME" ? true : false;
+			state.needTick = data.isOpenMetronome;
+			state.isShowFingering = data.showFingering ? true : false;
+			state.music = data.audioFileUrl;
+			state.accompany = data.metronomeUrl || data.metronomeUrl;
+			state.midiUrl = data.midiUrl;
+			state.parentCategoriesId = data.musicTag;
+			state.playMode = data.audioType === "MP3" ? "mp3" : "midi";
+			state.originSpeed = state.speed = data.speed;
+			state.track = data.track;
+			state.enableNotation = data.notation ? true : false;
+
+			// 映射声部ID
+			state.subjectId = mappingVoicePart(state.subjectId as any, "ORCHESTRA");
+			// console.log("🚀 ~ state.subjectId:", state.subjectId);
+			// 是否打击乐
+			state.isPercussion = state.subjectId == 23 || state.subjectId == 113 || state.subjectId == 121 || isRhythmicExercises();
+
+			// 设置指法
+			state.fingeringInfo = subjectFingering(state.subjectId);
+			// console.log("🚀 ~ state.fingeringInfo:", state.fingeringInfo, state.subjectId, state.track)
+			// state.isOpenPrepare = true
+		};
+
+		const setCustom = () => {
+			if (state.extConfigJson.multitrack) {
+				setGlobalData("multitrack", state.extConfigJson.multitrack);
+			}
+		};
+
+		onMounted(async () => {
+			(window as any).appName = "colexiu";
+			const res = await musicPracticeRecordGetLastEvaluationMusicalNotesPlayStats(query.id);
+			state.partIndex = Number(res?.data?.partIndex);
+			detailData.musicalNotesPlayStats = res?.data?.musicalNotesPlayStats?.notesData || [];
+			detailData.userMeasureScore = res?.data?.userMeasureScore || {};
+      for(let key in scoreData){
+        scoreData[key] = res?.data?.[key];
+      }
+			Promise.all([sysMusicScoreAccompanimentQueryPage(res?.data?.musicalNotesPlayStats?.examSongId)]).then((values) => {
+				getMusicInfo(values[0]);
+			});
+		});
+
+		const setPathColor = () => {
+			for (const note of detailData.musicalNotesPlayStats) {
+				const active = state.times[note.musicalNotesIndex];
+				const svgEl = document.getElementById("vf-" + active.id);
+				svgEl?.classList.add(colorsClass[note.musicalErrorType]);
+			}
+		};
+		const setMearureColor = () => {
+			for (let key in detailData.userMeasureScore) {
+				addMeasureScore(detailData.userMeasureScore[key], false);
+			}
+		};
+
+		/** 渲染完成 */
+		const handleRendered = (osmd: any) => {
+			state.musicRendered = true;
+			state.osmd = osmd;
+			state.times = formateTimes(osmd);
+			console.log("🚀 ~ state.times:", state.times);
+			setPathColor();
+			setMearureColor();
+			api_cloudLoading();
+		};
+		onMounted(() => {
+			window.addEventListener("resize", resetMusicScore);
+		});
+		onBeforeUnmount(() => {
+			window.removeEventListener("resize", resetMusicScore);
+		});
+
+		return () => (
+			<div class={[styles.shareBox, styles.detail, state.setting.eyeProtection && "eyeProtection"]} style={{ paddingLeft: detailData.paddingLeft }}>
+				{!state.musicRendered && (
+					<div class={styles.skeleton}>
+						<Skeleton class={styles.skeleton} row={8} />
+					</div>
+				)}
+				<div class={[styles.headHeight, detailData.headerHide && styles.headHide]} onClick={(e: Event) => e.stopPropagation()}>
+					<Transition name="van-slide-down">{state.musicRendered && <ShareTop scoreData={scoreData} />}</Transition>
+				</div>
+				<div id="scrollContainer" class={[styles.container, !state.setting.displayCursor && "hideCursor"]}>
+					<div class={styles.demos}>
+						<div>
+							<Note fill="#01C1B5" />
+							<span>演奏正确</span>
+						</div>
+						<div>
+							<Note fill="#067DD7" />
+							<span>节奏错误</span>
+						</div>
+						{!state.isPercussion ? (
+							<>
+								<div>
+									<Note fill="#FFAB25" />
+									<span>音准错误</span>
+								</div>
+								<div>
+									<Note fill="#CC75FF" />
+									<span>完成度不足</span>
+								</div>
+							</>
+						) : null}
+						<div>
+							<Note fill="#000" />
+							<span>未演奏</span>
+						</div>
+					</div>
+					{/* 曲谱渲染 */}
+					{!detailData.isLoading && <MusicScore onRendered={handleRendered} />}
+				</div>
+			</div>
+		);
+	},
+});

+ 23 - 0
src/report-share/orchestra-share/main.ts

@@ -0,0 +1,23 @@
+import "vant/lib/index.css";
+import "@varlet/ui/es/popup/style/index";
+import "@varlet/ui/es/snackbar/style/index";
+import "@varlet/ui/es/cell/style/index";
+import "@varlet/ui/es/switch/style/index";
+import { createApp } from "vue";
+import "/src/style.css";
+import App from "./App";
+import router from "./router";
+import "./theme.css";
+import { setStoreData } from "/src/store";
+
+(function () {
+	const u = navigator.userAgent;
+	setStoreData({
+		isApp: u.includes("ORCHESTRAAPPI") || u.includes("ORCHESTRAAPPA"),
+		platformApi: u.includes("ORCHESTRATEACHER") ? "/api-teacher" : u.includes("ORCHESTRASTUDENT") ? "/api-student" : "/api-backend",
+		platformType: "STUDENT", // u.includes("ORCHESTRATEACHER") ? "TEACHER" : u.includes("ORCHESTRASTUDENT") ? "STUDENT" : "WEB",
+		proxy: import.meta.env.DEV ? "/orchestra" : "",
+	});
+})();
+
+createApp(App).use(router).mount("#app");

+ 21 - 0
src/report-share/orchestra-share/note.tsx

@@ -0,0 +1,21 @@
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+  name: 'NoteSvg',
+  props: {
+    fill: String
+  },
+  render() {
+    return (
+      <svg width="7px" height="23px" viewBox="0 0 7 23" version="1.1" xmlns="http://www.w3.org/2000/svg" >
+          <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+              <g transform="translate(-55.000000, -24.000000)">
+                  <g transform="translate(55.000000, 24.000000)" fill={this.fill}>
+                      <path d="M1.95251677,0.68258909 C3.68583115,-0.400505943 5.78379192,-0.169765229 6.63844331,1.1979629 C7.4930947,2.56569103 6.78079761,4.55247575 5.04748323,5.63557079 C3.85503595,6.38069455 2.49000663,6.50399819 1.47594704,6.06306368 L1.47635248,22.0768926 L0.0162402201,22.0768926 L0.0154715991,4.11169688 C-0.117424115,2.8976469 0.612367024,1.52000759 1.95251677,0.68258909 Z" id="形状结合" transform="translate(3.500000, 11.038446) scale(-1, -1) translate(-3.500000, -11.038446) "></path>
+                  </g>
+              </g>
+          </g>
+      </svg>
+    )
+  }
+})

+ 15 - 0
src/report-share/orchestra-share/replay.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="33px" height="33px" viewBox="0 0 33 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>button-normal备份 3</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="评测报告(节奏)" transform="translate(-639.000000, -13.000000)">
+            <g id="button-normal备份-3" transform="translate(639.000000, 13.000000)">
+                <rect id="button-normal" fill="#EFF9FF" x="0" y="0" width="33" height="33" rx="16.5"></rect>
+                <g id="编组" transform="translate(8.000000, 8.000000)">
+                    <path d="M6,11.2838533 L6,5.70732273 C6,5.16019142 6.56518082,4.82349524 7.0294365,5.09706089 L11.6518082,7.87480443 C12.1160639,8.14837008 12.1160639,8.84280597 11.6518082,9.11637162 L7.0294365,11.8941152 C6.56518082,12.1887243 6,11.8309846 6,11.2838533 Z" id="形状" fill="#2AAAE9" fill-rule="nonzero"></path>
+                    <path d="M8.5,17 C13.1944204,17 17,13.1944204 17,8.5 C17,3.80557963 13.1944204,0 8.5,0 C6.7502475,0 5.12397972,0.528700969 3.77223303,1.43506655 C2.5629265,2.24592396 1.57333404,3.35904678 0.911600214,4.66629045 C0.328527255,5.81814095 0,7.12070465 0,8.5" id="椭圆形" stroke="#2AAAE9" stroke-width="2.5" stroke-linecap="round"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 24 - 0
src/report-share/orchestra-share/router.ts

@@ -0,0 +1,24 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
+import Home from "./index";
+import Notfind from "../../view/notfind";
+
+const routes: RouteRecordRaw[] = [
+	{
+		path: "/",
+		component: Home,
+	},
+	{
+		path: "/:pathMatch(.*)*",
+		component: Notfind,
+		meta: {
+			title: "404 Not Fund",
+		},
+	},
+];
+
+const router = createRouter({
+	history: createWebHashHistory(),
+	routes,
+});
+
+export default router;

文件差异内容过多而无法显示
+ 9 - 0
src/report-share/orchestra-share/share-top/image/arrow.svg


二进制
src/report-share/orchestra-share/share-top/image/icon-back.png


二进制
src/report-share/orchestra-share/share-top/image/icon-huifang.png


二进制
src/report-share/orchestra-share/share-top/image/icon-shiyi.png


+ 112 - 0
src/report-share/orchestra-share/share-top/index.module.less

@@ -0,0 +1,112 @@
+.headerTop {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    flex-shrink: 0;
+    padding: 8px 10px;
+    padding-bottom: 0;
+}
+
+.back {
+    display: flex;
+    align-items: center;
+    height: 100%;
+    padding: 0 11px 0 6px;
+
+    img {
+        display: block;
+        width: 32px;
+        height: 32px;
+    }
+}
+
+.left {
+    display: flex;
+    align-items: center;
+}
+
+.center {
+    display: flex;
+    align-items: center;
+
+    .cItem {
+        text-align: center;
+        padding: 0 12px;
+        white-space: nowrap;
+
+        &>div:first-child {
+            font-size: 12px;
+            color: #333333;
+            line-height: 14px;
+            margin-bottom: 6px;
+            font-weight: bold;
+        }
+
+        &>div:last-child {
+            font-size: 8px;
+            color: #777777;
+            line-height: 12px;
+            padding: 4px 8px;
+            border-radius: 14px;
+        }
+    }
+
+    .cItem:not(:last-child) {
+        border-right: 1px solid #EBDABF;
+    }
+
+    .active {
+        &>div:first-child {
+            color: #FF8057 !important;
+        }
+    }
+}
+
+.right {
+    display: flex;
+    align-items: center;
+
+    .btn {
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        font-size: 11px;
+        line-height: 16px;
+        font-weight: 400;
+        padding: 0 6px;
+
+        .iconBtn {
+            display: block;
+            width: 25px;
+            height: 25px;
+        }
+
+        span {
+            white-space: nowrap;
+        }
+
+        .btnWrap {
+            position: relative;
+            width: 25px;
+            height: 25px;
+        }
+    }
+}
+
+.popup {
+    :global {
+        .van-popup__close-icon {
+            top: 0;
+            right: -30px;
+            background-color: #fff;
+            border-radius: 50%;
+            padding: 4px;
+            font-size: 16px;
+            color: var(--van-primary-color);
+        }
+    }
+}

+ 92 - 0
src/report-share/orchestra-share/share-top/index.tsx

@@ -0,0 +1,92 @@
+import { computed, defineComponent, onBeforeUnmount, onMounted, reactive, ref, toRefs } from "vue";
+import styles from "./index.module.less";
+
+import Title from "./title";
+import { api_back } from "/src/helpers/communication";
+import state from "/src/state";
+import iconBack from "./image/icon-back.png";
+import iconShiyi from "./image/icon-shiyi.png";
+import iconhuifang from "./image/icon-huifang.png";
+import { Icon, Popup } from "vant";
+import TheVideo from "/src/components/the-video";
+
+type IItemType = "intonation" | "cadence" | "integrity";
+
+export default defineComponent({
+	name: "header-top",
+	props: {
+		scoreData: {
+			type: Object,
+			default: () => ({}),
+		},
+	},
+	setup(props) {
+		const { scoreData } = toRefs(props);
+		const level: any = {
+			BEGINNER: "入门级",
+			ADVANCED: "进阶级",
+			PERFORMER: "大师级",
+		};
+		// console.log("🚀 ~ scoreData:", scoreData.value)
+		const itemType = ref<IItemType>("intonation");
+		const showVideo = ref(false);
+		/** 返回 */
+		const handleBack = () => {
+			api_back();
+		};
+
+		const handleChange = (type: IItemType) => {
+			// itemType.value = type;
+		};
+
+		return () => (
+			<div class={styles.headerTop}>
+				<div class={styles.left}>
+					<div class={styles.back} onClick={handleBack}>
+						<img src={iconBack} />
+					</div>
+					<Title text={state.examSongName} rightView={false} />
+				</div>
+				<div class={styles.center}>
+					<div class={styles.cItem}>
+						<div>{level[scoreData.value.heardLevel]}</div>
+						<div>难度</div>
+					</div>
+					<div class={styles.cItem}>
+						<div>{scoreData.value.score}分</div>
+						<div>评测分数</div>
+					</div>
+					{state.isPercussion ? null : (
+						<>
+							<div onClick={() => handleChange("intonation")} class={[styles.cItem, itemType.value === "intonation" && styles.active]}>
+								<div>{scoreData.value.intonation}分</div>
+								<div>音准</div>
+							</div>
+							<div onClick={() => handleChange("cadence")} class={[styles.cItem, itemType.value === "cadence" && styles.active]}>
+								<div style={{ color: "#FF4E19" }}>{scoreData.value.cadence}分</div>
+								<div>节奏</div>
+							</div>
+							<div onClick={() => handleChange("integrity")} class={[styles.cItem, itemType.value === "integrity" && styles.active]}>
+								<div style={{ color: "#4EA1FF" }}>{scoreData.value.integrity}分</div>
+								<div>完成度</div>
+							</div>
+						</>
+					)}
+				</div>
+				<div class={styles.right}>
+					<div style={{display: scoreData.value.videoFilePath ? '' : 'none'}} class={styles.btn} onClick={() => (showVideo.value = true)}>
+						<img class={styles.iconBtn} src={iconhuifang} />
+						<span>回放</span>
+					</div>
+					{/* <div class={styles.btn}>
+						<img class={styles.iconBtn} src={iconShiyi} />
+						<span>释义</span>
+					</div> */}
+				</div>
+				<Popup class={["popup-custom", "van-scale", styles.popup]} transition="van-scale" v-model:show={showVideo.value} closeable>
+					<TheVideo src={showVideo.value ? scoreData.value.videoFilePath : ''} />
+				</Popup>
+			</div>
+		);
+	},
+});

+ 25 - 0
src/report-share/orchestra-share/share-top/title/index.module.less

@@ -0,0 +1,25 @@
+.container {
+  width: 20vw;
+  height: 31px;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  border-radius: 18px;
+  padding: 6px;
+
+  .noticeBar {
+    flex: 1;
+    padding: 0 6px;
+  }
+}
+
+.icon {
+  width: 26px;
+  height: 26px;
+  flex-shrink: 0;
+}
+
+.status {
+  margin-left: auto;
+  flex-shrink: 0;
+}

+ 37 - 0
src/report-share/orchestra-share/share-top/title/index.tsx

@@ -0,0 +1,37 @@
+import { defineComponent } from 'vue'
+import { NoticeBar } from 'vant'
+import styles from './index.module.less'
+
+import ArrowIcon from '../image/arrow.svg'
+
+export default defineComponent({
+  name: 'detail-title',
+  props: {
+    text: {
+      type: String,
+      default: ''
+    },
+    rightView: {
+      type: Boolean,
+      default: true,
+    },
+    onClick: {
+      type: Function,
+    } as any
+  },
+  render() {
+    return (
+      <div class={styles.container}>
+        <NoticeBar
+          text={this.text}
+          color="#000"
+          class={styles.noticeBar}
+          background="none"
+        />
+        {this.rightView ? (
+          <img class={styles.status} src={ArrowIcon}/>
+        ) : null}
+      </div>
+    )
+  }
+})

+ 9 - 0
src/report-share/orchestra-share/theme.css

@@ -0,0 +1,9 @@
+:root {
+    --van-primary-color: #ff8057;
+    --color-primary    : #ff8057;
+    --active-stave-box    : rgba(255, 159, 88, .19);
+}
+
+.vf-StaveSection {
+    display: none;
+}

二进制
src/report-share/orchestra-share/videobg.png


+ 2 - 2
src/view/evaluating/index.tsx

@@ -137,11 +137,11 @@ export const handlePerformDetection = async () => {
 };
 
 /** 记录小节分数 */
-const addMeasureScore = (measureScore: any) => {
+export const addMeasureScore = (measureScore: any, show = true) => {
 	evaluatingData.evaluatings[measureScore.measureRenderIndex] = {
 		...measureScore,
 		leve: getLeveByScoreMeasure(measureScore.score),
-		show: true,
+		show,
 	};
 	// console.log("🚀 ~ measureScore:", evaluatingData.evaluatings[measureScore.measureRenderIndex])
 };

部分文件因为文件数量过多而无法显示