소스 검색

添加速度和标签

lex-xin 3 달 전
부모
커밋
a7b093dea2
43개의 변경된 파일1879개의 추가작업 그리고 1737개의 파일을 삭제
  1. 133 137
      src/components/CCascader/index.tsx
  2. 1 5
      src/components/layout/modals/suggestion-option.tsx
  3. 1 6
      src/components/layout/modals/update-password.tsx
  4. 43 1
      src/store/modules/catchData.ts
  5. 1 1
      src/views/attend-class/index.module.less
  6. 2 2
      src/views/attend-class/model/class-work/index.module.less
  7. 6 6
      src/views/attend-class/model/train-settings/index.tsx
  8. 1 1
      src/views/attend-class/model/train-type/index.module.less
  9. 3 1
      src/views/attend-class/model/train-update/index.module.less
  10. 47 29
      src/views/attend-class/model/train-update/index.tsx
  11. 2 2
      src/views/classList/components/afterWorkDetail.module.less
  12. 2 1
      src/views/classList/components/afterWorkDetail.tsx
  13. 272 272
      src/views/classList/modals/Gotoclass.tsx
  14. 2 2
      src/views/classList/modals/TrainingDetails.tsx
  15. 2 2
      src/views/classList/modals/classTrainingDetails.tsx
  16. 2 2
      src/views/classList/work-item/index.module.less
  17. 302 303
      src/views/home/modals/chioseModal.tsx
  18. 2 2
      src/views/homework-record/detail/index.module.less
  19. 2 1
      src/views/homework-record/detail/index.tsx
  20. 2 2
      src/views/homework-record/index.module.less
  21. 2 1
      src/views/homework-record/index.tsx
  22. 84 77
      src/views/natural-resources/api.ts
  23. 1 0
      src/views/natural-resources/components/my-collect/index.tsx
  24. 25 1
      src/views/natural-resources/components/my-collect/search-group-resources.tsx
  25. 1 0
      src/views/natural-resources/components/my-resources/index.tsx
  26. 474 474
      src/views/natural-resources/components/my-resources/save-modal/index.tsx
  27. 27 2
      src/views/natural-resources/components/my-resources/search-group-resources.tsx
  28. 210 206
      src/views/natural-resources/components/my-resources/upload-modal/index.module.less
  29. 50 95
      src/views/natural-resources/components/my-resources/upload-modal/index.tsx
  30. 1 0
      src/views/natural-resources/components/share-resources/index.tsx
  31. 26 2
      src/views/natural-resources/components/share-resources/search-group-resources.tsx
  32. 3 4
      src/views/prepare-lessons/components/directory-main/select-lessonware/index.tsx
  33. 1 1
      src/views/prepare-lessons/components/lesson-main/courseware-presets/index.module.less
  34. 1 1
      src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx
  35. 3 5
      src/views/prepare-lessons/components/lesson-main/train/index.tsx
  36. 1 0
      src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx
  37. 104 78
      src/views/prepare-lessons/components/resource-main/components/resource-item/resource-search-group/index.tsx
  38. 4 4
      src/views/prepare-lessons/components/resource-main/components/select-music/index.tsx
  39. 0 1
      src/views/prepare-lessons/model/select-music/index.tsx
  40. 3 3
      src/views/prepare-lessons/model/select-music/select-item/index.tsx
  41. 1 0
      src/views/prepare-lessons/model/select-resources/select-item/index.tsx
  42. 27 2
      src/views/prepare-lessons/model/select-resources/select-item/resource-search-group/index.tsx
  43. 2 2
      src/views/studentList/modals/studentTraomomhDetails.tsx

+ 133 - 137
src/components/CCascader/index.tsx

