Explorar o código

Merge branch 'iteration-20240607-small' into jenkins

lex hai 10 meses
pai
achega
52b99a106f

+ 97 - 87
src/api/user.ts

@@ -1,87 +1,97 @@
-import request from '@/utils/request';
-
-/**
- * 用户登录
- * @param prams 登录参数
- */
-export const userLogin = (params: any) => {
-  return request.post('/edu-app/userlogin', {
-    requestType: 'form',
-    data: params
-  });
-};
-
-/**
- * 获取用户信息
- * returns user
- */
-export const getUserInfo = () => {
-  return request.get('/edu-app/user/getUserInfo');
-};
-
-/**
- * 老师端修改用户信息
- */
-export const api_teacherUpdate = (body: any) => {
-  return request.post('/edu-app/teacher/update', { data: body });
-};
-
-/**
- * 获取声部列表
- * returns subjects
- */
-export const getSubjectList = (params: any) => {
-  return request.post('/edu-app/subject/page', {
-    data: params
-  });
-};
-
-/**
- * 获取声部列表
- * returns subjects
- */
-export const getSubjectList2 = (params: any) => {
-  return request.post('/edu-app/subject/list', {
-    data: params
-  });
-};
-
-/**
- * 获取曲谱分类
- * @returns musicSheetCategories
- */
-export const getCategories = (params: any) => {
-  return request.post('/edu-app/musicSheetCategories/page', {
-    data: params
-  });
-};
-
-/**
- * 反馈购买未读条数
- * @returns suggestMessageUnread
- */
-export const suggestMessageUnread = (params?: any) => {
-  return request.get('/edu-app/sysSuggestion/suggestMessageUnread', {
-    params
-  });
-};
-
-/** 曲谱详情 */
-export const api_musicSheetDetail = (data: any) => {
-  return request.get(`/edu-app/musicSheet/detail/${data}`);
-};
-
-/** 获取乐器列表 */
-export const api_musicalInstrumentList = (data: any) => {
-  return request.post('/edu-app/musicalInstrument/list', {
-    data
-  });
-};
-
-/**
- * @description: 上课记录详情
- * @param params
- */
-export const api_cousseScheduleDetail = (id: string) => {
-  return request.post('/edu-app/courseSchedule/detail/' + id);
-};
+import request from '@/utils/request';
+
+/**
+ * 用户登录
+ * @param prams 登录参数
+ */
+export const userLogin = (params: any) => {
+  return request.post('/edu-app/userlogin', {
+    requestType: 'form',
+    data: params
+  });
+};
+
+/**
+ * 获取用户信息
+ * returns user
+ */
+export const getUserInfo = () => {
+  return request.get('/edu-app/user/getUserInfo');
+};
+
+/**
+ * 老师端修改用户信息
+ */
+export const api_teacherUpdate = (body: any) => {
+  return request.post('/edu-app/teacher/update', { data: body });
+};
+
+/**
+ * 获取声部列表
+ * returns subjects
+ */
+export const getSubjectList = (params: any) => {
+  return request.post('/edu-app/subject/page', {
+    data: params
+  });
+};
+
+/**
+ * 获取声部列表
+ * returns subjects
+ */
+export const getSubjectList2 = (params: any) => {
+  return request.post('/edu-app/subject/list', {
+    data: params
+  });
+};
+
+/**
+ * 获取曲谱分类
+ * @returns musicSheetCategories
+ */
+export const getCategories = (params: any) => {
+  return request.post('/edu-app/musicSheetCategories/page', {
+    data: params
+  });
+};
+
+/**
+ * 反馈购买未读条数
+ * @returns suggestMessageUnread
+ */
+export const suggestMessageUnread = (params?: any) => {
+  return request.get('/edu-app/sysSuggestion/suggestMessageUnread', {
+    params
+  });
+};
+
+/** 曲谱详情 */
+export const api_musicSheetDetail = (data: any) => {
+  return request.get(`/edu-app/musicSheet/detail/${data}`);
+};
+
+/** 获取乐器列表 */
+export const api_musicalInstrumentList = (data: any) => {
+  return request.post('/edu-app/musicalInstrument/list', {
+    data
+  });
+};
+
+/**
+ * @description: 上课记录详情
+ * @param params
+ */
+export const api_cousseScheduleDetail = (id: string) => {
+  return request.post('/edu-app/courseSchedule/detail/' + id);
+};
+
+/**
+ * @description: 标签列表
+ * @param params
+ */
+export const api_musicTagTree = (params?: any) => {
+  return request.get('/edu-app/musicTag/tree', {
+    params
+  });
+};

+ 1 - 0
src/components/layout/layoutTop.tsx

