liushengqiang 1 year ago
parent
commit
53e7f3343d

+ 1 - 18
README.md

@@ -1,18 +1 @@
-# Vue 3 + TypeScript + Vite
-
-This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
-
-## Recommended IDE Setup
-
-- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
-
-## Type Support For `.vue` Imports in TS
-
-TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
-
-If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
-
-1. Disable the built-in TypeScript Extension
-   1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
-   2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
-2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
+# 打谱软件

+ 10 - 20
src/pc/App.tsx

@@ -1,9 +1,9 @@
-import { computed, defineComponent } from "vue";
+import { computed, defineComponent, onBeforeMount } from "vue";
 import { RouterView } from "vue-router";
 import TheError from "../components/The-error";
 import { setUserInfo, storeData } from "../store";
 import { getQuery } from "../utils/queryString";
-import { employeeQueryUserInfo, studentQueryUserInfo, teacherQueryUserInfo } from "./api";
+import { studentQueryUserInfo, teacherQueryUserInfo } from "./api";
 import {
 	GlobalThemeOverrides,
 	NConfigProvider,
@@ -12,7 +12,7 @@ import {
 	NNotificationProvider,
 	darkTheme,
 } from "naive-ui";
-import { lighten } from "../utils";
+import { lighten, setToken } from "../utils";
 
 export default defineComponent({
 	name: "App",
@@ -32,11 +32,7 @@ export default defineComponent({
 		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") {
+			if (storeData.platformType === "TEACHER") {
 				return await teacherQueryUserInfo();
 			}
 			return await studentQueryUserInfo();
@@ -47,18 +43,12 @@ export default defineComponent({
 			setUserInfo(student);
 			// console.log("🚀 ~ res:", res);
 		};
-		// onBeforeMount(() => {
-		// 	if (query.Authorization) {
-		// 		setToken(query.Authorization);
-		// 	}
-		// 	setUser();
-		// 	setBehaviorId(getRandomKey())
-		// 	setCampId(query.campId || '')
-		// });
-		// onMounted(() => {
-		// 	const _loading = document.getElementById("loading")
-		// 	_loading && (document.body.removeChild(_loading))
-		// })
+		onBeforeMount(() => {
+			if (query.Authorization) {
+				setToken(query.Authorization);
+			}
+			setUser();
+		});
 
 		const inited = computed(() => {
 			return true;

+ 13 - 57
src/pc/api.ts

@@ -6,65 +6,21 @@ export const studentQueryUserInfo = async () => {
 };
 /** 获取老师信息 */
 export const teacherQueryUserInfo = () => {
-	return request.get(`/teacher/queryUserInfo`);
+	return request.get(`/user/getUserInfo`);
 };
-/** 后台用户信息 */
-export const employeeQueryUserInfo = () => {
-	return request.get(`/employee/queryUserInfo`);
+/** 创建曲谱 */
+export const api_musicSheetCreationSave = (data: any) => {
+	return request.post(`/musicSheetCreation/save`, { data, requestType: 'json' });
 };
-
-/** 获取曲谱信息 */
-export const sysMusicScoreAccompanimentQueryPage = (sysMusicScoreId: string) => {
-	return request.get("/sysMusicScoreAccompaniment/queryPage", {
-		params: {
-			clientType: "SMART_PRACTICE",
-			sysMusicScoreId,
-		},
-	});
-};
-
-/** 获取曲谱分类 */
-export const sysMusicScoreCategoriesQueryTree = (enable = false) => {
-	return request.get(`/sysMusicScoreCategories/queryTree`, {
-		params: {
-			parentId: 0,
-			// 后台详情忽略是否启用分类
-			enable,
-		},
-	});
-};
-
-/** 获取曲谱列表 */
-export const sysMusicScoreQueryPage2 = (params: any) => {
-	return request.get(`/sysMusicScore/queryPage2`, { params });
-};
-
-/** 提交意见反馈 */
-export const suggestionAdd = (data: any) => {
-	return request.post("/suggestion/add", { data });
-};
-
-/** 记录训练时长 */
-export const sysMusicRecordAdd = (data: any) => {
-	return request.post("/sysMusicRecord/add", { data });
-};
-/** 获取训练时长 */
-export const tempLittleArtistTrainingCampGetUserTrainingTime = () => {
-	return request.post("/tempLittleArtistTrainingCamp/getUserTrainingTime");
-};
-/** 添加作业记录 */
-export const studentCourseHomeworkAddStudentHomeworkRecord = (params: any) => {
-	return request.get("/studentCourseHomework/addStudentHomeworkRecord", { params });
-};
-/** 获取作业详情 */
-export const studentCourseHomeworkHomeworkDetail = (id: any) => {
-	return request.get(`/studentCourseHomework/homeworkDetail?id=${id}`);
+/** 曲谱列表 */
+export const api_musicSheetCreationPage = (data: any) => {
+	return request.post(`/musicSheetCreation/page`, { data, requestType: 'json' });
 };
-/** 获取进度详情 */
-export const lessonExaminationGetDetail = (params: any) => {
-	return request.get(`/lessonExamination/getDetail`, { params });
+/** 删除曲谱 */
+export const api_musicSheetCreationRemove = (data: any) => {
+	return request.post(`/musicSheetCreation/remove?id=` + data);
 };
-/** 添加进度评测记录 */
-export const lessonExaminationSubmit = (data: any) => {
-	return request.post(`/lessonExamination/submit`, { data, requestType: 'form' });
+/** 曲谱详情 */
+export const api_musicSheetCreationDetail = (data: any) => {
+	return request.get(`/musicSheetCreation/detail/${data}`);
 };

+ 155 - 0
src/pc/create/component/the-create/index.module.less

@@ -0,0 +1,155 @@
+.setbox {
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    border-radius: 6px;
+    background: #fff;
+    overflow: hidden;
+}
+
+.head {
+    position: relative;
+    line-height: 53px;
+    height: 53px;
+    text-align: center;
+    background: #F5F6FA;
+    color: #131415;
+    font-weight: 600;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 16px;
+    flex-shrink: 0;
+
+    .close {
+        position: absolute;
+        top: 50%;
+        right: 20px;
+        transform: translateY(-50%);
+    }
+}
+
+.content {
+    flex: 1;
+    padding: 30px;
+    overflow: hidden;
+}
+
+.lineTitle {
+    height: 21px;
+    font-size: 15px;
+    font-weight: 600;
+    color: #131415;
+    line-height: 21px;
+    margin-bottom: 10px;
+}
+
+.item {
+    text-align: center;
+    font-size: 14px;
+    font-weight: 400;
+    color: #777;
+    cursor: pointer;
+
+    .itemImg {
+        width: 100px;
+        height: 100px;
+        border: 2px solid #fff;
+        border-radius: 18px;
+        overflow: hidden;
+        margin-bottom: 7px;
+    }
+
+    .icon {
+        width: 100%;
+        height: 100%;
+    }
+
+    &.itemActive {
+        font-weight: 600;
+        color: var(--primary-color);
+
+        .itemImg {
+            border-color: var(--primary-color);
+        }
+    }
+}
+
+.beatItem {
+    position: relative;
+    width: 195px;
+    height: 110px;
+    background: #F5F5F7;
+    border-radius: 8px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+
+    .beatIcon {
+        width: 80%;
+        height: 60%;
+        cursor: pointer;
+
+        :global {
+            .svg-icon {
+                width: 100% !important;
+                height: 100% !important;
+            }
+        }
+    }
+
+    :global {
+        .n-input-number {
+            width: 80%;
+        }
+    }
+
+    .speedIcon {
+        font-size: 30px;
+    }
+}
+
+.btnItem {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    border-radius: 6px;
+    padding: 4px 8px;
+    cursor: pointer;
+
+    .btnItemIcon {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 60px;
+    }
+
+    &:hover {
+        background-color: rgba(0, 0, 0, 0.1);
+    }
+
+    .btnItemName {
+        font-size: 12px;
+    }
+    &.active{
+        background-color: #BADCFE;
+    }
+}
+
+.btns {
+    text-align: center;
+    padding: 15px 0;
+
+    :global {
+        .n-button {
+            width: 117px;
+            height: 35px;
+            padding: 0;
+            text-align: center;
+            font-size: 14px;
+            margin: 0 15px;
+        }
+    }
+}

+ 216 - 0
src/pc/create/component/the-create/index.tsx

@@ -0,0 +1,216 @@
+import {
+	NButton,
+	NCard,
+	NGi,
+	NGrid,
+	NIcon,
+	NInputNumber,
+	NLayout,
+	NLayoutContent,
+	NLayoutSider,
+	NModal,
+	NPopover,
+	NRadio,
+	NRadioGroup,
+	NScrollbar,
+	NSpace,
+	NTabPane,
+	NTable,
+	NTabs,
+	useMessage,
+} from "naive-ui";
+import { defineComponent, reactive, watch } from "vue";
+import { Close } from "@vicons/ionicons5";
+import styles from "./index.module.less";
+import { getImage } from "/src/pc/home/images";
+import { ABC_DATA } from "/src/pc/home/runtime";
+import TheIcon from "/src/components/The-icon";
+import TheSpeed from "/src/pc/home/component/the-speed";
+import { api_musicSheetCreationSave } from "/src/pc/api";
+export default defineComponent({
+	name: "TheCreate",
+	props: {
+		show: {
+			type: Boolean,
+			default: false,
+		},
+	},
+	emits: ["update:show", "create"],
+	setup(props, { emit }) {
+		const message = useMessage();
+		const instruments = [
+			{
+				label: "竖笛",
+				key: "shudi",
+				icon: getImage("icon_27_0.png"),
+			},
+			{
+				label: "排箫",
+				key: "paixiao",
+				icon: getImage("icon_27_1.png"),
+			},
+			{
+				label: "口风琴",
+				key: "koufengqin",
+				icon: getImage("icon_27_2.png"),
+			},
+			{
+				label: "陶笛",
+				key: "taodie",
+				icon: getImage("icon_27_3.png"),
+			},
+			{
+				label: "葫芦丝",
+				key: "hulusi",
+				icon: getImage("icon_27_4.png"),
+			},
+		];
+		const froms = reactive({
+			instrument: "shudi",
+			key: ABC_DATA.key[0],
+			meter: ABC_DATA.meter[0],
+			speed: 80,
+			measure: 30,
+		});
+
+		const handleCreate = async () => {
+			await api_musicSheetCreationSave({
+				creationData: "sd",
+				name: "sd",
+				creationConfig: "sd",
+				subjectId: 1,
+			});
+			emit('create')
+		};
+		return () => (
+			<NModal autoFocus={false} show={props.show} onUpdate:show={(val) => emit("update:show", val)}>
+				<div class={styles.setbox}>
+					<div class={styles.head}>
+						<div>新建乐谱</div>
+						<NButton
+							class={styles.close}
+							quaternary
+							circle
+							size="small"
+							onClick={() => emit("update:show", false)}
+						>
+							<NIcon component={Close} size={18} />
+						</NButton>
+					</div>
+					<div class={styles.content}>
+						<div class={styles.lineTitle}>声部</div>
+						<NSpace style={{ paddingBottom: "45px" }}>
+							{instruments.map((item) => (
+								<div
+									class={[styles.item, froms.instrument === item.key && styles.itemActive]}
+									onClick={() => (froms.instrument = item.key)}
+								>
+									<div class={styles.itemImg}>
+										<img class={styles.icon} src={item.icon} />
+									</div>
+									<div>{item.label}</div>
+								</div>
+							))}
+						</NSpace>
+						<NSpace style={{ paddingBottom: "45px" }}>
+							<NPopover to="body" trigger="click">
+								{{
+									trigger: () => (
+										<div>
+											<div class={styles.lineTitle}>调号</div>
+											<div class={styles.beatItem}>
+												<div class={[styles.beatIcon]}>
+													<TheIcon iconClassName={froms.key.icon} />
+												</div>
+												<div>{froms.key.name}</div>
+											</div>
+										</div>
+									),
+									default: () => (
+										<NGrid cols={5} xGap={20} yGap={8}>
+											{ABC_DATA.key.map((item) => (
+												<NGi>
+													<div
+														class={[styles.btnItem, froms.key.value === item.value && styles.active]}
+														onClick={() => (froms.key = item)}
+													>
+														<div class={[styles.btnItemIcon]}>
+															<TheIcon iconClassName={item.icon} />
+														</div>
+														<div class={styles.btnItemName}>{item.name}</div>
+													</div>
+												</NGi>
+											))}
+										</NGrid>
+									),
+								}}
+							</NPopover>
+
+							<NPopover to="body" trigger="click">
+								{{
+									trigger: () => (
+										<div>
+											<div class={styles.lineTitle}>拍号</div>
+											<div class={styles.beatItem}>
+												<div class={[styles.beatIcon]}>
+													<TheIcon iconClassName={froms.meter.icon} />
+												</div>
+												<div>{froms.meter.name}</div>
+											</div>
+										</div>
+									),
+									default: () => (
+										<NGrid cols={5} xGap={50} yGap={20}>
+											{ABC_DATA.meter.map((item) => (
+												<NGi>
+													<div
+														class={[styles.btnItem, froms.meter.value === item.value && styles.active]}
+														onClick={() => (froms.meter = item)}
+													>
+														<div class={[styles.btnItemIcon]}>
+															<TheIcon iconClassName={item.icon} />
+														</div>
+														<div class={styles.btnItemName}>{item.name}</div>
+													</div>
+												</NGi>
+											))}
+										</NGrid>
+									),
+								}}
+							</NPopover>
+							<div>
+								<div class={styles.lineTitle}>速度</div>
+								<div class={styles.beatItem}>
+									<NInputNumber size="large" v-model:value={froms.speed} showButton={false} min={50}>
+										{{
+											prefix: () => (
+												<div class={styles.speedIcon}>
+													<TheIcon iconClassName="icon-a-sudu-4fenyinfu" size={["2em", "1em"]} />
+												</div>
+											),
+										}}
+									</NInputNumber>
+								</div>
+							</div>
+							<div>
+								<div class={styles.lineTitle}>小节</div>
+								<div class={styles.beatItem}>
+									<NInputNumber size="large" v-model:value={froms.measure} min={4}></NInputNumber>
+								</div>
+							</div>
+						</NSpace>
+
+						<div class={styles.btns}>
+							<NButton round onClick={() => emit("update:show", false)}>
+								取消
+							</NButton>
+							<NButton round type="primary" onClick={() => handleCreate()}>
+								确定
+							</NButton>
+						</div>
+					</div>
+				</div>
+			</NModal>
+		);
+	},
+});

+ 87 - 0
src/pc/create/index.module.less

@@ -0,0 +1,87 @@
+.createItem {
+    position: relative;
+    width: 304px;
+    height: 233px;
+    background: #F9FAFD;
+    border: 2px solid rgba(209, 216, 235, 1);
+    border-radius: 12px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    font-size: 15px;
+    font-weight: 600;
+    cursor: pointer;
+    img{
+        width: 45px;
+        height: 45px;
+        margin-bottom: 23px;
+    }
+}
+
+.wrap {
+    padding: 24px;
+    border-radius: 15px;
+    background-color: #fff;
+}
+.item {
+    position: relative;
+    width: 304px;
+    height: 233px;
+    background: #F9FAFD;
+    border: 2px solid rgba(209, 216, 235, 1);
+    border-radius: 12px;
+    cursor: pointer;
+    display: flex;
+    flex-direction: column;
+    .icon_29{
+        height: 14px;
+        vertical-align: middle;
+        margin-right: 6px;
+        transform: translateY(-1px);
+    }
+    .bottomBtn{
+        width: 30px;
+        height: 30px;
+        margin: 0 6px;
+        &:hover{
+            opacity: .8;
+        }
+    }
+    .btn{
+        position: absolute;
+        right: 10px;
+        top: 16px;
+        display: block;
+        height: 30px;
+        &:hover{
+            opacity: .8;
+        }
+    }
+
+}
+.imgBox{
+    flex: 1;
+    overflow: hidden;
+    img {
+        width: 100%;
+    }
+}
+.itemBottom{
+    flex-shrink: 0;
+    padding: 8px 12px;
+    overflow: hidden;
+    .bottombox{
+        width: 100%;
+        display: flex;
+        align-items: center;
+    }
+    .bottomLeft{
+        flex: 1;
+        margin-right: 6px;
+    }
+    .time{
+        font-size: 12px;
+        color: #777;
+    }
+}

+ 108 - 0
src/pc/create/index.tsx

@@ -0,0 +1,108 @@
+import { defineComponent, onMounted, reactive } from "vue";
+import styles from "./index.module.less";
+import { NButton, NSpace, useDialog } from "naive-ui";
+import { getImage } from "../home/images";
+import TheCreate from "./component/the-create";
+import { storeData } from "/src/store";
+import { api_musicSheetCreationPage, api_musicSheetCreationRemove } from "../api";
+import { useRouter } from "vue-router";
+
+export default defineComponent({
+	name: "Create",
+	setup() {
+        const router = useRouter()
+		const dialog = useDialog();
+		const forms = reactive({
+			teacherId: storeData.user.id,
+			page: 1,
+			keyword: "",
+			rows: 20,
+		});
+		const data = reactive({
+			list: [] as any[],
+			addShow: false,
+			finish: false,
+		});
+		const getList = async () => {
+			const res = await api_musicSheetCreationPage({ ...forms });
+			if (res?.code == 200) {
+				data.list = res.data.rows;
+				data.finish = res.data.rows.length < forms.rows;
+			}
+		};
+		const handleReset = () => {
+			forms.page = 1;
+			data.finish = false;
+			data.list = [];
+			getList();
+		};
+		const handleDelte = (item: any) => {
+			dialog.warning({
+				title: "警告",
+				content: `确定删除${item.name}曲谱吗?`,
+				positiveText: "确定",
+				negativeText: "取消",
+				onPositiveClick: async () => {
+					await api_musicSheetCreationRemove(item.id);
+					handleReset();
+				},
+				onNegativeClick: () => {},
+			});
+		};
+		onMounted(() => {
+			getList();
+		});
+        const handleOpenNotaion = (item: any) => {
+            router.push({
+                path: '/',
+                query:{
+                    id: item.id
+                }
+            })
+        }
+		return () => (
+			<div class={styles.wrap}>
+				<NSpace size={18}>
+					<div class={styles.createItem} onClick={() => (data.addShow = true)}>
+						<img src={getImage("icon_29.png")} />
+						<div>新建乐谱</div>
+					</div>
+
+					{data.list.map((item) => (
+						<div class={styles.item} onClick={() => handleOpenNotaion(item)}>
+							<div class={styles.imgBox}>
+								<img src={getImage("icon_29.png")} />
+							</div>
+							<div class={styles.itemBottom}>
+								<div class={styles.bottombox}>
+									<div class={styles.bottomLeft}>
+										<div class={styles.itemtitle}>
+											<img class={styles.icon_29} src={getImage("icon_29_1.png")} />
+											<span>{item.name}</span>
+										</div>
+										<div class={styles.time}>{item.updateTime}</div>
+									</div>
+									<img class={styles.bottomBtn} src={getImage("icon_29_2.png")} />
+									<img
+										class={styles.bottomBtn}
+										src={getImage("icon_29_2.png")}
+										onClick={() => handleDelte(item)}
+									/>
+								</div>
+							</div>
+							<img class={styles.btn} src={getImage("icon_29_2.png")} />
+						</div>
+					))}
+				</NSpace>
+
+				<TheCreate
+					v-model:show={data.addShow}
+					onCreate={() => {
+						data.addShow = false;
+						handleReset();
+					}}
+				/>
+			</div>
+		);
+	},
+});

BIN
src/pc/home/images/icon_29.png


BIN
src/pc/home/images/icon_29_1.png


BIN
src/pc/home/images/icon_29_2.png


+ 7 - 0
src/pc/home/index.tsx

@@ -37,6 +37,8 @@ import { svg2canvas } from "/src/utils/svg2canvas";
 import { downloadFile } from "/src/utils";
 import FileBtn, { IFileBtnType } from "./component/file-btn";
 import TheSetting from "./component/the-setting";
+import { useRoute } from "vue-router";
+import { api_musicSheetCreationDetail } from "../api";
 
 const allPitches = [
 	"C,,,,",
@@ -153,6 +155,7 @@ function moveNote(note: string, step: number) {
 export default defineComponent({
 	name: "Home",
 	setup() {
+		const route = useRoute();
 		const message = useMessage();
 		const popup = reactive({
 			instrument: false,
@@ -906,7 +909,11 @@ export default defineComponent({
 		const instruments = computed(() => {
 			return ABCJS.synth.instrumentIndexToName.map((name, index) => ({ label: name, value: index }));
 		});
+		const getDetailData = async () => {
+			await api_musicSheetCreationDetail(route.query.id);
+		};
 		onMounted(async () => {
+			await getDetailData();
 			console.log(ABCJS);
 			await handleResetRender();
 			console.log(ABCJS.extractMeasures(data.music));

+ 5 - 1
src/pc/router.ts

@@ -1,8 +1,12 @@
 import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
 import Home from "./home/index";
-
+import Create from "./create/index";
 const routes: RouteRecordRaw[] = [
 	{
+		path: "/create",
+		component: Create,
+	},
+	{
 		path: "/",
 		component: Home,
 	},

+ 3 - 0
src/pc/theme.css

@@ -1,3 +1,6 @@
+:root{
+    --primary-color: #198CFE;
+}
 * {
     margin    : 0;
     padding   : 0;

+ 2 - 2
src/store.ts

@@ -34,9 +34,9 @@ export const storeData = reactive({
 	/** 用户信息 */
 	user: {} as IUser,
 	/** 端口 */
-	platformType: "STUDENT" as IPlatformType,
+	platformType: "TEACHER" as IPlatformType,
 	/** api地址前缀 */
-	platformApi: "/api-student" as IPlatformApi,
+	platformApi: "/edu-app" as IPlatformApi,
 	/** 开发模式api前缀 */
 	proxy: "" as IProxy,
 	/** 是否在APP中 */

+ 3 - 4
vite.config.ts

@@ -47,11 +47,10 @@ export default defineConfig({
 		port: 3050,
 		// https: true,
 		proxy: {
-			"^/gym/.*": {
-				target: "https://mstutest.dayaedu.com",
-				// target: "https://online.dayaedu.com",
+			"^/edu-app/.*": {
+				target: "https://test.lexiaoya.cn",
 				changeOrigin: true,
-				rewrite: (path) => path.replace(/^\/gym/, ""),
+				// rewrite: (path) => path.replace(/^\/edu-app/, ""),
 			},
 		},
 	},