@@ -121,7 +121,7 @@ export default defineComponent({
       () => {
         if (!state.popoverShow || !props.value) return;
         let ids = formatParentId(props.value, props.options);
-        console.log(ids, 'ids')
+        console.log(ids, 'ids');
         state.tagActiveId = ids[0].id;
         props.options.forEach((item: any) => {
           if (item.id === state.tagActiveId) {
@@ -202,16 +202,16 @@ export default defineComponent({
     // 重置
     const onReset = () => {
       // 重置默认选中第一个
-      const firstChild = props.options[0]
-      const children = firstChild.children ? firstChild.children[0] : null
-      console.log(firstChild, '1111111')
+      const firstChild = props.options[0];
+      const children = firstChild.children ? firstChild.children[0] : null;
+      // console.log(firstChild, '1111111');
       state.childSelectId = children?.value;
       state.tagActiveId = children?.value || firstChild.value || '';
       state.audioPlayTypes = '';
       state.tempAudioPlayTypes = '';
       state.selectParents = {};
       emit('update:value', children?.value || firstChild.value || '');
-      
+
       emit('moreId', {
         childId: children?.value,
         parentId: firstChild.value,
@@ -254,149 +254,145 @@ export default defineComponent({
       audioPlayTypeList.value = [{ name: '全部场景', id: '' }, ...tempAudio];
     });
     return () => (
-      <>
-        <NPopover
-          placement={props.placement as any}
-          v-model:show={state.popoverShow}
-          showArrow={false}
-          trigger="click"
-          displayDirective="show"
-          class={[styles.cascaderPopover, 'c-cascaderPopover']}>
-          {{
-            trigger: () => (
+      <NPopover
+        placement={props.placement as any}
+        v-model:show={state.popoverShow}
+        showArrow={false}
+        trigger="click"
+        displayDirective="show"
+        class={[styles.cascaderPopover, 'c-cascaderPopover']}>
+        {{
+          trigger: () => (
+            <div
+              class={[
+                styles.nBaseCascaser,
+                'nBaseCascaser',
+                state.popoverShow ? styles.nBaseCascaserActive : ''
+              ]}
+              title={valueText.value}>
               <div
                 class={[
-                  styles.nBaseCascaser,
-                  'nBaseCascaser',
-                  state.popoverShow ? styles.nBaseCascaserActive : ''
-                ]}
-                title={valueText.value}>
-                <div
-                  class={[
-                    styles['n-base-selection-tags'],
-                    'n-base-selection-tags'
-                  ]}>
-                  <div class={styles['n-base-selection-input']}>
-                    <div class={styles['n-base-selection-input__content']}>
-                      {valueText.value}
-                    </div>
+                  styles['n-base-selection-tags'],
+                  'n-base-selection-tags'
+                ]}>
+                <div class={styles['n-base-selection-input']}>
+                  <div class={styles['n-base-selection-input__content']}>
+                    {valueText.value}
                   </div>
+                </div>
 
-                  <div class={[styles['n-base-suffix']]}>
-                    <div
-                      class={[
-                        styles.arrow,
-                        props.arrowType === 'small' ? styles.arrowSmall : ''
-                      ]}>
-                      {props.arrowType === 'default' && (
-                        <img src={state.popoverShow ? arrowUp : arrowDown} />
-                      )}
-                      {props.arrowType === 'small' && (
-                        <img
-                          src={
-                            state.popoverShow ? arrowUpSmall : arrowDownSmall
-                          }
-                        />
-                      )}
-                    </div>
+                <div class={[styles['n-base-suffix']]}>
+                  <div
+                    class={[
+                      styles.arrow,
+                      props.arrowType === 'small' ? styles.arrowSmall : ''
+                    ]}>
+                    {props.arrowType === 'default' && (
+                      <img src={state.popoverShow ? arrowUp : arrowDown} />
+                    )}
+                    {props.arrowType === 'small' && (
+                      <img
+                        src={state.popoverShow ? arrowUpSmall : arrowDownSmall}
+                      />
+                    )}
                   </div>
                 </div>
-                <div
-                  class={[
-                    styles['n-base-selection-placeholder'],
-                    styles['n-base-selection-overlay']
-                  ]}>
-                  {!valueText.value && (
-                    <div class={styles.inner}>{props.placeholder}</div>
-                  )}
-                </div>
-                <div
-                  class={[
-                    styles['n-base-selection__border'],
-                    'n-base-selection__border'
-                  ]}></div>
-                <div class={styles['n-base-selection__state-border']}></div>
               </div>
-            ),
-            default: () => (
-              <div class={styles.baseContent}>
-                <NScrollbar
-                  class={styles.baseScrollBar}
-                  style={{ maxHeight: '400px' }}>
-                  {props.showAudioPlayType && (
-                    <>
-                      <div class={styles.baseContentTitle}>场景</div>
-                      <div class={styles.baseContentWrap}>
-                        {audioPlayTypeList.value.map((subject: any) => (
-                          <span
-                            class={[
-                              styles.tag,
-                              (state.audioPlayTypes || '') == subject.id &&
-                                styles.tagActive
-                            ]}
-                            onClick={() => {
-                              if (state.audioPlayTypes !== subject.id) {
-                                state.childSelectId = null;
-                              }
-                              state.audioPlayTypes = subject.id;
-                            }}>
-                            {subject.name}
-                          </span>
-                        ))}
-                      </div>
-                    </>
-                  )}
+              <div
+                class={[
+                  styles['n-base-selection-placeholder'],
+                  styles['n-base-selection-overlay']
+                ]}>
+                {!valueText.value && (
+                  <div class={styles.inner}>{props.placeholder}</div>
+                )}
+              </div>
+              <div
+                class={[
+                  styles['n-base-selection__border'],
+                  'n-base-selection__border'
+                ]}></div>
+              <div class={styles['n-base-selection__state-border']}></div>
+            </div>
+          ),
+          default: () => (
+            <div class={styles.baseContent}>
+              <NScrollbar
+                class={styles.baseScrollBar}
+                style={{ maxHeight: '400px' }}>
+                {props.showAudioPlayType && (
+                  <>
+                    <div class={styles.baseContentTitle}>场景</div>
+                    <div class={styles.baseContentWrap}>
+                      {audioPlayTypeList.value.map((subject: any) => (
+                        <span
+                          class={[
+                            styles.tag,
+                            (state.audioPlayTypes || '') == subject.id &&
+                              styles.tagActive
+                          ]}
+                          onClick={() => {
+                            if (state.audioPlayTypes !== subject.id) {
+                              state.childSelectId = null;
+                            }
+                            state.audioPlayTypes = subject.id;
+                          }}>
+                          {subject.name}
+                        </span>
+                      ))}
+                    </div>
+                  </>
+                )}
 
-                  {state.audioPlayTypes !== 'SING' && (
-                    <>
-                      <div class={styles.baseContentTitle}>
-                        {props.options[0].columnName}
-                      </div>
-                      <div class={styles.baseContentWrap}>
-                        {props.options.map((subject: any) => (
-                          <span
-                            class={[
-                              styles.tag,
-                              (state.tagActiveId || '') == subject.id &&
-                                styles.tagActive
-                            ]}
-                            onClick={() => {
-                              if (state.tagActiveId !== subject.id) {
-                                state.childSelectId = null;
-                              }
-                              state.tagActiveId = subject.id;
+                {state.audioPlayTypes !== 'SING' && (
+                  <>
+                    <div class={styles.baseContentTitle}>
+                      {props.options[0].columnName}
+                    </div>
+                    <div class={styles.baseContentWrap}>
+                      {props.options.map((subject: any) => (
+                        <span
+                          class={[
+                            styles.tag,
+                            (state.tagActiveId || '') == subject.id &&
+                              styles.tagActive
+                          ]}
+                          onClick={() => {
+                            if (state.tagActiveId !== subject.id) {
+                              state.childSelectId = null;
+                            }
+                            state.tagActiveId = subject.id;
 
-                              initParentSelect(subject);
-                            }}>
-                            {subject.name}
-                          </span>
-                        ))}
-                      </div>
-                      <ChildNodeSearch
-                        childShowAllCheck={props.childShowAllCheck}
-                        activeRow={state.selectParents}
-                        onSelectChildTag={(val: any) => {
-                          state.childSelectId = val;
-                        }}
-                      />
-                    </>
-                  )}
-                </NScrollbar>
-                <div class={styles.btnGroup}>
-                  <div class={[styles.btn, styles.btnCancel]} onClick={onReset}>
-                    重置
-                  </div>
-                  <div
-                    class={[styles.btn, styles.btnConfirm]}
-                    onClick={onConfirm}>
-                    确认
-                  </div>
+                            initParentSelect(subject);
+                          }}>
+                          {subject.name}
+                        </span>
+                      ))}
+                    </div>
+                    <ChildNodeSearch
+                      childShowAllCheck={props.childShowAllCheck}
+                      activeRow={state.selectParents}
+                      onSelectChildTag={(val: any) => {
+                        state.childSelectId = val;
+                      }}
+                    />
+                  </>
+                )}
+              </NScrollbar>
+              <div class={styles.btnGroup}>
+                <div class={[styles.btn, styles.btnCancel]} onClick={onReset}>
+                  重置
+                </div>
+                <div
+                  class={[styles.btn, styles.btnConfirm]}
+                  onClick={onConfirm}>
+                  确认
                 </div>
               </div>
-            )
-          }}
-        </NPopover>
-      </>
+            </div>
+          )
+        }}
+      </NPopover>
     );
   }
 });

+ 1 - 5
src/components/layout/modals/suggestion-option.tsx

@@ -5,8 +5,6 @@ import {
   NForm,
   NFormItem,
   NInput,
-  NSelect,
-  NSpace,
   useMessage,
   NUpload,
   UploadFileInfo,
@@ -19,7 +17,6 @@ import { useUserStore } from '/src/store/modules/users';
 import bgLine from '../images/bg-line.png';
 import chioseAdd from '../images/chioseAdd.png';
 import CSelect from '../../CSelect';
-import { policy } from '../../upload-file/api';
 import suggestClose from '../images/suggestClose.png';
 import inFront from '../images/inFront.png';
 import inBack from '../images/inBack.png';
@@ -31,14 +28,13 @@ import {
   getSuggestionList,
   sysParamConfigPage
 } from '../modals/api';
-import { nextTick } from 'process';
 import { getUploadSign, onFileUpload } from '/src/helpers/oss-file-upload';
 import SuggestionList from './suggestion-list';
 import { suggestMessageUnread } from '/src/api/user';
 import { modalClickMask } from '/src/state';
 
 export default defineComponent({
-  name: 'train-update',
+  name: 'suggestion-option',
   emits: ['close', 'submit'],
   setup(props, { emit, expose }) {
     const message = useMessage();

+ 1 - 6
src/components/layout/modals/update-password.tsx

@@ -6,21 +6,16 @@ import {
   NFormItem,
   NInput,
   NModal,
-  NSelect,
-  NSpace,
   useMessage
 } from 'naive-ui';
-import { useRouter } from 'vue-router';
 import { useUserStore } from '/src/store/modules/users';
-import { gradeToCN } from '/src/utils/contants';
-import { sendSms } from '/src/views/login/api';
 import { updatePassword } from '@/views/home/api';
 import openEye from '/src/views/login/images/openEye.png';
 import closeEye from '/src/views/login/images/closeEye.png';
 import SendSms from '/src/views/login/components/sendSms';
 import { modalClickMask } from '/src/state';
 export default defineComponent({
-  name: 'train-update',
+  name: 'update-password',
   emits: ['close', 'submit'],
   setup(props, { emit }) {
     const message = useMessage();

+ 43 - 1
src/store/modules/catchData.ts

@@ -8,6 +8,7 @@ import {
   api_musicTagTree
 } from '@/api/user';
 import deepClone from '/src/helpers/deep-clone';
+import { api_materialTagPage } from '/src/views/natural-resources/api';
 
 export const useCatchStore = defineStore('catch-store', {
   state: () => ({
@@ -16,7 +17,8 @@ export const useCatchStore = defineStore('catch-store', {
     subjectList: [] as any[], // 声部列表,
     musicInstrumentList: [] as any[], // 乐器列表,
     subjectInstruemnts: [] as any[], // 乐器列表,
-    musicTagTree: [] as any[] // 分类列表
+    musicTagTree: [] as any[], // 分类列表
+    materialTags: [] as any[] // 素材标签
   }),
   getters: {
     getBookVersion(): any[] {
@@ -90,6 +92,18 @@ export const useCatchStore = defineStore('catch-store', {
     },
     getMusicTagTree(): any[] {
       return this.musicTagTree;
+    },
+    getMaterialTags(): any[] {
+      return this.materialTags;
+    },
+    getAllMaterialTags(): any[] {
+      return [
+        {
+          label: '全部',
+          value: null
+        },
+        ...this.materialTags
+      ];
     }
   },
   actions: {
@@ -111,6 +125,9 @@ export const useCatchStore = defineStore('catch-store', {
     setMusicTagTree(tagTree: any[]) {
       this.musicTagTree = tagTree;
     },
+    setMaterialTags(materialTags: any[]) {
+      this.materialTags = materialTags;
+    },
     /**
      * 判断是否有声部数据,如不存在则获取声部列表
      * @returns Promise
@@ -293,6 +310,31 @@ export const useCatchStore = defineStore('catch-store', {
       } catch (e) {
         return Promise.reject(e);
       }
+    },
+    /**
+     * 获取所有标签
+     * @returns Promise
+     */
+    async getMaterialTagsApi() {
+      try {
+        // 判断是否存在声部数据
+        if (this.getMaterialTags && this.getMaterialTags.length > 0) {
+          return Promise.resolve();
+        }
+        const { data } = await api_materialTagPage({ page: 1, rows: 100 });
+        const result = data.rows || [];
+        const tempList: any = [];
+        result.forEach((item: any) => {
+          tempList.push({
+            label: item.name,
+            value: item.id
+          });
+        });
+        this.setMaterialTags(tempList || []);
+        return Promise.resolve();
+      } catch (e) {
+        return Promise.reject(e);
+      }
     }
   }
 });

+ 1 - 1
src/views/attend-class/index.module.less

@@ -824,7 +824,7 @@
 }
 
 .workVisiable {
-  width: 1358px;
+  width: 1420px;
 
 
   :global {

+ 2 - 2
src/views/attend-class/model/class-work/index.module.less

@@ -129,7 +129,7 @@
 }
 
 .workVisiable {
-  width: 1358px;
+  width: 1420px;
 
   :global {
     .c-cascaderPopover {
@@ -168,4 +168,4 @@
     height: 75vh;
     box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
   }
-}
+}

+ 6 - 6
src/views/attend-class/model/train-settings/index.tsx

@@ -98,13 +98,13 @@ export default defineComponent({
           configJson.practiceChapterBegin || configJson.practiceChapterEnd
             ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
             : '全部小节',
-          // `速度${configJson.evaluateSpeed}`,
+          `速度${configJson.evaluateSpeed || 0}`,
           `${configJson.trainingTimes}分达标`
         ];
       } else {
         tList = [
           `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-          `速度${configJson.practiceSpeed}`,
+          `速度${configJson.practiceSpeed || 0}`,
           `${configJson.trainingTimes}分钟`
         ];
       }
@@ -130,7 +130,7 @@ export default defineComponent({
           childs.forEach((child: any) => {
             system?.removeChild(child);
           })
-        });          
+        });
         const parts = xmlParse.getElementsByTagName('part');
         firstMeasures = parts[0]?.getElementsByTagName('measure');
         xmlStatus = 'success';
@@ -225,12 +225,12 @@ export default defineComponent({
           courseScheduleId: props.courseScheduleId || null
         };
         const lessonRes =  await lessonTrainingAdd(params);
-        if(lessonRes.code === 200){
-          if(lessonRes.data.status){
+        if (lessonRes.code === 200){
+          if (lessonRes.data.status){
             message.success('布置成功');
             emit('close');
             emit('confirm');
-          }else{
+          } else {
             handleLessonAddErr(lessonRes.data)
           }
         }

+ 1 - 1
src/views/attend-class/model/train-type/index.module.less

@@ -317,7 +317,7 @@
 }
 
 .trainInfo {
-  max-width: 82%;
+  max-width: 86%;
 
   .trainName {
     display: flex;

+ 3 - 1
src/views/attend-class/model/train-update/index.module.less

@@ -1,5 +1,7 @@
 .trainUpdate {
   padding: 24px 30px;
+  // height: 390px;
+  box-sizing:content-box;
 
   .updateBtnGroup {
     padding: 0;
@@ -44,4 +46,4 @@
   .scoreGroup {
     display: flex;
   }
-}
+}

+ 47 - 29
src/views/attend-class/model/train-update/index.tsx

@@ -1,11 +1,4 @@
-import {
-  PropType,
-  computed,
-  defineComponent,
-  onMounted,
-  reactive,
-  ref
-} from 'vue';
+import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
@@ -18,10 +11,6 @@ import {
   NTooltip,
   useMessage
 } from 'naive-ui';
-import {
-  lessonPreTrainingAdd,
-  lessonPreTrainingUpdate
-} from '/src/views/prepare-lessons/api';
 
 export default defineComponent({
   name: 'train-update',
@@ -116,25 +105,43 @@ export default defineComponent({
 
     onMounted(() => {
       const item = props.item;
+      console.log(item, 'item-----');
       if (item.trainId) {
         forms.id = item.trainId;
-        forms.practiceSpeed = Number(item.practiceSpeed);
+        // forms.practiceSpeed = Number(item.practiceSpeed);
         forms.type = item.trainingType;
         forms.minScore = item.practiceChapterBegin;
         forms.maxScore = item.practiceChapterEnd;
+        forms.difficulty = item.evaluateDifficult || 'BEGINNER';
         if (item.trainingType === 'PRACTICE') {
           forms.practiceTimes = item.trainingTimes;
+
+          forms.practiceSpeed = item.practiceSpeed
+            ? Number(item.practiceSpeed)
+            : item.playSpeed
+            ? item.playSpeed
+            : null;
+          forms.evaluationSpeed = item.practiceSpeed
+            ? Number(item.practiceSpeed)
+            : item.playSpeed
+            ? item.playSpeed
+            : null;
         } else {
           forms.evaluationScore = item.trainingTimes;
+
+          forms.evaluationSpeed = item.evaluateSpeed ? Number(item.evaluateSpeed) : item.playSpeed ? item.playSpeed : null
+          forms.practiceSpeed = item.evaluateSpeed ? Number(item.evaluateSpeed) : item.playSpeed ? item.playSpeed : null
         }
-        forms.difficulty = item.evaluateDifficult || 'BEGINNER';
-        forms.evaluationSpeed = item.evaluateSpeed;
+
+        // forms.evaluationSpeed = item.evaluateSpeed;
       } else {
         forms.minScore = 1;
         forms.maxScore = item.practiceChapterMax ? item.practiceChapterMax : 1;
+        forms.evaluationSpeed = item.playSpeed || null;
+        forms.practiceSpeed = item.playSpeed || null;
       }
       forms.audioPlayTypeArray = item.audioPlayTypeArray || [];
-      forms.containAccompaniment = item.containAccompaniment || null
+      forms.containAccompaniment = item.containAccompaniment || null;
       forms.baseMaxScore = item.practiceChapterMax || 99;
       forms.musicId = item.id;
       forms.musicName = item.musicName;
@@ -148,6 +155,7 @@ export default defineComponent({
           ref={formsRef}
           model={forms}
           labelAlign="right"
+          style={{ height: '300px' }}
           labelPlacement="left">
           <NFormItem
             label="训练方式"
@@ -249,6 +257,8 @@ export default defineComponent({
               <NFormItem
                 label="练习速度"
                 path="practiceSpeed"
+                showFeedback={true}
+                feedback="速度范围45-270"
                 rule={[
                   {
                     required: true,
@@ -264,6 +274,9 @@ export default defineComponent({
                   showButton={false}
                   style={{ width: '100%' }}
                   v-model:value={forms.practiceSpeed}
+                  onUpdate:value={(val: any) => {
+                    forms.evaluationSpeed = val;
+                  }}
                   placeholder="练习速度范围45~270"
                   clearable
                 />
@@ -332,9 +345,11 @@ export default defineComponent({
                   </NButton>
                 </NSpace>
               </NFormItem>
-              {/* <NFormItem
+              <NFormItem
                 label="评测速度"
                 path="evaluationSpeed"
+                showFeedback={true}
+                feedback="速度范围45-270"
                 rule={[
                   {
                     required: true,
@@ -344,15 +359,18 @@ export default defineComponent({
                   }
                 ]}>
                 <NInputNumber
-                  min={60}
+                  min={45}
                   max={270}
                   showButton={false}
                   style={{ width: '100%' }}
                   v-model:value={forms.evaluationSpeed}
-                  placeholder="评测速度范围60~270"
+                  onUpdate:value={(val: any) => {
+                    forms.practiceSpeed = val;
+                  }}
+                  placeholder="评测速度范围45~270"
                   clearable
                 />
-              </NFormItem> */}
+              </NFormItem>
               <NFormItem
                 label="达标分数"
                 path="evaluationScore"
@@ -380,16 +398,16 @@ export default defineComponent({
               </NFormItem>
             </>
           )}
-
-          <NSpace class={styles.updateBtnGroup}>
-            <NButton strong type="default" round onClick={() => emit('close')}>
-              取消
-            </NButton>
-            <NButton strong type="primary" round onClick={() => onSubmit()}>
-              确认
-            </NButton>
-          </NSpace>
         </NForm>
+
+        <NSpace class={styles.updateBtnGroup}>
+          <NButton strong type="default" round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton strong type="primary" round onClick={() => onSubmit()}>
+            确认
+          </NButton>
+        </NSpace>
       </div>
     );
   }

+ 2 - 2
src/views/classList/components/afterWorkDetail.module.less

@@ -247,7 +247,7 @@
 }
 
 .wordDetailModel {
-  width: 1012px;
+  width: 1092px;
 }
 
 .isok {
@@ -263,4 +263,4 @@
 .nosub {
   font-weight: 600;
   color: #aaa;
-}
+}

+ 2 - 1
src/views/classList/components/afterWorkDetail.tsx

@@ -141,7 +141,7 @@ export default defineComponent({
               if (trainingContent) {
                 const tempList = [
                   `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`,
-                  `速度${trainingContent.practiceSpeed}`,
+                  `速度${trainingContent.practiceSpeed || 0}`,
                   `${trainingContent.trainingTimes}分钟`
                 ];
                 pTitle += tempList.join(' | ') + ';';
@@ -156,6 +156,7 @@ export default defineComponent({
                   trainingContent.practiceChapterEnd
                     ? `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`
                     : '全部小节',
+                  `速度${trainingContent.evaluateSpeed || 0}`,
                   `${trainingContent.trainingTimes}分达标`
                 ];
                 eTitle += tempList.join(' | ') + ';';

+ 272 - 272
src/views/classList/modals/Gotoclass.tsx

@@ -1,272 +1,272 @@
-import { defineComponent, onMounted, reactive, ref } from 'vue';
-import styles from '../index.module.less';
-import {
-  NButton,
-  NForm,
-  NFormItem,
-  NSelect,
-  NSpace,
-  useMessage
-} from 'naive-ui';
-import {
-  bookVersionPage,
-  courseScheduleStart,
-  lessonCoursewarePage,
-  queryCourseware
-} from '@/views/prepare-lessons/api';
-import { useRouter } from 'vue-router';
-import { useThrottleFn } from '@vueuse/core';
-import { getCourseChapter } from '../api';
-import { useCatchStore } from '/src/store/modules/catchData';
-export default defineComponent({
-  name: 'train-update',
-  emits: ['close', 'preview'],
-  props: {
-    activeRow: {
-      type: Object,
-      default: () => ({ id: '', currentGradeNum: '' })
-    }
-  },
-  setup(props, { emit }) {
-    // 'practice' | 'evaluation'
-    const forms = reactive({
-      bookVersionId: null,
-      classGroupId: null,
-      category: null,
-      chapter: null,
-      subjectId: null,
-      musicTagList: [] as any,
-      loading: false,
-      list: [] as any,
-      chapterList: [] as any,
-      unit: null,
-      unitList: [],
-      subjectList: [] as any
-    });
-    const router = useRouter();
-    const catchStore = useCatchStore();
-    const message = useMessage();
-    const gotoClassPage = () => {
-      formsRef.value.validate(async (error: any) => {
-        if (error) return;
-        const { data } = await queryCourseware({
-          coursewareDetailKnowledgeId: forms.chapter,
-          subjectId: forms.subjectId,
-          page: 1,
-          rows: 99
-        });
-        if (data.rows && data.rows.length > 0) {
-          const res = await courseScheduleStart({
-            lessonCoursewareKnowledgeDetailId: forms.chapter,
-            classGroupId: props.activeRow.id,
-            subjectId: forms.subjectId
-          });
-
-          emit('close');
-          emit('preview', {
-            type: 'class',
-            classId: res.data, // 上课编号
-            lessonCourseId: forms.category,
-            classGroupId: props.activeRow.id,
-            subjectId: forms.subjectId,
-            detailId: forms.chapter
-          });
-        } else {
-          message.error('当前章节暂无课件,请重新选择');
-        }
-      });
-
-      /**
-       *         query: {
-            type: 'class',
-            classGroupId: item.id,
-            subjectId: prepareStore.getSubjectId,
-            detailId: prepareStore.getSelectKey // 章节id
-          }
-       */
-    };
-
-    const formsRef = ref();
-    const throttledFn = useThrottleFn(() => getLessonCourseware(), 500);
-    const getLessonCourseware = async () => {
-      forms.category = null;
-      forms.unit = null;
-      forms.category = null;
-      forms.chapter = null;
-      forms.loading = true;
-
-      if (forms.bookVersionId) {
-        try {
-          const { data } = await lessonCoursewarePage({
-            page: 1,
-            rows: 99,
-            type: 'COURSEWARE',
-            enableFlag: 1,
-            bookVersionId: forms.bookVersionId
-            // currentGradeNum: props.activeRow.currentGradeNum
-          });
-
-          forms.list = data.rows.map((item: any) => {
-            return {
-              label: item.name,
-              value: item.id
-            };
-          });
-        } catch {
-          //
-        }
-      } else {
-        forms.list = [];
-      }
-
-      forms.loading = false;
-    };
-    const getVersion = async () => {
-      forms.unit = null;
-      forms.chapter = null;
-
-      try {
-        const { data } = await bookVersionPage({
-          page: 1,
-          rows: 99,
-          type: 'COURSEWARE'
-        });
-        const temp = data.rows || [];
-        temp.forEach((item: any) => {
-          forms.musicTagList.push({
-            id: item.id,
-            name: item.name
-          });
-        });
-      } catch {
-        //
-      }
-    };
-
-    const getunitList = async () => {
-      forms.unit = null;
-      forms.chapter = null;
-      try {
-        if (forms.category) {
-          const res = await getCourseChapter(forms.category);
-          forms.unitList = res.data.lessonList.map((item: any) => {
-            return { ...item, label: item.name, value: item.id };
-          });
-        } else {
-          forms.unitList = [];
-        }
-      } catch (e) {
-        console.log(e);
-      }
-    };
-    const getchapterList = () => {
-      forms.chapter = null;
-      if (forms.unit) {
-        const item: any = forms.unitList.find((item: any) => {
-          return item.id === forms.unit;
-        });
-        forms.chapterList = item.knowledgeList.map((know: any) => {
-          return { ...know, label: know.name, value: know.id };
-        });
-        console.log('getchapterList', item);
-      } else {
-        forms.chapterList = [];
-      }
-      console.log('getchapterList');
-    };
-    onMounted(async () => {
-      await catchStore.getSubjects();
-      forms.subjectList = catchStore.getSubjectList.map((item: any) => {
-        return {
-          label: item.name,
-          value: item.id
-        };
-      });
-      getVersion();
-    });
-    return () => (
-      <div class={styles.trainUpdate}>
-        <NForm
-          labelAlign="left"
-          labelPlacement="left"
-          ref={formsRef}
-          model={forms}>
-          <NFormItem
-            path="bookVersionId"
-            rule={[{ required: true, message: '选择教材版本' }]}>
-            <NSelect
-              placeholder="选择教材版本"
-              clearable
-              options={[...forms.musicTagList]}
-              labelField="name"
-              valueField="id"
-              v-model:value={forms.bookVersionId}
-              onUpdate:value={() => throttledFn()}
-            />
-          </NFormItem>
-          <NFormItem
-            path="category"
-            rule={[{ required: true, message: '请选择册别' }]}>
-            <NSelect
-              {...({
-                options: [...forms.list],
-                placeholder: '选择册别',
-                clearable: true
-              } as any)}
-              disabled={!forms.bookVersionId}
-              v-model:value={forms.category}
-              onUpdate:value={() => getunitList()}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="unit"
-            rule={[{ required: true, message: '请选择单元' }]}>
-            <NSelect
-              disabled={!forms.category}
-              {...({
-                options: [...forms.unitList],
-                placeholder: '选择单元',
-                clearable: true
-              } as any)}
-              v-model:value={forms.unit}
-              onUpdate:value={() => getchapterList()}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="chapter"
-            rule={[{ required: true, message: '请选择章节' }]}>
-            <NSelect
-              disabled={!forms.unit}
-              {...({
-                options: [...forms.chapterList],
-                placeholder: '选择章节',
-                clearable: true
-              } as any)}
-              v-model:value={forms.chapter}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="subjectId"
-            rule={[{ required: true, message: '请选择乐器' }]}>
-            <NSelect
-              {...({
-                options: [...forms.subjectList],
-                placeholder: '选择乐器',
-                clearable: true
-              } as any)}
-              v-model:value={forms.subjectId}></NSelect>
-          </NFormItem>
-          <NSpace class={styles.updateBtnGroup}>
-            <NButton strong type="default" round onClick={() => emit('close')}>
-              取消
-            </NButton>
-            <NButton
-              strong
-              type="primary"
-              round
-              onClick={() => gotoClassPage()}>
-              确认
-            </NButton>
-          </NSpace>
-        </NForm>
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from '../index.module.less';
+import {
+  NButton,
+  NForm,
+  NFormItem,
+  NSelect,
+  NSpace,
+  useMessage
+} from 'naive-ui';
+import {
+  bookVersionPage,
+  courseScheduleStart,
+  lessonCoursewarePage,
+  queryCourseware
+} from '@/views/prepare-lessons/api';
+import { useRouter } from 'vue-router';
+import { useThrottleFn } from '@vueuse/core';
+import { getCourseChapter } from '../api';
+import { useCatchStore } from '/src/store/modules/catchData';
+export default defineComponent({
+  name: 'goto-class',
+  emits: ['close', 'preview'],
+  props: {
+    activeRow: {
+      type: Object,
+      default: () => ({ id: '', currentGradeNum: '' })
+    }
+  },
+  setup(props, { emit }) {
+    // 'practice' | 'evaluation'
+    const forms = reactive({
+      bookVersionId: null,
+      classGroupId: null,
+      category: null,
+      chapter: null,
+      subjectId: null,
+      musicTagList: [] as any,
+      loading: false,
+      list: [] as any,
+      chapterList: [] as any,
+      unit: null,
+      unitList: [],
+      subjectList: [] as any
+    });
+    const router = useRouter();
+    const catchStore = useCatchStore();
+    const message = useMessage();
+    const gotoClassPage = () => {
+      formsRef.value.validate(async (error: any) => {
+        if (error) return;
+        const { data } = await queryCourseware({
+          coursewareDetailKnowledgeId: forms.chapter,
+          subjectId: forms.subjectId,
+          page: 1,
+          rows: 99
+        });
+        if (data.rows && data.rows.length > 0) {
+          const res = await courseScheduleStart({
+            lessonCoursewareKnowledgeDetailId: forms.chapter,
+            classGroupId: props.activeRow.id,
+            subjectId: forms.subjectId
+          });
+
+          emit('close');
+          emit('preview', {
+            type: 'class',
+            classId: res.data, // 上课编号
+            lessonCourseId: forms.category,
+            classGroupId: props.activeRow.id,
+            subjectId: forms.subjectId,
+            detailId: forms.chapter
+          });
+        } else {
+          message.error('当前章节暂无课件,请重新选择');
+        }
+      });
+
+      /**
+       *         query: {
+            type: 'class',
+            classGroupId: item.id,
+            subjectId: prepareStore.getSubjectId,
+            detailId: prepareStore.getSelectKey // 章节id
+          }
+       */
+    };
+
+    const formsRef = ref();
+    const throttledFn = useThrottleFn(() => getLessonCourseware(), 500);
+    const getLessonCourseware = async () => {
+      forms.category = null;
+      forms.unit = null;
+      forms.category = null;
+      forms.chapter = null;
+      forms.loading = true;
+
+      if (forms.bookVersionId) {
+        try {
+          const { data } = await lessonCoursewarePage({
+            page: 1,
+            rows: 99,
+            type: 'COURSEWARE',
+            enableFlag: 1,
+            bookVersionId: forms.bookVersionId
+            // currentGradeNum: props.activeRow.currentGradeNum
+          });
+
+          forms.list = data.rows.map((item: any) => {
+            return {
+              label: item.name,
+              value: item.id
+            };
+          });
+        } catch {
+          //
+        }
+      } else {
+        forms.list = [];
+      }
+
+      forms.loading = false;
+    };
+    const getVersion = async () => {
+      forms.unit = null;
+      forms.chapter = null;
+
+      try {
+        const { data } = await bookVersionPage({
+          page: 1,
+          rows: 99,
+          type: 'COURSEWARE'
+        });
+        const temp = data.rows || [];
+        temp.forEach((item: any) => {
+          forms.musicTagList.push({
+            id: item.id,
+            name: item.name
+          });
+        });
+      } catch {
+        //
+      }
+    };
+
+    const getunitList = async () => {
+      forms.unit = null;
+      forms.chapter = null;
+      try {
+        if (forms.category) {
+          const res = await getCourseChapter(forms.category);
+          forms.unitList = res.data.lessonList.map((item: any) => {
+            return { ...item, label: item.name, value: item.id };
+          });
+        } else {
+          forms.unitList = [];
+        }
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    const getchapterList = () => {
+      forms.chapter = null;
+      if (forms.unit) {
+        const item: any = forms.unitList.find((item: any) => {
+          return item.id === forms.unit;
+        });
+        forms.chapterList = item.knowledgeList.map((know: any) => {
+          return { ...know, label: know.name, value: know.id };
+        });
+        console.log('getchapterList', item);
+      } else {
+        forms.chapterList = [];
+      }
+      console.log('getchapterList');
+    };
+    onMounted(async () => {
+      await catchStore.getSubjects();
+      forms.subjectList = catchStore.getSubjectList.map((item: any) => {
+        return {
+          label: item.name,
+          value: item.id
+        };
+      });
+      getVersion();
+    });
+    return () => (
+      <div class={styles.trainUpdate}>
+        <NForm
+          labelAlign="left"
+          labelPlacement="left"
+          ref={formsRef}
+          model={forms}>
+          <NFormItem
+            path="bookVersionId"
+            rule={[{ required: true, message: '选择教材版本' }]}>
+            <NSelect
+              placeholder="选择教材版本"
+              clearable
+              options={[...forms.musicTagList]}
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.bookVersionId}
+              onUpdate:value={() => throttledFn()}
+            />
+          </NFormItem>
+          <NFormItem
+            path="category"
+            rule={[{ required: true, message: '请选择册别' }]}>
+            <NSelect
+              {...({
+                options: [...forms.list],
+                placeholder: '选择册别',
+                clearable: true
+              } as any)}
+              disabled={!forms.bookVersionId}
+              v-model:value={forms.category}
+              onUpdate:value={() => getunitList()}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="unit"
+            rule={[{ required: true, message: '请选择单元' }]}>
+            <NSelect
+              disabled={!forms.category}
+              {...({
+                options: [...forms.unitList],
+                placeholder: '选择单元',
+                clearable: true
+              } as any)}
+              v-model:value={forms.unit}
+              onUpdate:value={() => getchapterList()}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="chapter"
+            rule={[{ required: true, message: '请选择章节' }]}>
+            <NSelect
+              disabled={!forms.unit}
+              {...({
+                options: [...forms.chapterList],
+                placeholder: '选择章节',
+                clearable: true
+              } as any)}
+              v-model:value={forms.chapter}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="subjectId"
+            rule={[{ required: true, message: '请选择乐器' }]}>
+            <NSelect
+              {...({
+                options: [...forms.subjectList],
+                placeholder: '选择乐器',
+                clearable: true
+              } as any)}
+              v-model:value={forms.subjectId}></NSelect>
+          </NFormItem>
+          <NSpace class={styles.updateBtnGroup}>
+            <NButton strong type="default" round onClick={() => emit('close')}>
+              取消
+            </NButton>
+            <NButton
+              strong
+              type="primary"
+              round
+              onClick={() => gotoClassPage()}>
+              确认
+            </NButton>
+          </NSpace>
+        </NForm>
+      </div>
+    );
+  }
+});

+ 2 - 2
src/views/classList/modals/TrainingDetails.tsx

@@ -60,14 +60,14 @@ export default defineComponent({
           configJson.practiceChapterBegin || configJson.practiceChapterEnd
             ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
             : '全部小节',
-          // `速度${configJson.evaluateSpeed}`,
+          `速度${configJson.evaluateSpeed || 0}`,
           `${configJson.trainingTimes}分达标`
         ];
         // console.log('configJson.evaluateDifficult--', tList);
       } else {
         tList = [
           `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-          `速度${configJson.practiceSpeed}`,
+          `速度${configJson.practiceSpeed || 0}`,
           `${configJson.trainingTimes}分钟`
         ];
         // console.log('configJson.evaluateDifficult', tList);

+ 2 - 2
src/views/classList/modals/classTrainingDetails.tsx

@@ -55,13 +55,13 @@ export default defineComponent({
           configJson.practiceChapterBegin || configJson.practiceChapterEnd
             ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
             : '全部小节',
-          // `速度${configJson.evaluateSpeed}`,
+          `速度${configJson.evaluateSpeed || 0}`,
           `${configJson.trainingTimes}分达标`
         ];
       } else {
         tList = [
           `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-          `速度${configJson.practiceSpeed}`,
+          `速度${configJson.practiceSpeed || 0}`,
           `${configJson.trainingTimes}分钟`
         ];
       }

+ 2 - 2
src/views/classList/work-item/index.module.less

@@ -126,7 +126,7 @@
 }
 
 .trainInfo {
-  max-width: 82%;
+  max-width: 86%;
 
   .trainName {
     display: flex;
@@ -181,4 +181,4 @@
 .reportModel {
   width: 1200px;
   overflow: hidden;
-}
+}

+ 302 - 303
src/views/home/modals/chioseModal.tsx

@@ -1,303 +1,302 @@
-import { defineComponent, onMounted, reactive, ref } from 'vue';
-import styles from './chioseModal.module.less';
-import {
-  NButton,
-  NForm,
-  NFormItem,
-  NSelect,
-  NSpace,
-  useMessage
-} from 'naive-ui';
-import { useRouter } from 'vue-router';
-import { classGroupList, getCourseChapter } from '../../classList/api';
-import {
-  bookVersionPage,
-  courseScheduleStart,
-  lessonCoursewarePage,
-  queryCourseware
-} from '../../prepare-lessons/api';
-import { useThrottleFn } from '@vueuse/core';
-import { useCatchStore } from '/src/store/modules/catchData';
-import { gradeToCN } from '/src/utils/contants';
-export default defineComponent({
-  name: 'train-update',
-  emits: ['close', 'preview'],
-  setup(props, { emit }) {
-    const forms = reactive({
-      currentClass: null,
-      bookVersionId: null,
-      classGroupId: null,
-      category: null,
-      chapter: null,
-      subjectId: null,
-      gradeList: [] as any,
-      classList: [] as any,
-      musicTagList: [] as any,
-      loading: false,
-      list: [] as any,
-      chapterList: [] as any,
-      unit: null,
-      unitList: [],
-      subjectList: [] as any
-    });
-    const router = useRouter();
-    const catchStore = useCatchStore();
-    const message = useMessage();
-    const gotoClassPage = () => {
-      formsRef.value.validate(async (error: any) => {
-        if (error) return;
-        const { data } = await queryCourseware({
-          coursewareDetailKnowledgeId: forms.chapter,
-          subjectId: forms.subjectId,
-          page: 1,
-          rows: 99
-        });
-        if (data.rows && data.rows.length > 0) {
-          const res = await courseScheduleStart({
-            lessonCoursewareKnowledgeDetailId: forms.chapter,
-            classGroupId: forms.currentClass,
-            subjectId: forms.subjectId
-          });
-          emit('close');
-          emit('preview', {
-            type: 'class',
-            classId: res.data, // 上课编号
-            classGroupId: forms.currentClass,
-            lessonCourseId: forms.category, // 册别编号
-            subjectId: forms.subjectId,
-            detailId: forms.chapter
-          });
-        } else {
-          message.error('当前章节暂无课件,请重新选择');
-        }
-      });
-    };
-
-    const formsRef = ref();
-    const throttledFn = useThrottleFn(() => getLessonCourseware(), 500);
-    const getLessonCourseware = async () => {
-      forms.category = null;
-      forms.unit = null;
-      forms.category = null;
-      forms.chapter = null;
-      forms.loading = true;
-
-      if (forms.bookVersionId) {
-        try {
-          const { data } = await lessonCoursewarePage({
-            page: 1,
-            rows: 99,
-            type: 'COURSEWARE',
-            enableFlag: 1,
-            bookVersionId: forms.bookVersionId
-            // currentGradeNum: props.activeRow.currentGradeNum
-          });
-
-          forms.list = data.rows.map((item: any) => {
-            return {
-              label: item.name,
-              value: item.id
-            };
-          });
-        } catch {
-          //
-        }
-      } else {
-        forms.list = [];
-      }
-
-      forms.loading = false;
-    };
-    const getVersion = async () => {
-      forms.unit = null;
-      forms.chapter = null;
-
-      try {
-        const { data } = await bookVersionPage({
-          page: 1,
-          rows: 99,
-          type: 'COURSEWARE'
-        });
-        const temp = data.rows || [];
-        temp.forEach((item: any) => {
-          forms.musicTagList.push({
-            id: item.id,
-            name: item.name
-          });
-        });
-      } catch {
-        //
-      }
-    };
-
-    const getunitList = async () => {
-      forms.unit = null;
-      forms.chapter = null;
-      try {
-        if (forms.category) {
-          const res = await getCourseChapter(forms.category);
-          forms.unitList = res.data.lessonList.map((item: any) => {
-            return { ...item, label: item.name, value: item.id };
-          });
-        } else {
-          forms.unitList = [];
-        }
-      } catch (e) {
-        console.log(e);
-      }
-    };
-    const getchapterList = () => {
-      forms.chapter = null;
-      if (forms.unit) {
-        const item: any = forms.unitList.find((item: any) => {
-          return item.id === forms.unit;
-        });
-        forms.chapterList = item.knowledgeList.map((know: any) => {
-          return { ...know, label: know.name, value: know.id };
-        });
-        console.log('getchapterList', item);
-      } else {
-        forms.chapterList = [];
-      }
-      console.log('getchapterList');
-    };
-
-    // 获取年级班级
-    const getClassList = async () => {
-      try {
-        const { data } = await classGroupList({ removeZeroClass: true });
-
-        const cList = data.rows || [];
-        const gradeList: any = [];
-        cList.forEach((item: any) => {
-          gradeList.push({
-            label: item.name,
-            value: item.id
-          });
-        });
-        forms.gradeList = gradeList;
-
-        console.log(forms.gradeList, 'gradeList');
-      } catch (e: any) {
-        //
-        console.log(e, 'e');
-      }
-    };
-
-    onMounted(async () => {
-      await getClassList();
-      await catchStore.getSubjects();
-      forms.subjectList = catchStore.getSubjectList.map((item: any) => {
-        return {
-          label: item.name,
-          value: item.id
-        };
-      });
-      getVersion();
-    });
-    return () => (
-      <div class={styles.trainUpdate}>
-        <NForm
-          labelAlign="left"
-          labelPlacement="left"
-          ref={formsRef}
-          model={forms}>
-          <NFormItem
-            path="currentClass"
-            rule={[
-              {
-                required: true,
-                message: '请选择班级',
-                trigger: 'change'
-              }
-            ]}>
-            <NSelect
-              v-model:value={forms.currentClass}
-              placeholder="请选择班级"
-              options={forms.gradeList as any}
-              clearable
-              onUpdate:value={() => {
-                forms.classGroupId = null;
-                getClassList();
-              }}
-            />
-          </NFormItem>
-          <NFormItem
-            path="bookVersionId"
-            rule={[{ required: true, message: '选择教材版本' }]}>
-            <NSelect
-              placeholder="选择教材版本"
-              clearable
-              options={[...forms.musicTagList]}
-              labelField="name"
-              valueField="id"
-              v-model:value={forms.bookVersionId}
-              onUpdate:value={() => throttledFn()}
-            />
-          </NFormItem>
-          <NFormItem
-            path="category"
-            rule={[{ required: true, message: '请选择册别' }]}>
-            <NSelect
-              {...({
-                options: [...forms.list],
-                placeholder: '选择册别',
-                clearable: true
-              } as any)}
-              disabled={!forms.bookVersionId}
-              v-model:value={forms.category}
-              onUpdate:value={() => getunitList()}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="unit"
-            rule={[{ required: true, message: '请选择单元' }]}>
-            <NSelect
-              disabled={!forms.category}
-              {...({
-                options: [...forms.unitList],
-                placeholder: '选择单元',
-                clearable: true
-              } as any)}
-              v-model:value={forms.unit}
-              onUpdate:value={() => getchapterList()}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="chapter"
-            rule={[{ required: true, message: '请选择章节' }]}>
-            <NSelect
-              disabled={!forms.unit}
-              {...({
-                options: [...forms.chapterList],
-                placeholder: '选择章节',
-                clearable: true
-              } as any)}
-              v-model:value={forms.chapter}></NSelect>
-          </NFormItem>
-          <NFormItem
-            path="subjectId"
-            rule={[{ required: true, message: '请选择乐器' }]}>
-            <NSelect
-              {...({
-                options: [...forms.subjectList],
-                placeholder: '选择乐器',
-                clearable: true
-              } as any)}
-              v-model:value={forms.subjectId}></NSelect>
-          </NFormItem>
-          <NSpace class={styles.updateBtnGroup}>
-            <NButton strong type="default" round onClick={() => emit('close')}>
-              取消
-            </NButton>
-            <NButton
-              strong
-              type="primary"
-              round
-              onClick={() => gotoClassPage()}>
-              确认
-            </NButton>
-          </NSpace>
-        </NForm>
-      </div>
-    );
-  }
-});
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+import styles from './chioseModal.module.less';
+import {
+  NButton,
+  NForm,
+  NFormItem,
+  NSelect,
+  NSpace,
+  useMessage
+} from 'naive-ui';
+import { useRouter } from 'vue-router';
+import { classGroupList, getCourseChapter } from '../../classList/api';
+import {
+  bookVersionPage,
+  courseScheduleStart,
+  lessonCoursewarePage,
+  queryCourseware
+} from '../../prepare-lessons/api';
+import { useThrottleFn } from '@vueuse/core';
+import { useCatchStore } from '/src/store/modules/catchData';
+export default defineComponent({
+  name: 'chiose-modal',
+  emits: ['close', 'preview'],
+  setup(props, { emit }) {
+    const forms = reactive({
+      currentClass: null,
+      bookVersionId: null,
+      classGroupId: null,
+      category: null,
+      chapter: null,
+      subjectId: null,
+      gradeList: [] as any,
+      classList: [] as any,
+      musicTagList: [] as any,
+      loading: false,
+      list: [] as any,
+      chapterList: [] as any,
+      unit: null,
+      unitList: [],
+      subjectList: [] as any
+    });
+    const router = useRouter();
+    const catchStore = useCatchStore();
+    const message = useMessage();
+    const gotoClassPage = () => {
+      formsRef.value.validate(async (error: any) => {
+        if (error) return;
+        const { data } = await queryCourseware({
+          coursewareDetailKnowledgeId: forms.chapter,
+          subjectId: forms.subjectId,
+          page: 1,
+          rows: 99
+        });
+        if (data.rows && data.rows.length > 0) {
+          const res = await courseScheduleStart({
+            lessonCoursewareKnowledgeDetailId: forms.chapter,
+            classGroupId: forms.currentClass,
+            subjectId: forms.subjectId
+          });
+          emit('close');
+          emit('preview', {
+            type: 'class',
+            classId: res.data, // 上课编号
+            classGroupId: forms.currentClass,
+            lessonCourseId: forms.category, // 册别编号
+            subjectId: forms.subjectId,
+            detailId: forms.chapter
+          });
+        } else {
+          message.error('当前章节暂无课件,请重新选择');
+        }
+      });
+    };
+
+    const formsRef = ref();
+    const throttledFn = useThrottleFn(() => getLessonCourseware(), 500);
+    const getLessonCourseware = async () => {
+      forms.category = null;
+      forms.unit = null;
+      forms.category = null;
+      forms.chapter = null;
+      forms.loading = true;
+
+      if (forms.bookVersionId) {
+        try {
+          const { data } = await lessonCoursewarePage({
+            page: 1,
+            rows: 99,
+            type: 'COURSEWARE',
+            enableFlag: 1,
+            bookVersionId: forms.bookVersionId
+            // currentGradeNum: props.activeRow.currentGradeNum
+          });
+
+          forms.list = data.rows.map((item: any) => {
+            return {
+              label: item.name,
+              value: item.id
+            };
+          });
+        } catch {
+          //
+        }
+      } else {
+        forms.list = [];
+      }
+
+      forms.loading = false;
+    };
+    const getVersion = async () => {
+      forms.unit = null;
+      forms.chapter = null;
+
+      try {
+        const { data } = await bookVersionPage({
+          page: 1,
+          rows: 99,
+          type: 'COURSEWARE'
+        });
+        const temp = data.rows || [];
+        temp.forEach((item: any) => {
+          forms.musicTagList.push({
+            id: item.id,
+            name: item.name
+          });
+        });
+      } catch {
+        //
+      }
+    };
+
+    const getunitList = async () => {
+      forms.unit = null;
+      forms.chapter = null;
+      try {
+        if (forms.category) {
+          const res = await getCourseChapter(forms.category);
+          forms.unitList = res.data.lessonList.map((item: any) => {
+            return { ...item, label: item.name, value: item.id };
+          });
+        } else {
+          forms.unitList = [];
+        }
+      } catch (e) {
+        console.log(e);
+      }
+    };
+    const getchapterList = () => {
+      forms.chapter = null;
+      if (forms.unit) {
+        const item: any = forms.unitList.find((item: any) => {
+          return item.id === forms.unit;
+        });
+        forms.chapterList = item.knowledgeList.map((know: any) => {
+          return { ...know, label: know.name, value: know.id };
+        });
+        console.log('getchapterList', item);
+      } else {
+        forms.chapterList = [];
+      }
+      console.log('getchapterList');
+    };
+
+    // 获取年级班级
+    const getClassList = async () => {
+      try {
+        const { data } = await classGroupList({ removeZeroClass: true });
+
+        const cList = data.rows || [];
+        const gradeList: any = [];
+        cList.forEach((item: any) => {
+          gradeList.push({
+            label: item.name,
+            value: item.id
+          });
+        });
+        forms.gradeList = gradeList;
+
+        console.log(forms.gradeList, 'gradeList');
+      } catch (e: any) {
+        //
+        console.log(e, 'e');
+      }
+    };
+
+    onMounted(async () => {
+      await getClassList();
+      await catchStore.getSubjects();
+      forms.subjectList = catchStore.getSubjectList.map((item: any) => {
+        return {
+          label: item.name,
+          value: item.id
+        };
+      });
+      getVersion();
+    });
+    return () => (
+      <div class={styles.trainUpdate}>
+        <NForm
+          labelAlign="left"
+          labelPlacement="left"
+          ref={formsRef}
+          model={forms}>
+          <NFormItem
+            path="currentClass"
+            rule={[
+              {
+                required: true,
+                message: '请选择班级',
+                trigger: 'change'
+              }
+            ]}>
+            <NSelect
+              v-model:value={forms.currentClass}
+              placeholder="请选择班级"
+              options={forms.gradeList as any}
+              clearable
+              onUpdate:value={() => {
+                forms.classGroupId = null;
+                getClassList();
+              }}
+            />
+          </NFormItem>
+          <NFormItem
+            path="bookVersionId"
+            rule={[{ required: true, message: '选择教材版本' }]}>
+            <NSelect
+              placeholder="选择教材版本"
+              clearable
+              options={[...forms.musicTagList]}
+              labelField="name"
+              valueField="id"
+              v-model:value={forms.bookVersionId}
+              onUpdate:value={() => throttledFn()}
+            />
+          </NFormItem>
+          <NFormItem
+            path="category"
+            rule={[{ required: true, message: '请选择册别' }]}>
+            <NSelect
+              {...({
+                options: [...forms.list],
+                placeholder: '选择册别',
+                clearable: true
+              } as any)}
+              disabled={!forms.bookVersionId}
+              v-model:value={forms.category}
+              onUpdate:value={() => getunitList()}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="unit"
+            rule={[{ required: true, message: '请选择单元' }]}>
+            <NSelect
+              disabled={!forms.category}
+              {...({
+                options: [...forms.unitList],
+                placeholder: '选择单元',
+                clearable: true
+              } as any)}
+              v-model:value={forms.unit}
+              onUpdate:value={() => getchapterList()}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="chapter"
+            rule={[{ required: true, message: '请选择章节' }]}>
+            <NSelect
+              disabled={!forms.unit}
+              {...({
+                options: [...forms.chapterList],
+                placeholder: '选择章节',
+                clearable: true
+              } as any)}
+              v-model:value={forms.chapter}></NSelect>
+          </NFormItem>
+          <NFormItem
+            path="subjectId"
+            rule={[{ required: true, message: '请选择乐器' }]}>
+            <NSelect
+              {...({
+                options: [...forms.subjectList],
+                placeholder: '选择乐器',
+                clearable: true
+              } as any)}
+              v-model:value={forms.subjectId}></NSelect>
+          </NFormItem>
+          <NSpace class={styles.updateBtnGroup}>
+            <NButton strong type="default" round onClick={() => emit('close')}>
+              取消
+            </NButton>
+            <NButton
+              strong
+              type="primary"
+              round
+              onClick={() => gotoClassPage()}>
+              确认
+            </NButton>
+          </NSpace>
+        </NForm>
+      </div>
+    );
+  }
+});

+ 2 - 2
src/views/homework-record/detail/index.module.less

@@ -247,7 +247,7 @@
 }
 
 .wordDetailModel {
-  width: 1012px;
+  width: 1092px;
 }
 
 .isok {
@@ -263,4 +263,4 @@
 .nosub {
   font-weight: 600;
   color: #aaa;
-}
+}

+ 2 - 1
src/views/homework-record/detail/index.tsx

@@ -120,7 +120,7 @@ export default defineComponent({
               if (trainingContent) {
                 const tempList = [
                   `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`,
-                  `速度${trainingContent.practiceSpeed}`,
+                  `速度${trainingContent.practiceSpeed || 0}`,
                   `${trainingContent.trainingTimes}分钟`
                 ];
                 pTitle += tempList.join(' | ') + ';';
@@ -135,6 +135,7 @@ export default defineComponent({
                   trainingContent.practiceChapterEnd
                     ? `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`
                     : '全部小节',
+                  `速度${trainingContent.evaluateSpeed || 0}`,
                   `${trainingContent.trainingTimes}分达标`
                 ];
                 eTitle += tempList.join(' | ') + ';';

+ 2 - 2
src/views/homework-record/index.module.less

@@ -79,7 +79,7 @@
 }
 
 .workVisiable {
-  width: 1358px;
+  width: 1420px;
 
   :global {
     .c-cascaderPopover {
@@ -365,4 +365,4 @@
       line-height: 18px;
     }
   }
-}
+}

+ 2 - 1
src/views/homework-record/index.tsx

@@ -160,7 +160,7 @@ export default defineComponent({
                 if (trainingContent) {
                   const tempList = [
                     `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`,
-                    `速度${trainingContent.practiceSpeed}`,
+                    `速度${trainingContent.practiceSpeed || 0}`,
                     `${trainingContent.trainingTimes}分钟`
                   ];
                   pTitle += tempList.join(' | ') + ';';
@@ -178,6 +178,7 @@ export default defineComponent({
                     trainingContent.practiceChapterEnd
                       ? `${trainingContent.practiceChapterBegin}-${trainingContent.practiceChapterEnd}小节`
                       : '全部小节',
+                    `速度${trainingContent.evaluateSpeed || 0}`,
                     `${trainingContent.trainingTimes}分达标`
                   ];
                   eTitle += tempList.join(' | ') + ';';

+ 84 - 77
src/views/natural-resources/api.ts

@@ -1,77 +1,84 @@
-import request from '@/utils/request';
-
-/**
- * 资源 - 曲目列表
- */
-export const materialQueryPage = (params: any) => {
-  return request.post('/edu-app/material/queryPage', {
-    data: params
-  });
-};
-
-/**
- * 资源 - 收藏/取消收藏
- */
-export const favorite = (params: any) => {
-  return request.post('/edu-app/material/favorite', {
-    data: params
-  });
-};
-
-/**
- * 资源 - 删除
- */
-export const materialRemove = (params: any) => {
-  return request.post('/edu-app/material/remove', {
-    requestType: 'form',
-    data: params
-  });
-};
-
-/** 音乐教材-新增 */
-export const api_lessonCoursewareSave = (params: any): Promise<any> => {
-  return request.post('/edu-app/lessonCourseware/save', {
-    data: params
-  });
-};
-
-/** 音乐教材-修改 */
-export const api_lessonCoursewareUpdate = (params: any): Promise<any> => {
-  return request.post('/edu-app/lessonCourseware/update', {
-    data: params
-  });
-};
-
-/** 资源-新增 */
-export const materialSave = (params: any[]): Promise<any> => {
-  return request.post('/edu-app/material/save', {
-    data: params
-  });
-};
-
-/** 资源-修改 */
-export const materialUpdate = (params: any): Promise<any> => {
-  return request.post('/edu-app/material/update', {
-    data: params
-  });
-};
-/** 资源-批量修改 */
-export const materialUpdateAll = (params: any): Promise<any> => {
-  return request.post('/edu-app/material/updateAll', {
-    data: params
-  });
-};
-
-/** 资源-批量删除 */
-export const materialRemoveAll = (params: any): Promise<any> => {
-  return request.post('/edu-app/material/removeAll', {
-    data: params
-  });
-};
-
-/** 资源-批量删除-曲谱 */
-export const materialRemoveMusic = (params: any): Promise<any> => {
-  return request.post('/edu-app/material/removeMusic', {
-    data: params
-  });
-};
+import request from '@/utils/request';
+
+/**
+ * 资源 - 曲目列表
+ */
+export const materialQueryPage = (params: any) => {
+  return request.post('/edu-app/material/queryPage', {
+    data: params
+  });
+};
+
+/**
+ * 资源 - 收藏/取消收藏
+ */
+export const favorite = (params: any) => {
+  return request.post('/edu-app/material/favorite', {
+    data: params
+  });
+};
+
+/**
+ * 资源 - 删除
+ */
+export const materialRemove = (params: any) => {
+  return request.post('/edu-app/material/remove', {
+    requestType: 'form',
+    data: params
+  });
+};
+
+/** 音乐教材-新增 */
+export const api_lessonCoursewareSave = (params: any): Promise<any> => {
+  return request.post('/edu-app/lessonCourseware/save', {
+    data: params
+  });
+};
+
+/** 音乐教材-修改 */
+export const api_lessonCoursewareUpdate = (params: any): Promise<any> => {
+  return request.post('/edu-app/lessonCourseware/update', {
+    data: params
+  });
+};
+
+/** 资源-新增 */
+export const materialSave = (params: any[]): Promise<any> => {
+  return request.post('/edu-app/material/save', {
+    data: params
+  });
+};
+
+/** 资源-修改 */
+export const materialUpdate = (params: any): Promise<any> => {
+  return request.post('/edu-app/material/update', {
+    data: params
+  });
+};
+/** 资源-批量修改 */
+export const materialUpdateAll = (params: any): Promise<any> => {
+  return request.post('/edu-app/material/updateAll', {
+    data: params
+  });
+};
+
+/** 资源-批量删除 */
+export const materialRemoveAll = (params: any): Promise<any> => {
+  return request.post('/edu-app/material/removeAll', {
+    data: params
+  });
+};
+
+/** 资源-批量删除-曲谱 */
+export const materialRemoveMusic = (params: any): Promise<any> => {
+  return request.post('/edu-app/material/removeMusic', {
+    data: params
+  });
+};
+
+/** 素材标签分页 */
+export const api_materialTagPage = (params: any): Promise<any> => {
+  return request.post('/edu-app/materialTag/page', {
+    data: params
+  });
+};

+ 1 - 0
src/views/natural-resources/components/my-collect/index.tsx

@@ -32,6 +32,7 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        materialTagId: null, // 标签
         bookVersionId: null,
         musicalInstrumentId: null,
         subjectId: null,

+ 25 - 1
src/views/natural-resources/components/my-collect/search-group-resources.tsx

@@ -25,7 +25,8 @@ export default defineComponent({
       name: '',
       audioPlayTypes: '',
       bookVersionId: null,
-      subjectId: null
+      subjectId: null,
+      materialTagId: null
     });
     const state = reactive({
       tempSubjectId: null
@@ -135,6 +136,7 @@ export default defineComponent({
 
       // 获取教材分类列表
       await catchStore.getMusicSheetCategory();
+      await catchStore.getMaterialTagsApi();
       // 获取声部列表
       await catchStore.getSubjects();
 
@@ -311,6 +313,28 @@ export default defineComponent({
             </NFormItem>
           )}
 
+          {/* 乐谱没有标签 */}
+          {forms.type !== 'MUSIC' && (
+            <NFormItem label="标签:">
+              <NSpace class={styles.spaceSection2}>
+                {catchStore.getAllMaterialTags.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.materialTagId === subject.value &&
+                        styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.materialTagId = subject.value;
+                      onSearch();
+                    }}>
+                    {subject.label}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
           <TheSearch
             class={styles.inputSearch}
             round

+ 1 - 0
src/views/natural-resources/components/my-resources/index.tsx

@@ -43,6 +43,7 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        materialTagId: null, // 标签
         bookVersionId: null,
         musicalInstrumentId: null,
         subjectId: null,

+ 474 - 474
src/views/natural-resources/components/my-resources/save-modal/index.tsx

@@ -1,474 +1,474 @@
-import { PropType, computed, defineComponent, reactive, ref } from 'vue';
-import styles from './index.module.less';
-import {
-  NButton,
-  NSpace,
-  NUpload,
-  NUploadDragger,
-  UploadCustomRequestOptions,
-  UploadFileInfo,
-  useMessage
-} from 'naive-ui';
-// import iconUploadAdd from '../../../images/icon-upload-add.png';
-import { NaturalTypeEnum, PageEnum } from '/src/enums/pageEnum';
-// import { policy } from '/src/components/upload-file/api';
-import { formatUrlType } from '../upload-modal';
-// import axios from 'axios';
-import {
-  getUploadSign,
-  onFileUpload,
-  onOnlyFileUpload
-  // ossSwitch
-} from '/src/helpers/oss-file-upload';
-
-export default defineComponent({
-  name: 'save-modal',
-  props: {
-    fileList: {
-      type: String,
-      default: ''
-    },
-    imageList: {
-      type: Array,
-      default: () => []
-    },
-    accept: {
-      // 支持类型
-      type: String,
-      default: '.jpg,.png,.jpeg,.gif'
-    },
-    showType: {
-      type: String as PropType<'default' | 'custom'>,
-      default: 'default'
-    },
-    showFileList: {
-      type: Boolean,
-      default: true
-    },
-    max: {
-      type: Number as PropType<number>,
-      default: 1
-    },
-    multiple: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    disabled: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    bucketName: {
-      type: String,
-      default: 'gyt'
-    },
-    directoryDnd: {
-      type: Boolean as PropType<boolean>,
-      default: false
-    },
-    path: {
-      type: String,
-      default: ''
-    },
-    fileName: {
-      type: String,
-      default: ''
-    }
-  },
-  emits: ['close', 'confrim'],
-  setup(props, { emit }) {
-    const ossUploadUrl = `https://${props.bucketName}.ks3-cn-beijing.ksyuncs.com/`;
-    const message = useMessage();
-    const visiable = ref<boolean>(false);
-    const btnLoading = ref<boolean>(false);
-    const tempFiileBuffer = ref();
-    const uploadRef = ref();
-    const state = reactive([]) as any;
-
-    const fileListRef = ref<UploadFileInfo[]>([]);
-    const uploadList = ref([] as any);
-
-    // 获取文件后缀名
-    function getFileExtension(filename: string) {
-      return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2);
-    }
-
-    // 判断是否是允许的文件类型
-    function isAllowedFileType(filename: string, allowedExtensions: any) {
-      const extension = getFileExtension(filename).toLowerCase();
-      return allowedExtensions.includes(extension);
-    }
-
-    const onBeforeUpload = async (options: any) => {
-      const file = options.file;
-      // 文件大小
-      let isLt2M = true;
-
-      const allowedExtensions = [
-        'jpg',
-        'jpeg',
-        'png',
-        'mp4',
-        // 'ppt',
-        // 'pptx',
-        'mp3'
-      ];
-      if (!isAllowedFileType(file.file.name, allowedExtensions)) {
-        message.error('文件格式不支持');
-        return false;
-      }
-
-      const type = file.type.includes('image')
-        ? NaturalTypeEnum.IMG
-        : file.type.includes('audio')
-        ? NaturalTypeEnum.SONG
-        : file.type.includes('video')
-        ? NaturalTypeEnum.VIDEO
-        : file.type.includes(
-            'vnd.openxmlformats-officedocument.presentationml.presentation'
-          ) || file.type.includes('vnd.ms-powerpoint')
-        ? NaturalTypeEnum.PPT
-        : 'other';
-
-      if (type === 'other') {
-        message.error(`文件格式不支持`);
-        return false;
-      }
-      const size = type === 'IMG' ? 2 : type === 'SONG' ? 20 : 500;
-      if (size) {
-        isLt2M = file.file.size / 1024 / 1024 < size;
-        if (!isLt2M) {
-          const typeStr =
-            type === 'IMG' ? '图片' : type === 'SONG' ? '音频' : '视频';
-          message.error(`${typeStr}大小不能超过${size}M`);
-          return false;
-        }
-      }
-
-      if (!isLt2M) {
-        return isLt2M;
-      }
-      // 是否裁切
-      // if (props.cropper && type === 'IMG') {
-      //   getBase64(file.file, (imageUrl: any) => {
-      //     const target = Object.assign({}, props.options, {
-      //       img: imageUrl,
-      //       name: file.file.name // 上传文件名
-      //     });
-      //     visiable.value = true;
-
-      //     setTimeout(() => {
-      //       CropperModal.value?.edit(target);
-      //     }, 100);
-      //   });
-      //   return false;
-      // }
-
-      try {
-        btnLoading.value = true;
-        const name = file.file.name;
-        const suffix = name.slice(name.lastIndexOf('.'));
-        const fileName = `${props.path}${Date.now() + file.id + suffix}`;
-        const obj = {
-          filename: fileName,
-          bucketName: props.bucketName,
-          postData: {
-            filename: fileName,
-            acl: 'public-read',
-            key: fileName,
-            unknowValueField: []
-          }
-        };
-        // const { data } = await policy(obj);
-        const { data } = await getUploadSign(obj);
-        state.push({
-          id: file.id,
-          tempFiileBuffer: file.file,
-          policy: data.policy,
-          signature: data.signature,
-          acl: 'public-read',
-          key: fileName,
-          KSSAccessKeyId: data.kssAccessKeyId,
-          name: fileName
-        });
-      } catch {
-        //
-        // message.error('上传失败')
-        btnLoading.value = false;
-        return false;
-      }
-      return true;
-    };
-    // const getBase64 = async (img: any, callback: any) => {
-    //   const reader = new FileReader();
-    //   reader.addEventListener('load', () => callback(reader.result));
-    //   reader.readAsDataURL(img);
-    // };
-
-    const onFinish = (options: any) => {
-      onFinishAfter(options);
-    };
-    const onFinishAfter = async (options: any) => {
-      console.log(options, 'onFinishAfter');
-      const item = state.find((c: any) => c.id == options.file.id);
-      const type = formatUrlType(options.file.url);
-      let coverImg = '';
-      if (type === 'IMG') {
-        coverImg = options.file.url;
-      } else if (type === 'SONG') {
-        coverImg = PageEnum.SONG_DEFAULT_COVER;
-      } else if (type === 'PPT') {
-        coverImg = PageEnum.PPT_DEFAULT_COVER;
-      } else if (type === 'VIDEO') {
-        // 获取视频封面图
-        coverImg = await getVideoCoverImg(item.tempFiileBuffer);
-      }
-
-      uploadList.value.push({
-        coverImg,
-        content: options.file.url,
-        id: options.file.id,
-        name: options.file.name
-          ? options.file.name.slice(0, options.file.name.lastIndexOf('.'))
-          : ''
-      });
-
-      visiable.value = false;
-      btnLoading.value = false;
-    };
-    const getVideoMsg = (file: any) => {
-      return new Promise((resolve, reject) => {
-        // let dataURL = '';
-        const videoElement = document.createElement('video');
-        videoElement.setAttribute('crossOrigin', 'Anonymous'); // 处理跨域
-        videoElement.setAttribute('preload', 'auto'); // auto|metadata|none
-        videoElement.muted = true;
-        videoElement.autoplay = true;
-        videoElement.src = URL.createObjectURL(file);
-        // Listen for 'canplay' to ensure the video is ready for frame capture
-        videoElement.addEventListener('loadedmetadata', () => {
-          // 这里开始播放
-          videoElement.play();
-          setTimeout(() => {
-            // 过500ms 暂停, 解决空白问题
-            videoElement.currentTime = 0;
-            videoElement.pause();
-            // 创建canvas元素
-            const canvas: any = document.createElement('canvas');
-            canvas.width = videoElement.videoWidth;
-            canvas.height = videoElement.videoHeight;
-
-            // 将视频帧绘制到canvas上
-            // const ctx = canvas.getContext('2d');
-
-            // console.log(videoElement);
-            // ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
-            canvas
-              .getContext('2d')
-              .drawImage(videoElement, 0, 0, canvas.width, canvas.height);
-
-            // 将canvas图像转换为base64格式的数据URI
-            // const dataUrl = canvas.toDataURL('image/png');
-            // 返回base64格式的数据URI
-            // resolve(dataUrl);
-            canvas.toBlob((blob: any) => {
-              resolve(blob);
-            });
-          }, 500);
-        });
-
-        // 如果视频加载出错,则返回错误信息
-        videoElement.addEventListener('error', (e: any) => {
-          reject(e);
-        });
-        // return new Promise((resolve, reject) => {
-        //   videoElement.addEventListener('loadedmetadata', () => {
-        //     // 这里开始播放
-        //     videoElement.play()
-        //     setTimeout(() => {
-        //       // 过500ms 暂停, 解决空白问题
-        //       videoElement.pause()
-        //       // 创建canvas元素
-        //       const canvas = document.createElement('canvas');
-        //       canvas.width = videoElement.videoWidth;
-        //       canvas.height = videoElement.videoHeight;
-
-        //       // 将视频帧绘制到canvas上
-        //       const ctx = canvas.getContext('2d');
-
-        //       console.log(videoElement);
-        //       ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
-
-        //       // 将canvas图像转换为base64格式的数据URI
-        //       const dataUrl = canvas.toDataURL('image/png');
-        //       console.log(dataUrl);
-        //       thumbnail.src = dataUrl;
-        //       thumbnail.style.display = 'inline';
-        //       // 返回base64格式的数据URI
-        //       resolve(dataUrl);
-        //     }, 500);
-        //   });
-
-        //   // 如果视频加载出错,则返回错误信息
-        //   videoElement.addEventListener('error', () => {
-        //     reject(`Failed to load video: ${videoUrl}`);
-        //   });
-        // });
-
-        // videoElement.addEventListener('canplay', function () {
-        //   console.log('Video can play');
-        //   const canvas: any = document.createElement('canvas'),
-        //     width = videoElement.videoWidth,
-        //     height = videoElement.videoHeight;
-
-        //   canvas.width = width;
-        //   canvas.height = height;
-        //   canvas.getContext('2d').drawImage(videoElement, 0, 0, width, height);
-
-        //   canvas.toBlob((blob: any) => {
-        //     resolve(blob);
-        //   });
-        // });
-        // videoElement.addEventListener('error', function (e) {
-        //   console.error('Error loading video:', e);
-        //   reject(e);
-        // });
-      });
-    };
-
-    const getVideoCoverImg = async (file: any) => {
-      try {
-        btnLoading.value = true;
-        const imgBlob: any = await getVideoMsg(file || tempFiileBuffer.value);
-        const fileName = `${props.path}${Date.now() + '.png'}`;
-        const obj = {
-          filename: fileName,
-          bucketName: props.bucketName,
-          postData: {
-            filename: fileName,
-            acl: 'public-read',
-            key: fileName,
-            unknowValueField: []
-          }
-        };
-        const { data } = await getUploadSign(obj);
-
-        const fileParams = {
-          policy: data.policy,
-          signature: data.signature,
-          key: fileName,
-          acl: 'public-read',
-          KSSAccessKeyId: data.kssAccessKeyId,
-          name: fileName,
-          file: imgBlob
-        } as any;
-        const res = await onOnlyFileUpload(ossUploadUrl, fileParams);
-
-        return res;
-      } finally {
-        btnLoading.value = false;
-      }
-    };
-
-    const onRemove = async (file: any) => {
-      const index = uploadList.value.findIndex(
-        (update: any) => update.id === file.file.id
-      );
-      uploadList.value.splice(index, 1);
-      btnLoading.value = false;
-      return true;
-    };
-
-    const uploadStatus = computed(() => {
-      let status = false;
-      fileListRef.value.forEach((file: any) => {
-        if (file.status !== 'finished') {
-          status = true;
-        }
-      });
-      return status || fileListRef.value.length <= 0;
-    });
-
-    const onCustomRequest = ({
-      file,
-      // data,
-      // headers,
-      // withCredentials,
-      action,
-      onFinish,
-      onError,
-      onProgress
-    }: UploadCustomRequestOptions) => {
-      const item = state.find((c: any) => {
-        return c.id == file.id;
-      });
-
-      item.file = file;
-      onFileUpload({ file, action, data: item, onProgress, onFinish, onError });
-    };
-
-    const onSubmit = async () => {
-      const list: any = [];
-      fileListRef.value.forEach((file: any) => {
-        const item = uploadList.value.find(
-          (child: any) => child.id === file.id
-        );
-        if (item) {
-          list.push(item);
-        }
-      });
-      emit('confrim', list);
-    };
-
-    return () => (
-      <div class={styles.saveModal}>
-        <NUpload
-          ref={uploadRef}
-          action={ossUploadUrl}
-          // data={(file: any) => {
-
-          //   return { ...more };
-          // }}
-          customRequest={onCustomRequest}
-          v-model:fileList={fileListRef.value}
-          // accept=".jpg,jpeg,.png,audio/mp3,video/mp4,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation"
-          accept=".jpg,jpeg,.png,audio/mp3,video/mp4"
-          multiple={true}
-          max={10}
-          // disabled={props.disabled}
-          showFileList={true}
-          showPreviewButton
-          onBeforeUpload={(options: any) => onBeforeUpload(options)}
-          onFinish={(options: any) => {
-            onFinish(options);
-          }}
-          onRemove={(options: any) => onRemove(options)}>
-          <NUploadDragger>
-            <div class={styles.uploadBtn}>
-              <div class={styles.iconUploadAdd} />
-              <h3>点击或者拖动文件到该区域来上传</h3>
-              <p>
-                {/* 仅支持JPG、PNG、MP3、MP4、PPT格式文件,单次最多支持 */}
-                仅支持JPG、PNG、MP3、MP4,单次最多支持
-                <br />
-                上传10个文件
-              </p>
-            </div>
-          </NUploadDragger>
-        </NUpload>
-
-        <NSpace class={styles.btnGroup} justify="center">
-          <NButton round onClick={() => emit('close')}>
-            取消
-          </NButton>
-          <NButton
-            round
-            type="primary"
-            disabled={uploadStatus.value || btnLoading.value}
-            onClick={onSubmit}>
-            确定
-          </NButton>
-        </NSpace>
-      </div>
-    );
-  }
-});
+import { PropType, computed, defineComponent, reactive, ref } from 'vue';
+import styles from './index.module.less';
+import {
+  NButton,
+  NSpace,
+  NUpload,
+  NUploadDragger,
+  UploadCustomRequestOptions,
+  UploadFileInfo,
+  useMessage
+} from 'naive-ui';
+// import iconUploadAdd from '../../../images/icon-upload-add.png';
+import { NaturalTypeEnum, PageEnum } from '/src/enums/pageEnum';
+// import { policy } from '/src/components/upload-file/api';
+import { formatUrlType } from '../upload-modal';
+// import axios from 'axios';
+import {
+  getUploadSign,
+  onFileUpload,
+  onOnlyFileUpload
+  // ossSwitch
+} from '/src/helpers/oss-file-upload';
+
+export default defineComponent({
+  name: 'save-modal',
+  props: {
+    fileList: {
+      type: String,
+      default: ''
+    },
+    imageList: {
+      type: Array,
+      default: () => []
+    },
+    accept: {
+      // 支持类型
+      type: String,
+      default: '.jpg,.png,.jpeg,.gif'
+    },
+    showType: {
+      type: String as PropType<'default' | 'custom'>,
+      default: 'default'
+    },
+    showFileList: {
+      type: Boolean,
+      default: true
+    },
+    max: {
+      type: Number as PropType<number>,
+      default: 1
+    },
+    multiple: {
+      type: Boolean as PropType<boolean>,
+      default: false
+    },
+    disabled: {
+      type: Boolean as PropType<boolean>,
+      default: false
+    },
+    bucketName: {
+      type: String,
+      default: 'gyt'
+    },
+    directoryDnd: {
+      type: Boolean as PropType<boolean>,
+      default: false
+    },
+    path: {
+      type: String,
+      default: ''
+    },
+    fileName: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['close', 'confrim'],
+  setup(props, { emit }) {
+    const ossUploadUrl = `https://${props.bucketName}.ks3-cn-beijing.ksyuncs.com/`;
+    const message = useMessage();
+    const visiable = ref<boolean>(false);
+    const btnLoading = ref<boolean>(false);
+    const tempFiileBuffer = ref();
+    const uploadRef = ref();
+    const state = reactive([]) as any;
+
+    const fileListRef = ref<UploadFileInfo[]>([]);
+    const uploadList = ref([] as any);
+
+    // 获取文件后缀名
+    function getFileExtension(filename: string) {
+      return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2);
+    }
+
+    // 判断是否是允许的文件类型
+    function isAllowedFileType(filename: string, allowedExtensions: any) {
+      const extension = getFileExtension(filename).toLowerCase();
+      return allowedExtensions.includes(extension);
+    }
+
+    const onBeforeUpload = async (options: any) => {
+      const file = options.file;
+      // 文件大小
+      let isLt2M = true;
+
+      const allowedExtensions = [
+        'jpg',
+        'jpeg',
+        'png',
+        'mp4',
+        // 'ppt',
+        // 'pptx',
+        'mp3'
+      ];
+      if (!isAllowedFileType(file.file.name, allowedExtensions)) {
+        message.error('文件格式不支持');
+        return false;
+      }
+
+      const type = file.type.includes('image')
+        ? NaturalTypeEnum.IMG
+        : file.type.includes('audio')
+        ? NaturalTypeEnum.SONG
+        : file.type.includes('video')
+        ? NaturalTypeEnum.VIDEO
+        : file.type.includes(
+            'vnd.openxmlformats-officedocument.presentationml.presentation'
+          ) || file.type.includes('vnd.ms-powerpoint')
+        ? NaturalTypeEnum.PPT
+        : 'other';
+
+      if (type === 'other') {
+        message.error(`文件格式不支持`);
+        return false;
+      }
+      const size = type === 'IMG' ? 2 : type === 'SONG' ? 20 : 500;
+      if (size) {
+        isLt2M = file.file.size / 1024 / 1024 < size;
+        if (!isLt2M) {
+          const typeStr =
+            type === 'IMG' ? '图片' : type === 'SONG' ? '音频' : '视频';
+          message.error(`${typeStr}大小不能超过${size}M`);
+          return false;
+        }
+      }
+
+      if (!isLt2M) {
+        return isLt2M;
+      }
+      // 是否裁切
+      // if (props.cropper && type === 'IMG') {
+      //   getBase64(file.file, (imageUrl: any) => {
+      //     const target = Object.assign({}, props.options, {
+      //       img: imageUrl,
+      //       name: file.file.name // 上传文件名
+      //     });
+      //     visiable.value = true;
+
+      //     setTimeout(() => {
+      //       CropperModal.value?.edit(target);
+      //     }, 100);
+      //   });
+      //   return false;
+      // }
+
+      try {
+        btnLoading.value = true;
+        const name = file.file.name;
+        const suffix = name.slice(name.lastIndexOf('.'));
+        const fileName = `${props.path}${Date.now() + file.id + suffix}`;
+        const obj = {
+          filename: fileName,
+          bucketName: props.bucketName,
+          postData: {
+            filename: fileName,
+            acl: 'public-read',
+            key: fileName,
+            unknowValueField: []
+          }
+        };
+        // const { data } = await policy(obj);
+        const { data } = await getUploadSign(obj);
+        state.push({
+          id: file.id,
+          tempFiileBuffer: file.file,
+          policy: data.policy,
+          signature: data.signature,
+          acl: 'public-read',
+          key: fileName,
+          KSSAccessKeyId: data.kssAccessKeyId,
+          name: fileName
+        });
+      } catch {
+        //
+        // message.error('上传失败')
+        btnLoading.value = false;
+        return false;
+      }
+      return true;
+    };
+    // const getBase64 = async (img: any, callback: any) => {
+    //   const reader = new FileReader();
+    //   reader.addEventListener('load', () => callback(reader.result));
+    //   reader.readAsDataURL(img);
+    // };
+
+    const onFinish = (options: any) => {
+      onFinishAfter(options);
+    };
+    const onFinishAfter = async (options: any) => {
+      console.log(options, 'onFinishAfter');
+      const item = state.find((c: any) => c.id == options.file.id);
+      const type = formatUrlType(options.file.url);
+      let coverImg = '';
+      if (type === 'IMG') {
+        coverImg = options.file.url;
+      } else if (type === 'SONG') {
+        coverImg = PageEnum.SONG_DEFAULT_COVER;
+      } else if (type === 'PPT') {
+        coverImg = PageEnum.PPT_DEFAULT_COVER;
+      } else if (type === 'VIDEO') {
+        // 获取视频封面图
+        coverImg = await getVideoCoverImg(item.tempFiileBuffer);
+      }
+
+      uploadList.value.push({
+        coverImg,
+        content: options.file.url,
+        id: options.file.id,
+        name: options.file.name
+          ? options.file.name.slice(0, options.file.name.lastIndexOf('.'))
+          : ''
+      });
+
+      visiable.value = false;
+      btnLoading.value = false;
+    };
+    const getVideoMsg = (file: any) => {
+      return new Promise((resolve, reject) => {
+        // let dataURL = '';
+        const videoElement = document.createElement('video');
+        videoElement.setAttribute('crossOrigin', 'Anonymous'); // 处理跨域
+        videoElement.setAttribute('preload', 'auto'); // auto|metadata|none
+        videoElement.muted = true;
+        videoElement.autoplay = true;
+        videoElement.src = URL.createObjectURL(file);
+        // Listen for 'canplay' to ensure the video is ready for frame capture
+        videoElement.addEventListener('loadedmetadata', () => {
+          // 这里开始播放
+          videoElement.play();
+          setTimeout(() => {
+            // 过500ms 暂停, 解决空白问题
+            videoElement.currentTime = 0;
+            videoElement.pause();
+            // 创建canvas元素
+            const canvas: any = document.createElement('canvas');
+            canvas.width = videoElement.videoWidth;
+            canvas.height = videoElement.videoHeight;
+
+            // 将视频帧绘制到canvas上
+            // const ctx = canvas.getContext('2d');
+
+            // console.log(videoElement);
+            // ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+            canvas
+              .getContext('2d')
+              .drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+
+            // 将canvas图像转换为base64格式的数据URI
+            // const dataUrl = canvas.toDataURL('image/png');
+            // 返回base64格式的数据URI
+            // resolve(dataUrl);
+            canvas.toBlob((blob: any) => {
+              resolve(blob);
+            });
+          }, 500);
+        });
+
+        // 如果视频加载出错,则返回错误信息
+        videoElement.addEventListener('error', (e: any) => {
+          reject(e);
+        });
+        // return new Promise((resolve, reject) => {
+        //   videoElement.addEventListener('loadedmetadata', () => {
+        //     // 这里开始播放
+        //     videoElement.play()
+        //     setTimeout(() => {
+        //       // 过500ms 暂停, 解决空白问题
+        //       videoElement.pause()
+        //       // 创建canvas元素
+        //       const canvas = document.createElement('canvas');
+        //       canvas.width = videoElement.videoWidth;
+        //       canvas.height = videoElement.videoHeight;
+
+        //       // 将视频帧绘制到canvas上
+        //       const ctx = canvas.getContext('2d');
+
+        //       console.log(videoElement);
+        //       ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+
+        //       // 将canvas图像转换为base64格式的数据URI
+        //       const dataUrl = canvas.toDataURL('image/png');
+        //       console.log(dataUrl);
+        //       thumbnail.src = dataUrl;
+        //       thumbnail.style.display = 'inline';
+        //       // 返回base64格式的数据URI
+        //       resolve(dataUrl);
+        //     }, 500);
+        //   });
+
+        //   // 如果视频加载出错,则返回错误信息
+        //   videoElement.addEventListener('error', () => {
+        //     reject(`Failed to load video: ${videoUrl}`);
+        //   });
+        // });
+
+        // videoElement.addEventListener('canplay', function () {
+        //   console.log('Video can play');
+        //   const canvas: any = document.createElement('canvas'),
+        //     width = videoElement.videoWidth,
+        //     height = videoElement.videoHeight;
+
+        //   canvas.width = width;
+        //   canvas.height = height;
+        //   canvas.getContext('2d').drawImage(videoElement, 0, 0, width, height);
+
+        //   canvas.toBlob((blob: any) => {
+        //     resolve(blob);
+        //   });
+        // });
+        // videoElement.addEventListener('error', function (e) {
+        //   console.error('Error loading video:', e);
+        //   reject(e);
+        // });
+      });
+    };
+
+    const getVideoCoverImg = async (file: any) => {
+      try {
+        btnLoading.value = true;
+        const imgBlob: any = await getVideoMsg(file || tempFiileBuffer.value);
+        const fileName = `${props.path}${Date.now() + '.png'}`;
+        const obj = {
+          filename: fileName,
+          bucketName: props.bucketName,
+          postData: {
+            filename: fileName,
+            acl: 'public-read',
+            key: fileName,
+            unknowValueField: []
+          }
+        };
+        const { data } = await getUploadSign(obj);
+
+        const fileParams = {
+          policy: data.policy,
+          signature: data.signature,
+          key: fileName,
+          acl: 'public-read',
+          KSSAccessKeyId: data.kssAccessKeyId,
+          name: fileName,
+          file: imgBlob
+        } as any;
+        const res = await onOnlyFileUpload(ossUploadUrl, fileParams);
+
+        return res;
+      } finally {
+        btnLoading.value = false;
+      }
+    };
+
+    const onRemove = async (file: any) => {
+      const index = uploadList.value.findIndex(
+        (update: any) => update.id === file.file.id
+      );
+      uploadList.value.splice(index, 1);
+      btnLoading.value = false;
+      return true;
+    };
+
+    const uploadStatus = computed(() => {
+      let status = false;
+      fileListRef.value.forEach((file: any) => {
+        if (file.status !== 'finished') {
+          status = true;
+        }
+      });
+      return status || fileListRef.value.length <= 0;
+    });
+
+    const onCustomRequest = ({
+      file,
+      // data,
+      // headers,
+      // withCredentials,
+      action,
+      onFinish,
+      onError,
+      onProgress
+    }: UploadCustomRequestOptions) => {
+      const item = state.find((c: any) => {
+        return c.id == file.id;
+      });
+
+      item.file = file;
+      onFileUpload({ file, action, data: item, onProgress, onFinish, onError });
+    };
+
+    const onSubmit = async () => {
+      const list: any = [];
+      fileListRef.value.forEach((file: any) => {
+        const item = uploadList.value.find(
+          (child: any) => child.id === file.id
+        );
+        if (item) {
+          list.push(item);
+        }
+      });
+      emit('confrim', list);
+    };
+
+    return () => (
+      <div class={styles.saveModal}>
+        <NUpload
+          ref={uploadRef}
+          action={ossUploadUrl}
+          // data={(file: any) => {
+
+          //   return { ...more };
+          // }}
+          customRequest={onCustomRequest}
+          v-model:fileList={fileListRef.value}
+          // accept=".jpg,jpeg,.png,audio/mp3,video/mp4,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation"
+          accept=".jpg,jpeg,.png,audio/mp3,video/mp4"
+          multiple={true}
+          max={10}
+          // disabled={props.disabled}
+          showFileList={true}
+          showPreviewButton
+          onBeforeUpload={(options: any) => onBeforeUpload(options)}
+          onFinish={(options: any) => {
+            onFinish(options);
+          }}
+          onRemove={(options: any) => onRemove(options)}>
+          <NUploadDragger>
+            <div class={styles.uploadBtn}>
+              <div class={styles.iconUploadAdd} />
+              <h3>点击或者拖动文件到该区域来上传</h3>
+              <p>
+                {/* 仅支持JPG、PNG、MP3、MP4、PPT格式文件,单次最多支持 */}
+                仅支持JPG、PNG、MP3、MP4,单次最多支持
+                <br />
+                上传10个文件
+              </p>
+            </div>
+          </NUploadDragger>
+        </NUpload>
+
+        <NSpace class={styles.btnGroup} justify="center">
+          <NButton round onClick={() => emit('close')}>
+            取消
+          </NButton>
+          <NButton
+            round
+            type="primary"
+            disabled={uploadStatus.value || btnLoading.value}
+            onClick={onSubmit}>
+            确定
+          </NButton>
+        </NSpace>
+      </div>
+    );
+  }
+});

+ 27 - 2
src/views/natural-resources/components/my-resources/search-group-resources.tsx

@@ -31,7 +31,8 @@ export default defineComponent({
       name: '',
       audioPlayTypes: ['PLAY'],
       bookVersionId: null,
-      subjectId: null
+      subjectId: null,
+      materialTagId: null
     });
     const state = reactive({
       tempSubjectId: null,
@@ -67,6 +68,8 @@ export default defineComponent({
 
       // 获取声部列表
       await catchStore.getSubjects();
+      // 获取素材标签
+      await catchStore.getMaterialTagsApi();
 
       if (forms.subjectId) {
         state.tempSubjectId = forms.subjectId;
@@ -114,6 +117,7 @@ export default defineComponent({
                   // forms.subjectId = null;
                   // state.tempSubjectId = null;
 
+                  forms.materialTagId = null
                   // onSearch();
                   formatFirstSubject();
                 }}>
@@ -269,11 +273,32 @@ export default defineComponent({
             </NSpace>
           </NFormItem>
 
+          {/* 乐谱没有标签 */}
+          {forms.type !== 'MUSIC' && (
+            <NFormItem label="标签:">
+              <NSpace class={styles.spaceSection2}>
+                {catchStore.getAllMaterialTags.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.materialTagId === subject.value && styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.materialTagId = subject.value;
+                      onSearch();
+                    }}>
+                    {subject.label}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
           <TheSearch
             class={styles.inputSearch}
             value={forms.name}
             onUpdate:value={(val: string) => {
-              forms.name = val
+              forms.name = val;
             }}
             round
             onSearch={(val: string) => {

+ 210 - 206
src/views/natural-resources/components/my-resources/upload-modal/index.module.less

@@ -1,206 +1,210 @@
-.uploadModal {
-  padding-top: 40px;
-}
-
-.formModal {
-  min-height: 45vh;
-  padding: 0 40px 0;
-
-  .formSpace {
-    gap: 40px 24px !important;
-  }
-
-  .previewModal {
-    position: relative;
-    width: 320px;
-    height: 180px;
-    margin-bottom: 12px;
-    border: 1px solid #DCE2F1;
-    border-radius: 10px;
-    overflow: hidden;
-
-    &:hover {
-      border-color: #198CFE;
-    }
-
-    .image {
-      width: 320px;
-      height: 180px;
-
-      img {
-        width: inherit;
-        height: fit-content;
-        min-height: 100%;
-      }
-    }
-
-    .titleType {
-      position: absolute;
-      top: 6px;
-      left: 6px;
-      width: 22px;
-      height: 22px;
-      z-index: 99;
-    }
-
-    &:hover {
-      .iconUploadDelete {
-        opacity: 1;
-        display: block;
-      }
-    }
-
-    .iconUploadDelete {
-      position: absolute;
-      top: 7px;
-      right: 7px;
-      width: 27px;
-      height: 27px;
-      z-index: 99;
-      cursor: pointer;
-      opacity: 0;
-      display: none;
-    }
-
-    .commonType {
-      display: flex;
-      align-items: center;
-      position: absolute;
-      bottom: 0;
-      left: 0;
-      font-size: 12Px;
-      font-weight: 600;
-      color: #FFFFFF;
-      height: 43px;
-      // background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
-      width: 100%;
-      border-radius: 0 0 10px 10px;
-      justify-content: space-between;
-      padding-right: 12px;
-      padding-left: 12px;
-      z-index: 99;
-      background: rgba(0, 0, 0, 0.3);
-      backdrop-filter: blur(1px);
-
-      .changeCover {
-        background: #FFFFFF;
-        border-radius: 4px;
-        color: #131415 !important;
-        --n-height: 24px !important;
-        --n-padding: 0 8px !important;
-        font-size: max(14px, 12Px);
-      }
-
-      :global {
-        .n-switch {
-          margin-left: 8px;
-        }
-
-        .n-switch__rail {
-          background-color: #ccc;
-        }
-
-        .n-switch.n-switch--active .n-switch__rail {
-          background-color: var(--n-rail-color-active);
-        }
-      }
-    }
-  }
-
-  .formItem {
-    width: 320px;
-
-    :global {
-
-      .n-input {
-        margin-bottom: 12px;
-      }
-
-      .n-input,
-      .n-base-selection {
-        border-radius: 8px;
-        font-size: 18px;
-
-        .n-input__input-el,
-        .n-input__input-el::placeholder,
-        .n-tag__content {
-          font-size: 18px;
-        }
-      }
-
-      .n-form-item-feedback-wrapper {
-        min-height: 12px;
-      }
-
-      .n-upload-trigger+.n-upload-file-list {
-        margin-top: 12px;
-      }
-    }
-  }
-}
-
-.btnGroup {
-  padding: 32px 0;
-
-  :global {
-    .n-button {
-      height: 47px;
-      min-width: 156px;
-    }
-  }
-}
-
-
-
-.uploadFile {
-  margin-bottom: 12px;
-
-  :global {
-    .n-upload-dragger {
-      padding: 0;
-      border: none;
-    }
-  }
-
-  .uploadBtn {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-direction: column;
-    width: 320px;
-    height: 180px;
-    padding-top: 20px;
-    background: #F9FAFD;
-    border-radius: 10px;
-    border: 1px solid #DCE2F1;
-    font-size: 18px;
-    color: #9EADD9;
-
-    &:hover {
-      border-color: #198CFE;
-    }
-
-    .iconUploadAdd {
-      width: 50px;
-      height: 50px;
-      margin-bottom: 20px;
-    }
-  }
-}
-
-
-.uploadCover {
-  width: 920px;
-
-  :global {
-
-    .n-card-header {
-      padding-top: 0;
-      padding-bottom: 0;
-
-      .n-card-header__close {
-        margin-top: 65px;
-      }
-    }
-  }
-}
+.uploadModal {
+  padding-top: 40px;
+}
+
+.mb12 {
+  margin-bottom: 12px;
+}
+
+.formModal {
+  min-height: 45vh;
+  padding: 0 40px 0;
+
+  .formSpace {
+    gap: 40px 24px !important;
+  }
+
+  .previewModal {
+    position: relative;
+    width: 320px;
+    height: 180px;
+    margin-bottom: 12px;
+    border: 1px solid #DCE2F1;
+    border-radius: 10px;
+    overflow: hidden;
+
+    &:hover {
+      border-color: #198CFE;
+    }
+
+    .image {
+      width: 320px;
+      height: 180px;
+
+      img {
+        width: inherit;
+        height: fit-content;
+        min-height: 100%;
+      }
+    }
+
+    .titleType {
+      position: absolute;
+      top: 6px;
+      left: 6px;
+      width: 22px;
+      height: 22px;
+      z-index: 99;
+    }
+
+    &:hover {
+      .iconUploadDelete {
+        opacity: 1;
+        display: block;
+      }
+    }
+
+    .iconUploadDelete {
+      position: absolute;
+      top: 7px;
+      right: 7px;
+      width: 27px;
+      height: 27px;
+      z-index: 99;
+      cursor: pointer;
+      opacity: 0;
+      display: none;
+    }
+
+    .commonType {
+      display: flex;
+      align-items: center;
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      font-size: 12Px;
+      font-weight: 600;
+      color: #FFFFFF;
+      height: 43px;
+      // background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
+      width: 100%;
+      border-radius: 0 0 10px 10px;
+      justify-content: space-between;
+      padding-right: 12px;
+      padding-left: 12px;
+      z-index: 99;
+      background: rgba(0, 0, 0, 0.3);
+      backdrop-filter: blur(1px);
+
+      .changeCover {
+        background: #FFFFFF;
+        border-radius: 4px;
+        color: #131415 !important;
+        --n-height: 24px !important;
+        --n-padding: 0 8px !important;
+        font-size: max(14px, 12Px);
+      }
+
+      :global {
+        .n-switch {
+          margin-left: 8px;
+        }
+
+        .n-switch__rail {
+          background-color: #ccc;
+        }
+
+        .n-switch.n-switch--active .n-switch__rail {
+          background-color: var(--n-rail-color-active);
+        }
+      }
+    }
+  }
+
+  .formItem {
+    width: 320px;
+
+    :global {
+
+      .n-input {
+        margin-bottom: 12px;
+      }
+
+      .n-input,
+      .n-base-selection {
+        border-radius: 8px;
+        font-size: 18px;
+
+        .n-input__input-el,
+        .n-input__input-el::placeholder,
+        .n-tag__content {
+          font-size: 18px;
+        }
+      }
+
+      .n-form-item-feedback-wrapper {
+        min-height: 12px;
+      }
+
+      .n-upload-trigger+.n-upload-file-list {
+        margin-top: 12px;
+      }
+    }
+  }
+}
+
+.btnGroup {
+  padding: 32px 0;
+
+  :global {
+    .n-button {
+      height: 47px;
+      min-width: 156px;
+    }
+  }
+}
+
+
+
+.uploadFile {
+  margin-bottom: 12px;
+
+  :global {
+    .n-upload-dragger {
+      padding: 0;
+      border: none;
+    }
+  }
+
+  .uploadBtn {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    width: 320px;
+    height: 180px;
+    padding-top: 20px;
+    background: #F9FAFD;
+    border-radius: 10px;
+    border: 1px solid #DCE2F1;
+    font-size: 18px;
+    color: #9EADD9;
+
+    &:hover {
+      border-color: #198CFE;
+    }
+
+    .iconUploadAdd {
+      width: 50px;
+      height: 50px;
+      margin-bottom: 20px;
+    }
+  }
+}
+
+
+.uploadCover {
+  width: 920px;
+
+  :global {
+
+    .n-card-header {
+      padding-top: 0;
+      padding-bottom: 0;
+
+      .n-card-header__close {
+        margin-top: 65px;
+      }
+    }
+  }
+}

+ 50 - 95
src/views/natural-resources/components/my-resources/upload-modal/index.tsx

@@ -29,7 +29,11 @@ import iconAudio from '@common/images/icon-audio.png';
 import iconMusic from '@common/images/icon-music.png';
 import iconPPT from '@common/images/icon-ppt.png';
 import iconUploadDelete from '../../../images/btn-remove2.png';
-import { materialSave, materialUpdateAll } from '../../../api';
+import {
+  api_materialTagPage,
+  materialSave,
+  materialUpdateAll
+} from '../../../api';
 import { NaturalTypeEnum } from '@/enums/pageEnum';
 import { scrollToErrorForm } from '/src/utils';
 import UploadCover from '../upload-cover';
@@ -70,6 +74,7 @@ export default defineComponent({
     const catchStore = useCatchStore();
     const formRef = ref();
     const message = useMessage();
+    const materialTags = ref<any[]>([]);
 
     // const uploadRef = ref();
     // const uploadList = ref([] as any);
@@ -126,6 +131,7 @@ export default defineComponent({
               openFlag: item.openFlag,
               coverImg: item.coverImg,
               name: item.name,
+              tagIds: item.tagIds?.join(','),
               type: item.type,
               enableFlag: 1,
               content: item.content,
@@ -164,6 +170,18 @@ export default defineComponent({
 
     const isUpdate = computed(() => (props.list.length > 0 ? true : false));
 
+    /** 获取素材标签 */
+    const getMaterialTags = async () => {
+      const res = await api_materialTagPage({ page: 1, rows: 1000 });
+      const result = res.data.rows || [];
+      if (res.code === 200 && Array.isArray(result)) {
+        materialTags.value = result.map((item: any) => ({
+          label: item.name,
+          value: item.id
+        }));
+      }
+    };
+
     onMounted(async () => {
       const list = props.list || [];
       const temps: any[] = [];
@@ -179,7 +197,7 @@ export default defineComponent({
           sourceFrom: item.sourceFrom,
           enableFlag: item.enableFlag,
           content: item.content,
-
+          tagIds: item.tagIds?.split(','),
           id: item.id
         });
       });
@@ -187,6 +205,7 @@ export default defineComponent({
 
       // console.log(temps, 'uploadForms');
       await catchStore.getSubjects();
+      await getMaterialTags();
     });
 
     // 全选
@@ -289,19 +308,20 @@ export default defineComponent({
                     />
                   </NFormItem>
                   <NFormItem
+                    class={styles.mb12}
                     path={`list[${index}].instrumentIds`}
                     showFeedback={false}
                     rule={[
                       {
                         required: true,
-                        message: '请选择素材可用乐器',
+                        message: '请选择资源可用乐器',
                         trigger: 'change',
                         type: 'array'
                       }
                     ]}>
                     <NCascader
                       v-model:value={item.instrumentIds}
-                      placeholder="请选择素材可用乐器(可多选)"
+                      placeholder="请选择资源可用乐器(可多选)"
                       options={catchStore.getEnableSubjects}
                       checkStrategy="child"
                       showPath={false}
@@ -315,107 +335,42 @@ export default defineComponent({
                       maxTagCount="responsive"
                       v-slots={{
                         action: () => (
-                          <>
-                            <NButton
-                              text
-                              style=" --n-width: 100% "
-                              onClick={() =>
-                                chioseAll(item, catchStore.getEnableSubjects)
-                              }>
-                              全选
-                            </NButton>
-                          </>
+                          <NButton
+                            text
+                            style=" --n-width: 100% "
+                            onClick={() =>
+                              chioseAll(item, catchStore.getEnableSubjects)
+                            }>
+                            全选
+                          </NButton>
                         )
                       }}
                     />
                   </NFormItem>
-                </div>
-              ))}
-
-              {/* {!isUpdate.value && (
-                <div class={styles.formItem}>
-                  <UploadFile
-                    v-model:fileList={uploadForms.uploadUrl}
-                    accept=".jpg,jpeg,.png,audio/mp3,video/mp4"
-                    showFileList={false}
-                    ref={uploadRef}
-                    // cropper
-                    multiple
-                    max={10}
-                    // options={{
-                    //   autoCropWidth: 320,
-                    //   autoCropHeight: 180,
-                    //   fixedBox: true
-                    // }}
-                    onFinished={(val: any) => {
-                      console.log(val, 'val');
-                      uploadList.value.push({
-                        instrumentIds: uploadForms.instrumentIds || [],
-                        openFlag: true,
-                        coverImg: val.coverImg,
-                        name: uploadForms.name || '',
-                        type: formatUrlType(val.content),
-                        enableFlag: 1,
-                        content: val.content
-                      });
-                      // uploadForms.list.push({
-                      //   instrumentIds: uploadForms.instrumentIds || [],
-                      //   openFlag: true,
-                      //   coverImg: val.coverImg,
-                      //   name: uploadForms.name || '',
-                      //   type: formatUrlType(val.content),
-                      //   enableFlag: 1,
-                      //   content: val.content
-                      // });
-                      const timer = setTimeout(() => {
-                        uploadForms.list.push(...uploadList.value);
-                        uploadList.value = [];
-                        uploadForms.uploadUrl = '';
-                        uploadForms.name = '';
-                        uploadForms.instrumentIds = [];
-                        uploadRef.value.handleClearFile();
-                      }, 1000);
-                    }}
-                  />
-                  <NFormItem showFeedback={false}>
-                    <NInput
-                      v-model:value={uploadForms.name}
-                      placeholder="请输入资源名称"
-                      maxlength={25}
-                      clearable
-                    />
-                  </NFormItem>
-                  <NFormItem showFeedback={false}>
+                  <NFormItem
+                    path={`list[${index}].tagIds`}
+                    showFeedback={false}>
                     <NSelect
-                      v-model:value={uploadForms.instrumentIds}
-                      placeholder="请选择素材可用声部(可多选)"
-                      options={catchStore.getSubjectList}
-                      labelField="name"
-                      valueField="id"
-                      multiple
-                      maxTagCount={2}
+                      placeholder="请选择资源标签(最多选择3个)"
+                      options={materialTags.value}
                       clearable
-                      v-slots={{
-                        action: () => (
-                          <>
-                            <NButton
-                              text
-                              style=" --n-width: 100% "
-                              onClick={() =>
-                                chioseAll(
-                                  uploadForms,
-                                  catchStore.getSubjectList
-                                )
-                              }>
-                              全选
-                            </NButton>
-                          </>
-                        )
+                      filterable
+                      multiple
+                      maxTagCount="responsive"
+                      value={item.tagIds}
+                      onUpdate:value={(newValue: any) => {
+                        if (newValue.length > 3) {
+                          // 如果超过 3 个,截取前 3 个
+                          item.tagIds = newValue.slice(0, 3);
+                          message.info('最多选择3个标签');
+                        } else {
+                          item.tagIds = newValue;
+                        }
                       }}
                     />
                   </NFormItem>
                 </div>
-              )} */}
+              ))}
             </NSpace>
           </NForm>
         </NScrollbar>

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

@@ -25,6 +25,7 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        materialTagId: null, // 标签
         audioPlayTypes: [] as any,
         musicalInstrumentId: null,
         bookVersionId: null,

+ 26 - 2
src/views/natural-resources/components/share-resources/search-group-resources.tsx

@@ -122,7 +122,8 @@ export default defineComponent({
       audioPlayTypes: '',
       bookVersionId: null as any,
       // musicSheetCategoriesId: null as any,
-      subjectId: null
+      subjectId: null,
+      materialTagId: null
     });
     const state = reactive({
       tempSubjectId: null
@@ -272,6 +273,7 @@ export default defineComponent({
       // 获取教材分类列表
       // await catchStore.getMusicSheetCategory();
       await catchStore.getMusicTagTreeApi();
+      await catchStore.getMaterialTagsApi();
       _initTags();
       // console.log(data, 'data');
       // 获取声部列表
@@ -446,12 +448,34 @@ export default defineComponent({
             </NFormItem>
           )}
 
+          {/* 乐谱没有标签 */}
+          {forms.type !== 'MUSIC' && (
+            <NFormItem label="标签:">
+              <NSpace class={styles.spaceSection2}>
+                {catchStore.getAllMaterialTags.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+                      forms.materialTagId === subject.value &&
+                        styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.materialTagId = subject.value;
+                      onSearch();
+                    }}>
+                    {subject.label}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
+
           <TheSearch
             class={styles.inputSearch}
             round
             value={forms.name}
             onUpdate:value={(val: string) => {
-              forms.name = val
+              forms.name = val;
             }}
             onSearch={(val: string) => {
               forms.name = val;

+ 3 - 4
src/views/prepare-lessons/components/directory-main/select-lessonware/index.tsx

@@ -106,7 +106,6 @@ export default defineComponent({
     const getSearchDetail = async () => {
       try {
         const { data } = await api_lessonCoursewareTeacherCategory();
-        console.log(data, 'data');
 
         const result = data || []
 
@@ -188,7 +187,7 @@ export default defineComponent({
                   ))}
                 </NSpace>
               </NFormItem>}
-              
+
               {treeList.gradeList.length > 0 && <NFormItem label="年级:">
                 <NSpace class={styles.spaceSection}>
                   {treeList.gradeList?.map((subject: any) => (
@@ -219,7 +218,7 @@ export default defineComponent({
                   ))}
                 </NSpace>
               </NFormItem>}
-              
+
               {treeList.bookTypeList.length > 0 && <NFormItem label="册别:">
                 <NSpace class={styles.spaceSection}>
                   {treeList.bookTypeList?.map((subject: any) => (
@@ -239,7 +238,7 @@ export default defineComponent({
                   ))}
                 </NSpace>
               </NFormItem>}
-              
+
 
               <NFormItem label="乐器:">
                 <NSpace class={styles.spaceSection}>

+ 1 - 1
src/views/prepare-lessons/components/lesson-main/courseware-presets/index.module.less

@@ -388,7 +388,7 @@
 }
 
 .workVisiable {
-  width: 1358px;
+  width: 1420px;
 
   :global {
     .c-cascaderPopover {

+ 1 - 1
src/views/prepare-lessons/components/lesson-main/courseware/addCourseware.tsx

@@ -898,7 +898,7 @@ export default defineComponent({
                           eventGlobal.emit('checkCoursewareForm', 'subject')
                           return
                         }
-                        
+
                         await addDragCoursewareItem(
                           {
                             materialId: dropItem.id,

+ 3 - 5
src/views/prepare-lessons/components/lesson-main/train/index.tsx

@@ -120,21 +120,19 @@ export default defineComponent({
               configJson.practiceChapterBegin || configJson.practiceChapterEnd
                 ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
                 : '全部小节',
-              // `速度${configJson.evaluateSpeed}`,
+              `速度${configJson.evaluateSpeed || 0}`,
               `${configJson.trainingTimes}分达标`
             ];
           } else {
             tList = [
               `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-              `速度${configJson.practiceSpeed}`,
+              `速度${configJson.practiceSpeed || 0}`,
               `${configJson.trainingTimes}分钟`
             ];
           }
           temp.push({
             typeList: tList || [],
-            audioPlayTypeArray:row.audioPlayTypes
-            ? row.audioPlayTypes.split(',')
-            : [],
+            audioPlayTypeArray: row.audioPlayTypes ? row.audioPlayTypes.split(',') : [],
             ...row
           });
         });

+ 1 - 0
src/views/prepare-lessons/components/resource-main/components/resource-item/index.tsx

@@ -54,6 +54,7 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        materialTagId: null,
         bookVersionId: null,
         musicalInstrumentId: null,
         subjectId: null,

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

@@ -2,12 +2,8 @@ import { PropType, defineComponent, onMounted, reactive, ref } from 'vue';
 import styles from './index.module.less';
 import {
   NButton,
-  NCascader,
   NInput,
-  NSelect,
-  NSpace,
-  NTreeSelect,
-  TreeSelectOverrideNodeClickBehavior
+  NSpace
 } from 'naive-ui';
 import { resourceTypeArray } from '/src/utils/searchArray';
 import { useCatchStore } from '/src/store/modules/catchData';
@@ -29,6 +25,7 @@ export default defineComponent({
     const catchStore = useCatchStore();
     const musics = ref('');
     const subjects = ref('');
+    const materials = ref('')
     const forms = reactive({
       type: 'MUSIC', //
       name: '',
@@ -36,7 +33,8 @@ export default defineComponent({
       subjectId: null as any,
       audioPlayTypes: props.type === 'myResources' ? 'PLAY' : '',
       // musicSheetCategoriesId: null,
-      musicalInstrumentId: ''
+      musicalInstrumentId: '',
+      materialTagId: null
     });
     const resourceType = ref([] as any);
 
@@ -68,6 +66,23 @@ export default defineComponent({
         ...tags
       ];
     };
+    const materialTagList = ref<any[]>([]);
+    const _initMaterialTag = () => {
+      const tags = catchStore.getMaterialTags;
+      tags.forEach((item: any) => {
+        item.columnName = '标签';
+        item.name = item.label;
+        item.id = item.value;
+      });
+      materialTagList.value = [
+        {
+          columnName: '标签',
+          name: '全部标签',
+          id: ''
+        },
+        ...tags
+      ];
+    };
     const formatParentCurrentValue = (list: any) => {
       for (const item of list) {
         if (item.instruments && item.instruments.length > 0) {
@@ -83,12 +98,12 @@ export default defineComponent({
     const _initSubjectTags = () => {
       const tags = catchStore.getSubjectList;
       formatParentCurrentValue(tags);
-      if(tags.length > 0) {
-        tags[0].columnName = '声部'
+      if (tags.length > 0) {
+        tags[0].columnName = '声部';
 
-        const firstChild = tags[0]
-        forms.subjectId = firstChild.value
-        forms.musicalInstrumentId = firstChild.children[0]?.value
+        const firstChild = tags[0];
+        forms.subjectId = firstChild.value;
+        forms.musicalInstrumentId = firstChild.children[0]?.value;
         subjects.value = firstChild.children[0]?.value
       }
       tagSubjectList.value = tags
@@ -98,6 +113,8 @@ export default defineComponent({
       // await catchStore.getMusicSheetCategory();
       await catchStore.getMusicTagTreeApi();
       _initTags();
+      await catchStore.getMaterialTagsApi();
+      _initMaterialTag();
       // 获取教材分类列表
       await catchStore.getSubjects();
       _initSubjectTags();
@@ -113,82 +130,91 @@ export default defineComponent({
       onSearch()
     });
     return () => (
-      <>
-        <div class={styles.searchGroup}>
-          <NSpace size="small" class={styles.btnType}>
-            {resourceType.value.map((item: any) => (
-              <NButton
-                type={forms.type === item.value ? 'primary' : 'default'}
-                secondary={forms.type === item.value ? false : true}
-                round
-                size="small"
-                focusable={false}
-                onClick={() => {
-                  forms.type = item.value;
-                  debouncedRequest();
-                }}>
-                {item.label}
-              </NButton>
-            ))}
-          </NSpace>
+      <div class={styles.searchGroup}>
+        <NSpace size="small" class={styles.btnType}>
+          {resourceType.value.map((item: any) => (
+            <NButton
+              type={forms.type === item.value ? 'primary' : 'default'}
+              secondary={forms.type === item.value ? false : true}
+              round
+              size="small"
+              focusable={false}
+              onClick={() => {
+                forms.type = item.value;
+                debouncedRequest();
+              }}>
+              {item.label}
+            </NButton>
+          ))}
+        </NSpace>
 
-          <div class={styles.searchSelect}>
-            {forms.type === 'MUSIC' && props.type === 'shareResources' && (
-              <CCascader
-                placeholder="全部教材"
-                showPath
-                v-model:value={musics.value}
-                options={tagList.value}
-                onUpdate:value={(value: any) => {
-                  console.log(value, 'value');
-                  forms.bookVersionId = value || '';
-                  onSearch();
-                }}
-              />
-            )}
+        <div class={styles.searchSelect}>
+          {forms.type === 'MUSIC' && props.type === 'shareResources' && (
             <CCascader
-              placeholder="全部声部"
-              childShowAllCheck={false}
+              placeholder="全部教材"
               showPath
-              showAudioPlayType={props.type === 'myResources' || forms.type !== 'MUSIC' ? false : true}
-              v-model:value={subjects.value}
-              options={tagSubjectList.value}
-              onMoreId={(val: any) => {
-                forms.musicalInstrumentId = val.childId;
-                forms.subjectId = val.parentId;
-                if (props.type !== 'myResources') {
-                  forms.audioPlayTypes = val.audioPlayTypes;
-                }
+              v-model:value={musics.value}
+              options={tagList.value}
+              onUpdate:value={(value: any) => {
+                forms.bookVersionId = value || '';
                 onSearch();
               }}
             />
-          </div>
-
-          <NInput
-            type="text"
-            placeholder="请输入搜索关键词"
-            clearable
-            v-model:value={forms.name}
-            class={styles.inputSearch}
-            onKeyup={(e: KeyboardEvent) => {
-              if (e.code === 'Enter') {
-                debouncedRequest();
+          )}
+          {forms.type !== 'MUSIC' && (
+            <CCascader
+              placeholder="全部标签"
+              showPath
+              v-model:value={materials.value}
+              options={materialTagList.value}
+              onUpdate:value={(value: any) => {
+                forms.materialTagId = value || '';
+                onSearch();
+              }}
+            />
+          )}
+          <CCascader
+            placeholder="全部声部"
+            childShowAllCheck={false}
+            showPath
+            showAudioPlayType={props.type === 'myResources' || forms.type !== 'MUSIC' ? false : true}
+            v-model:value={subjects.value}
+            options={tagSubjectList.value}
+            onMoreId={(val: any) => {
+              forms.musicalInstrumentId = val.childId;
+              forms.subjectId = val.parentId;
+              if (props.type !== 'myResources') {
+                forms.audioPlayTypes = val.audioPlayTypes;
               }
+              onSearch();
             }}
-            onClear={() => {
-              forms.name = '';
-              debouncedRequest();
-            }}>
-            {{
-              prefix: () => (
-                <span
-                  class={'icon-search-input'}
-                  onClick={() => debouncedRequest()}></span>
-              )
-            }}
-          </NInput>
+          />
         </div>
-      </>
+
+        <NInput
+          type="text"
+          placeholder="请输入搜索关键词"
+          clearable
+          v-model:value={forms.name}
+          class={styles.inputSearch}
+          onKeyup={(e: KeyboardEvent) => {
+            if (e.code === 'Enter') {
+              debouncedRequest();
+            }
+          }}
+          onClear={() => {
+            forms.name = '';
+            debouncedRequest();
+          }}>
+          {{
+            prefix: () => (
+              <span
+                class={'icon-search-input'}
+                onClick={() => debouncedRequest()}></span>
+            )
+          }}
+        </NInput>
+      </div>
     );
   }
 });

+ 4 - 4
src/views/prepare-lessons/components/resource-main/components/select-music/index.tsx

@@ -13,7 +13,6 @@ import CardType from '/src/components/card-type';
 import TheEmpty from '/src/components/TheEmpty';
 import { useThrottleFn } from '@vueuse/core';
 import { usePrepareStore } from '/src/store/modules/prepareLessons';
-import { musicSheetPage } from '/src/views/prepare-lessons/api';
 import TrainUpdate from '/src/views/attend-class/model/train-update';
 import requestOrigin from 'umi-request';
 import CardPreview from '/src/components/card-preview';
@@ -44,13 +43,13 @@ export const typeFormat = (trainingType: string, configJson: any) => {
       configJson.practiceChapterBegin || configJson.practiceChapterEnd
         ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
         : '全部小节',
-      // `速度${configJson.evaluateSpeed}`,
+      `速度${configJson.evaluateSpeed || 0}`,
       `${configJson.trainingTimes}分达标`
     ];
   } else {
     tList = [
       `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-      `速度${configJson.practiceSpeed}`,
+      `速度${configJson.practiceSpeed || 0}`,
       `${configJson.trainingTimes}分钟`
     ];
   }
@@ -141,6 +140,7 @@ export default defineComponent({
             refFlag: row.refFlag,
             isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
             content: row.id,
+            playSpeed: row.playSpeed ? Number(row.playSpeed) : null, // 原速
             audioPlayTypeArray: row.audioPlayTypes
               ? row.audioPlayTypes.split(',')
               : [],
@@ -211,7 +211,7 @@ export default defineComponent({
           childs.forEach((child: any) => {
             system?.removeChild(child);
           })
-        });         
+        });
         const parts = xmlParse.getElementsByTagName('part');
         firstMeasures = parts[0]?.getElementsByTagName('measure');
         xmlStatus = 'success';

+ 0 - 1
src/views/prepare-lessons/model/select-music/index.tsx

@@ -3,7 +3,6 @@ import { PropType, defineComponent, onMounted, ref, toRefs } from 'vue';
 import styles from './index.module.less';
 import SelectItem from './select-item';
 import { useResizeObserver } from '@vueuse/core';
-import { emit } from 'process';
 import { useCatchStore } from '/src/store/modules/catchData';
 
 export default defineComponent({

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

@@ -1,12 +1,11 @@
-import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
-import { PropType, defineComponent, onMounted, reactive, watch } from 'vue';
+import { NScrollbar, NSpin } from 'naive-ui';
+import { PropType, defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import CardType from '@/components/card-type';
 import SearchGroup from './search-group';
 import TheEmpty from '/src/components/TheEmpty';
 import { useDebounceFn, useThrottleFn, useResizeObserver } from '@vueuse/core';
 import { usePrepareStore } from '/src/store/modules/prepareLessons';
-import { musicSheetPage } from '../../../api';
 import CardPreview from '/src/components/card-preview';
 import { favorite, materialQueryPage } from '/src/views/natural-resources/api';
 
@@ -95,6 +94,7 @@ export default defineComponent({
             refFlag: row.refFlag,
             content: row.id,
             xmlFileUrl: row.xmlFileUrl,
+            playSpeed: row.playSpeed ? Number(row.playSpeed) : null, // 原速
             audioPlayTypeArray: row.audioPlayTypes
               ? row.audioPlayTypes.split(',')
               : [],

+ 1 - 0
src/views/prepare-lessons/model/select-resources/select-item/index.tsx

@@ -72,6 +72,7 @@ export default defineComponent({
       searchGroup: {
         type: 'MUSIC', //
         name: '',
+        materialTagId: null,
         bookVersionId: null,
         subjectId: null,
         audioPlayTypes: props.type === 'myResources' ? ['PLAY'] : [],

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

@@ -171,7 +171,8 @@ export default defineComponent({
       subjectId: subjectId.value as any,
       // grade: null as any,
       audioPlayTypes: props.type == 'myResources' ? 'PLAY' : '',
-      bookVersionId: null as any
+      bookVersionId: null as any,
+      materialTagId: null
       // musicSheetCategoriesId: null as any
     });
     const state = reactive({
@@ -396,6 +397,7 @@ export default defineComponent({
       _initTags();
       // 获取声部
       await catchStore.getSubjects();
+      await catchStore.getMaterialTagsApi();
 
       forms.subjectId = null;
 
@@ -412,7 +414,7 @@ export default defineComponent({
       console.log(props.searchGroup, 'searchGroup - parent');
       if (props.searchGroup.type) {
         const tempSearchGroup = props.searchGroup;
-        forms.type = tempSearchGroup.type || 'MUSIC'
+        forms.type = tempSearchGroup.type || 'MUSIC';
         forms.audioPlayTypes = tempSearchGroup?.audioPlayTypes
           ? tempSearchGroup.audioPlayTypes.join('_')
           : '';
@@ -488,6 +490,7 @@ export default defineComponent({
                   forms.audioPlayTypes =
                     props.type === 'myResources' ? 'PLAY' : '';
 
+                  forms.materialTagId = null
                   formatFirstSubject();
                   onSearch();
 
@@ -629,6 +632,28 @@ export default defineComponent({
               </NSpace>
             </NFormItem>
           )}
+
+          {forms.type !== 'MUSIC' && (
+            <NFormItem label="标签:">
+              <NSpace class={styles.spaceSection}>
+                {catchStore.getAllMaterialTags.map((subject: any) => (
+                  <span
+                    class={[
+                      styles.textBtn,
+
+                      forms.materialTagId === subject.value &&
+                        styles.textBtnActive
+                    ]}
+                    onClick={() => {
+                      forms.materialTagId = subject.value;
+                      onSearch();
+                    }}>
+                    {subject.label}
+                  </span>
+                ))}
+              </NSpace>
+            </NFormItem>
+          )}
         </NForm>
       </div>
     );

+ 2 - 2
src/views/studentList/modals/studentTraomomhDetails.tsx

@@ -59,14 +59,14 @@ export default defineComponent({
           configJson.practiceChapterBegin || configJson.practiceChapterEnd
             ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
             : '全部小节',
-          // `速度${configJson.evaluateSpeed}`,
+          `速度${configJson.evaluateSpeed || 0}`,
           `${configJson.trainingTimes}分达标`
         ];
         // console.log('configJson.evaluateDifficult--', tList);
       } else {
         tList = [
           `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
-          `速度${configJson.practiceSpeed}`,
+          `速度${configJson.practiceSpeed || 0}`,
           `${configJson.trainingTimes}分钟`
         ];
         // console.log('configJson.evaluateDifficult', tList);