@@ -65,6 +65,7 @@ export default defineComponent({
 
     const oncheckEditStatus = (callBack: any) => {
       showHeadFlag.value = false;
+      userInfoStatus.value = false;
       if (prepareStore.getIsEditResource) {
         eventGlobal.emit('pageBeforeLeave', () => callBack());
       } else {

+ 379 - 377
src/custom-plugins/guide-page/home-guide.tsx

@@ -1,377 +1,379 @@
-import { NButton } from 'naive-ui';
-import {
-  defineComponent,
-  nextTick,
-  onMounted,
-  onUnmounted,
-  reactive,
-  ref,
-  watch
-} from 'vue';
-import styles from './index.module.less';
-import { getImage } from './images';
-import { eventGlobal, px2vw, px2vwH } from '@/utils/index';
-import { getGuidance, setGuidance } from './api';
-export default defineComponent({
-  name: 'coai-guide',
-  emits: ['close'],
-  setup(props, { emit }) {
-    const data = reactive({
-      box: {
-        height: '0px'
-      } as any,
-      show: false,
-      /**
-       *
-            width:  px2vw(840),
-            height:  px2vw(295)
-       */
-      steps: [
-        {
-          ele: '',
-          eleRect: {} as DOMRect,
-          img: getImage('home1.png'),
-          handStyle: {
-            top: '0.91rem'
-          },
-          imgStyle: {
-            top: px2vw(-400 / 2),
-            left: px2vw(-734 / 2),
-            width: px2vw(734),
-            height: px2vw(295)
-          },
-          btnsStyle: {
-            bottom: px2vw(240),
-            left: px2vw(-128)
-          },
-          boxStyle: {
-            border: 'none',
-            width: 0,
-            height: 0,
-            backgroundColor: 'transparent',
-            position: 'fixed',
-            top: `50%`,
-            left: '50%'
-            // visibility: 'hidden'
-          },
-          eleRectPadding: {
-            left: 0,
-            top: 0,
-            width: 0,
-            height: 0
-          }
-        },
-        {
-          ele: '',
-          img: getImage('home2.png'),
-          imgStyle: {
-            top: '100%',
-            left: px2vw(-290),
-            width: px2vw(401),
-            height: px2vw(227)
-          },
-          btnsStyle: {
-            bottom: '30px',
-            left: px2vw(-130)
-          },
-          boxStyle: {},
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          }
-        },
-        {
-          ele: '',
-          img: getImage('home6.png'),
-          imgStyle: {
-            top: '100%',
-            left: px2vw(-310),
-            width: px2vw(477),
-            height: px2vw(227)
-          },
-          btnsStyle: {
-            bottom: '30px',
-            left: px2vw(-150)
-          },
-          boxStyle: {},
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          }
-        },
-        {
-          ele: '',
-          img: getImage('home4.png'),
-          imgStyle: {
-            top: '100%',
-            left: px2vw(-310),
-            width: px2vw(477),
-            height: px2vw(227)
-          },
-          btnsStyle: {
-            bottom: '30px',
-            left: px2vw(-150)
-          },
-          boxStyle: {},
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          }
-        },
-        {
-          ele: '',
-          img: getImage('home3.png'),
-          handStyle: {
-            top: '-1.39rem',
-            left: '0.17rem',
-            transform: 'rotate(180deg)'
-          },
-          imgStyle: {
-            top: px2vw(-4),
-            width: px2vw(454),
-            height: px2vw(227),
-            left: px2vw(-150)
-          },
-          btnsStyle: {
-            bottom: '30px',
-            left: px2vw(8)
-          },
-          boxStyle: {
-            borderRadius: '30px'
-          },
-          eleRectPadding: {
-            left: 7,
-            top: 9,
-            width: 14,
-            height: 14
-          }
-        },
-        {
-          ele: '',
-          img: getImage('home5.png'),
-          handStyle: {
-            top: '-1.39rem',
-            left: '0.17rem',
-            transform: 'rotate(180deg)'
-          },
-          imgStyle: {
-            top: px2vw(-194),
-            width: px2vw(621),
-            height: px2vw(223),
-            left: px2vw(-624)
-          },
-          btnsStyle: {
-            top: px2vw(-42),
-            left: px2vw(-460)
-          },
-          boxStyle: {},
-          eleRectPadding: {
-            left: 7,
-            top: 7,
-            width: 14,
-            height: 14
-          }
-        }
-      ],
-      step: 0
-    });
-    const tipShow = ref(false);
-    // const res =  setGuidance({guideTag:'teacher-guideInfo',guideValue:'{}'})
-    const guideInfo = ref({} as any);
-    const getAllGuidance = async () => {
-      try {
-        const res = await getGuidance({ guideTag: 'teacher-guideInfo' });
-        if (res.data) {
-          guideInfo.value = JSON.parse(res.data?.guideValue) || null;
-        } else {
-          guideInfo.value = {};
-        }
-
-        if (guideInfo.value && guideInfo.value.homeGuide) {
-          tipShow.value = false;
-        } else {
-          tipShow.value = true;
-        }
-      } catch (e) {
-        console.log(e);
-      }
-      // const guideInfo = localStorage.getItem('teacher-guideInfo');
-    };
-    getAllGuidance();
-    const getStepELe = () => {
-      const ele: HTMLElement = document.getElementById(
-        data.step === data.steps.length - 1
-          ? 'moveNPopover'
-          : `home-${data.step}`
-      )!;
-      // console.log(`coai-${data.step}`, data.steps[data.step].eleRectPadding);
-      if (ele) {
-        const eleRect = ele.getBoundingClientRect();
-        const left = data.steps[data.step].eleRectPadding?.left || 0;
-        const top = data.steps[data.step].eleRectPadding?.top || 0;
-        const width = data.steps[data.step].eleRectPadding?.width || 0;
-        const height = data.steps[data.step].eleRectPadding?.height || 0;
-        data.box = {
-          left: eleRect.x - left + 'px',
-          top: eleRect.y - top + 'px',
-          width: eleRect.width + width + 'px',
-          height: eleRect.height + height + 'px'
-        };
-      } else {
-        handleNext();
-      }
-    };
-
-    const onResetGuide = async (name: string) => {
-      try {
-        if (name !== 'Home') return;
-        if (!guideInfo.value) {
-          guideInfo.value = { homeGuide: false };
-        } else {
-          guideInfo.value.homeGuide = false;
-        }
-        try {
-          await setGuidance({
-            guideTag: 'teacher-guideInfo',
-            guideValue: JSON.stringify(guideInfo.value)
-          });
-        } catch (e) {
-          console.log(e);
-        }
-        data.step = 0;
-        getStepELe();
-        tipShow.value = true;
-      } catch {
-        //
-      }
-    };
-    onMounted(() => {
-      getStepELe();
-      window.addEventListener('resize', resetSize);
-      eventGlobal.on('teacher-guideInfo', onResetGuide);
-    });
-    const resetSize = () => {
-      getStepELe();
-    };
-
-    onUnmounted(() => {
-      window.removeEventListener('resize', resetSize);
-      eventGlobal.off('teacher-guideInfo', onResetGuide);
-    });
-
-    const handleNext = () => {
-      if (data.step >= data.steps.length - 1) {
-        endGuide();
-        return;
-      }
-      data.step = data.step + 1;
-      getStepELe();
-    };
-
-    const endGuide = async () => {
-      // let guideInfo =
-      //   JSON.parse(localStorage.getItem('teacher-guideInfo') || '{}') || null;
-      if (!guideInfo.value) {
-        guideInfo.value = { homeGuide: true };
-      } else {
-        guideInfo.value.homeGuide = true;
-      }
-      try {
-        const res = await setGuidance({
-          guideTag: 'teacher-guideInfo',
-          guideValue: JSON.stringify(guideInfo.value)
-        });
-      } catch (e) {
-        console.log(e);
-      }
-      // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
-      tipShow.value = false;
-      //  localStorage.setItem('endC')
-    };
-    return () => (
-      <>
-        {tipShow.value ? (
-          <div
-            v-model:show={tipShow.value}
-            class={['n-modal-mask', 'n-modal-mask-guide']}>
-            <div class={styles.content} onClick={() => handleNext()}>
-              <div
-                class={styles.backBtn}
-                onClick={(e: Event) => {
-                  e.stopPropagation();
-                  endGuide();
-                }}>
-                跳过
-              </div>
-              <div
-                class={styles.box}
-                style={{ ...data.box, ...data.steps[data.step].boxStyle }}
-                id={`modeType-${data.step}`}>
-                {data.steps.map((item: any, index) => (
-                  <div
-                    onClick={(e: Event) => e.stopPropagation()}
-                    class={styles.item}
-                    style={
-                      item.type == 'bottom'
-                        ? {
-                            display: index === data.step ? '' : 'none',
-                            left: `${item.eleRect?.left}px`,
-                            top: `-${item.imgStyle?.height}`
-                          }
-                        : {
-                            display: index === data.step ? '' : 'none',
-                            left: `${item.eleRect?.left}px`,
-                            top: `${data.box?.height}`
-                          }
-                    }>
-                    <img
-                      class={styles.img}
-                      style={item.imgStyle}
-                      src={item.img}
-                    />
-                    {/* <img
-                      class={styles.iconHead}
-                      style={item.handStyle}
-                      src={getImage('indexDot.png')}
-                    /> */}
-                    <div class={styles.btns} style={item.btnsStyle}>
-                      {data.step + 1 == data.steps.length ? (
-                        <>
-                          <div
-                            class={[styles.endBtn]}
-                            onClick={() => endGuide()}>
-                            完成
-                          </div>
-                          <div
-                            class={styles.nextBtn}
-                            onClick={() => {
-                              data.step = 0;
-                              getStepELe();
-                            }}>
-                            再看一遍
-                          </div>
-                        </>
-                      ) : (
-                        <div class={styles.btn} onClick={() => handleNext()}>
-                          {data.step !== 0
-                            ? `下一步 ${data.step}/${data.steps.length - 1}`
-                            : '开始体验'}
-                        </div>
-                      )}
-                    </div>
-                  </div>
-                ))}
-              </div>
-            </div>
-          </div>
-        ) : null}
-      </>
-    );
-  }
-});
+import { NButton } from 'naive-ui';
+import {
+  defineComponent,
+  nextTick,
+  onMounted,
+  onUnmounted,
+  reactive,
+  ref,
+  watch
+} from 'vue';
+import styles from './index.module.less';
+import { getImage } from './images';
+import { eventGlobal, px2vw, px2vwH } from '@/utils/index';
+import { getGuidance, setGuidance } from './api';
+export default defineComponent({
+  name: 'coai-guide',
+  emits: ['close'],
+  setup(props, { emit }) {
+    const data = reactive({
+      box: {
+        height: '0px'
+      } as any,
+      show: false,
+      /**
+       *
+            width:  px2vw(840),
+            height:  px2vw(295)
+       */
+      steps: [
+        {
+          ele: '',
+          eleRect: {} as DOMRect,
+          img: getImage('home1.png'),
+          handStyle: {
+            top: '0.91rem'
+          },
+          imgStyle: {
+            top: px2vw(-400 / 2),
+            left: px2vw(-734 / 2),
+            width: px2vw(734),
+            height: px2vw(295)
+          },
+          btnsStyle: {
+            bottom: px2vw(240),
+            left: px2vw(-128)
+          },
+          boxStyle: {
+            border: 'none',
+            width: 0,
+            height: 0,
+            backgroundColor: 'transparent',
+            position: 'fixed',
+            top: `50%`,
+            left: '50%'
+            // visibility: 'hidden'
+          },
+          eleRectPadding: {
+            left: 0,
+            top: 0,
+            width: 0,
+            height: 0
+          }
+        },
+        {
+          ele: '',
+          img: getImage('home2.png'),
+          imgStyle: {
+            top: '100%',
+            left: px2vw(-290),
+            width: px2vw(401),
+            height: px2vw(227)
+          },
+          btnsStyle: {
+            bottom: '30px',
+            left: px2vw(-130)
+          },
+          boxStyle: {},
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          }
+        },
+        {
+          ele: '',
+          img: getImage('home6.png'),
+          imgStyle: {
+            top: '100%',
+            left: px2vw(-310),
+            width: px2vw(477),
+            height: px2vw(227)
+          },
+          btnsStyle: {
+            bottom: '30px',
+            left: px2vw(-150)
+          },
+          boxStyle: {},
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          }
+        },
+        {
+          ele: '',
+          img: getImage('home4.png'),
+          imgStyle: {
+            top: '100%',
+            left: px2vw(-310),
+            width: px2vw(477),
+            height: px2vw(227)
+          },
+          btnsStyle: {
+            bottom: '30px',
+            left: px2vw(-150)
+          },
+          boxStyle: {},
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          }
+        },
+        {
+          ele: '',
+          img: getImage('home3.png'),
+          handStyle: {
+            top: '-1.39rem',
+            left: '0.17rem',
+            transform: 'rotate(180deg)'
+          },
+          imgStyle: {
+            top: px2vw(-4),
+            width: px2vw(454),
+            height: px2vw(227),
+            left: px2vw(-150)
+          },
+          btnsStyle: {
+            bottom: '30px',
+            left: px2vw(8)
+          },
+          boxStyle: {
+            borderRadius: '30px'
+          },
+          eleRectPadding: {
+            left: 7,
+            top: 9,
+            width: 14,
+            height: 14
+          }
+        },
+        {
+          ele: '',
+          img: getImage('home5.png'),
+          handStyle: {
+            top: '-1.39rem',
+            left: '0.17rem',
+            transform: 'rotate(180deg)'
+          },
+          imgStyle: {
+            top: px2vw(-194),
+            width: px2vw(621),
+            height: px2vw(223),
+            left: px2vw(-624)
+          },
+          btnsStyle: {
+            top: px2vw(-42),
+            left: px2vw(-460)
+          },
+          boxStyle: {},
+          eleRectPadding: {
+            left: 7,
+            top: 7,
+            width: 14,
+            height: 14
+          }
+        }
+      ],
+      step: 0
+    });
+    const tipShow = ref(false);
+    // const res =  setGuidance({guideTag:'teacher-guideInfo',guideValue:'{}'})
+    const guideInfo = ref({} as any);
+    const getAllGuidance = async () => {
+      try {
+        const res = await getGuidance({ guideTag: 'teacher-guideInfo' });
+        if (res.data) {
+          guideInfo.value = JSON.parse(res.data?.guideValue) || null;
+        } else {
+          guideInfo.value = {};
+        }
+
+        if (guideInfo.value && guideInfo.value.homeGuide) {
+          tipShow.value = false;
+        } else {
+          tipShow.value = true;
+        }
+      } catch (e) {
+        console.log(e);
+      }
+      // const guideInfo = localStorage.getItem('teacher-guideInfo');
+    };
+    getAllGuidance();
+    const getStepELe = () => {
+      const ele: HTMLElement = document.getElementById(
+        data.step === data.steps.length - 1
+          ? 'moveNPopover'
+          : `home-${data.step}`
+      )!;
+      // console.log(`coai-${data.step}`, data.steps[data.step].eleRectPadding);
+      if (ele) {
+        const eleRect = ele.getBoundingClientRect();
+        const left = data.steps[data.step].eleRectPadding?.left || 0;
+        const top = data.steps[data.step].eleRectPadding?.top || 0;
+        const width = data.steps[data.step].eleRectPadding?.width || 0;
+        const height = data.steps[data.step].eleRectPadding?.height || 0;
+
+        console.log(eleRect, height);
+        data.box = {
+          left: eleRect.x - left + 'px',
+          top: eleRect.y - top + 'px',
+          width: eleRect.width + width + 'px',
+          height: eleRect.height + height + 'px'
+        };
+      } else {
+        handleNext();
+      }
+    };
+
+    const onResetGuide = async (name: string) => {
+      try {
+        if (name !== 'Home') return;
+        if (!guideInfo.value) {
+          guideInfo.value = { homeGuide: false };
+        } else {
+          guideInfo.value.homeGuide = false;
+        }
+        try {
+          await setGuidance({
+            guideTag: 'teacher-guideInfo',
+            guideValue: JSON.stringify(guideInfo.value)
+          });
+        } catch (e) {
+          console.log(e);
+        }
+        data.step = 0;
+        getStepELe();
+        tipShow.value = true;
+      } catch {
+        //
+      }
+    };
+    onMounted(() => {
+      getStepELe();
+      window.addEventListener('resize', resetSize);
+      eventGlobal.on('teacher-guideInfo', onResetGuide);
+    });
+    const resetSize = () => {
+      getStepELe();
+    };
+
+    onUnmounted(() => {
+      window.removeEventListener('resize', resetSize);
+      eventGlobal.off('teacher-guideInfo', onResetGuide);
+    });
+
+    const handleNext = () => {
+      if (data.step >= data.steps.length - 1) {
+        endGuide();
+        return;
+      }
+      data.step = data.step + 1;
+      getStepELe();
+    };
+
+    const endGuide = async () => {
+      // let guideInfo =
+      //   JSON.parse(localStorage.getItem('teacher-guideInfo') || '{}') || null;
+      if (!guideInfo.value) {
+        guideInfo.value = { homeGuide: true };
+      } else {
+        guideInfo.value.homeGuide = true;
+      }
+      try {
+        const res = await setGuidance({
+          guideTag: 'teacher-guideInfo',
+          guideValue: JSON.stringify(guideInfo.value)
+        });
+      } catch (e) {
+        console.log(e);
+      }
+      // localStorage.setItem('teacher-guideInfo', JSON.stringify(guideInfo));
+      tipShow.value = false;
+      //  localStorage.setItem('endC')
+    };
+    return () => (
+      <>
+        {tipShow.value ? (
+          <div
+            v-model:show={tipShow.value}
+            class={['n-modal-mask', 'n-modal-mask-guide']}>
+            <div class={styles.content} onClick={() => handleNext()}>
+              <div
+                class={styles.backBtn}
+                onClick={(e: Event) => {
+                  e.stopPropagation();
+                  endGuide();
+                }}>
+                跳过
+              </div>
+              <div
+                class={styles.box}
+                style={{ ...data.box, ...data.steps[data.step].boxStyle }}
+                id={`modeType-${data.step}`}>
+                {data.steps.map((item: any, index) => (
+                  <div
+                    onClick={(e: Event) => e.stopPropagation()}
+                    class={styles.item}
+                    style={
+                      item.type == 'bottom'
+                        ? {
+                            display: index === data.step ? '' : 'none',
+                            left: `${item.eleRect?.left}px`,
+                            top: `-${item.imgStyle?.height}`
+                          }
+                        : {
+                            display: index === data.step ? '' : 'none',
+                            left: `${item.eleRect?.left}px`,
+                            top: `${data.box?.height}`
+                          }
+                    }>
+                    <img
+                      class={styles.img}
+                      style={item.imgStyle}
+                      src={item.img}
+                    />
+                    {/* <img
+                      class={styles.iconHead}
+                      style={item.handStyle}
+                      src={getImage('indexDot.png')}
+                    /> */}
+                    <div class={styles.btns} style={item.btnsStyle}>
+                      {data.step + 1 == data.steps.length ? (
+                        <>
+                          <div
+                            class={[styles.endBtn]}
+                            onClick={() => endGuide()}>
+                            完成
+                          </div>
+                          <div
+                            class={styles.nextBtn}
+                            onClick={() => {
+                              data.step = 0;
+                              getStepELe();
+                            }}>
+                            再看一遍
+                          </div>
+                        </>
+                      ) : (
+                        <div class={styles.btn} onClick={() => handleNext()}>
+                          {data.step !== 0
+                            ? `下一步 ${data.step}/${data.steps.length - 1}`
+                            : '开始体验'}
+                        </div>
+                      )}
+                    </div>
+                  </div>
+                ))}
+              </div>
+            </div>
+          </div>
+        ) : null}
+      </>
+    );
+  }
+});

