|
@@ -1,95 +1,14 @@
|
|
|
-import { defineComponent, nextTick, reactive, watch, toRef } from "vue";
|
|
|
-import styles from "./index.module.less";
|
|
|
-import iconClose from "../image/close2.svg";
|
|
|
-import {
|
|
|
- Cell,
|
|
|
- Field,
|
|
|
- NoticeBar,
|
|
|
- Popup,
|
|
|
- Radio,
|
|
|
- RadioGroup,
|
|
|
- Slider,
|
|
|
- Switch,
|
|
|
- Tab,
|
|
|
- Tabs,
|
|
|
- closeToast,
|
|
|
- showLoadingToast,
|
|
|
- showToast,
|
|
|
-} from "vant";
|
|
|
-import state, { IPlatform } from "/src/state";
|
|
|
-import { api_closeCamera, api_openCamera, api_savePicture } from "/src/helpers/communication";
|
|
|
-
|
|
|
-import iconInfo from "../image/info.svg";
|
|
|
-import iconDown from "../image/down.svg";
|
|
|
-import iconTv from "../image/tv.svg";
|
|
|
-import iconYijian from "../image/yijian.svg";
|
|
|
-import iconSubtract from "../image/subtract.png";
|
|
|
-import iconAdd from "../image/add.png";
|
|
|
-import ScreenModel from "../../custom-plugins/helper-model/screen-model";
|
|
|
-import Recommendation from "../../custom-plugins/helper-model/recommendation";
|
|
|
-import { svg2canvas } from "/src/utils/svg2canvas";
|
|
|
-import { getQuery } from "/src/utils/queryString";
|
|
|
-import { browser } from "/src/utils";
|
|
|
-import { storeData } from "/src/store";
|
|
|
-import useDrag from "/src/view/plugins/useDrag/index";
|
|
|
-import Dragbom from "/src/view/plugins/useDrag/dragbom";
|
|
|
-import { setGuidance } from "/src/page-instrument/custom-plugins/guide-page/api";
|
|
|
+import { defineComponent } from "vue";
|
|
|
+import styles from "./index.module.less"
|
|
|
+import { headImg } from "../image";
|
|
|
+import { headTopData } from "../index"
|
|
|
+import { Switch, showToast, Field } from "vant";
|
|
|
+import state from "/src/state"
|
|
|
|
|
|
export default defineComponent({
|
|
|
- name: "header-settting",
|
|
|
+ name: "settting",
|
|
|
setup() {
|
|
|
- const query = getQuery();
|
|
|
- const helperData = reactive({
|
|
|
- show: false,
|
|
|
- recommendationShow: false, // 建议
|
|
|
- });
|
|
|
- const downPng = () => {
|
|
|
- showLoadingToast({ message: "下载中", duration: 0 });
|
|
|
- setTimeout(async () => {
|
|
|
- const svg: any = document.getElementById("osmdSvgPage1")?.cloneNode(true);
|
|
|
- if (!svg) return showToast({ message: "保存失败", type: "fail" });
|
|
|
- const cw = svg.width.animVal.value;
|
|
|
- const ch = svg.height.animVal.value;
|
|
|
- const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
|
- rect.setAttribute("x", "0");
|
|
|
- rect.setAttribute("y", "0");
|
|
|
- rect.setAttribute("width", `${cw * 2}`);
|
|
|
- rect.setAttribute("height", `${ch * 2}`);
|
|
|
- rect.setAttribute("fill", "#fff");
|
|
|
- svg.prepend(rect);
|
|
|
- if (svg) {
|
|
|
- const _canvas = svg2canvas(svg.outerHTML);
|
|
|
- const browserInfo = browser();
|
|
|
- if (state.platform === IPlatform.PC || !browserInfo.isApp) {
|
|
|
- let el: any = document.createElement("a");
|
|
|
- // 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
|
|
|
- el.href = _canvas.toDataURL();
|
|
|
- el.download = state.examSongName;
|
|
|
-
|
|
|
- // 创建一个点击事件并对 a 标签进行触发
|
|
|
- const event = new MouseEvent("click");
|
|
|
- el.dispatchEvent(event);
|
|
|
- setTimeout(() => {
|
|
|
- showToast({ message: "保存成功", type: "success" });
|
|
|
- el = null;
|
|
|
- }, 300);
|
|
|
- } else {
|
|
|
- const base64 = _canvas.toDataURL("image/png", 1);
|
|
|
- const res = await api_savePicture({
|
|
|
- base64,
|
|
|
- });
|
|
|
- if (res?.content?.status === "success") {
|
|
|
- showToast({ message: "保存成功", type: "success" });
|
|
|
- } else {
|
|
|
- showToast({ message: "保存失败", type: "fail" });
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }, 500);
|
|
|
- };
|
|
|
-
|
|
|
- const formatterTimeMs = (value: any) => value = String(Math.min(3000, value));
|
|
|
- // 加减评测频率
|
|
|
+ // 加减评测频率
|
|
|
const operateHz = (type: number) => {
|
|
|
const minFrequency = state.baseFrequency - 10, maxFrequency = state.baseFrequency + 10
|
|
|
let currentFrequency = state.setting.frequency
|
|
@@ -102,228 +21,72 @@ export default defineComponent({
|
|
|
}
|
|
|
state.setting.frequency = currentFrequency >= 0 ? currentFrequency : 0
|
|
|
}
|
|
|
-
|
|
|
- const parentClassName = "recommenBoxClass_drag";
|
|
|
- const userId = storeData.user?.id ? String(storeData.user?.id) : '';
|
|
|
- const positionInfo = state.platform !== IPlatform.PC ? {
|
|
|
- styleDrag: { value: null }
|
|
|
- } : useDrag(
|
|
|
- [
|
|
|
- `${parentClassName} .top_drag`,
|
|
|
- `${parentClassName} .bom_drag`
|
|
|
- ],
|
|
|
- parentClassName,
|
|
|
- toRef(helperData, 'recommendationShow'),
|
|
|
- userId
|
|
|
- )
|
|
|
- // 完成拖动弹窗引导页
|
|
|
- const handleGuide = async () => {
|
|
|
- state.guideInfo.teacherDrag = true;
|
|
|
- try{
|
|
|
- const res = await setGuidance({guideTag:'guideInfo',guideValue:JSON.stringify(state.guideInfo)})
|
|
|
- }catch(e){
|
|
|
- console.log(e)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ const formatterTimeMs = (value: any) => value = String(Math.min(3000, value));
|
|
|
return () => (
|
|
|
- <div class={styles["header-settting"]}>
|
|
|
- <div class={[styles.content, state.platform === IPlatform.PC && styles.pcContent]}>
|
|
|
- { state.platform === IPlatform.PC && <div class={'top_drag'}></div> }
|
|
|
- <Tabs border animated swipeable>
|
|
|
- <Tab title="全局设置">
|
|
|
- <NoticeBar
|
|
|
- class={styles.noticebar}
|
|
|
- left-icon={iconInfo}
|
|
|
- text="全局设置会更改所有乐谱练习及评测"
|
|
|
- />
|
|
|
- <Cell title="护眼模式" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.eyeProtection}></Switch>,
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- {/* 节拍器 音量注释掉了 这里的代码也一并注释了 state.setting.beatVolume = state.setting.beatVolume || 50 */}
|
|
|
- {/* <Cell
|
|
|
- title="节拍器音量"
|
|
|
- class={styles.sliderWrap}
|
|
|
- center
|
|
|
- >
|
|
|
- {{
|
|
|
- extra: () => (
|
|
|
- <Slider
|
|
|
- class={[styles.slider, styles.sliderVolume]}
|
|
|
- min={0}
|
|
|
- max={100}
|
|
|
- v-model:modelValue={state.setting.beatVolume}
|
|
|
- >
|
|
|
- {{
|
|
|
- button: () => <div class={styles.sliderBtn}>{state.setting.beatVolume}</div>,
|
|
|
- }}
|
|
|
- </Slider>
|
|
|
- ),
|
|
|
- }}
|
|
|
- </Cell> */}
|
|
|
- <div class={styles.btnsbar}>
|
|
|
- {/* <div class={styles.btn} onClick={downPng}>
|
|
|
- <img src={iconDown} />
|
|
|
- 下载曲谱
|
|
|
- </div> */}
|
|
|
- <div class={styles.btn} onClick={() => (helperData.show = true)}>
|
|
|
- <img src={iconTv} />
|
|
|
- 投屏帮助
|
|
|
- </div>
|
|
|
- <div class={styles.btn} onClick={() => (helperData.recommendationShow = true)}>
|
|
|
- <img src={iconYijian} />
|
|
|
- 意见反馈
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </Tab>
|
|
|
- <Tab title="练习设置">
|
|
|
- <Cell title="循环播放" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.repeatAutoPlay}></Switch>,
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- <Cell class={[state.modeType == "evaluating" && styles.disabled]} title="显示指法" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.displayFingering} disabled={!state.fingeringInfo.name || !state.isShowFingering}></Switch>,
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- </Tab>
|
|
|
- <Tab title="评测设置">
|
|
|
- <Cell class={[query.workRecord && styles.disabled]} title="评测难度" center>
|
|
|
- {{
|
|
|
- extra: () => (
|
|
|
- <RadioGroup
|
|
|
- iconSize={20}
|
|
|
- class={styles.radioGroup}
|
|
|
- v-model={state.setting.evaluationDifficulty}
|
|
|
- >
|
|
|
- <Radio name="BEGINNER">入门</Radio>
|
|
|
- <Radio name="ADVANCED">进阶</Radio>
|
|
|
- <Radio name="PERFORMER">大师</Radio>
|
|
|
- </RadioGroup>
|
|
|
- ),
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
-
|
|
|
- <Cell title="延迟检测" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.soundEffect}></Switch>,
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- <Cell title="摄像头" center>
|
|
|
- {{
|
|
|
- extra: () => (
|
|
|
- <Switch
|
|
|
- v-model={state.setting.camera}
|
|
|
- onChange={ async (value) => {
|
|
|
- if (value) {
|
|
|
- const res = await api_openCamera();
|
|
|
- // 没有授权
|
|
|
- if (res?.content?.reson) {
|
|
|
- state.setting.camera = false
|
|
|
- }
|
|
|
- } else {
|
|
|
- api_closeCamera();
|
|
|
- }
|
|
|
- }}
|
|
|
- ></Switch>
|
|
|
- ),
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- <Cell
|
|
|
- style={{ display: state.setting.camera ? "" : "none" }}
|
|
|
- title="透明度"
|
|
|
- class={styles.sliderWrap}
|
|
|
- center
|
|
|
- >
|
|
|
- {{
|
|
|
- extra: () => (
|
|
|
- <Slider
|
|
|
- class={styles.slider}
|
|
|
- min={0}
|
|
|
- max={100}
|
|
|
- v-model:modelValue={state.setting.cameraOpacity}
|
|
|
- >
|
|
|
- {{
|
|
|
- button: () => <div class={styles.sliderBtn}>{state.setting.cameraOpacity}</div>,
|
|
|
- }}
|
|
|
- </Slider>
|
|
|
- ),
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- {/* <Cell title="保存到相册" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.saveToAlbum}></Switch>,
|
|
|
- }}
|
|
|
- </Cell> */}
|
|
|
- <Cell title="开启伴奏" center>
|
|
|
- {{
|
|
|
- extra: () => <Switch v-model={state.setting.enableAccompaniment}></Switch>,
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
- <Cell title="标准音高" center>
|
|
|
- {/* {{
|
|
|
- extra: () => (
|
|
|
- <RadioGroup
|
|
|
- iconSize={20}
|
|
|
- class={styles.radioGroup}
|
|
|
- v-model={state.setting.frequency}
|
|
|
- >
|
|
|
- <Radio name={440}>440Hz</Radio>
|
|
|
- <Radio name={442}>442Hz</Radio>
|
|
|
- </RadioGroup>
|
|
|
- ),
|
|
|
- }} */}
|
|
|
- {{
|
|
|
- extra: () => (
|
|
|
- <div class={styles.operateHz}>
|
|
|
- <img src={iconSubtract} onClick={() => operateHz(1)} />
|
|
|
- <span>{state.setting.frequency}HZ</span>
|
|
|
- <img src={iconAdd} onClick={() => operateHz(2)} />
|
|
|
- </div>
|
|
|
- )
|
|
|
- }}
|
|
|
- </Cell>
|
|
|
-
|
|
|
- <Field class={styles.reactionTime} label="反应时间(毫秒)" type="digit"
|
|
|
- placeholder="最大可输入3000毫秒"
|
|
|
- formatter={formatterTimeMs}
|
|
|
- v-model:modelValue={state.setting.reactionTimeMs} />
|
|
|
- </Tab>
|
|
|
- </Tabs>
|
|
|
+ <div class={styles.settting}>
|
|
|
+ <div class={styles.head}>
|
|
|
+ <img class={styles.headTit} src={headImg("settingName.png")} />
|
|
|
+ <img class={styles.closeImg} src={headImg("closeImg.png")} onClick={()=>{ headTopData.settingMode = false }} />
|
|
|
</div>
|
|
|
- <Popup
|
|
|
- class={["popup-custom", styles.screen]}
|
|
|
- v-model:show={helperData.show}
|
|
|
- onClose={() => {
|
|
|
- helperData.show = false;
|
|
|
- }}
|
|
|
- position="right"
|
|
|
- teleport="body"
|
|
|
- >
|
|
|
- <ScreenModel
|
|
|
- onClose={(open: Boolean) => {
|
|
|
- helperData.show = false;
|
|
|
- }}
|
|
|
- />
|
|
|
- </Popup>
|
|
|
- <Popup
|
|
|
- v-model:show={helperData.recommendationShow}
|
|
|
- class="popup-custom van-scale center-closeBtn recommenBoxClass_drag"
|
|
|
- transition="van-scale"
|
|
|
- teleport="body"
|
|
|
- closeable
|
|
|
- style={positionInfo.styleDrag.value}
|
|
|
- >
|
|
|
- <Recommendation
|
|
|
- onClose={() => {
|
|
|
- helperData.recommendationShow = false;
|
|
|
- }}
|
|
|
- />
|
|
|
- { state.platform === IPlatform.PC && <Dragbom showGuide={!state.guideInfo?.teacherDrag} /> }
|
|
|
- </Popup>
|
|
|
+ <div class={styles.content}>
|
|
|
+ <div class={styles.conBox}>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>指法</div>
|
|
|
+ <Switch v-model={state.setting.displayFingering}></Switch>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>循环播放</div>
|
|
|
+ <Switch v-model={state.setting.repeatAutoPlay}></Switch>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>旋律线</div>
|
|
|
+ <Switch v-model={state.setting.melodyLine}></Switch>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>标准音高</div>
|
|
|
+ <div class={styles.frequency}>
|
|
|
+ <img src={headImg("cutImg.png")} class={[styles.btn]} onClick={() => operateHz(1)} />
|
|
|
+ <div class={styles.frequencyNum}>{state.setting.frequency}HZ</div>
|
|
|
+ <img src={headImg("addImg.png")} class={[styles.btn]} onClick={() => operateHz(2)} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>反应时间</div>
|
|
|
+ <div class={styles.reactionTimeBox}>
|
|
|
+ <Field class={styles.reactionTime} type="digit"
|
|
|
+ placeholder="最大可输入3000毫秒"
|
|
|
+ formatter={formatterTimeMs}
|
|
|
+ input-align={'center'}
|
|
|
+ v-model:modelValue={state.setting.reactionTimeMs} />
|
|
|
+ <div class={styles.timeName}>毫秒</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>切换谱面</div>
|
|
|
+ <div class={styles.radioBox}>
|
|
|
+ {
|
|
|
+ [{name:'单行谱',value:true},{name:'多行谱',value:false}].map(item=>{
|
|
|
+ return <div class={ state.isSingleLine===item.value && styles.active } onClick={ ()=>{ state.isSingleLine = item.value } }>{item.name}</div>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBox}>
|
|
|
+ <div class={styles.tit}>转谱</div>
|
|
|
+ <div class={styles.radioBox}>
|
|
|
+ {
|
|
|
+ [{name:'五线谱',value:'staff'},{name:'首调',value:'firstTone'},{name:'固定谱',value:'fixedTone'}].map(item=>{
|
|
|
+ return <div class={ state.musicRenderType===item.value && styles.active } onClick={ ()=>{ state.musicRenderType = item.value as any} }>{item.name}</div>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class={styles.cellBtnBox}>
|
|
|
+ <img src={headImg("tpbz.png")} />
|
|
|
+ <img src={headImg("yjfk.png")} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
);
|
|
|
},
|