+ 44 - 2
src/store/modules/catchData.ts

@@ -4,7 +4,8 @@ import {
   getSubjectList,
   getSubjectList2,
   getCategories,
-  api_musicalInstrumentList
+  api_musicalInstrumentList,
+  api_musicTagTree
 } from '@/api/user';
 import deepClone from '/src/helpers/deep-clone';
 
@@ -14,7 +15,8 @@ export const useCatchStore = defineStore('catch-store', {
     musicTypeList: [] as any[], // 乐谱分类
     subjectList: [] as any[], // 声部列表,
     musicInstrumentList: [] as any[], // 乐器列表,
-    subjectInstruemnts: [] as any[] // 乐器列表,
+    subjectInstruemnts: [] as any[], // 乐器列表,
+    musicTagTree: [] as any[] // 分类列表
   }),
   getters: {
     getBookVersion(): any[] {
@@ -82,6 +84,9 @@ export const useCatchStore = defineStore('catch-store', {
         },
         ...this.subjectInstruemnts
       ];
+    },
+    getMusicTagTree(): any[] {
+      return this.musicTagTree;
     }
   },
   actions: {
@@ -100,6 +105,9 @@ export const useCatchStore = defineStore('catch-store', {
     setMusicInstruments(instruments: any[]) {
       this.musicInstrumentList = instruments;
     },
+    setMusicTagTree(tagTree: any[]) {
+      this.musicTagTree = tagTree;
+    },
     /**
      * 判断是否有声部数据,如不存在则获取声部列表
      * @returns Promise
@@ -250,6 +258,40 @@ export const useCatchStore = defineStore('catch-store', {
       } catch (e) {
         return Promise.reject(e);
       }
+    },
+
+    // ?queryCategory=true
+    /**
+     * 获取层级
+     * @returns Promise
+     */
+    async getMusicTagTreeApi() {
+      try {
+        // // 判断是否存在声部数据
+        if (this.getMusicTagTree && this.getMusicTagTree.length > 0) {
+          return Promise.resolve();
+        }
+        const { data } = await api_musicTagTree({
+          queryCategory: true
+        });
+
+        const result = data || [];
+        result.forEach((item: any) => {
+          if (item.children && item.children.length > 0) {
+            item.children.forEach((child: any) => {
+              child.children =
+                child.categoriesList && child.categoriesList.length > 0
+                  ? child.categoriesList
+                  : '';
+            });
+          }
+        });
+        console.log(result, 'result');
+        this.setMusicTagTree(result || []);
+        return Promise.resolve();
+      } catch (e) {
+        return Promise.reject(e);
+      }
     }
   }
 });

+ 2 - 1
src/views/natural-resources/components/share-resources/index.tsx

@@ -97,7 +97,8 @@ export default defineComponent({
     };
 
     onMounted(() => {
-      getList();
+      // 会在搜索组件里面调用,因为有初始化搜索条件
+      // getList();
     });
     return () => (
       <>

+ 94 - 9
src/views/natural-resources/components/share-resources/search-group-resources.tsx

@@ -22,11 +22,15 @@ export default defineComponent({
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
-      bookVersionId: null,
+      grade: null as any,
+      bookVersionId: null as any,
+      musicSheetCategoriesId: null as any,
       subjectId: null
     });
     const state = reactive({
-      tempSubjectId: null
+      tempSubjectId: null,
+      gradeList: [] as any[],
+      musicCategory: [] as any
     });
 
     const onSearch = () => {
@@ -87,10 +91,37 @@ export default defineComponent({
       });
       return obj;
     };
+
+    const onChangeSearch = (type: string, list: any) => {
+      if (type === 'version') {
+        console.log(list, 'list');
+        state.gradeList = list || [];
+        if (state.gradeList.length > 0) {
+          forms.grade = state.gradeList[0].id;
+          state.musicCategory = state.gradeList[0].children || [];
+          if (state.musicCategory.length > 0) {
+            forms.musicSheetCategoriesId = state.musicCategory[0].id;
+          }
+        } else {
+          state.musicCategory = [] as any;
+          forms.grade = null;
+          forms.musicSheetCategoriesId = null;
+        }
+      } else if (type === 'grade') {
+        state.musicCategory = list || [];
+        if (state.musicCategory.length > 0) {
+          forms.musicSheetCategoriesId = state.musicCategory[0].id;
+        } else {
+          forms.musicSheetCategoriesId = null;
+        }
+      }
+    };
+
     onMounted(async () => {
       // console.log('加载');
       // 获取教材分类列表
-      await catchStore.getMusicSheetCategory();
+      // await catchStore.getMusicSheetCategory();
+      await catchStore.getMusicTagTreeApi();
       // 获取声部列表
       await catchStore.getSubjects();
 
@@ -99,7 +130,22 @@ export default defineComponent({
         // hiddenHeight.value = collapseWrapRef.value.offsetHeight / line.value;
         // 默认隐藏
         getLive();
+
+        const musicTagTreeList = catchStore.getMusicTagTree;
+        if (musicTagTreeList.length > 0) {
+          forms.bookVersionId = musicTagTreeList[0].id;
+          state.gradeList = musicTagTreeList[0].children || [];
+          if (state.gradeList.length > 0) {
+            forms.grade = state.gradeList[0].id;
+            state.musicCategory = state.gradeList[0].children || [];
+            if (state.musicCategory.length > 0) {
+              forms.musicSheetCategoriesId = state.musicCategory[0].id;
+            }
+          }
+        }
       }
+
+      onSearch();
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -147,7 +193,46 @@ export default defineComponent({
           </NButton> */}
         </div>
         <NForm labelAlign="left" labelPlacement="left">
-          {forms.type === 'MUSIC' && (
+          <NFormItem label="版本:">
+            <NSpace class={styles.spaceSection}>
+              {catchStore.getMusicTagTree.map((subject: any) => (
+                <span
+                  class={[
+                    styles.textBtn,
+                    forms.bookVersionId === subject.id && styles.textBtnActive
+                  ]}
+                  onClick={() => {
+                    forms.bookVersionId = subject.id;
+                    onChangeSearch('version', subject.children || []);
+                    onSearch();
+                  }}>
+                  {subject.name}
+                </span>
+              ))}
+            </NSpace>
+          </NFormItem>
+          {state.gradeList.length > 0 && (
+            <NFormItem label="年级:">
+              <NSpace class={styles.spaceSection}>
+                {state.gradeList.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.grade === subject.id && styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.grade = subject.id;
+                      onChangeSearch('grade', subject.children || []);
+                      onSearch();
+                    }}>
+                    {subject.name}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
+          {forms.type === 'MUSIC' && state.musicCategory.length > 0 && (
             <div class={[styles.collapsSection]}>
               <NFormItem label="教材:">
                 <div
@@ -158,20 +243,20 @@ export default defineComponent({
                   ]}
                   ref={collapseWrapRef}>
                   <NSpace class={[styles.spaceSection2]}>
-                    {catchStore.getAllMusicCategories.map((music: any) => (
+                    {state.musicCategory.map((music: any) => (
                       <NButton
                         ref={musicCateRef}
-                        secondary={forms.bookVersionId === music.id}
-                        quaternary={forms.bookVersionId !== music.id}
+                        secondary={forms.musicSheetCategoriesId === music.id}
+                        quaternary={forms.musicSheetCategoriesId !== music.id}
                         strong
                         focusable={false}
                         type={
-                          forms.bookVersionId === music.id
+                          forms.musicSheetCategoriesId === music.id
                             ? 'primary'
                             : 'default'
                         }
                         onClick={() => {
-                          forms.bookVersionId = music.id;
+                          forms.musicSheetCategoriesId = music.id;
                           onSearch();
                         }}>
                         {music.name}

+ 158 - 155
src/views/natural-resources/model/add-teaching/index.module.less

@@ -1,155 +1,158 @@
-.container {
-  min-height: 100%;
-  display: flex;
-  flex-direction: column;
-
-  :global {
-
-    .n-base-selection--error-status,
-    .n-input--error-status {
-      animation: errorRotate 0.3s ease 3;
-    }
-  }
-}
-
-.closeBtn {
-  position: absolute;
-  top: -15px;
-  right: -10px;
-
-  img {
-    width: 44px;
-    height: 44px;
-  }
-}
-
-.topForms {
-  padding: 40px 40px 0;
-  display: flex;
-  align-items: center;
-
-  :global {
-    .n-upload {
-      width: 210px !important;
-    }
-
-    .n-upload-trigger.n-upload-trigger--image-card {
-      width: 210px !important;
-      height: 297px !important;
-    }
-
-    .n-upload-file.n-upload-file--image-card-type {
-      width: 210px !important;
-      height: 297px !important;
-      border-radius: 12px;
-    }
-
-    .n-upload-dragger {
-      border-radius: 12px;
-      background: #F9FAFD;
-      border: 2px solid #DCE2F1;
-
-      &:hover {
-        border: 2px solid #198CFE;
-      }
-    }
-  }
-
-  .uploadContent {
-    .iconUpload {
-      width: 60px;
-      height: 60px;
-    }
-
-    p {
-      padding-top: 32px;
-      font-size: 18px;
-      color: #9EADD9;
-      line-height: 25px;
-    }
-  }
-
-  .topFormInput {
-    margin-left: 60px;
-  }
-}
-
-.menuTitle {
-  display: flex;
-  align-items: center;
-  padding: 20px 40px;
-  font-size: 18px;
-  font-weight: 600;
-  color: #131415;
-  // border-bottom: 1px solid #EDEEF3;
-
-  .iconMenu {
-    margin-right: 8px;
-    width: 24px;
-    height: 24px;
-  }
-}
-
-.lessonItem {
-  border-radius: 20px;
-  background: #F7F9FF;
-  position: relative;
-  margin: 0 40px 24px;
-  padding: 24px 26px 0;
-  --n-border: 1px solid #289bff !important;
-
-  :global {
-    .n-input {
-      width: 320px;
-    }
-  }
-
-  .btnGroupAll {
-    gap: 8px 24px !important;
-  }
-
-  .btnImg {
-    width: 50px;
-    height: 50px;
-  }
-}
-
-.line {
-  background-color: #EDEEF3;
-  width: calc(100% - 80px);
-  margin: 0 auto;
-  height: 1px;
-}
-
-//
-.addUnitBtn {
-
-  height: 52px;
-  border-radius: 12px;
-  margin: 24px 40px 0;
-
-  width: calc(100% - 80px) !important;
-  background: #E8F4FF;
-
-  &:not(.n-button--disabled):hover,
-  &:not(.n-button--disabled):active,
-  &:not(.n-input--disabled).n-input--focus {
-    background: #E8F4FF;
-  }
-
-  img {
-    width: 16px;
-    height: 16px;
-  }
-}
-
-.btnGroup {
-  padding: 40px 0;
-
-  :global {
-    .n-button {
-      height: 47px;
-      min-width: 156px;
-    }
-  }
-}
+.container {
+  min-height: 100%;
+  display: flex;
+  flex-direction: column;
+
+  :global {
+
+    .n-base-selection--error-status,
+    .n-input--error-status {
+      animation: errorRotate 0.3s ease 3;
+    }
+  }
+}
+
+.closeBtn {
+  position: absolute;
+  top: -15px;
+  right: -10px;
+  background: transparent;
+  width: 44px;
+  height: 44px;
+
+  img {
+    width: 44px;
+    height: 44px;
+  }
+}
+
+.topForms {
+  padding: 40px 40px 0;
+  display: flex;
+  align-items: center;
+
+  :global {
+    .n-upload {
+      width: 210px !important;
+    }
+
+    .n-upload-trigger.n-upload-trigger--image-card {
+      width: 210px !important;
+      height: 297px !important;
+    }
+
+    .n-upload-file.n-upload-file--image-card-type {
+      width: 210px !important;
+      height: 297px !important;
+      border-radius: 12px;
+    }
+
+    .n-upload-dragger {
+      border-radius: 12px;
+      background: #F9FAFD;
+      border: 2px solid #DCE2F1;
+
+      &:hover {
+        border: 2px solid #198CFE;
+      }
+    }
+  }
+
+  .uploadContent {
+    .iconUpload {
+      width: 60px;
+      height: 60px;
+    }
+
+    p {
+      padding-top: 32px;
+      font-size: 18px;
+      color: #9EADD9;
+      line-height: 25px;
+    }
+  }
+
+  .topFormInput {
+    margin-left: 60px;
+  }
+}
+
+.menuTitle {
+  display: flex;
+  align-items: center;
+  padding: 20px 40px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #131415;
+  // border-bottom: 1px solid #EDEEF3;
+
+  .iconMenu {
+    margin-right: 8px;
+    width: 24px;
+    height: 24px;
+  }
+}
+
+.lessonItem {
+  border-radius: 20px;
+  background: #F7F9FF;
+  position: relative;
+  margin: 0 40px 24px;
+  padding: 24px 26px 0;
+  --n-border: 1px solid #289bff !important;
+
+  :global {
+    .n-input {
+      width: 320px;
+    }
+  }
+
+  .btnGroupAll {
+    gap: 8px 24px !important;
+  }
+
+  .btnImg {
+    width: 50px;
+    height: 50px;
+  }
+}
+
+.line {
+  background-color: #EDEEF3;
+  width: calc(100% - 80px);
+  margin: 0 auto;
+  height: 1px;
+}
+
+//
+.addUnitBtn {
+
+  height: 52px;
+  border-radius: 12px;
+  margin: 24px 40px 0;
+
+  width: calc(100% - 80px) !important;
+  background: #E8F4FF;
+
+  &:not(.n-button--disabled):hover,
+  &:not(.n-button--disabled):active,
+  &:not(.n-input--disabled).n-input--focus {
+    background: #E8F4FF;
+  }
+
+  img {
+    width: 16px;
+    height: 16px;
+  }
+}
+
+.btnGroup {
+  padding: 40px 0;
+
+  :global {
+    .n-button {
+      height: 47px;
+      min-width: 156px;
+    }
+  }
+}

+ 471 - 467
src/views/natural-resources/model/add-teaching/index.tsx

@@ -1,467 +1,471 @@
-import {
-  NButton,
-  NCascader,
-  NForm,
-  NFormItem,
-  NInput,
-  NScrollbar,
-  NSelect,
-  NSpace,
-  useMessage
-} from 'naive-ui';
-import {
-  TransitionGroup,
-  defineComponent,
-  onMounted,
-  reactive,
-  ref
-} from 'vue';
-import styles from './index.module.less';
-import UploadFile from '@/components/upload-file';
-import { nextTick } from 'vue';
-import { scrollToErrorForm } from '@/utils';
-import { api_lessonCoursewareSave } from '../../api';
-import iconUpload from '../../images/icon-upload.png';
-import iconUpload2 from '../../images/icon-upload2.png';
-import iconAdd from '../../images/icon-add.png';
-import iconMenu from '../../images/icon-menu.png';
-import btnAdd from '../../images/btn-add.png';
-import btnDelete from '../../images/btn-delete.png';
-import btnUp from '../../images/btn-up.png';
-import btnDown from '../../images/btn-down.png';
-import btnRemove from '../../images/btn-remove.png';
-import { lessonCoursewareDetail } from '/src/views/prepare-lessons/api';
-import { useCatchStore } from '/src/store/modules/catchData';
-export const BOOK_DATA = {
-  grades: [
-    { label: '一年级', value: 1 },
-    { label: '二年级', value: 2 },
-    { label: '三年级', value: 3 },
-    { label: '四年级', value: 4 },
-    { label: '五年级', value: 5 },
-    { label: '六年级', value: 6 },
-    { label: '七年级', value: 7 },
-    { label: '八年级', value: 8 },
-    { label: '九年级', value: 9 }
-  ],
-  bookTypes: [
-    { label: '上册', value: 'LAST' },
-    { label: '下册', value: 'NEXT' }
-  ]
-};
-
-/** 添加单元 */
-const createLesson = () => {
-  return {
-    key: 'item' + Date.now(),
-    name: '', // 单元名称
-    lessonTargetDesc: '', // 课时目标描述
-    knowledgeList: [
-      {
-        key: Date.now() + '' + 0,
-        name: '' // 章节名称
-      }
-    ] // 章节信息
-  };
-};
-const initState = () => ({
-  id: null, // 教材id
-  name: '',
-  currentGradeNum: null as any,
-  instrumentIds: null as any,
-  // bookType: null, // 上下册
-  coverImg: '', // 封面
-  instruemntIds: [] as any,
-  enableFlag: true, // 状态
-  type: 'COURSEWARE', // 教材类型:COURSEWARE,THEORY,可用值:COURSEWARE,THEORY
-  lessonList: [createLesson()] // 单元列表
-});
-
-export default defineComponent({
-  name: 'addNatural',
-  props: {
-    item: {
-      type: Object,
-      default: () => ({})
-    }
-  },
-  emits: ['close', 'confirm'],
-  setup(props, { emit }) {
-    const catchStore = useCatchStore();
-    const message = useMessage();
-    const data = reactive({
-      uploading: false,
-      subjectList: [] as any
-    });
-    const formRef = ref();
-    const form = reactive(initState());
-    const handleSave = () => {
-      formRef.value?.validate((err: any) => {
-        if (err) {
-          nextTick(scrollToErrorForm);
-          return;
-        }
-        handleSubmit();
-      });
-    };
-    const handleSubmit = async () => {
-      data.uploading = true;
-      try {
-        const { currentGradeNum, instrumentIds, ...more } = form;
-        await api_lessonCoursewareSave({
-          currentGradeNum: currentGradeNum.join(','),
-          instrumentIds: instrumentIds.join(','),
-          ...more
-        });
-        Object.assign(form, initState());
-        message.success(props.item.id ? '保存成功' : '添加成功');
-        emit('close', true);
-        emit('confirm');
-      } catch {
-        //
-      }
-      data.uploading = false;
-    };
-
-    onMounted(async () => {
-      await catchStore.getSubjects();
-      if (props.item.id) {
-        const { data } = await lessonCoursewareDetail({ id: props.item.id });
-        form.id = data.id;
-        form.name = data.name;
-        form.currentGradeNum = data.currentGradeNum
-          ? data.currentGradeNum.split(',').map((item: any) => Number(item))
-          : null;
-        form.instrumentIds = data.instrumentIds
-          ? data.instrumentIds.split(',').map((item: any) => item)
-          : null;
-        // form.bookType = data.bookType;
-        form.coverImg = data.coverImg;
-        form.lessonList = [];
-        const lessonList = data.lessonList || [];
-        const tempLesson: any[] = [];
-        lessonList.forEach((item: any) => {
-          const tmpItem: any = {
-            id: item.id,
-            key: 'item' + Date.now() + '-' + Math.random() * 100,
-            name: item.name,
-            lessonTargetDesc: item.lessonTargetDesc,
-            knowledgeList: [] as any
-          };
-
-          if (item.knowledgeList && item.knowledgeList.length) {
-            item.knowledgeList.forEach((knowledge: any) => {
-              tmpItem.knowledgeList.push({
-                id: knowledge.id,
-                key: Date.now() + '-' + Math.random() * 100,
-                name: knowledge.name
-              });
-            });
-          }
-          tempLesson.push(tmpItem);
-        });
-
-        form.lessonList = tempLesson;
-      }
-
-      data.subjectList = catchStore.getEnableSingleAllSubjects(
-        form.instrumentIds
-      );
-    });
-    return () => (
-      <div class={styles.container}>
-        <NScrollbar style={{ 'max-height': '65vh' }}>
-          <NForm
-            ref={formRef}
-            labelPlacement="left"
-            labelWidth={120}
-            model={form}>
-            <div class={styles.topForms}>
-              <NFormItem
-                path="coverImg"
-                rule={[
-                  {
-                    required: true,
-                    message: '请上传教材封面',
-                    trigger: ['change']
-                  }
-                ]}>
-                <UploadFile
-                  cropper
-                  // tips="建议尺寸:210*297, 文件大小: 5MB以内;"
-                  v-model:fileList={form.coverImg}
-                  showType="custom"
-                  size={2}
-                  accept=".jpg,jpeg,.png"
-                  options={{
-                    autoCropWidth: 210,
-                    autoCropHeight: 297,
-                    fixedBox: true
-                  }}>
-                  {{
-                    custom: () => (
-                      <div class={styles.uploadContent}>
-                        <img src={iconUpload2} class={styles.iconUpload} />
-                        <p>请上传教材封面</p>
-                      </div>
-                    )
-                  }}
-                </UploadFile>
-              </NFormItem>
-              <div class={styles.topFormInput}>
-                <NFormItem
-                  style={{ minWidth: '360px' }}
-                  path="name"
-                  rule={[
-                    {
-                      required: true,
-                      message: '请输入教材名称',
-                      trigger: ['blur', 'change']
-                    }
-                  ]}>
-                  <NInput
-                    placeholder="请输入教材名称"
-                    maxlength={25}
-                    v-model:value={form.name}
-                    clearable></NInput>
-                </NFormItem>
-                <NFormItem
-                  path="currentGradeNum"
-                  rule={{
-                    required: true,
-                    message: '请选择年级',
-                    trigger: 'change',
-                    type: 'array'
-                  }}>
-                  <NSelect
-                    style={{ minWidth: '360px' }}
-                    placeholder="请选择年级"
-                    options={BOOK_DATA.grades}
-                    v-model:value={form.currentGradeNum}
-                    clearable
-                    multiple
-                    filterable
-                    maxTagCount={3}
-                  />
-                </NFormItem>
-                <NFormItem
-                  path="instrumentIds"
-                  style={{ width: '360px' }}
-                  rule={{
-                    required: true,
-                    message: '请选择乐器',
-                    trigger: 'change',
-                    type: 'array'
-                  }}>
-                  <NCascader
-                    placeholder="请选择乐器"
-                    options={data.subjectList}
-                    v-model:value={form.instrumentIds}
-                    checkStrategy="child"
-                    showPath={false}
-                    childrenField="instruments"
-                    expandTrigger="hover"
-                    labelField="name"
-                    valueField="id"
-                    clearable
-                    filterable
-                    multiple
-                    maxTagCount="responsive"
-                    style={{ width: '400px' }}
-                  />
-                </NFormItem>
-                {/* <NFormItem
-                  path="bookType"
-                  style={{ width: '360px' }}
-                  rule={{
-                    required: true,
-                    message: '请选择册别',
-                    trigger: 'change'
-                  }}>
-                  <NSelect
-                    placeholder="请选择册别"
-                    options={BOOK_DATA.bookTypes}
-                    v-model:value={form.bookType}
-                    clearable
-                  />
-                </NFormItem> */}
-              </div>
-            </div>
-
-            <div class={styles.menuTitle}>
-              <img src={iconMenu} class={styles.iconMenu} />
-              目录
-            </div>
-            <TransitionGroup name="list" tag="div">
-              {form.lessonList.map((item, index) => {
-                return (
-                  <NSpace
-                    class={styles.lessonItem}
-                    wrap={false}
-                    wrapItem={false}
-                    align="start"
-                    key={item.key}>
-                    <NFormItem
-                      label="单元名称"
-                      labelPlacement="top"
-                      path={`lessonList[${index}].name`}
-                      rule={{
-                        required: true,
-                        message: '填写单元名称',
-                        trigger: ['blur', 'change']
-                      }}>
-                      <NInput
-                        placeholder="填写单元名称"
-                        maxlength={25}
-                        v-model:value={item.name}
-                        clearable></NInput>
-                    </NFormItem>
-                    <TransitionGroup name="list" tag="div">
-                      {item.knowledgeList.map((know, knowIndex) => {
-                        return (
-                          <NFormItem
-                            style={{
-                              '--n-label-height': knowIndex === 0 ? '26px' : '0'
-                            }}
-                            labelPlacement="top"
-                            label={knowIndex === 0 ? '章节名称' : ''}
-                            key={know.key}
-                            path={`lessonList[${index}].knowledgeList[${knowIndex}].name`}
-                            rule={{
-                              required: true,
-                              message: '填写章节名称',
-                              trigger: ['blur', 'change']
-                            }}>
-                            <NSpace
-                              wrap={false}
-                              align="center"
-                              class={styles.btnGroupAll}
-                              wrapItem={false}>
-                              <NInput
-                                maxlength={25}
-                                placeholder="填写章节名称"
-                                v-model:value={know.name}
-                                clearable></NInput>
-                              <NButton
-                                quaternary
-                                circle
-                                onClick={() => {
-                                  item.knowledgeList.splice(knowIndex + 1, 0, {
-                                    name: '',
-                                    key: Date.now() + '' + knowIndex
-                                  });
-                                }}>
-                                {{
-                                  icon: () => (
-                                    <img src={btnAdd} class={styles.btnImg} />
-                                  )
-                                }}
-                              </NButton>
-                              <NButton
-                                quaternary
-                                circle
-                                disabled={item.knowledgeList.length < 2}
-                                onClick={() => {
-                                  item.knowledgeList.splice(knowIndex, 1);
-                                }}>
-                                {{
-                                  icon: () => (
-                                    <img
-                                      src={btnDelete}
-                                      class={styles.btnImg}
-                                    />
-                                  )
-                                }}
-                              </NButton>
-                              <NButton
-                                quaternary
-                                circle
-                                disabled={knowIndex === 0}
-                                onClick={() => {
-                                  if (knowIndex === 0) return;
-                                  const tmp = item.knowledgeList[knowIndex - 1];
-                                  item.knowledgeList[knowIndex - 1] =
-                                    item.knowledgeList[knowIndex];
-                                  item.knowledgeList[knowIndex] = tmp;
-                                }}>
-                                {{
-                                  icon: () => (
-                                    <img src={btnUp} class={styles.btnImg} />
-                                  )
-                                }}
-                              </NButton>
-                              <NButton
-                                quaternary
-                                circle
-                                disabled={
-                                  knowIndex === item.knowledgeList.length - 1
-                                }
-                                onClick={() => {
-                                  if (
-                                    knowIndex ===
-                                    item.knowledgeList.length - 1
-                                  )
-                                    return;
-                                  const tmp = item.knowledgeList[knowIndex + 1];
-                                  item.knowledgeList[knowIndex + 1] =
-                                    item.knowledgeList[knowIndex];
-                                  item.knowledgeList[knowIndex] = tmp;
-                                }}>
-                                {{
-                                  icon: () => (
-                                    <img src={btnDown} class={styles.btnImg} />
-                                  )
-                                }}
-                              </NButton>
-                            </NSpace>
-                          </NFormItem>
-                        );
-                      })}
-                    </TransitionGroup>
-                    <NButton
-                      class={styles.closeBtn}
-                      secondary
-                      circle
-                      size="small"
-                      disabled={form.lessonList.length < 2}
-                      onClick={() => {
-                        form.lessonList.splice(index, 1);
-                      }}>
-                      <img src={btnRemove} />
-                    </NButton>
-                  </NSpace>
-                );
-              })}
-            </TransitionGroup>
-            <div class={styles.line}></div>
-            <NButton
-              block
-              class={styles.addUnitBtn}
-              ghost
-              color="#198CFE"
-              onClick={() => {
-                form.lessonList.push(createLesson());
-              }}>
-              {{
-                icon: () => <img src={iconAdd} />,
-                default: () => '新增单元'
-              }}
-            </NButton>
-          </NForm>
-        </NScrollbar>
-        <NSpace class={styles.btnGroup} justify="center">
-          <NButton round onClick={() => emit('close')}>
-            取消
-          </NButton>
-          <NButton
-            round
-            loading={data.uploading}
-            type="primary"
-            onClick={() => handleSave()}>
-            保存
-          </NButton>
-        </NSpace>
-      </div>
-    );
-  }
-});
+import {
+  NButton,
+  NCascader,
+  NForm,
+  NFormItem,
+  NInput,
+  NScrollbar,
+  NSelect,
+  NSpace,
+  useMessage
+} from 'naive-ui';
+import {
+  TransitionGroup,
+  defineComponent,
+  onMounted,
+  reactive,
+  ref
+} from 'vue';
+import styles from './index.module.less';
+import UploadFile from '@/components/upload-file';
+import { nextTick } from 'vue';
+import { scrollToErrorForm } from '@/utils';
+import { api_lessonCoursewareSave } from '../../api';
+import iconUpload from '../../images/icon-upload.png';
+import iconUpload2 from '../../images/icon-upload2.png';
+import iconAdd from '../../images/icon-add.png';
+import iconMenu from '../../images/icon-menu.png';
+import btnAdd from '../../images/btn-add.png';
+import btnDelete from '../../images/btn-delete.png';
+import btnUp from '../../images/btn-up.png';
+import btnDown from '../../images/btn-down.png';
+import btnRemove from '../../images/btn-remove.png';
+import { lessonCoursewareDetail } from '/src/views/prepare-lessons/api';
+import { useCatchStore } from '/src/store/modules/catchData';
+export const BOOK_DATA = {
+  grades: [
+    { label: '一年级', value: 1 },
+    { label: '二年级', value: 2 },
+    { label: '三年级', value: 3 },
+    { label: '四年级', value: 4 },
+    { label: '五年级', value: 5 },
+    { label: '六年级', value: 6 },
+    { label: '七年级', value: 7 },
+    { label: '八年级', value: 8 },
+    { label: '九年级', value: 9 }
+  ],
+  bookTypes: [
+    { label: '上册', value: 'LAST' },
+    { label: '下册', value: 'NEXT' }
+  ]
+};
+
+/** 添加单元 */
+const createLesson = () => {
+  return {
+    key: 'item' + Date.now(),
+    name: '', // 单元名称
+    lessonTargetDesc: '', // 课时目标描述
+    knowledgeList: [
+      {
+        key: Date.now() + '' + 0,
+        name: '' // 章节名称
+      }
+    ] // 章节信息
+  };
+};
+const initState = () => ({
+  id: null, // 教材id
+  name: '',
+  currentGradeNum: null as any,
+  instrumentIds: null as any,
+  // bookType: null, // 上下册
+  coverImg: '', // 封面
+  instruemntIds: [] as any,
+  enableFlag: true, // 状态
+  type: 'COURSEWARE', // 教材类型:COURSEWARE,THEORY,可用值:COURSEWARE,THEORY
+  lessonList: [] as any // 单元列表
+});
+
+export default defineComponent({
+  name: 'addNatural',
+  props: {
+    item: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const message = useMessage();
+    const data = reactive({
+      uploading: false,
+      subjectList: [] as any
+    });
+    const formRef = ref();
+    const form = reactive(initState());
+    const handleSave = () => {
+      formRef.value?.validate((err: any) => {
+        if (err) {
+          nextTick(scrollToErrorForm);
+          return;
+        }
+        handleSubmit();
+      });
+    };
+    const handleSubmit = async () => {
+      data.uploading = true;
+      try {
+        const { currentGradeNum, instrumentIds, ...more } = form;
+        await api_lessonCoursewareSave({
+          currentGradeNum: currentGradeNum.join(','),
+          instrumentIds: instrumentIds.join(','),
+          ...more
+        });
+        Object.assign(form, initState());
+        message.success(props.item.id ? '保存成功' : '添加成功');
+        emit('close', true);
+        emit('confirm');
+      } catch {
+        //
+      }
+      data.uploading = false;
+    };
+
+    onMounted(async () => {
+      if (!props.item.id) {
+        form.lessonList = [createLesson()];
+      }
+      await catchStore.getSubjects();
+      if (props.item.id) {
+        // form.lessonList = [];
+        const { data } = await lessonCoursewareDetail({ id: props.item.id });
+        form.id = data.id;
+        form.name = data.name;
+        form.currentGradeNum = data.currentGradeNum
+          ? data.currentGradeNum.split(',').map((item: any) => Number(item))
+          : null;
+        form.instrumentIds = data.instrumentIds
+          ? data.instrumentIds.split(',').map((item: any) => item)
+          : null;
+        // form.bookType = data.bookType;
+        form.coverImg = data.coverImg;
+        form.lessonList = [];
+        const lessonList = data.lessonList || [];
+        const tempLesson: any[] = [];
+        lessonList.forEach((item: any) => {
+          const tmpItem: any = {
+            id: item.id,
+            key: 'item' + Date.now() + '-' + Math.random() * 100,
+            name: item.name,
+            lessonTargetDesc: item.lessonTargetDesc,
+            knowledgeList: [] as any
+          };
+
+          if (item.knowledgeList && item.knowledgeList.length) {
+            item.knowledgeList.forEach((knowledge: any) => {
+              tmpItem.knowledgeList.push({
+                id: knowledge.id,
+                key: Date.now() + '-' + Math.random() * 100,
+                name: knowledge.name
+              });
+            });
+          }
+          tempLesson.push(tmpItem);
+        });
+
+        form.lessonList = tempLesson;
+      }
+
+      data.subjectList = catchStore.getEnableSingleAllSubjects(
+        form.instrumentIds
+      );
+    });
+    return () => (
+      <div class={styles.container}>
+        <NScrollbar style={{ 'max-height': '65vh' }}>
+          <NForm
+            ref={formRef}
+            labelPlacement="left"
+            labelWidth={120}
+            model={form}>
+            <div class={styles.topForms}>
+              <NFormItem
+                path="coverImg"
+                rule={[
+                  {
+                    required: true,
+                    message: '请上传教材封面',
+                    trigger: ['change']
+                  }
+                ]}>
+                <UploadFile
+                  cropper
+                  // tips="建议尺寸:210*297, 文件大小: 5MB以内;"
+                  v-model:fileList={form.coverImg}
+                  showType="custom"
+                  size={2}
+                  accept=".jpg,jpeg,.png"
+                  options={{
+                    autoCropWidth: 210,
+                    autoCropHeight: 297,
+                    fixedBox: true
+                  }}>
+                  {{
+                    custom: () => (
+                      <div class={styles.uploadContent}>
+                        <img src={iconUpload2} class={styles.iconUpload} />
+                        <p>请上传教材封面</p>
+                      </div>
+                    )
+                  }}
+                </UploadFile>
+              </NFormItem>
+              <div class={styles.topFormInput}>
+                <NFormItem
+                  style={{ minWidth: '360px' }}
+                  path="name"
+                  rule={[
+                    {
+                      required: true,
+                      message: '请输入教材名称',
+                      trigger: ['blur', 'change']
+                    }
+                  ]}>
+                  <NInput
+                    placeholder="请输入教材名称"
+                    maxlength={25}
+                    v-model:value={form.name}
+                    clearable></NInput>
+                </NFormItem>
+                <NFormItem
+                  path="currentGradeNum"
+                  rule={{
+                    required: true,
+                    message: '请选择年级',
+                    trigger: 'change',
+                    type: 'array'
+                  }}>
+                  <NSelect
+                    style={{ minWidth: '360px' }}
+                    placeholder="请选择年级"
+                    options={BOOK_DATA.grades}
+                    v-model:value={form.currentGradeNum}
+                    clearable
+                    multiple
+                    filterable
+                    maxTagCount={3}
+                  />
+                </NFormItem>
+                <NFormItem
+                  path="instrumentIds"
+                  style={{ width: '360px' }}
+                  rule={{
+                    required: true,
+                    message: '请选择乐器',
+                    trigger: 'change',
+                    type: 'array'
+                  }}>
+                  <NCascader
+                    placeholder="请选择乐器"
+                    options={data.subjectList}
+                    v-model:value={form.instrumentIds}
+                    checkStrategy="child"
+                    showPath={false}
+                    childrenField="instruments"
+                    expandTrigger="hover"
+                    labelField="name"
+                    valueField="id"
+                    clearable
+                    filterable
+                    multiple
+                    maxTagCount="responsive"
+                    style={{ width: '400px' }}
+                  />
+                </NFormItem>
+                {/* <NFormItem
+                  path="bookType"
+                  style={{ width: '360px' }}
+                  rule={{
+                    required: true,
+                    message: '请选择册别',
+                    trigger: 'change'
+                  }}>
+                  <NSelect
+                    placeholder="请选择册别"
+                    options={BOOK_DATA.bookTypes}
+                    v-model:value={form.bookType}
+                    clearable
+                  />
+                </NFormItem> */}
+              </div>
+            </div>
+
+            <div class={styles.menuTitle}>
+              <img src={iconMenu} class={styles.iconMenu} />
+              目录
+            </div>
+            <TransitionGroup name="list" tag="div">
+              {form.lessonList.map((item, index) => {
+                return (
+                  <NSpace
+                    class={styles.lessonItem}
+                    wrap={false}
+                    wrapItem={false}
+                    align="start"
+                    key={item.key}>
+                    <NFormItem
+                      label="单元名称"
+                      labelPlacement="top"
+                      path={`lessonList[${index}].name`}
+                      rule={{
+                        required: true,
+                        message: '填写单元名称',
+                        trigger: ['blur', 'change']
+                      }}>
+                      <NInput
+                        placeholder="填写单元名称"
+                        maxlength={25}
+                        v-model:value={item.name}
+                        clearable></NInput>
+                    </NFormItem>
+                    <TransitionGroup name="list" tag="div">
+                      {item.knowledgeList.map((know, knowIndex) => {
+                        return (
+                          <NFormItem
+                            style={{
+                              '--n-label-height': knowIndex === 0 ? '26px' : '0'
+                            }}
+                            labelPlacement="top"
+                            label={knowIndex === 0 ? '章节名称' : ''}
+                            key={know.key}
+                            path={`lessonList[${index}].knowledgeList[${knowIndex}].name`}
+                            rule={{
+                              required: true,
+                              message: '填写章节名称',
+                              trigger: ['blur', 'change']
+                            }}>
+                            <NSpace
+                              wrap={false}
+                              align="center"
+                              class={styles.btnGroupAll}
+                              wrapItem={false}>
+                              <NInput
+                                maxlength={25}
+                                placeholder="填写章节名称"
+                                v-model:value={know.name}
+                                clearable></NInput>
+                              <NButton
+                                quaternary
+                                circle
+                                onClick={() => {
+                                  item.knowledgeList.splice(knowIndex + 1, 0, {
+                                    name: '',
+                                    key: Date.now() + '' + knowIndex
+                                  });
+                                }}>
+                                {{
+                                  icon: () => (
+                                    <img src={btnAdd} class={styles.btnImg} />
+                                  )
+                                }}
+                              </NButton>
+                              <NButton
+                                quaternary
+                                circle
+                                disabled={item.knowledgeList.length < 2}
+                                onClick={() => {
+                                  item.knowledgeList.splice(knowIndex, 1);
+                                }}>
+                                {{
+                                  icon: () => (
+                                    <img
+                                      src={btnDelete}
+                                      class={styles.btnImg}
+                                    />
+                                  )
+                                }}
+                              </NButton>
+                              <NButton
+                                quaternary
+                                circle
+                                disabled={knowIndex === 0}
+                                onClick={() => {
+                                  if (knowIndex === 0) return;
+                                  const tmp = item.knowledgeList[knowIndex - 1];
+                                  item.knowledgeList[knowIndex - 1] =
+                                    item.knowledgeList[knowIndex];
+                                  item.knowledgeList[knowIndex] = tmp;
+                                }}>
+                                {{
+                                  icon: () => (
+                                    <img src={btnUp} class={styles.btnImg} />
+                                  )
+                                }}
+                              </NButton>
+                              <NButton
+                                quaternary
+                                circle
+                                disabled={
+                                  knowIndex === item.knowledgeList.length - 1
+                                }
+                                onClick={() => {
+                                  if (
+                                    knowIndex ===
+                                    item.knowledgeList.length - 1
+                                  )
+                                    return;
+                                  const tmp = item.knowledgeList[knowIndex + 1];
+                                  item.knowledgeList[knowIndex + 1] =
+                                    item.knowledgeList[knowIndex];
+                                  item.knowledgeList[knowIndex] = tmp;
+                                }}>
+                                {{
+                                  icon: () => (
+                                    <img src={btnDown} class={styles.btnImg} />
+                                  )
+                                }}
+                              </NButton>
+                            </NSpace>
+                          </NFormItem>
+                        );
+                      })}
+                    </TransitionGroup>
+                    <NButton
+                      class={styles.closeBtn}
+                      secondary
+                      circle
+                      size="small"
+                      disabled={form.lessonList.length < 2}
+                      onClick={() => {
+                        form.lessonList.splice(index, 1);
+                      }}>
+                      <img src={btnRemove} />
+                    </NButton>
+                  </NSpace>
+                );
+              })}
+            </TransitionGroup>
+            <div class={styles.line}></div>
+            <NButton
+              block
+              class={styles.addUnitBtn}
+              ghost
+              color="#198CFE"
+              onClick={() => {
+                form.lessonList.push(createLesson());
+              }}>
+              {{
+                icon: () => <img src={iconAdd} />,
+                default: () => '新增单元'
+              }}
+            </NButton>
+          </NForm>
+        </NScrollbar>
+        <NSpace class={styles.btnGroup} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton
+            round
+            loading={data.uploading}
+            type="primary"
+            onClick={() => handleSave()}>
+            保存
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 51 - 3
src/views/prepare-lessons/components/resource-main/components/resource-item/resource-search-group/index.tsx

@@ -18,10 +18,13 @@ export default defineComponent({
   },
   setup(props, { emit }) {
     const catchStore = useCatchStore();
+    const musics = ref([] as any);
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
-      bookVersionId: null,
+      grade: null as any,
+      bookVersionId: null as any,
+      musicSheetCategoriesId: null,
       musicalInstrumentId: ''
     });
     const resourceType = ref([] as any);
@@ -32,8 +35,26 @@ export default defineComponent({
 
     const debouncedRequest = useThrottleFn(() => onSearch(), 500);
 
+    const formatParentId = (id: any, list: any, ids = [] as any) => {
+      for (const item of list) {
+        if (item.children && item.children.length > 0) {
+          const cIds: any = formatParentId(id, item.children, [
+            ...ids,
+            item.id
+          ]);
+          if (cIds.includes(id)) {
+            return cIds;
+          }
+        }
+        if (item.id === id) {
+          return [...ids, id];
+        }
+      }
+      return ids;
+    };
     onMounted(async () => {
-      await catchStore.getMusicSheetCategory();
+      // await catchStore.getMusicSheetCategory();
+      await catchStore.getMusicTagTreeApi();
       // 获取教材分类列表
       await catchStore.getSubjects();
       // if (props.type === 'myCollect') {
@@ -94,7 +115,7 @@ export default defineComponent({
           </div>
           {forms.type === 'MUSIC' && props.type === 'shareResources' && (
             <div class={styles.searchSelect}>
-              <NSelect
+              {/* <NSelect
                 placeholder="全部教材"
                 options={[
                   { name: '全部教材', id: null },
@@ -107,6 +128,33 @@ export default defineComponent({
                 onUpdate:value={() => {
                   onSearch();
                 }}
+              /> */}
+              <NCascader
+                placeholder="全部教材"
+                options={[
+                  { id: '', name: '全部教材' },
+                  ...catchStore.getMusicTagTree
+                ]}
+                style={{ width: '100%' }}
+                childrenField="children"
+                valueField="id"
+                labelField="name"
+                checkStrategy="child"
+                expandTrigger="hover"
+                showPath={false}
+                v-model:value={musics.value}
+                onUpdate:value={(value: any) => {
+                  // onSearch();
+                  const selectValue = formatParentId(value, [
+                    { id: '', name: '全部教材' },
+                    ...catchStore.getMusicTagTree
+                  ]);
+
+                  forms.bookVersionId = selectValue[0] || '';
+                  forms.grade = selectValue[1] || '';
+                  forms.musicSheetCategoriesId = selectValue[2] || null;
+                  onSearch();
+                }}
               />
             </div>
           )}

+ 150 - 101
src/views/prepare-lessons/components/resource-main/components/select-music/resource-search-group/index.tsx

@@ -1,101 +1,150 @@
-import { PropType, defineComponent, onMounted, reactive } from 'vue';
-import styles from './index.module.less';
-import { NButton, NCascader, NInput, NSelect, NSpace } from 'naive-ui';
-import { useCatchStore } from '/src/store/modules/catchData';
-import { useThrottleFn } from '@vueuse/core';
-
-export default defineComponent({
-  name: 'resource-search-group',
-  props: {
-    type: {
-      type: String as PropType<'myMusic' | 'sahreMusic' | 'collectMusic'>,
-      default: 'myMusic'
-    }
-  },
-  emits: ['search'],
-  setup(props, { emit }) {
-    const catchStore = useCatchStore();
-    const forms = reactive({
-      name: '',
-      musicSheetCategoriesId: null,
-      musicalInstrumentId: null
-    });
-
-    const onSearch = () => {
-      emit('search', forms);
-    };
-
-    const throttledFn = useThrottleFn(() => onSearch(), 500);
-
-    onMounted(async () => {
-      // 获取教材分类列表
-      await catchStore.getMusicSheetCategory();
-      // 获取声部列表
-      await catchStore.getSubjects();
-    });
-    return () => (
-      <>
-        <div class={styles.searchGroup}>
-          {props.type !== 'myMusic' && (
-            <div class={styles.searchSelect}>
-              <NSelect
-                placeholder="全部教材"
-                options={[
-                  { name: '全部教材', id: null },
-                  ...catchStore.getMusicCategories
-                ]}
-                clearable
-                labelField="name"
-                valueField="id"
-                v-model:value={forms.musicSheetCategoriesId}
-                onUpdate:value={() => {
-                  onSearch();
-                }}
-              />
-            </div>
-          )}
-
-          <div class={styles.searchSelect}>
-            <NCascader
-              placeholder="全部乐器"
-              v-model:value={forms.musicalInstrumentId}
-              options={[...catchStore.getSubjectList]}
-              checkStrategy="child"
-              showPath={false}
-              childrenField="instruments"
-              expandTrigger="hover"
-              clearable
-              filterable
-              onUpdate:value={() => {
-                onSearch();
-              }}
-            />
-          </div>
-          <NInput
-            type="text"
-            placeholder="请输入搜索关键词"
-            clearable
-            v-model:value={forms.name}
-            class={styles.inputSearch}
-            onKeyup={(e: KeyboardEvent) => {
-              if (e.code === 'Enter') {
-                throttledFn();
-              }
-            }}
-            onClear={() => {
-              forms.name = '';
-              throttledFn();
-            }}>
-            {{
-              prefix: () => (
-                <span
-                  class={'icon-search-input'}
-                  onClick={() => throttledFn()}></span>
-              )
-            }}
-          </NInput>
-        </div>
-      </>
-    );
-  }
-});
+import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import { NButton, NCascader, NInput, NSelect, NSpace } from 'naive-ui';
+import { useCatchStore } from '/src/store/modules/catchData';
+import { useThrottleFn } from '@vueuse/core';
+
+export default defineComponent({
+  name: 'resource-search-group',
+  props: {
+    type: {
+      type: String as PropType<'myMusic' | 'sahreMusic' | 'collectMusic'>,
+      default: 'myMusic'
+    }
+  },
+  emits: ['search'],
+  setup(props, { emit }) {
+    const catchStore = useCatchStore();
+    const musics = ref([] as any);
+    const forms = reactive({
+      name: '',
+      grade: null as any,
+      bookVersionId: null as any,
+      musicSheetCategoriesId: null,
+      musicalInstrumentId: null
+    });
+
+    const onSearch = () => {
+      emit('search', forms);
+    };
+
+    const throttledFn = useThrottleFn(() => onSearch(), 500);
+
+    const formatParentId = (id: any, list: any, ids = [] as any) => {
+      for (const item of list) {
+        if (item.children && item.children.length > 0) {
+          const cIds: any = formatParentId(id, item.children, [
+            ...ids,
+            item.id
+          ]);
+          if (cIds.includes(id)) {
+            return cIds;
+          }
+        }
+        if (item.id === id) {
+          return [...ids, id];
+        }
+      }
+      return ids;
+    };
+
+    onMounted(async () => {
+      // 获取教材分类列表
+      // await catchStore.getMusicSheetCategory();
+      await catchStore.getMusicTagTreeApi();
+      // 获取声部列表
+      await catchStore.getSubjects();
+    });
+    return () => (
+      <>
+        <div class={styles.searchGroup}>
+          {props.type !== 'myMusic' && (
+            <div class={styles.searchSelect}>
+              {/* <NSelect
+                placeholder="全部教材"
+                options={[
+                  { name: '全部教材', id: null },
+                  ...catchStore.getMusicCategories
+                ]}
+                clearable
+                labelField="name"
+                valueField="id"
+                v-model:value={forms.musicSheetCategoriesId}
+                onUpdate:value={() => {
+                  onSearch();
+                }}
+              /> */}
+              <NCascader
+                placeholder="全部教材"
+                options={[
+                  { id: '', name: '全部教材' },
+                  ...catchStore.getMusicTagTree
+                ]}
+                style={{ width: '100%' }}
+                childrenField="children"
+                valueField="id"
+                labelField="name"
+                checkStrategy="child"
+                expandTrigger="hover"
+                showPath={false}
+                v-model:value={musics.value}
+                onUpdate:value={(value: any) => {
+                  // onSearch();
+                  const selectValue = formatParentId(value, [
+                    { id: '', name: '全部教材' },
+                    ...catchStore.getMusicTagTree
+                  ]);
+
+                  forms.bookVersionId = selectValue[0] || '';
+                  forms.grade = selectValue[1] || '';
+                  forms.musicSheetCategoriesId = selectValue[2] || null;
+                  onSearch();
+                }}
+              />
+            </div>
+          )}
+
+          <div class={styles.searchSelect}>
+            <NCascader
+              placeholder="全部乐器"
+              v-model:value={forms.musicalInstrumentId}
+              options={[...catchStore.getSubjectList]}
+              checkStrategy="child"
+              showPath={false}
+              childrenField="instruments"
+              expandTrigger="hover"
+              clearable
+              filterable
+              onUpdate:value={() => {
+                onSearch();
+              }}
+            />
+          </div>
+          <NInput
+            type="text"
+            placeholder="请输入搜索关键词"
+            clearable
+            v-model:value={forms.name}
+            class={styles.inputSearch}
+            onKeyup={(e: KeyboardEvent) => {
+              if (e.code === 'Enter') {
+                throttledFn();
+              }
+            }}
+            onClear={() => {
+              forms.name = '';
+              throttledFn();
+            }}>
+            {{
+              prefix: () => (
+                <span
+                  class={'icon-search-input'}
+                  onClick={() => throttledFn()}></span>
+              )
+            }}
+          </NInput>
+        </div>
+      </>
+    );
+  }
+});

+ 11 - 2
src/views/prepare-lessons/model/select-music/select-item/index.tsx

@@ -114,11 +114,14 @@ export default defineComponent({
     //   }
     // );
 
-    const throttledFnSearch = useDebounceFn(item => {
+    const onSearch = (item: any) => {
       state.pagination.page = 1;
       state.tableList = [];
       state.searchGroup = Object.assign(state.searchGroup, item);
       getList();
+    };
+    const throttledFnSearch = useDebounceFn(item => {
+      onSearch(item);
     }, 500);
 
     const throttledFn = useThrottleFn(() => {
@@ -159,7 +162,13 @@ export default defineComponent({
         <div class={className}>
           <SearchGroup
             type={props.type}
-            onSearch={(item: any) => throttledFnSearch(item)}
+            onSearch={(item: any, type: any) => {
+              if (type) {
+                onSearch(item);
+                return;
+              }
+              throttledFnSearch(item);
+            }}
           />
         </div>
 

+ 140 - 47
src/views/prepare-lessons/model/select-music/select-item/search-group.tsx

@@ -26,16 +26,20 @@ export default defineComponent({
     const catchStore = useCatchStore();
     const forms = reactive({
       name: '',
-      musicSheetCategoriesId: null,
+      grade: null as any,
+      bookVersionId: null as any,
+      musicSheetCategoriesId: null as any,
       musicalInstrumentId: null
     });
 
     const state = reactive({
-      tempSubjectId: null
+      tempSubjectId: null,
+      gradeList: [] as any[],
+      musicCategory: [] as any
     });
 
-    const onSearch = () => {
-      emit('search', forms);
+    const onSearch = (type?: string) => {
+      emit('search', forms, type);
     };
 
     const throttledFn = useThrottleFn(() => {
@@ -100,9 +104,36 @@ export default defineComponent({
       return obj;
     };
 
+    const onChangeSearch = (type: string, list: any) => {
+      if (type === 'version') {
+        state.gradeList = list || [];
+        if (state.gradeList.length > 0) {
+          forms.grade = state.gradeList[0].id;
+          state.musicCategory = state.gradeList[0].children || [];
+          if (state.musicCategory.length > 0) {
+            forms.musicSheetCategoriesId = state.musicCategory[0].id;
+          }
+        } else {
+          state.musicCategory = [] as any;
+          forms.grade = null;
+          forms.musicSheetCategoriesId = null;
+        }
+      } else if (type === 'grade') {
+        state.musicCategory = list || [];
+        if (state.musicCategory.length > 0) {
+          forms.musicSheetCategoriesId = state.musicCategory[0].id;
+        } else {
+          forms.musicSheetCategoriesId = null;
+        }
+      }
+
+      console.log(state.musicCategory, 'state.musicCategory');
+    };
+
     onMounted(async () => {
       // 获取教材分类列表
-      await catchStore.getMusicSheetCategory();
+      // await catchStore.getMusicSheetCategory();
+      await catchStore.getMusicTagTreeApi();
       // 获取声部列表
       await catchStore.getSubjects();
 
@@ -110,6 +141,22 @@ export default defineComponent({
       hiddenHeight.value = collapseWrapRef.value?.offsetHeight / line.value;
       // 默认隐藏
       getLive();
+
+      const musicTagTreeList = catchStore.getMusicTagTree;
+      if (musicTagTreeList.length > 0) {
+        forms.bookVersionId = musicTagTreeList[0].id;
+        state.gradeList = musicTagTreeList[0].children || [];
+        if (state.gradeList.length > 0) {
+          forms.grade = state.gradeList[0].id;
+          state.musicCategory = state.gradeList[0].children || [];
+          if (state.musicCategory.length > 0) {
+            forms.musicSheetCategoriesId = state.musicCategory[0].id;
+          }
+        }
+      }
+      console.log(state.musicCategory, 'state.musicCategory');
+
+      onSearch('timer');
     });
     return () => (
       <div class={styles.searchGroup}>
@@ -119,53 +166,99 @@ export default defineComponent({
               styles.collapsSection,
               props.type === 'myResources' && styles.collapsSectionEmpty
             ]}>
-            <NFormItem label="教材:">
-              <div
-                class={[
-                  styles.collapseWrap,
-                  loadingCollapse.value ? '' : styles.hideButton,
-                  isCollapse.value ? '' : styles.isHidden
-                ]}
-                ref={collapseWrapRef}>
-                <NSpace class={[styles.spaceSection]}>
-                  {catchStore.getAllMusicCategories.map((music: any) => (
-                    <NButton
-                      ref={musicCateRef}
-                      secondary={forms.musicSheetCategoriesId === music.id}
-                      quaternary={forms.musicSheetCategoriesId !== music.id}
-                      strong
-                      focusable={false}
-                      type={
-                        forms.musicSheetCategoriesId === music.id
-                          ? 'primary'
-                          : 'default'
-                      }
+            <NFormItem label="版本:">
+              <NSpace class={styles.spaceSection2}>
+                {catchStore.getMusicTagTree.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.bookVersionId === subject.id && styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.bookVersionId = subject.id;
+                      onChangeSearch('version', subject.children || []);
+                      onSearch();
+                    }}>
+                    {subject.name}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+            {state.gradeList.length > 0 && (
+              <NFormItem label="年级:">
+                <NSpace class={styles.spaceSection2}>
+                  {state.gradeList.map((subject: any) => (
+                    <span
+                      class={[
+                        styles.textBtn,
+                        forms.grade === subject.id && styles.textBtnActive
+                      ]}
                       onClick={() => {
-                        forms.musicSheetCategoriesId = music.id;
-                        throttledFn();
+                        forms.grade = subject.id;
+                        onChangeSearch('grade', subject.children || []);
+                        onSearch();
                       }}>
-                      {music.name}
-                    </NButton>
+                      {subject.name}
+                    </span>
                   ))}
-                  {line.value > 1 && (
-                    <div
-                      class={styles.collaoseGroup}
-                      onClick={() => {
-                        setCollapse(!isCollapse.value);
-                      }}>
-                      <NImage
-                        previewDisabled
-                        src={isCollaose}
-                        class={[
-                          styles.collaoseBtn,
-                          isCollapse.value ? styles.isStart : ''
-                        ]}></NImage>
-                    </div>
-                  )}
                 </NSpace>
-              </div>
-            </NFormItem>
+              </NFormItem>
+            )}
           </div>
+          {state.musicCategory.length > 0 && (
+            <div
+              class={[
+                styles.collapsSection,
+                props.type === 'myResources' && styles.collapsSectionEmpty
+              ]}>
+              <NFormItem label="教材:">
+                <div
+                  class={[
+                    styles.collapseWrap,
+                    loadingCollapse.value ? '' : styles.hideButton,
+                    isCollapse.value ? '' : styles.isHidden
+                  ]}
+                  ref={collapseWrapRef}>
+                  <NSpace class={[styles.spaceSection]}>
+                    {state.musicCategory.map((music: any) => (
+                      <NButton
+                        ref={musicCateRef}
+                        secondary={forms.musicSheetCategoriesId === music.id}
+                        quaternary={forms.musicSheetCategoriesId !== music.id}
+                        strong
+                        focusable={false}
+                        type={
+                          forms.musicSheetCategoriesId === music.id
+                            ? 'primary'
+                            : 'default'
+                        }
+                        onClick={() => {
+                          forms.musicSheetCategoriesId = music.id;
+                          throttledFn();
+                        }}>
+                        {music.name}
+                      </NButton>
+                    ))}
+                    {line.value > 1 && (
+                      <div
+                        class={styles.collaoseGroup}
+                        onClick={() => {
+                          setCollapse(!isCollapse.value);
+                        }}>
+                        <NImage
+                          previewDisabled
+                          src={isCollaose}
+                          class={[
+                            styles.collaoseBtn,
+                            isCollapse.value ? styles.isStart : ''
+                          ]}></NImage>
+                      </div>
+                    )}
+                  </NSpace>
+                </div>
+              </NFormItem>
+            </div>
+          )}
 
           <NFormItem label="乐器:">
             <NSpace class={styles.spaceSection2}>

+ 15 - 3
src/views/prepare-lessons/model/select-resources/select-item/index.tsx

@@ -114,7 +114,7 @@ export default defineComponent({
       }
     };
 
-    const throttledFnSearch = useDebounceFn(item => {
+    const onSearch = (item: any) => {
       state.pagination.page = 1;
       state.tableList = [];
       const { subjectId, ...res } = item;
@@ -124,6 +124,9 @@ export default defineComponent({
         subjectId: null
       });
       getList();
+    };
+    const throttledFnSearch = useDebounceFn(item => {
+      onSearch(item);
     }, 500);
 
     // 添加资源
@@ -192,7 +195,10 @@ export default defineComponent({
           state.searchHeight = height + 'px';
         }
       );
-      getList();
+
+      if (props.type !== 'shareResources') {
+        getList();
+      }
 
       if (props.type === 'relateResources') {
         eventGlobal.on('onCoursewareUpdate', onUpdate);
@@ -241,7 +247,13 @@ export default defineComponent({
             <ResourceSearchGroup
               type={props.type}
               // subjectId={prepareStore.getSubjectId as any}
-              onSearch={(item: any) => throttledFnSearch(item)}
+              onSearch={(item: any, type: any) => {
+                if (type) {
+                  onSearch(item);
+                  return;
+                }
+                throttledFnSearch(item);
+              }}
             />
           )}
         </div>

+ 1 - 1
src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.module.less

@@ -112,7 +112,7 @@
     line-height: var(--n-blank-height);
 
     &:last-child {
-      margin-left: -12Px;
+      // margin-left: -12Px;
     }
   }
 }

+ 142 - 48
src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx

@@ -44,15 +44,19 @@ export default defineComponent({
       type: 'MUSIC', //
       name: '',
       subjectId: subjectId.value as any,
-      bookVersionId: null
+      grade: null as any,
+      bookVersionId: null as any,
+      musicSheetCategoriesId: null as any
     });
     const state = reactive({
-      tempSubjectId: null
+      tempSubjectId: null,
+      gradeList: [] as any[],
+      musicCategory: [] as any
     });
     const resourceType = ref([] as any);
 
-    const onSearch = () => {
-      emit('search', forms);
+    const onSearch = (type?: string) => {
+      emit('search', forms, type);
     };
 
     const throttleFn = useThrottleFn(() => onSearch(), 500);
@@ -114,6 +118,31 @@ export default defineComponent({
       });
       return obj;
     };
+
+    const onChangeSearch = (type: string, list: any) => {
+      if (type === 'version') {
+        console.log(list, 'list');
+        state.gradeList = list || [];
+        if (state.gradeList.length > 0) {
+          forms.grade = state.gradeList[0].id;
+          state.musicCategory = state.gradeList[0].children || [];
+          if (state.musicCategory.length > 0) {
+            forms.musicSheetCategoriesId = state.musicCategory[0].id;
+          } else {
+            forms.musicSheetCategoriesId = null;
+          }
+        } else {
+          state.musicCategory = [] as any;
+        }
+      } else if (type === 'grade') {
+        state.musicCategory = list || [];
+        if (state.musicCategory.length > 0) {
+          forms.musicSheetCategoriesId = state.musicCategory[0].id;
+        } else {
+          forms.musicSheetCategoriesId = null;
+        }
+      }
+    };
     onMounted(async () => {
       // if (props.type === 'myCollect') {
       //   resourceType.value.push({
@@ -130,8 +159,9 @@ export default defineComponent({
         // }
       });
 
-      // 获取教材分类列表
-      await catchStore.getMusicSheetCategory();
+      // // 获取教材分类列表
+      // await catchStore.getMusicSheetCategory();
+      await catchStore.getMusicTagTreeApi();
       // 获取声部
       await catchStore.getSubjects();
 
@@ -157,6 +187,23 @@ export default defineComponent({
         hiddenHeight.value = collapseWrapRef.value?.offsetHeight / line.value;
         // 默认隐藏
         getLive();
+
+        const musicTagTreeList = catchStore.getMusicTagTree;
+        if (musicTagTreeList.length > 0) {
+          forms.bookVersionId = musicTagTreeList[0].id;
+          state.gradeList = musicTagTreeList[0].children || [];
+          if (state.gradeList.length > 0) {
+            forms.grade = state.gradeList[0].id;
+            state.musicCategory = state.gradeList[0].children || [];
+            if (state.musicCategory.length > 0) {
+              forms.musicSheetCategoriesId = state.musicCategory[0].id;
+            }
+          }
+        }
+      }
+
+      if (props.type === 'shareResources') {
+        onSearch('timer');
       }
     });
     return () => (
@@ -207,54 +254,101 @@ export default defineComponent({
         </div>
         <NForm labelAlign="left" labelPlacement="left">
           {forms.type === 'MUSIC' && props.type === 'shareResources' && (
-            <div class={styles.collapsSection}>
-              <NFormItem label="教材:">
-                <div
-                  class={[
-                    styles.collapseWrap,
-                    loadingCollapse.value ? '' : styles.hideButton,
-                    isCollapse.value ? '' : styles.isHidden
-                  ]}
-                  ref={collapseWrapRef}>
-                  <NSpace class={[styles.spaceSection]}>
-                    {catchStore.getAllMusicCategories.map((music: any) => (
-                      <NButton
-                        ref={musicCateRef}
-                        secondary={forms.bookVersionId === music.id}
-                        quaternary={forms.bookVersionId !== music.id}
-                        strong
-                        focusable={false}
-                        type={
-                          forms.bookVersionId === music.id
-                            ? 'primary'
-                            : 'default'
-                        }
+            <>
+              <NFormItem label="版本:">
+                <NSpace class={styles.spaceSection}>
+                  {catchStore.getMusicTagTree.map((subject: any) => (
+                    <span
+                      class={[
+                        styles.textBtn,
+                        forms.bookVersionId === subject.id &&
+                          styles.textBtnActive
+                      ]}
+                      onClick={() => {
+                        forms.bookVersionId = subject.id;
+                        onChangeSearch('version', subject.children || []);
+                        onSearch();
+                      }}>
+                      {subject.name}
+                    </span>
+                  ))}
+                </NSpace>
+              </NFormItem>
+              {state.gradeList.length > 0 && (
+                <NFormItem label="年级:">
+                  <NSpace class={styles.spaceSection}>
+                    {state.gradeList.map((subject: any) => (
+                      <span
+                        class={[
+                          styles.textBtn,
+                          forms.grade === subject.id && styles.textBtnActive
+                        ]}
                         onClick={() => {
-                          forms.bookVersionId = music.id;
+                          forms.grade = subject.id;
+                          onChangeSearch('grade', subject.children || []);
                           onSearch();
                         }}>
-                        {music.name}
-                      </NButton>
+                        {subject.name}
+                      </span>
                     ))}
-                    {line.value > 1 && (
-                      <div
-                        class={styles.collaoseGroup}
-                        onClick={() => {
-                          setCollapse(!isCollapse.value);
-                        }}>
-                        <NImage
-                          previewDisabled
-                          src={isCollaose}
-                          class={[
-                            styles.collaoseBtn,
-                            isCollapse.value ? styles.isStart : ''
-                          ]}></NImage>
-                      </div>
-                    )}
                   </NSpace>
+                </NFormItem>
+              )}
+              {state.musicCategory.length > 0 && (
+                <div class={styles.collapsSection}>
+                  <NFormItem label="教材:">
+                    <div
+                      class={[
+                        styles.collapseWrap,
+                        loadingCollapse.value ? '' : styles.hideButton,
+                        isCollapse.value ? '' : styles.isHidden
+                      ]}
+                      ref={collapseWrapRef}>
+                      <NSpace class={[styles.spaceSection]}>
+                        {state.musicCategory.map((music: any) => (
+                          <NButton
+                            ref={musicCateRef}
+                            secondary={
+                              forms.musicSheetCategoriesId === music.id
+                            }
+                            quaternary={
+                              forms.musicSheetCategoriesId !== music.id
+                            }
+                            strong
+                            focusable={false}
+                            type={
+                              forms.musicSheetCategoriesId === music.id
+                                ? 'primary'
+                                : 'default'
+                            }
+                            onClick={() => {
+                              forms.musicSheetCategoriesId = music.id;
+                              onSearch();
+                            }}>
+                            {music.name}
+                          </NButton>
+                        ))}
+                        {line.value > 1 && (
+                          <div
+                            class={styles.collaoseGroup}
+                            onClick={() => {
+                              setCollapse(!isCollapse.value);
+                            }}>
+                            <NImage
+                              previewDisabled
+                              src={isCollaose}
+                              class={[
+                                styles.collaoseBtn,
+                                isCollapse.value ? styles.isStart : ''
+                              ]}></NImage>
+                          </div>
+                        )}
+                      </NSpace>
+                    </div>
+                  </NFormItem>
                 </div>
-              </NFormItem>
-            </div>
+              )}
+            </>
           )}
 
           <NFormItem label="乐器:">

+ 39 - 23
src/views/setting/components/schoolInfo/index.tsx

@@ -10,7 +10,6 @@ import {
   NInput,
   NModal,
   NSpace,
-  useDialog,
   useMessage
 } from 'naive-ui';
 import { defineComponent, nextTick, onMounted, reactive, ref } from 'vue';
@@ -62,6 +61,7 @@ export default defineComponent({
       resetVisiable: false,
       resetLoading: false,
       resetMessage: '',
+      resetMessageType: 'reset',
       activeRow: {} as any,
 
       modal: false,
@@ -138,6 +138,7 @@ export default defineComponent({
                 onClick={() => {
                   data.resetMessage = `重置"${row.nickname}"的密码,是否继续?`;
                   data.resetVisiable = true;
+                  data.resetMessageType = 'reset';
                   data.activeRow = row;
                 }}>
                 重置密码
@@ -224,35 +225,50 @@ export default defineComponent({
       getList();
     });
 
-    const dialog = useDialog();
+    // const dialog = useDialog();
     const message = useMessage();
     const handleChange = (row: any) => {
       const statuStr = row.status === 'LOCKED' ? '解冻' : '冻结';
-      dialog.warning({
-        title: '温馨提示',
-        content: `是否${statuStr}"${row.nickname}"?`,
-        positiveText: '确定',
-        negativeText: '取消',
-        maskClosable: false,
-        onPositiveClick: async () => {
-          await api_tenantInfoUpdateStatus({
-            ids: [row.id],
-            status: row.status === 'LOCKED' ? 'ACTIVATION' : 'LOCKED'
-          });
-          getList();
-          message.success(statuStr + '成功');
-        }
-      });
+      // dialog.warning({
+      //   title: '温馨提示',
+      //   content: `是否${statuStr}"${row.nickname}"?`,
+      //   positiveText: '确定',
+      //   negativeText: '取消',
+      //   maskClosable: false,
+      //   onPositiveClick: async () => {
+      //     await api_tenantInfoUpdateStatus({
+      //       ids: [row.id],
+      //       status: row.status === 'LOCKED' ? 'ACTIVATION' : 'LOCKED'
+      //     });
+      //     getList();
+      //     message.success(statuStr + '成功');
+      //   }
+      // });
+      data.resetMessageType = 'locked';
+      data.resetVisiable = true;
+      data.resetMessage = `是否${statuStr}"${row.nickname}"?`;
+      data.activeRow = row;
     };
     // 重置密码
     const onResetPassword = async () => {
       data.resetLoading = true;
       try {
-        await api_userResetPassword({
-          userId: data.activeRow.id,
-          clientType: 'TEACHER'
-        });
-        message.success('重置成功');
+        if (data.resetMessageType === 'locked') {
+          const statuStr = data.activeRow.status === 'LOCKED' ? '解冻' : '冻结';
+          await api_tenantInfoUpdateStatus({
+            ids: [data.activeRow.id],
+            status: data.activeRow.status === 'LOCKED' ? 'ACTIVATION' : 'LOCKED'
+          });
+          getList();
+          message.success(statuStr + '成功');
+        } else {
+          await api_userResetPassword({
+            userId: data.activeRow.id,
+            clientType: 'TEACHER'
+          });
+          message.success('重置成功');
+        }
+
         data.resetVisiable = false;
       } catch {
         //
@@ -472,7 +488,7 @@ export default defineComponent({
           v-model:show={data.resetVisiable}
           preset="card"
           class={['modalTitle', styles.removeVisiable1]}
-          title={'重置密码'}>
+          title={data.resetMessageType === 'reset' ? '重置密码' : '温馨提示'}>
           <TheMessageDialog
             content={data.resetMessage}
             cancelButtonText="取消"

+ 2 - 2
vite.config.ts

@@ -23,8 +23,8 @@ function resolve(dir: string) {
 }
 // https://vitejs.dev/config/
 // https://github.com/vitejs/vite/issues/1930 .env
-// const proxyUrl = 'https://dev.kt.colexiu.com/';
-const proxyUrl = 'https://test.kt.colexiu.com';
+const proxyUrl = 'https://dev.kt.colexiu.com/';
+// const proxyUrl = 'https://test.kt.colexiu.com';
 // const proxyUrl = 'http://192.168.3.14:7989';
 const now = new Date().getTime();
 export default defineConfig(() => {