Browse Source

Merge branch 'feature/0516-courseware' into online

lex 9 months ago
parent
commit
9a6af355b9
29 changed files with 1334 additions and 545 deletions
  1. 7 7
      src/components/TheLink/index.tsx
  2. 3 2
      src/components/pagination/index.tsx
  3. 32 2
      src/views/content-manage/music-manage/modal/musicPreView.tsx
  4. 14 13
      src/views/educational-manage/component/category-list.tsx
  5. 59 7
      src/views/educational-manage/component/material-list.tsx
  6. 106 43
      src/views/educational-manage/model/addMaterial.tsx
  7. 116 62
      src/views/educational-manage/model/selectMusicSheet.tsx
  8. 15 3
      src/views/knowledge-manage/knowledge-detail/index.tsx
  9. 8 3
      src/views/knowledge-manage/knowledge-list/index.tsx
  10. 22 20
      src/views/music-library/music-sheet/component/music-list.tsx
  11. 9 9
      src/views/music-library/music-sheet/modal/music-operation.tsx
  12. 96 3
      src/views/music-library/project-music-sheet/module/gyt/addMusic.tsx
  13. 31 2
      src/views/music-library/project-music-sheet/module/gyt/updateMusic.tsx
  14. 1 1
      src/views/system-manage/menu-manage/index.tsx
  15. 1 0
      src/views/teaching-manage/after-class-training-detail/index.tsx
  16. 52 19
      src/views/teaching-manage/after-class-training-detail/model/addMaterialTrainingClass.tsx
  17. 30 7
      src/views/teaching-manage/after-class-training-detail/model/addTrainStandard.tsx
  18. 21 0
      src/views/teaching-manage/api.ts
  19. 394 187
      src/views/teaching-manage/courseware-manage/components/courseConfiguration.tsx
  20. 165 88
      src/views/teaching-manage/courseware-manage/index.tsx
  21. 23 1
      src/views/teaching-manage/courseware-manage/model/CourseKnowledgePoint.tsx
  22. 4 1
      src/views/teaching-manage/teaching-plan/plan-detail.tsx
  23. 2 19
      src/views/teaching-manage/unit-test/index.module.less
  24. 1 1
      src/views/teaching-manage/unit-test/index.tsx
  25. 48 11
      src/views/teaching-manage/unit-test/model/addQuestionBank.tsx
  26. 18 6
      src/views/teaching-manage/unit-test/model/addQuestionList.tsx
  27. 28 20
      src/views/teaching-manage/unit-test/unit-test-index/editAndUpdate.tsx
  28. 26 6
      src/views/teaching-manage/unit-test/unit-test-index/previewUnit.tsx
  29. 2 2
      vite.config.ts

+ 7 - 7
src/components/TheLink/index.tsx

@@ -36,12 +36,12 @@ export default defineComponent({
     })
 
     return () =>
-      disabled.value ? (
-        slots.default && slots.default()
-      ) : (
-        <RouterLink to={props.to} target={props.target}>
-          {slots.default && slots.default()}
-        </RouterLink>
-      )
+        disabled.value ? (
+            slots.default && slots.default()
+        ) : (
+            <RouterLink to={props.to} target={props.target}>
+              {slots.default && slots.default()}
+            </RouterLink>
+        )
   }
 })

+ 3 - 2
src/components/pagination/index.tsx

@@ -44,7 +44,7 @@ export default defineComponent({
       type: Array as PropType<any>,
       default: () => [10, 20, 30, 40]
     },
-    pageSlot:{
+    pageSlot: {
       type: Number,
       default: 9
     }
@@ -69,6 +69,7 @@ export default defineComponent({
     }
     // 当前分页大小发生改变时的回调函数
     const onUpdatePageSize = (pageSize: number) => {
+      emit('update:page', 1)
       emit('update:pageSize', pageSize)
       emit('list')
 
@@ -168,7 +169,7 @@ export default defineComponent({
         pageSizes={props.pageSizes}
         onUpdatePage={onUpdatePage}
         onUpdatePageSize={onUpdatePageSize}
-        pageSlot = {props.pageSlot}
+        pageSlot={props.pageSlot}
       ></NPagination>
     )
   }

+ 32 - 2
src/views/content-manage/music-manage/modal/musicPreView.tsx

@@ -10,10 +10,40 @@ export default defineComponent({
     }
   },
   setup(props, { emit }) {
+    // const userStore = useUserStore()
+    // const token = userStore.getToken
+    // const prefix = /(localhost|192)/.test(location.host)
+    //   ? 'https://ponline.colexiu.com'
+    //   : location.origin
+    // const src =
+    //   prefix +
+    //   `/orchestra-music-score/?_t=${Date.now()}&id=${
+    //     props.item.id
+    //   }&modelType=practice&modeType=json&Authorization=${token}`
+
     const userStore = useUserStore()
     const token = userStore.getToken
-    const prefix = /(localhost|192)/.test(location.host) ? 'https://ponline.colexiu.com' : location.origin
-    const src = prefix + `/orchestra-music-score/?_t=${Date.now()}&id=${props.item.id}&modelType=practice&modeType=json&Authorization=${token}`
+    const apiUrls = {
+      dev: 'https://dev.kt.colexiu.com',
+      test: 'https://test.lexiaoya.cn',
+      online: 'https://mec.colexiu.com'
+    }
+
+    const environment = location.origin.includes('//dev')
+      ? 'dev'
+      : location.origin.includes('//test')
+      ? 'test'
+      : location.origin.includes('//mec.colexiu')
+      ? 'online'
+      : 'dev'
+    const apiUrl = apiUrls[environment]
+    // const prefix = /(localhost|192)/.test(location.host) ? 'http://dev.resource.colexiu.com/' : location.origin
+    const prefix = /(localhost|192)/.test(location.host) ? 'https://dev.kt.colexiu.com/' : apiUrl
+    let src =
+      prefix +
+      `/instrument/?_t=${Date.now()}&id=${
+        props.item.id
+      }&modelType=practise&modeType=json&Authorization=${token}&isCbs=true`
     return () => (
       <div>
         <iframe width={'667px'} height={'375px'} frameborder="0" src={src}></iframe>

+ 14 - 13
src/views/educational-manage/component/category-list.tsx

@@ -35,7 +35,7 @@ export default defineComponent({
     })
     const searchForm = reactive({
       keyword: '',
-      times: null as any,
+      // times: null as any,
       operatorId: '' //创建人
     })
 
@@ -122,10 +122,11 @@ export default defineComponent({
     const getList = async () => {
       try {
         state.loading = true
-        const { times, ...reset } = searchForm
+        // const { times, ...reset } = searchForm
         const body = {
-          ...reset,
-          ...getTimes(times, ['startTime', 'endTime']),
+          // ...reset,
+          ... searchForm,
+          // ...getTimes(times, ['startTime', 'endTime']),
           page: state.pagination.page,
           rows: state.pagination.rows
         }
@@ -190,15 +191,15 @@ export default defineComponent({
               clearable
             />
           </NFormItem> */}
-          <NFormItem path="times" label="时间">
-            <NDatePicker
-              class={styles.datepicker}
-              value-format="yyyy.MM.dd"
-              v-model:value={searchForm.times}
-              type="daterange"
-              clearable
-            />
-          </NFormItem>
+          {/*<NFormItem path="times" label="时间">*/}
+          {/*  <NDatePicker*/}
+          {/*    class={styles.datepicker}*/}
+          {/*    value-format="yyyy.MM.dd"*/}
+          {/*    v-model:value={searchForm.times}*/}
+          {/*    type="daterange"*/}
+          {/*    clearable*/}
+          {/*  />*/}
+          {/*</NFormItem>*/}
           <NFormItem>
             <NSpace>
               <NButton type="primary" onClick={onSearch}>

+ 59 - 7
src/views/educational-manage/component/material-list.tsx

@@ -27,6 +27,7 @@ import { getLessonType, lessonType } from '@/views/knowledge-manage/knowledgeTyp
 import { filterTimes, getTimes } from '@/utils/dateUtil'
 import { useRoute } from 'vue-router'
 import { subjectPage } from '@views/system-manage/subject-manage/api'
+import TheTooltip from '@/components/TheTooltip'
 
 const classType: { [_: string]: any } = {
   VIDEO: '视频',
@@ -58,6 +59,7 @@ export default defineComponent({
     const searchForm = reactive({
       keyword: null as any,
       time: null as any,
+      containMusic: null as any,
       courseTypeCode: null,
       materialCategoryId: null,
       type: null
@@ -74,7 +76,7 @@ export default defineComponent({
         category.list = data?.rows || []
       } catch {}
     }
-    provide('categoryList', category)
+    // provide('categoryList', category)
     // 声部
     const subjects = reactive({
       list: [] as any
@@ -106,7 +108,9 @@ export default defineComponent({
               <NDescriptions labelPlacement="left" column={1}>
                 <NDescriptionsItem label="素材名称">{row.name}</NDescriptionsItem>
                 <NDescriptionsItem label="素材编号">{row.id}</NDescriptionsItem>
-                <NDescriptionsItem label="素材分类">{row.materialCategoryName}</NDescriptionsItem>
+                <NDescriptionsItem label="素材分类">
+                  <TheTooltip content={row.materialCategoryName} />
+                </NDescriptionsItem>
               </NDescriptions>
             )
           }
@@ -142,15 +146,35 @@ export default defineComponent({
           }
         },
         {
+          title: '关联曲目',
+          key: 'type',
+          render(row: any) {
+            return (
+              <NDescriptions labelPlacement="left" column={1}>
+                <NDescriptionsItem label="曲目名称">
+                  <TheTooltip content={row.materialRef?.relateMaterialInfo?.name || '--'} />
+                </NDescriptionsItem>
+                <NDescriptionsItem label="曲目状态">
+                  {row.materialRef?.relateMaterialInfo
+                    ? row.materialRef?.relateMaterialInfo?.status
+                      ? '启用'
+                      : '停用'
+                    : '--'}
+                </NDescriptionsItem>
+              </NDescriptions>
+            )
+          }
+        },
+        {
           title: '操作信息',
-          key: 'updateTime',
+          key: 'createTime',
           render(row: any) {
             return (
               <NDescriptions labelPlacement="left" column={1}>
                 <NDescriptionsItem label="上传人">{row.operatorName}</NDescriptionsItem>
 
                 <NDescriptionsItem label="上传时间">
-                  {row.updateTime ? row.updateTime : '--'}
+                  {row.createTime ? row.createTime : '--'}
                 </NDescriptionsItem>
               </NDescriptions>
             )
@@ -178,10 +202,17 @@ export default defineComponent({
           render(row: any) {
             return (
               <NSpace>
+                {/* <NButton
+                  type={row.enableFlag ? 'error' : 'success'}
+                  text
+                  v-auth="material/update1599948375910109186"
+                  onClick={() => handleChange(row)}
+                >
+                  {row.enableFlag ? '停用' : '启用'}
+                </NButton> */}
                 <NButton
                   type="primary"
                   text
-                  v-auth="material/detail1608362411857137665"
                   onClick={() => {
                     state.isLook = true
                     state.materail = row
@@ -244,7 +275,16 @@ export default defineComponent({
         const { data } = await fetchMaterialList(body)
         state.loading = false
         state.pagination.pageTotal = Number(data.total)
-        state.dataList = data.rows || []
+        const result = data.rows || []
+        result.forEach((item: any) => {
+          if (item.materialRefs && item.materialRefs.length > 0) {
+            item.materialRef = item.materialRefs[0]
+          } else {
+            item.materialRef = {}
+          }
+        })
+
+        state.dataList = result || []
       } catch {
         state.loading = false
       }
@@ -285,7 +325,6 @@ export default defineComponent({
     }
 
     onMounted(() => {
-      state.pagination.page = 1
       getList()
     })
 
@@ -330,6 +369,18 @@ export default defineComponent({
           <NFormItem label="课程类型" path="courseTypeCode">
             <NSelect clearable v-model:value={searchForm.courseTypeCode} options={lessonType} />
           </NFormItem>
+          <NFormItem label="关联曲目" path="containMusic">
+            <NSelect
+              clearable
+              v-model:value={searchForm.containMusic}
+              options={
+                [
+                  { label: '关联', value: true },
+                  { label: '不关联', value: false }
+                ] as any
+              }
+            />
+          </NFormItem>
           <NFormItem label="搜索时间" path="time">
             <NDatePicker
               class={styles.datepicker}
@@ -387,6 +438,7 @@ export default defineComponent({
             <AddMaterial
               item={state.materail}
               isLook={state.isLook}
+              categoryList={category.list}
               onClose={() => {
                 state.visiableCity = false
               }}

+ 106 - 43
src/views/educational-manage/model/addMaterial.tsx

@@ -9,16 +9,13 @@ import {
   NForm,
   NFormItem,
   NInput,
-  NInputNumber,
-  NModal,
+  NInputGroup,
   NRadio,
   NRadioGroup,
   NSelect,
   NSpace,
   NSpin,
   NSwitch,
-  NTag,
-  NUpload,
   useMessage
 } from 'naive-ui'
 import { defineComponent, inject, onMounted, reactive, ref, watch } from 'vue'
@@ -31,7 +28,7 @@ import SelectMusicSheet from './selectMusicSheet'
 export default defineComponent({
   name: 'addMaterial',
   emits: ['handleSuccess', 'close'],
-  props: ['item', 'isLook'],
+  props: ['item', 'isLook', 'categoryList'],
   setup(props, { emit }) {
     const message = useMessage()
     const loading = ref(false)
@@ -40,9 +37,10 @@ export default defineComponent({
     const saveModel = reactive({
       name: '',
       sn: '', //序号
-      materialCategoryId: '', //素材分类
+      materialCategoryId: null, //素材分类
       // adviseStudyTimeSecond: null,
       type: materialType.视频,
+      materialRefs: [] as any,
       content: '', // 视频、图片链接或者是曲目编号
       courseTypeCode: [], // 课程类型
       enableFlag: true //启用状态
@@ -63,9 +61,20 @@ export default defineComponent({
           })
           if (saveModel.type === 'SONG') {
             musicOpentions.music = {
-              musicSheetName: res.data.contentDesc
+              name: res.data.contentDesc
             }
           }
+          //  else {
+          //   if (res.data.materialRefs && res.data.materialRefs.length > 0) {
+          //     res.data.materialRefs.forEach((row: any) => {
+          //       saveModel.materialRefs.push({
+          //         resourceId: row.resourceId,
+          //         knowledgeType: row.knowledgeType,
+          //         resourceName: row.resourceName
+          //       })
+          //     })
+          //   }
+          // }
           console.log('🚀 ~ saveModel', saveModel)
         }
         loading.value = false
@@ -117,7 +126,7 @@ export default defineComponent({
         }
       ]
     }
-    const categoryList = inject('categoryList', { list: [] }).list || []
+    // const categoryList = inject('categoryList', { list: [] }).list || []
     const submit = () => {
       formRef.value?.validate(async (err) => {
         if (!err) {
@@ -151,7 +160,8 @@ export default defineComponent({
     // 添加曲谱
     const musicOpentions = reactive({
       show: false,
-      music: '' as any
+      music: '' as any,
+      type: ''
     })
     const hanldeSelectMusic = (musicItem: any) => {
       musicOpentions.music = musicItem
@@ -184,7 +194,8 @@ export default defineComponent({
               <NFormItem label="素材分类" path="materialCategoryId">
                 <NCascader
                   v-model:value={saveModel.materialCategoryId}
-                  options={categoryList}
+                  placeholder="请选择素材分类"
+                  options={props.categoryList}
                   checkStrategy="child"
                   childrenField="subMaterialCategoryList"
                   expandTrigger="hover"
@@ -226,40 +237,75 @@ export default defineComponent({
               </NRadioGroup>
             </NFormItem>
 
-            <NFormItem label="上传素材" path="content" ref={formContentRef} required>
-              {saveModel.type === materialType.曲目 ? (
-                <NSpace>
-                  <NButton
+            <NSpace justify="space-between" item-style={{ flex: 1 }}>
+              <NFormItem label="上传素材" path="content" ref={formContentRef} required>
+                {saveModel.type === materialType.曲目 ? (
+                  <NSpace>
+                    <NButton
+                      disabled={props.isLook}
+                      type="primary"
+                      onClick={() => {
+                        musicOpentions.show = true
+                        musicOpentions.type = 'upload'
+                      }}
+                    >
+                      选择曲谱
+                    </NButton>
+                    {musicOpentions.music && (
+                      <NInput disabled value={musicOpentions.music?.name}></NInput>
+                    )}
+                  </NSpace>
+                ) : (
+                  <UploadFile
+                    accept={
+                      saveModel.type === materialType.视频
+                        ? 'video/*'
+                        : saveModel.type === materialType.图片
+                        ? 'image/*'
+                        : ''
+                    }
+                    path="courseware/"
+                    listType={saveModel.type === materialType.图片 ? 'image-card' : 'image'}
+                    v-model:fileList={saveModel.content}
+                    size={1024}
                     disabled={props.isLook}
-                    type="primary"
-                    onClick={() => (musicOpentions.show = true)}
-                  >
-                    选择曲谱
-                  </NButton>
-                  {musicOpentions.music && (
-                    <NInput readonly value={musicOpentions.music?.musicSheetName}></NInput>
-                  )}
-                </NSpace>
-              ) : (
-                <UploadFile
-                  accept={
-                    saveModel.type === materialType.视频
-                      ? 'video/*'
-                      : saveModel.type === materialType.图片
-                      ? 'image/*'
-                      : ''
-                  }
-                  path="courseware/"
-                  listType={saveModel.type === materialType.图片 ? 'image-card' : 'image'}
-                  v-model:fileList={saveModel.content}
-                  size={1024}
-                  disabled={props.isLook}
-                  onReadFileInputEventAsArrayBuffer={() => {
-                    formContentRef.value?.restoreValidation()
-                  }}
-                ></UploadFile>
+                    onReadFileInputEventAsArrayBuffer={() => {
+                      formContentRef.value?.restoreValidation()
+                    }}
+                  ></UploadFile>
+                )}
+              </NFormItem>
+
+              {saveModel.type !== 'SONG' && (
+                <NFormItem label="关联曲目">
+                  <NSpace>
+                    <NButton
+                      disabled={props.isLook}
+                      type="primary"
+                      onClick={() => {
+                        musicOpentions.show = true
+                        musicOpentions.type = 'correlation'
+                      }}
+                    >
+                      选择曲谱
+                    </NButton>
+                    {saveModel.materialRefs.length > 0 && (
+                      <NInputGroup>
+                        <NInput disabled value={saveModel.materialRefs[0]?.resourceName}></NInput>
+                        <NButton
+                          type="primary"
+                          onClick={() => {
+                            saveModel.materialRefs = []
+                          }}
+                        >
+                          删除
+                        </NButton>
+                      </NInputGroup>
+                    )}
+                  </NSpace>
+                </NFormItem>
               )}
-            </NFormItem>
+            </NSpace>
           </NForm>
           {props.isLook ? (
             ''
@@ -276,7 +322,24 @@ export default defineComponent({
         </NSpin>
         <NDrawer width="80vw" height="100vh" v-model:show={musicOpentions.show}>
           <NDrawerContent title="选择曲谱" closable>
-            <SelectMusicSheet onSelect={(row: any) => hanldeSelectMusic(row)} />
+            <SelectMusicSheet
+              type={musicOpentions.type}
+              onSelect={(row: any) => {
+                console.log(musicOpentions.type, row)
+                if (musicOpentions.type === 'upload') {
+                  hanldeSelectMusic(row)
+                } else {
+                  saveModel.materialRefs = [
+                    {
+                      resourceId: row.id,
+                      knowledgeType: 'MUSIC',
+                      resourceName: row.name
+                    }
+                  ]
+                  musicOpentions.show = false
+                }
+              }}
+            />
           </NDrawerContent>
         </NDrawer>
       </div>

+ 116 - 62
src/views/educational-manage/model/selectMusicSheet.tsx

@@ -1,14 +1,32 @@
 import Pagination from '@/components/pagination'
 import SaveForm from '@/components/save-form'
 import { musicSheetPage, musicTagPage } from '@/views/content-manage/api'
-import { subjectBasicConfigPage } from '@/views/system-manage/api'
-import { NButton, NImage, NSpace, NTag, NDataTable, NFormItem, NInput, NSelect } from 'naive-ui'
+import { subjectPage, sysApplicationPage } from '@/views/system-manage/api'
+import {
+  NButton,
+  NImage,
+  NSpace,
+  NTag,
+  NDataTable,
+  NFormItem,
+  NInput,
+  NSelect,
+  NCascader
+} from 'naive-ui'
 import { defineComponent, onMounted, reactive, ref } from 'vue'
-import { accompanimentTypeArray, audioTypeArray } from '@/utils/searchArray'
 import styles from './index.module.less'
+import { musicSheetCategoriesQueryTree } from '@views/music-library/api'
+import { appKey } from '@/utils/constant'
+import TheTooltip from '@/components/TheTooltip'
 
 export default defineComponent({
   name: 'selectMusicSheet',
+  props: {
+    type: {
+      type: String,
+      default: 'upload'
+    }
+  },
   emits: ['select'],
   setup(props, { emit }) {
     const state = reactive({
@@ -20,16 +38,18 @@ export default defineComponent({
       },
       searchForm: {
         keyword: null,
-        musicTag: null,
-        musicSubject: null,
-        audioType: null,
-        accompanimentType: null,
+        musicCategoryId: null,
+        subjectId: null,
+        // playMode: null,
+        // accompanimentType: null,
         status: null,
-        topFlag: null
+        topFlag: null,
+        useAppId: [] as any
       },
       dataList: [] as any,
       subjectList: [] as any,
-      tagList: [] as any,
+      musicSheetCategories: [] as any,
+      useProjectData: [] as any, // 适用项目行数据
       visiableMusic: false,
       musicOperation: 'add',
       musicData: {} as any
@@ -41,60 +61,72 @@ export default defineComponent({
           title: '曲目名称',
           key: 'id',
           render(row: any) {
-            return `${row.musicSheetName}(${row.id})`
+            return `${row.name}(${row.id})`
+          }
+        },
+        {
+          title: '适用项目',
+          key: 'musicSheetExtend.useApplicationNames',
+          redner(row: any) {
+            return (
+              <TheTooltip
+                content={
+                  row.musicSheetExtend && row.musicSheetExtend.useApplicationNames
+                    ? row.musicSheetExtend.useApplicationNames
+                    : ''
+                }
+              />
+            )
+          }
+        },
+        {
+          title: '状态',
+          minWidth: '50px',
+          key: 'status',
+          render(row: any) {
+            return (
+              <NTag type={row.status ? 'primary' : 'default'}>{row.status ? '启用' : '停用'}</NTag>
+            )
           }
         },
         {
           title: '曲目封面',
-          key: 'titleImg',
+          key: 'musicCover',
           render(row: any) {
-            return <NImage width={35} height={35} src={row.titleImg} />
+            return <NImage width={35} height={35} src={row.musicCover} />
           }
         },
         {
           title: '分类',
-          key: 'musicSheetCategoriesName',
+          key: 'musicCategoryName'
         },
         {
           title: '伴奏类型',
-          key: 'accompanimentType',
+          key: 'audioType',
           render(row: any) {
-            return row.accompanimentType === 'HOMEMODE' ? '自制伴奏' : '普通伴奏'
+            return row.audioType === 'HOMEMODE' ? '自制伴奏' : '普通伴奏'
           }
         },
         {
           title: '可用声部',
-          key: 'musicSubject',
+          key: 'subjectNames',
           render(row: any) {
-            return <NTag type="primary">{row.musicSubject}</NTag>
+            return <TheTooltip content={row.subjectNames} />
           }
         },
         {
           title: '播放类型',
-          key: 'audioType',
+          key: 'playMode',
           render(row: any) {
             return (
               <>
-                {row.audioType === 'MP3' && <NTag type="primary">MP3</NTag>}
-                {row.audioType === 'MIDI' && <NTag type="default">MIDI</NTag>}
+                {row.playMode === 'MP3' && <NTag type="primary">MP3</NTag>}
+                {row.playMode === 'MIDI' && <NTag type="default">MIDI</NTag>}
               </>
             )
           }
         },
         {
-          title: '能否转简谱',
-          key: 'notation',
-          render(row: any) {
-            return (
-              <NTag type={row.notation ? 'primary' : 'default'}>{row.notation ? '是' : '否'}</NTag>
-            )
-          }
-        },
-        // {
-        //   title: '排序',
-        //   key: 'sortNumber'
-        // },
-        {
           title: '操作',
           key: 'operation',
           fixed: 'right',
@@ -113,7 +145,15 @@ export default defineComponent({
     const getList = async () => {
       try {
         state.loading = true
-        const { data } = await musicSheetPage({ page: state.pagination.page, rows: state.pagination.rows, ...state.searchForm,status: 1 })
+        const { data } = await musicSheetPage({
+          page: state.pagination.page,
+          rows: state.pagination.rows,
+          ...state.searchForm,
+          useAppId: state.searchForm.useAppId
+            ? state.searchForm.useAppId.join(',')
+            : state.searchForm.useAppId,
+          status: props.type === 'upload' ? 1 : null
+        })
         state.loading = false
         state.pagination.pageTotal = Number(data.total)
         state.dataList = data.rows || []
@@ -122,27 +162,42 @@ export default defineComponent({
       }
     }
 
-    // 获取标签
-    const getTagList = async () => {
+    // app列表
+    const initUseAppList = async () => {
       try {
-        const { data } = await musicTagPage({ page: 1, rows: 999 })
+        const appKeys = Object.keys(appKey)
+        const { data } = await sysApplicationPage({ page: 1, rows: 999 })
         const tempList = data.rows || []
-        tempList.forEach((item: any) => {
-          item.label = item.name
-          item.value = item.id
+        state.useProjectData = []
+        const filter = tempList.filter((next: any) => {
+          return appKeys.includes(next.appKey)
+        })
+        filter.forEach((item: any) => {
+          state.useProjectData.push({
+            ...item,
+            label: item.appName,
+            value: item.id
+          })
         })
-        state.tagList = tempList
       } catch {}
     }
 
+    // 获取标签
+    const getTagList = async () => {
+      try {
+        const { data } = await musicSheetCategoriesQueryTree({})
+        state.musicSheetCategories = data || []
+      } catch (e) {}
+    }
+
     // 获取声部
     const getSubjectList = async () => {
       try {
-        const { data } = await subjectBasicConfigPage({ page: 1, rows: 999 })
+        const { data } = await subjectPage({ page: 1, rows: 999 })
         const tempList = data.rows || []
         tempList.forEach((item: any) => {
-          item.label = item.subjectName
-          item.value = item.subjectId
+          item.label = item.name
+          item.value = item.id + ''
         })
         state.subjectList = tempList
       } catch {}
@@ -164,6 +219,7 @@ export default defineComponent({
     onMounted(() => {
       getTagList()
       getSubjectList()
+      initUseAppList()
       getList()
     })
     return () => (
@@ -182,36 +238,34 @@ export default defineComponent({
               clearable
             />
           </NFormItem>
-          <NFormItem label="标签" path="musicTag">
-            <NSelect
-              placeholder="请选择标签"
-              v-model:value={state.searchForm.musicTag}
-              options={state.tagList}
+          <NFormItem label="曲目分类" path="musicCategoryId">
+            <NCascader
+              valueField="id"
+              labelField="name"
+              children-field="musicSheetCategoriesList"
+              placeholder="请选择曲目分类"
+              v-model:value={state.searchForm.musicCategoryId}
+              options={state.musicSheetCategories}
               clearable
             />
           </NFormItem>
           <NFormItem label="声部" path="musicSubject">
             <NSelect
               placeholder="请选择声部"
-              v-model:value={state.searchForm.musicSubject}
+              v-model:value={state.searchForm.subjectId}
               options={state.subjectList}
               clearable
             />
           </NFormItem>
-          <NFormItem label="播放类型" path="audioType">
-            <NSelect
-              placeholder="请选择播放类型"
-              v-model:value={state.searchForm.audioType}
-              options={audioTypeArray}
-              clearable
-            />
-          </NFormItem>
-          <NFormItem label="伴奏类型" path="accompanimentType">
+          <NFormItem label="适用项目" path="useAppId">
             <NSelect
-              placeholder="请选择伴奏类型"
-              v-model:value={state.searchForm.accompanimentType}
-              options={accompanimentTypeArray}
+              placeholder="请选择适用项目"
+              v-model:value={state.searchForm.useAppId}
+              options={state.useProjectData}
+              multiple
+              maxTagCount={1}
               clearable
+              filterable
             />
           </NFormItem>
           <NFormItem>

+ 15 - 3
src/views/knowledge-manage/knowledge-detail/index.tsx

@@ -59,6 +59,7 @@ export default defineComponent({
           render(row: any) {
             return (
               <TheLink
+                authLink="material/page1750897012676493314"
                 to={{ path: '/educationalManage/educationalManage', query: { id: row.materialId } }}
               >
                 {row.materialName}
@@ -70,12 +71,23 @@ export default defineComponent({
           title: '素材分类',
           key: 'materialCategoryName'
         },
+        // {
+        //   title: '分段编号',
+        //   key: 'sn',
+        //   render(row: any) {
+        //     return (
+        //       <TheLink
+        //         authLink="material/page1599589713102299138"
+        //         to={{ path: '/educationalManage/educationalManage' }}
+        //       >
+        //         {row.sn}
+        //       </TheLink>
+        //     )
+        //   }
+        // },
         {
           title: '分段编号',
           key: 'sn',
-          render(row: any) {
-            return <TheLink to={{ path: '/educationalManage/educationalManage' }}>{row.sn}</TheLink>
-          }
         },
         {
           title: '课程类型',

+ 8 - 3
src/views/knowledge-manage/knowledge-list/index.tsx

@@ -20,12 +20,13 @@ import { defineComponent, onMounted, reactive, ref, provide } from 'vue'
 import { fetchKnowledgeList, fetchDelKnowledge, knowledgePointStatus } from '../api'
 import { knowledgeTypeData, lessonType } from '../knowledgeTypeData'
 import KnowledgeModel from './component/knowledgeModel'
-import { useRouter } from 'vue-router'
+import { useRoute, useRouter } from 'vue-router'
 import { filterTimes, getTimes } from '@/utils/dateUtil'
 export default defineComponent({
   name: 'knowledge-manage',
   setup() {
     const router = useRouter()
+    const route = useRoute()
     const state = reactive({
       loading: false,
       pagination: {
@@ -40,7 +41,7 @@ export default defineComponent({
     })
 
     const searchForm = reactive({
-      keyword: null,
+      keyword: null as any,
       time: null,
       courseTypeCode: null,
       operatorId: null,
@@ -74,6 +75,10 @@ export default defineComponent({
     }
 
     onMounted(() => {
+      console.log(route.query)
+      if (route.query.keyword) {
+        searchForm.keyword = route.query.keyword
+      }
       getList()
     })
 
@@ -293,7 +298,7 @@ export default defineComponent({
             onSetModel={(val: any) => Object.assign(searchForm, val)}
           >
             <NFormItem path="search" label="关键字">
-              <NInput v-model:value={searchForm.keyword} placeholder="知识名称/编号" clearable />
+              <NInput v-model:value={searchForm.keyword} placeholder="知识名称/编号" clearable />
             </NFormItem>
             <NFormItem label="课程类型" path="courseTypeCode">
               <NSelect clearable v-model:value={searchForm.courseTypeCode} options={lessonType} />

+ 22 - 20
src/views/music-library/music-sheet/component/music-list.tsx

@@ -37,7 +37,7 @@ import { getMapValueByKey } from '@/utils/filters'
 import { appKey, musicSheetSourceType, musicSheetType } from '@/utils/constant'
 import { getSelectDataFromObj } from '@/utils/objectUtil'
 import { sysApplicationPage } from '@views/menu-manage/api'
-import {getOwnerName, copyText} from '@views/music-library/musicUtil'
+import { getOwnerName, copyText } from '@views/music-library/musicUtil'
 import styles from './music-list.module.less'
 import MusicCreateImg from '../modal/music-create-img'
 import TheTooltip from '@components/TheTooltip'
@@ -106,10 +106,12 @@ export default defineComponent({
                   <TheTooltip content={row.name} />
                 </NDescriptionsItem>
                 <NDescriptionsItem label="编号">
-                  <div onDblclick={() => {
-                    copyText(message,row.id)
-                  }}>
-                    <TheTooltip content={row.id}/>
+                  <div
+                    onDblclick={() => {
+                      copyText(message, row.id)
+                    }}
+                  >
+                    <TheTooltip content={row.id} />
                   </div>
                 </NDescriptionsItem>
               </NDescriptions>
@@ -688,21 +690,21 @@ export default defineComponent({
           </NFormItem>
           <NFormItem label="数据修复" path="dataCorrect">
             <NSelect
-                v-model={[state.searchForm.dataCorrect, 'value']}
-                placeholder="请选择数据修复"
-                clearable
-                options={
-                  [
-                    {
-                      label: '是',
-                      value: true
-                    },
-                    {
-                      label: '否',
-                      value: false
-                    }
-                  ] as any
-                }
+              v-model={[state.searchForm.dataCorrect, 'value']}
+              placeholder="请选择数据修复"
+              clearable
+              options={
+                [
+                  {
+                    label: '是',
+                    value: true
+                  },
+                  {
+                    label: '否',
+                    value: false
+                  }
+                ] as any
+              }
             />
           </NFormItem>
           <NFormItem>

+ 9 - 9
src/views/music-library/music-sheet/modal/music-operation.tsx

@@ -317,7 +317,7 @@ export default defineComponent({
       musicFirstImg: '', //首调图片
       musicJianImg: '', // 简谱固定调
       isEvxml: false, // 是否是evxml
-      isShowFingering: true, // 是否显示指法
+      isShowFingering: true // 是否显示指法
     })
     const state = reactive({
       loading: false,
@@ -376,7 +376,7 @@ export default defineComponent({
             extConfigJson: JSON.stringify({
               repeatedBeats: forms.repeatedBeats ? 1 : 0,
               gradualTimes: forms.graduals,
-              isEvxml: forms.isEvxml ? 1 : 0,
+              isEvxml: forms.isEvxml ? 1 : 0
             }),
             subjectIds: forms.subjectIds.join(',')
           }
@@ -1111,7 +1111,7 @@ export default defineComponent({
                 path="playSpeed"
                 rule={[
                   {
-                    required: false,
+                    required: true,
                     message: '请输入速度'
                   }
                 ]}
@@ -1122,7 +1122,7 @@ export default defineComponent({
                   min="0"
                   style="width:100%"
                 />
-              </NFormItemGi>            
+              </NFormItemGi>
             </NGrid>
             <NAlert showIcon={false} style={{ marginBottom: '12px' }}>
               曲目上传
@@ -1184,7 +1184,7 @@ export default defineComponent({
                 >
                   <UploadFile
                     disabled={state.previewMode}
-                    size={10}
+                    size={30}
                     v-model:imageList={state.musicSheetAccompanimentUrlList}
                     tips="仅支持上传.mp3格式文件"
                     listType="image"
@@ -1234,7 +1234,7 @@ export default defineComponent({
                   <UploadFile
                     desc={'MIDI文件'}
                     disabled={state.previewMode}
-                    size={10}
+                    size={30}
                     v-model:fileList={forms.midiFileUrl}
                     tips="仅支持上传.MID格式文件"
                     listType="image"
@@ -1259,7 +1259,7 @@ export default defineComponent({
                 <UploadFile
                   desc={'XML文件'}
                   disabled={state.previewMode}
-                  size={10}
+                  size={30}
                   key={'xmlFileUrl'}
                   v-model:fileList={forms.xmlFileUrl}
                   tips="仅支持上传.xml/.mxml格式文件"
@@ -1345,7 +1345,7 @@ export default defineComponent({
                   <NRadio value={'SINGLE'}>是</NRadio>
                   <NRadio value={'CONCERT'}>否</NRadio>
                 </NRadioGroup>
-              </NFormItemGi> 
+              </NFormItemGi>
               <NFormItemGi
                 label="是否显示指法"
                 path="isShowFingering"
@@ -1360,7 +1360,7 @@ export default defineComponent({
                   <NRadio value={true}>是</NRadio>
                   <NRadio value={false}>否</NRadio>
                 </NRadioGroup>
-              </NFormItemGi>                       
+              </NFormItemGi>
             </NGrid>
 
             {forms.musicSheetType && (

+ 96 - 3
src/views/music-library/project-music-sheet/module/gyt/addMusic.tsx

@@ -20,7 +20,7 @@ import {
 } from 'naive-ui'
 import Pagination from '@components/pagination'
 import { getMapValueByKey, getSelectDataFromObj } from '@/utils/objectUtil'
-import {appKey, musicSheetSourceType, musicSheetType} from '@/utils/constant'
+import {appKey, musicSheetAvailableType, musicSheetSourceType, musicSheetType} from '@/utils/constant'
 import {musicSheetApplicationExtendCategoryList, musicSheetApplicationExtendSaveBatch, musicSheetApplicationOwnerList, musicSheetPage} from '@views/music-library/api'
 import deepClone from '@/utils/deep.clone'
 import { getOwnerName } from '@views/music-library/musicUtil'
@@ -79,6 +79,7 @@ export default defineComponent({
       useProjectData: [] as any, // 适用项目行数据
       userIdDisable: true,
       userIdData: [] as any,
+      globalAvailableType : null as any,
     })
 
     onMounted(async () => {
@@ -190,6 +191,10 @@ export default defineComponent({
       const params = [] as any[]
       for (let i = 0; i < state.selectRowData.length; i++) {
         const item = state.selectRowData[i]
+        if (!item.availableType) {
+          message.error('可用途径不能为空')
+          return
+        }
         if (!item.projectMusicCategoryId) {
           message.error('曲目分类不能为空')
           return
@@ -202,6 +207,7 @@ export default defineComponent({
           ...item,
           musicSheetId: item.id,
           musicSheetCategoryId: item.projectMusicCategoryId,
+          availableType: item.availableType,
           applicationId: props.appId,
           id: null
         })
@@ -281,6 +287,94 @@ export default defineComponent({
       field.push({
         title(column: any) {
           return (
+              <NSpace>
+                可用途径
+                <NButton
+                    type="primary"
+                    size="small"
+                    text
+                    onClick={() => {
+                      dialogs.create({
+                        title: '请选择可用途径',
+                        showIcon: false,
+                        content: () => {
+                          return h(
+                              'div',
+                              {
+                                class: 'flex flex-col justify-center items-center text-14px'
+                              },
+                              [
+                                // icon
+                                h(NSelect, {
+                                  onUpdateValue(v) {
+                                    state.globalAvailableType = v
+                                  },
+                                  clearable: true,
+                                  options: [
+                                    {
+                                      label: '学校',
+                                      value: 'ORG'
+                                    },
+                                    {
+                                      label: '平台',
+                                      value: 'PLATFORM'
+                                    },
+                                  ]
+                                })
+                              ]
+                          )
+                        },
+                        positiveText: '确定',
+                        negativeText: '取消',
+                        onPositiveClick: () => {
+                          for (let i = 0; i < state.selectRowData.length; i++) {
+                            const item = state.selectRowData[i]
+                            item.availableType = state.globalAvailableType
+                          }
+                        }
+                      })
+                    }}
+                >
+                  <NIcon size={15} style="padding-left: 5px;margin-top:4px">
+                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
+                      <path d="M2 26h28v2H2z" fill="currentColor"></path>
+                      <path
+                          d="M25.4 9c.8-.8.8-2 0-2.8l-3.6-3.6c-.8-.8-2-.8-2.8 0l-15 15V24h6.4l15-15zm-5-5L24 7.6l-3 3L17.4 7l3-3zM6 22v-3.6l10-10l3.6 3.6l-10 10H6z"
+                          fill="currentColor"
+                      ></path>
+                    </svg>
+                  </NIcon>
+                </NButton>
+              </NSpace>
+          )
+        },
+        key: 'availableType',
+        render: (row: any) => {
+          return (
+              <NSelect
+                  placeholder="请选择可用途径"
+                  value={row.availableType}
+                  options={[
+                    {
+                      label: '学校',
+                      value: 'ORG'
+                    },
+                    {
+                      label: '平台',
+                      value: 'PLATFORM'
+                    },
+                  ]}
+                  onUpdateValue={(value) => {
+                    row['availableType'] = value
+                  }}
+                  clearable
+              />
+          )
+        }
+      })
+      field.push({
+        title(column: any) {
+          return (
             <NSpace>
               曲目分类
               <NButton
@@ -337,7 +431,6 @@ export default defineComponent({
           )
         },
         key: 'projectMusicCategoryId',
-        fixed: 'right',
         width: 200,
         render: (row: any) => {
           // })
@@ -415,7 +508,6 @@ export default defineComponent({
           )
         },
         key: 'sortNo',
-        fixed: 'right',
         width: 150,
         render: (row: any) => {
           return h(NInputNumber, {
@@ -642,6 +734,7 @@ export default defineComponent({
                 data={state.selectRowData}
                 rowKey={(row: any) => row.id}
                 maxHeight={500}
+                scrollX={1800}
               ></NDataTable>
             </div>
           )}

+ 31 - 2
src/views/music-library/project-music-sheet/module/gyt/updateMusic.tsx

@@ -1,6 +1,8 @@
 import {defineComponent, onMounted, reactive, ref} from "vue";
-import {NButton, NCascader, NForm, NFormItem, NInputNumber, NSpace, useMessage} from "naive-ui";
+import {NButton, NCascader, NForm, NFormItem, NInputNumber, NSelect, NSpace, useMessage} from "naive-ui";
 import {musicSheetApplicationExtendCategoryApplicationExtendInfo, musicSheetApplicationExtendUpdate} from "@views/music-library/api";
+import {getSelectDataFromObj} from "@/utils/objectUtil";
+import {musicSheetAvailableType} from "@/utils/constant";
 
 export default defineComponent({
   name: 'project-music-cooleshow-edu-updateMusic',
@@ -25,6 +27,7 @@ export default defineComponent({
     const forms = reactive({
       musicSheetCategoryId: null as any,
       sortNo: null as any,
+      availableType : null as any,
     })
     const formsRef = ref()
 
@@ -43,7 +46,7 @@ export default defineComponent({
       }
       forms.musicSheetCategoryId = data[0].musicSheetCategoryId
       forms.sortNo = data[0].sortNo
-
+      forms.availableType = data[0].availableType
     })
 
     const onSubmit = async () => {
@@ -102,6 +105,32 @@ export default defineComponent({
                 />
               </NFormItem>
               <NFormItem
+                  label="可用途径"
+                  path="availableType"
+                  rule={[
+                    {
+                      required: true,
+                      message: '请选择可用途径'
+                    }
+                  ]}
+              >
+                <NSelect
+                    placeholder="请选择可用途径"
+                    options={[
+                      {
+                        label: '学校',
+                        value: 'ORG'
+                      },
+                      {
+                        label: '平台',
+                        value: 'PLATFORM'
+                      },
+                    ]}
+                    v-model:value={forms.availableType}
+                    clearable
+                />
+              </NFormItem>
+              <NFormItem
                   label="排序值"
                   path="sortNo"
                   rule={[

+ 1 - 1
src/views/system-manage/menu-manage/index.tsx

@@ -139,7 +139,7 @@ export default defineComponent({
     const getList = async () => {
       try {
         state.loading = true
-        state.expandedRowKeys = []
+        // state.expandedRowKeys = []
         const { data } = await sysMenuPage({
           ...state.searchForm,
           parentId: 0,

+ 1 - 0
src/views/teaching-manage/after-class-training-detail/index.tsx

@@ -66,6 +66,7 @@ export default defineComponent({
           render(row: any) {
             return (
               <TheLink
+                authLink="material/page1750897012676493314"
                 to={{ path: '/educationalManage/educationalManage', query: { id: row.materialId } }}
               >
                 {row.materialName}

+ 52 - 19
src/views/teaching-manage/after-class-training-detail/model/addMaterialTrainingClass.tsx

@@ -182,7 +182,16 @@ export default defineComponent({
         const { data } = await lessonTrainingDetailMaterialPage(tranbody)
         state.loading = false
         state.pagination.pageTotal = Number(data.total)
-        state.dataList = data.rows || []
+        // state.dataList = data.rows || []
+        const tempRows = data.rows || []
+        tempRows.forEach((row: any) => {
+          row.tempIndex = new Date().getTime() + '' + Math.random()
+          // state.dataList.push({
+          //   ...row
+          // })
+        })
+        console.log(tempRows, 'rows')
+        state.dataList = tempRows
       } catch {
         state.loading = false
       }
@@ -198,21 +207,45 @@ export default defineComponent({
 
     // 素材关联知识点
     const handleSave = async () => {
-      state.saveLoading = true
-      const list = state.checkList.map((n: any) => {
-        const item = state.selectCheckList.find((item: any) => item.materialId === n)
-        return {
-          materialId: n,
-          knowledgePointId: item.knowledgePointId,
-          lessonTrainingId: props.parentData.id
-        }
+      // state.saveLoading = true
+      // const list = state.checkList.map((n: any) => {
+      //   const item = state.selectCheckList.find((item: any) => item.tempIndex === n)
+      //   return {
+      //     materialId: item.materialId,
+      //     knowledgePointId: item.knowledgePointId,
+      //     lessonTrainingId: props.parentData.id
+      //   }
+      // })
+      // try {
+      //   const res: any = await lessonTrainingDetailBatchInsert(list)
+      //   message.success('保存成功')
+      //   emit('handleSuccess')
+      // } catch (error) {}
+      // state.saveLoading = false
+      dialog.warning({
+        title: '提示',
+        content: '请确保作业曲目已添加到业务系统',
+        positiveText: '确定',
+        negativeText: '取消',
+        onPositiveClick: async () => {
+          state.saveLoading = true
+          const list = state.checkList.map((n: any) => {
+            const item = state.selectCheckList.find((item: any) => item.tempIndex === n)
+            return {
+              materialId: item.materialId,
+              knowledgePointId: item.knowledgePointId,
+              lessonTrainingId: props.parentData.id
+            }
+          })
+          try {
+            const res: any = await lessonTrainingDetailBatchInsert(list)
+            message.success('保存成功')
+            emit('handleSuccess')
+          } catch (error) {}
+          state.saveLoading = false
+        },
+        onNegativeClick: () => {}
       })
-      try {
-        const res: any = await lessonTrainingDetailBatchInsert(list)
-        message.success('保存成功')
-        emit('handleSuccess')
-      } catch (error) {}
-      state.saveLoading = false
     }
 
     return () => (
@@ -294,7 +327,7 @@ export default defineComponent({
         <NDataTable
           loading={state.loading}
           maxHeight="calc(100vh - 270px)"
-          rowKey={(row: any) => row.materialId}
+          rowKey={(row: any) => row.tempIndex}
           columns={columns()}
           data={state.dataList}
           v-model:checkedRowKeys={state.checkList}
@@ -303,15 +336,15 @@ export default defineComponent({
             // 处理删除的数据
             const tempList: any = []
             state.selectCheckList.forEach((item: any) => {
-              if (state.checkList.includes(item.materialId)) {
+              if (state.checkList.includes(item.tempIndex)) {
                 tempList.push(item)
               }
             })
 
             // 添加新增的数据
             state.checkList.forEach((key: string) => {
-              const item = state.dataList.find((item: any) => item.materialId === key)
-              const index = state.selectCheckList.findIndex((item: any) => item.materialId === key)
+              const item = state.dataList.find((item: any) => item.tempIndex === key)
+              const index = state.selectCheckList.findIndex((item: any) => item.tempIndex === key)
               if (index <= -1) {
                 tempList.push(item)
               }

+ 30 - 7
src/views/teaching-manage/after-class-training-detail/model/addTrainStandard.tsx

@@ -16,6 +16,7 @@ import {
 } from 'naive-ui'
 import { defineComponent, reactive } from 'vue'
 import { lessonTrainingDetailBatchInsert, lessonTrainingDetailTempBatchUpSet } from '../../api'
+import ColVideo from '@/components/col-video'
 
 export default defineComponent({
   name: 'addTrainStandard',
@@ -29,14 +30,35 @@ export default defineComponent({
   setup(props, { emit }) {
     console.log('🚀 ~ props', props.item)
     const userStore = useUserStore()
-    const prefix = /(localhost|192)/.test(location.host)
-      ? 'https://ponline.colexiu.com'
-      : location.origin //
-    const src =
+    // const prefix = /(localhost|192)/.test(location.host)
+    //   ? 'https://test.resource.colexiu.com'
+    //   : location.origin //
+    // const src =
+    //   prefix +
+    //   `/instrument/?_t=${Date.now()}&id=${props.item.content}&modelType=practice&Authorization=${
+    //     userStore.getToken
+    //   }&`
+    const apiUrls = {
+      dev: 'https://dev.kt.colexiu.com',
+      test: 'https://test.kt.colexiu.com',
+      online: 'https://mec.colexiu.com'
+    }
+
+    const environment = location.origin.includes('//dev')
+      ? 'dev'
+      : location.origin.includes('//test')
+      ? 'test'
+      : location.origin.includes('//mec.colexiu')
+      ? 'online'
+      : 'dev'
+    const apiUrl = apiUrls[environment]
+    // const prefix = /(localhost|192)/.test(location.host) ? 'http://dev.resource.colexiu.com/' : location.origin
+    const prefix = /(localhost|192)/.test(location.host) ? 'https://test.kt.colexiu.com' : apiUrl
+    let src =
       prefix +
-      `/orchestra-music-score/?_t=${Date.now()}&id=${
+      `/instrument/?_t=${Date.now()}&id=${
         props.item.content
-      }&modelType=practice&Authorization=${userStore.getToken}`
+      }&modelType=practise&modeType=json&Authorization=${userStore.getToken}&isCbs=true&zoom=0.8`
     const message = useMessage()
     const state = reactive({
       current: 1,
@@ -166,7 +188,8 @@ export default defineComponent({
         <div>{props.item?.materialName}</div>
         {props.item?.type == 'VIDEO' && (
           <div>
-            <video style={{ width: '100%' }} src={props.item.content} controls></video>
+            {/* <video style={{ width: '100%' }} src={props.item.content} controls></video> */}
+            <ColVideo styleValue={{ width: '100%', height: '375px' }} src={props.item.content} />
 
             {state.list.map((item: any) => {
               return (

+ 21 - 0
src/views/teaching-manage/api.ts

@@ -587,3 +587,24 @@ export const lessonCoursewareDetailLock = (data: any) => {
     method: 'post'
   } as any)
 }
+
+/**
+ * 课件导入,单元测验导入,课后训练导入
+ */
+export const api_openFileImportInfoSave = (data: any) => {
+  return request({
+    url: `/cbs-app/open/fileImportInfo/save`,
+    method: 'post',
+    data
+  } as any)
+}
+
+/**
+ * 课件导入,单元测验导入,课后训练导入
+ */
+export const api_removeTraining = (id: any) => {
+  return request({
+    url: `/cbs-app/lessonCoursewareDetail/removeTraining/` + id,
+    method: 'post'
+  } as any)
+}

+ 394 - 187
src/views/teaching-manage/courseware-manage/components/courseConfiguration.tsx

@@ -5,6 +5,7 @@ import {
   NDialog,
   NDrawer,
   NDrawerContent,
+  NDropdown,
   NEmpty,
   NForm,
   NFormItem,
@@ -15,7 +16,10 @@ import {
   NModal,
   NSelect,
   NSpace,
+  NSpin,
   NTooltip,
+  NUpload,
+  UploadCustomRequestOptions,
   useDialog,
   useMessage
 } from 'naive-ui'
@@ -28,7 +32,9 @@ import {
   lessonTrainingPage,
   lessonCoursewareDetailRemove,
   lessonCoursewareExaminationMapperQueryAll,
-  lessonCoursewareDetailLock
+  lessonCoursewareDetailLock,
+  api_openFileImportInfoSave,
+  api_removeTraining
 } from '../../api'
 import styles from '../index.module.less'
 import { EditFilled, DeleteFilled, LockFilled, UnlockFilled } from '@vicons/antd'
@@ -36,6 +42,8 @@ import CourseKnowledgePoint from '../model/CourseKnowledgePoint'
 import SelectAfterClassTraining from '../model/selectAfterClassTraining'
 import AddUnitTest from '../model/AddUnitTest'
 import TheLink from '@/components/TheLink'
+import { api_uploadFile } from '@/plugins/uploadFile'
+import Button from 'naive-ui/es/button/src/Button'
 
 export default defineComponent({
   name: 'courseConfiguration',
@@ -56,7 +64,8 @@ export default defineComponent({
       name: '', //课时名称
       lessonTargetDesc: '', //课时名称
       lessonTrainingId: '', //课后作业
-      lockEnable: 'true'
+      lockEnable: 'true',
+      accessScope: 0
     })
     // 课件添加课程
     const addCourseware = () => {
@@ -66,7 +75,8 @@ export default defineComponent({
             lessonCoursewareId: route.query.id,
             name: addForm.name,
             lessonTargetDesc: addForm.lessonTargetDesc,
-            lockEnable: addForm.lockEnable
+            lockEnable: addForm.lockEnable,
+            accessScope: addForm.accessScope
           }
           let res: any
           if (addForm.id) {
@@ -194,235 +204,402 @@ export default defineComponent({
         }
       })
     }
+
+    /** 删除选择的作业 */
+    const hanldeRemoveTraning = (item: any) => {
+      const d = dialog.warning({
+        title: '警告',
+        content: `是否确认删除作业?`,
+        positiveText: '确定',
+        negativeText: '取消',
+        onPositiveClick: async () => {
+          d.loading = true
+          try {
+            const res = await api_removeTraining(item.id)
+            message.success('删除成功')
+            getDetail()
+          } catch (error) {}
+          d.loading = false
+        }
+      })
+    }
+
+    const customRequest_importData = reactive({
+      loading: false,
+      dataType: 'EXAMINATION',
+      importRef: null as any
+    })
+    const customRequest_importFile = async (data: UploadCustomRequestOptions) => {
+      console.log(data.file)
+      const msg = message.loading('正在上传文件', { duration: 0 })
+      customRequest_importData.loading = true
+      const fileUrl = await api_uploadFile(data.file.file, () => {})
+      const res = await api_openFileImportInfoSave({
+        dataType: customRequest_importData.dataType,
+        fileName: data.file.name,
+        importUrl: fileUrl,
+        lessonId: route.query.id
+      })
+      console.log('🚀 ~ res:', res)
+      customRequest_importData.loading = false
+      if (res.data) {
+        msg.destroy()
+        // 空表格
+        if (res.data.insertRow === 0 && res.data.invalidRow === 0) {
+          message.error('导入失败,表格为空')
+          return
+        }
+        if (res.data.respUrl) {
+          dialog.error({
+            title: '信息',
+            content: () => (
+              <NSpace>
+                <div>导入失败,点击下载错误信息</div>
+                <a href={res.data.respUrl} download>
+                  下载
+                </a>
+              </NSpace>
+            )
+          })
+          return
+        }
+        getDetail()
+        message.success('导入成功')
+      } else {
+        message.error('请下载模板后,填写数据再导入')
+      }
+    }
     return () => (
       <div class={styles.courseConfiguration}>
-        <NSpace>
-          <NButton
-            disabled={route.query.isLook ? true : false}
-            type="primary"
-            onClick={() => {
-              addForm.name = ''
-              addForm.lessonTargetDesc = ''
-              addForm.lessonTrainingId = ''
-              addForm.id = ''
-              addForm.lockEnable = ''
-              addForm.open = true
-            }}
-          >
-            添加课程
-          </NButton>
-          <NButton
-            type="primary"
-            disabled={route.query.isLook ? true : false}
-            onClick={() => {
-              unitData.open = true
-              unitData.model = {}
-            }}
-          >
-            添加阶段自测
-          </NButton>
-        </NSpace>
-        <NAlert class={styles.title} title="教学内容" />
-        <NGrid xGap={12} yGap={8} cols={3}>
-          {state.dataList.map((item: any) => {
-            const mapper = state.mapperList.find((n: any) => n.parentCoursewareDetailId == item.id)
-            return (
-              <>
-                <NGi>
-                  <NCard
-                    title={item.name}
-                    style={{
-                      '--n-padding-top': '5px',
-                      '--n-padding-bottom': '5px',
-                      height: '100%'
+        <NSpin show={customRequest_importData.loading}>
+          <NSpace justify="space-between">
+            <NSpace>
+              <NButton
+                disabled={route.query.isLook ? true : false}
+                type="primary"
+                onClick={() => {
+                  addForm.name = ''
+                  addForm.lessonTargetDesc = ''
+                  addForm.lessonTrainingId = ''
+                  addForm.id = ''
+                  addForm.lockEnable = ''
+                  addForm.accessScope = 0
+                  addForm.open = true
+                }}
+              >
+                添加课程
+              </NButton>
+              <NButton
+                type="primary"
+                disabled={route.query.isLook ? true : false}
+                onClick={() => {
+                  unitData.open = true
+                  unitData.model = {}
+                }}
+              >
+                添加阶段自测
+              </NButton>
+            </NSpace>
+            <NSpace style={{ marginLeft: 'auto' }}>
+              <NDropdown
+                size="huge"
+                trigger="hover"
+                options={[
+                  {
+                    key: '3',
+                    type: 'render',
+                    render: () => (
+                      <NButton
+                        size="large"
+                        quaternary
+                        tag="a"
+                        //@ts-ignore
+                        href="https://oss.dayaedu.com/daya-docs/%E5%8D%95%E5%85%83%E6%B5%8B%E9%AA%8C%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
+                        download
+                      >
+                        单元测验模板
+                      </NButton>
+                    )
+                  },
+                  {
+                    key: '1',
+                    type: 'render',
+                    render: () => (
+                      <NButton
+                        size="large"
+                        quaternary
+                        tag="a"
+                        //@ts-ignore
+                        href="https://oss.dayaedu.com/daya-docs/%E8%AF%BE%E5%90%8E%E8%AE%AD%E7%BB%83%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
+                        download
+                      >
+                        课后训练模板
+                      </NButton>
+                    )
+                  }
+                ]}
+              >
+                <NButton type="primary" v-auth="downloadUnitQuiz1702251742292344833">
+                  下载模板
+                </NButton>
+              </NDropdown>
+              <div>
+                <NUpload
+                  multiple={false}
+                  ref={(el: any) => (customRequest_importData.importRef = el)}
+                  showFileList={false}
+                  accept=".xlsx"
+                  customRequest={customRequest_importFile}
+                >
+                  <NDropdown
+                    size="huge"
+                    trigger="hover"
+                    options={[
+                      { label: '课件', key: 'COURSEWARE' },
+                      { label: '单元测验', key: 'EXAMINATION' },
+                      { label: '课后训练', key: 'HOMEWORK' },
+                      { label: '素材关联曲目', key: 'COURSEWARE_REF_MATERIAL' }
+                    ]}
+                    onSelect={(key: string) => {
+                      customRequest_importData.dataType = key
+                      console.log(customRequest_importData.importRef)
+                      customRequest_importData.importRef?.clear()
+                      customRequest_importData.importRef?.openOpenFileDialog()
                     }}
                   >
-                    {{
-                      default: () => (
-                        <div>
-                          <div style={{ paddingBottom: '12px' }}>{item.lessonTargetDesc}</div>
-                          <table style={{ width: '100%' }}>
-                            <tr>
-                              <td>建议学习时长</td>
-                              <td style={{ 'text-align': 'right' }}>
-                                {item.lessonDurationSecond || '0'}s
-                              </td>
-                            </tr>
-                            <tr>
-                              <td>知识点</td>
-                              <td style={{ 'text-align': 'right' }}>
-                                {item.knowledgePointIds?.split(',').filter(Boolean).length || 0}个
-                              </td>
-                            </tr>
-                            <tr>
-                              <td>课后作业</td>
-                              <td style={{ 'text-align': 'right' }}>
-                                {item.lessonTrainingId ? (
-                                  <TheLink
-                                    // to={`/#/afterClassTrainingDetail?id=${item.lessonTrainingId}&name=${item.lessonTrainingName}&courseTypeCode=TRUMPET_SINGLE`}
-                                    to={{
-                                      path: '/afterClassTrainingManage',
-                                      query: { id: item.lessonTrainingId }
-                                    }}
-                                  >
-                                    {item.lessonTrainingName}
-                                  </TheLink>
-                                ) : (
-                                  '无'
-                                )}
-                              </td>
-                            </tr>
-                          </table>
-                        </div>
-                      ),
-                      'header-extra': () => (
-                        <>
-                          <NTooltip>
-                            {{
-                              default: () => (item.lockFlag ? '解锁' : '锁定'),
-                              trigger: () => (
-                                <NButton
-                                  disabled={route.query.isLook ? true : false}
-                                  quaternary
-                                  circle
-                                  onClick={() => toggleLock(item)}
-                                >
-                                  <NIcon
-                                    component={item.lockFlag ? <LockFilled /> : <UnlockFilled />}
-                                  />
-                                </NButton>
-                              )
-                            }}
-                          </NTooltip>
-
-                          <NTooltip>
-                            {{
-                              default: () => '编辑',
-                              trigger: () => (
-                                <NButton
-                                  disabled={route.query.isLook ? true : false}
-                                  quaternary
-                                  circle
-                                  onClick={() => {
-                                    addForm.name = item.name
-                                    addForm.lessonTargetDesc = item.lessonTargetDesc
-                                    addForm.id = item.id
-                                    addForm.lockEnable = item.lockEnable + ''
-                                    addForm.open = true
-                                  }}
-                                >
-                                  <NIcon component={<EditFilled />} />
-                                </NButton>
-                              )
-                            }}
-                          </NTooltip>
-                          <NTooltip>
-                            {{
-                              default: () => '删除',
-                              trigger: () => (
-                                <NButton
-                                  disabled={route.query.isLook ? true : false}
-                                  quaternary
-                                  circle
-                                  onClick={() => hanldeDelete(item)}
-                                >
-                                  <NIcon component={<DeleteFilled />} />
-                                </NButton>
-                              )
-                            }}
-                          </NTooltip>
-                        </>
-                      ),
-                      action: () => (
-                        <NSpace justify="space-around">
-                          <NButton
-                            text
-                            disabled={route.query.isLook ? true : false}
-                            onClick={() => {
-                              courseData.title = item.name
-                              courseData.open = true
-                              courseData.item = item
-                            }}
-                          >
-                            选择知识点
-                          </NButton>
-                          <NButton
-                            text
-                            disabled={route.query.isLook ? true : false}
-                            onClick={() => {
-                              addForm.id = item.id
-                              addForm.lessonTargetDesc = item.lessonTargetDesc
-                              addForm.name = item.name
-                              afterTrain.open = true
-                            }}
-                          >
-                            选择课后作业
-                          </NButton>
-                        </NSpace>
-                      )
-                    }}
-                  </NCard>
-                </NGi>
-                {mapper && (
+                    <NButton type="primary" onClick={(e: Event) => e.stopPropagation()}>
+                      导入数据
+                    </NButton>
+                  </NDropdown>
+                </NUpload>
+              </div>
+            </NSpace>
+          </NSpace>
+          <NAlert class={styles.title} title="教学内容" />
+          <NGrid xGap={12} yGap={8} cols={3}>
+            {state.dataList.map((item: any) => {
+              const mapper = state.mapperList.find(
+                (n: any) => n.parentCoursewareDetailId == item.id
+              )
+              return (
+                <>
                   <NGi>
                     <NCard
-                      title={mapper.name}
+                      title={item.name}
                       style={{
                         '--n-padding-top': '5px',
                         '--n-padding-bottom': '5px',
-                        '--n-color': 'rgba(238,243,254,1)',
-                        '--n-action-color': 'rgba(238,243,254,1)',
                         height: '100%'
                       }}
                     >
                       {{
                         default: () => (
                           <div>
-                            <div style={{ paddingBottom: '12px' }}>{mapper.desc}</div>
+                            <div style={{ paddingBottom: '12px' }}>{item.lessonTargetDesc}</div>
                             <table style={{ width: '100%' }}>
                               <tr>
-                                <td>单团学生</td>
+                                <td>建议学习时长</td>
                                 <td style={{ 'text-align': 'right' }}>
-                                  {mapper?.details?.[0]?.unitExaminationName || '无'}
+                                  {item.lessonDurationSecond || '0'}s
                                 </td>
                               </tr>
                               <tr>
-                                <td>双团学生</td>
+                                <td>知识点</td>
                                 <td style={{ 'text-align': 'right' }}>
-                                  {mapper?.details?.[1]?.unitExaminationName || '无'}
+                                  {item.knowledgePointIds?.split(',').filter(Boolean).length || 0}个
                                 </td>
                               </tr>
                               <tr>
-                                <td>多团学生</td>
+                                <td>课后作业</td>
                                 <td style={{ 'text-align': 'right' }}>
-                                  {mapper?.details?.[2]?.unitExaminationName || '无'}
+                                  {item.lessonTrainingId ? (
+                                    <>
+                                      <TheLink
+                                        // to={`/#/afterClassTrainingDetail?id=${item.lessonTrainingId}&name=${item.lessonTrainingName}&courseTypeCode=TRUMPET_SINGLE`}
+                                        authLink="afterClassTrainingManage1599968711187746818"
+                                        to={{
+                                          path: '/afterClassTrainingManage',
+                                          query: { id: item.lessonTrainingId }
+                                        }}
+                                      >
+                                        {item.lessonTrainingName}
+                                      </TheLink>
+
+                                      <NTooltip>
+                                        {{
+                                          default: () => '删除',
+                                          trigger: () => (
+                                            <NButton
+                                              v-auth="lessonCoursewareDetail/removeTraining1793827126242213890"
+                                              quaternary
+                                              size="small"
+                                              circle
+                                              onClick={() => hanldeRemoveTraning(item)}
+                                            >
+                                              <NIcon component={<DeleteFilled />} />
+                                            </NButton>
+                                          )
+                                        }}
+                                      </NTooltip>
+                                    </>
+                                  ) : (
+                                    '无'
+                                  )}
                                 </td>
                               </tr>
                             </table>
                           </div>
                         ),
+                        'header-extra': () => (
+                          <>
+                            <NTooltip>
+                              {{
+                                default: () => (item.lockFlag ? '解锁' : '锁定'),
+                                trigger: () => (
+                                  <NButton
+                                    disabled={route.query.isLook ? true : false}
+                                    quaternary
+                                    circle
+                                    onClick={() => toggleLock(item)}
+                                  >
+                                    <NIcon
+                                      component={item.lockFlag ? <LockFilled /> : <UnlockFilled />}
+                                    />
+                                  </NButton>
+                                )
+                              }}
+                            </NTooltip>
+
+                            <NTooltip>
+                              {{
+                                default: () => '编辑',
+                                trigger: () => (
+                                  <NButton
+                                    disabled={route.query.isLook ? true : false}
+                                    quaternary
+                                    circle
+                                    onClick={() => {
+                                      addForm.name = item.name
+                                      addForm.lessonTargetDesc = item.lessonTargetDesc
+                                      addForm.id = item.id
+                                      addForm.lockEnable = item.lockEnable + ''
+                                      addForm.accessScope = item.accessScope ?? 0
+                                      addForm.open = true
+                                    }}
+                                  >
+                                    <NIcon component={<EditFilled />} />
+                                  </NButton>
+                                )
+                              }}
+                            </NTooltip>
+                            <NTooltip>
+                              {{
+                                default: () => '删除',
+                                trigger: () => (
+                                  <NButton
+                                    disabled={route.query.isLook ? true : false}
+                                    quaternary
+                                    circle
+                                    onClick={() => hanldeDelete(item)}
+                                  >
+                                    <NIcon component={<DeleteFilled />} />
+                                  </NButton>
+                                )
+                              }}
+                            </NTooltip>
+                          </>
+                        ),
                         action: () => (
                           <NSpace justify="space-around">
                             <NButton
                               text
                               disabled={route.query.isLook ? true : false}
                               onClick={() => {
-                                unitData.open = true
-                                unitData.model = mapper
+                                courseData.title = item.name
+                                courseData.open = true
+                                courseData.item = item
+                              }}
+                            >
+                              选择知识点
+                            </NButton>
+                            <NButton
+                              text
+                              disabled={route.query.isLook ? true : false}
+                              onClick={() => {
+                                addForm.id = item.id
+                                addForm.lessonTargetDesc = item.lessonTargetDesc
+                                addForm.name = item.name
+                                afterTrain.open = true
                               }}
                             >
-                              编辑阶段自测
+                              选择课后作业
                             </NButton>
                           </NSpace>
                         )
                       }}
                     </NCard>
                   </NGi>
-                )}
-              </>
-            )
-          })}
-        </NGrid>
+                  {mapper && (
+                    <NGi>
+                      <NCard
+                        title={mapper.name}
+                        style={{
+                          '--n-padding-top': '5px',
+                          '--n-padding-bottom': '5px',
+                          '--n-color': 'rgba(238,243,254,1)',
+                          '--n-action-color': 'rgba(238,243,254,1)',
+                          height: '100%'
+                        }}
+                      >
+                        {{
+                          default: () => (
+                            <div>
+                              <div style={{ paddingBottom: '12px' }}>{mapper.desc}</div>
+                              <table style={{ width: '100%' }}>
+                                <tr>
+                                  <td>单团学生</td>
+                                  <td style={{ 'text-align': 'right' }}>
+                                    {mapper?.details?.[0]?.unitExaminationName || '无'}
+                                  </td>
+                                </tr>
+                                <tr>
+                                  <td>双团学生</td>
+                                  <td style={{ 'text-align': 'right' }}>
+                                    {mapper?.details?.[1]?.unitExaminationName || '无'}
+                                  </td>
+                                </tr>
+                                <tr>
+                                  <td>多团学生</td>
+                                  <td style={{ 'text-align': 'right' }}>
+                                    {mapper?.details?.[2]?.unitExaminationName || '无'}
+                                  </td>
+                                </tr>
+                              </table>
+                            </div>
+                          ),
+                          action: () => (
+                            <NSpace justify="space-around">
+                              <NButton
+                                text
+                                disabled={route.query.isLook ? true : false}
+                                onClick={() => {
+                                  unitData.open = true
+                                  unitData.model = mapper
+                                }}
+                              >
+                                编辑阶段自测
+                              </NButton>
+                            </NSpace>
+                          )
+                        }}
+                      </NCard>
+                    </NGi>
+                  )}
+                </>
+              )
+            })}
+          </NGrid>
+        </NSpin>
         {state.dataList.length ? null : <NEmpty />}
 
         {/* 课程编辑 */}
@@ -465,6 +642,36 @@ export default defineComponent({
               ></NSelect>
             </NFormItem>
             <NFormItem
+              label="是否免费"
+              required
+              path="accessScope"
+              rule={[
+                {
+                  type: 'number',
+                  required: true,
+                  message: '设置是否免费',
+                  trigger: ['blur', 'change']
+                }
+              ]}
+            >
+              <NSelect
+                v-model:value={addForm.accessScope}
+                options={
+                  [
+                    {
+                      label: '是',
+                      value: 0
+                    },
+                    {
+                      label: '否',
+                      value: 1
+                    }
+                  ] as any
+                }
+                clearable
+              ></NSelect>
+            </NFormItem>
+            <NFormItem
               label="教学目标"
               required
               path="lessonTargetDesc"

+ 165 - 88
src/views/teaching-manage/courseware-manage/index.tsx

@@ -12,6 +12,9 @@ import {
   NInput,
   NSelect,
   NSpace,
+  NSpin,
+  NUpload,
+  UploadCustomRequestOptions,
   useDialog,
   useMessage
 } from 'naive-ui'
@@ -20,13 +23,15 @@ import dayjs from 'dayjs'
 import {
   lessonCoursewarePage,
   lessonCoursewareUpdateEnableFlag,
-  lessonCoursewareDelete
+  lessonCoursewareDelete,
+  api_openFileImportInfoSave
 } from '../api'
 import { InternalRowData } from 'naive-ui/es/data-table/src/interface'
 import { useRouter } from 'vue-router'
 import { knowledgeTypeData, lessonType } from '@/views/knowledge-manage/knowledgeTypeData'
 import { orchestraTypes } from '../teachingData'
 import { sysEmployeePage } from '@/views/system-manage/api'
+import { api_uploadFile } from '@/plugins/uploadFile'
 
 export default defineComponent({
   name: 'courseware-manage',
@@ -334,99 +339,171 @@ export default defineComponent({
       saveForm.value?.reset()
     }
 
+    const customRequest_importData = reactive({
+      loading: false,
+      importRef: null as any
+    })
+    const customRequest_importFile = async (data: UploadCustomRequestOptions) => {
+      console.log(data.file)
+      customRequest_importData.loading = true
+      try {
+        const fileUrl = await api_uploadFile(data.file.file, () => {})
+        const res = await api_openFileImportInfoSave({
+          dataType: 'COURSEWARE',
+          fileName: data.file.name,
+          importUrl: fileUrl
+        })
+        console.log('🚀 ~ res:', res)
+        if (res.data) {
+          // 空表格
+          if (res.data.insertRow === 0 && res.data.invalidRow === 0) {
+            message.error('导入失败,表格为空')
+            return
+          }
+          if (res.data.respUrl) {
+            dialog.error({
+              title: '信息',
+              content: () => (
+                <NSpace>
+                  <div>导入失败,点击下载错误信息</div>
+                  <a href={res.data.respUrl} download>
+                    下载
+                  </a>
+                </NSpace>
+              )
+            })
+            return
+          }
+          message.success('导入成功')
+        }
+      } catch {}
+      customRequest_importData.loading = false
+    }
+
     return () => (
       <div class="system-menu-container">
-        <div class={['section-container']}>
-          <SaveForm
-            ref={saveForm}
-            model={searchForm}
-            onSubmit={onSubmit}
-            onSetModel={(val: any) => Object.assign(searchForm, val)}
-            saveKey="courseware-manage-ad-key"
-          >
-            <NFormItem path="keyword" label="关键字">
-              <NInput
-                v-model:value={searchForm.keyword}
-                placeholder="请输入课件名称/编号"
-                clearable
-              />
-            </NFormItem>
-            <NFormItem path="courseTypeCode" label="课程类型">
-              <NSelect
-                placeholder="请选择课程类型"
-                clearable
-                v-model:value={searchForm.courseTypeCode}
-                options={lessonType}
-              />
-            </NFormItem>
-            <NFormItem path="enableFlag" label="是否启用">
-              <NSelect
-                placeholder="是否启用"
-                clearable
-                v-model:value={searchForm.enableFlag}
-                options={[
-                  { label: '是', value: 1 },
-                  { label: '否', value: 0 }
-                ]}
-              />
-            </NFormItem>
-            <NFormItem path="orchestraType" label="乐团类型">
-              <NSelect
-                placeholder="请输入乐团类型"
-                clearable
-                v-model:value={searchForm.orchestraType}
-                options={state.orchestraTypeList}
-              />
-            </NFormItem>
-            <NFormItem path="operatorId" label="更新人">
-              <NSelect
-                placeholder="请输入更新人"
-                clearable
-                v-model:value={searchForm.operatorId}
-                options={state.staffList}
-                filterable
-              />
-            </NFormItem>
-            <NFormItem>
+        <NSpin show={customRequest_importData.loading}>
+          <div class={['section-container']}>
+            <SaveForm
+              ref={saveForm}
+              model={searchForm}
+              onSubmit={onSubmit}
+              onSetModel={(val: any) => Object.assign(searchForm, val)}
+              saveKey="courseware-manage-ad-key"
+            >
+              <NFormItem path="keyword" label="关键字">
+                <NInput
+                  v-model:value={searchForm.keyword}
+                  placeholder="请输入课件名称/编号"
+                  clearable
+                />
+              </NFormItem>
+              <NFormItem path="courseTypeCode" label="课程类型">
+                <NSelect
+                  placeholder="请选择课程类型"
+                  clearable
+                  v-model:value={searchForm.courseTypeCode}
+                  options={lessonType}
+                />
+              </NFormItem>
+              <NFormItem path="enableFlag" label="是否启用">
+                <NSelect
+                  placeholder="是否启用"
+                  clearable
+                  v-model:value={searchForm.enableFlag}
+                  options={[
+                    { label: '是', value: 1 },
+                    { label: '否', value: 0 }
+                  ]}
+                />
+              </NFormItem>
+              <NFormItem path="orchestraType" label="乐团类型">
+                <NSelect
+                  placeholder="请输入乐团类型"
+                  clearable
+                  v-model:value={searchForm.orchestraType}
+                  options={state.orchestraTypeList}
+                />
+              </NFormItem>
+              <NFormItem path="operatorId" label="更新人">
+                <NSelect
+                  placeholder="请输入更新人"
+                  clearable
+                  v-model:value={searchForm.operatorId}
+                  options={state.staffList}
+                  filterable
+                />
+              </NFormItem>
+              <NFormItem>
+                <NSpace>
+                  <NButton type="primary" onClick={onSearch}>
+                    搜索
+                  </NButton>
+                  <NButton type="default" onClick={onBtnReset}>
+                    重置
+                  </NButton>
+                </NSpace>
+              </NFormItem>
+            </SaveForm>
+            <NSpace style={{ paddingBottom: '12px' }} justify="space-between">
+              <NButton
+                type="primary"
+                v-auth="coursewareDetail1607207526805606402"
+                onClick={() => {
+                  state.visiableKnowledge = true
+                  router.push({
+                    path: '/coursewareDetail'
+                  })
+                }}
+              >
+                新增课件
+              </NButton>
               <NSpace>
-                <NButton type="primary" onClick={onSearch}>
-                  搜索
-                </NButton>
-                <NButton type="default" onClick={onBtnReset}>
-                  重置
+                <NButton
+                  v-auth="downloadCoursewareTemplate1793540443017875457"
+                  type="primary"
+                  tag="a"
+                  //@ts-ignore
+                  href="https://oss.dayaedu.com/daya-docs/%E8%AF%BE%E4%BB%B6%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
+                  download
+                >
+                  下载课件模板
                 </NButton>
+                <div v-auth="Importcourseware1793540542561292290">
+                  <NUpload
+                    ref={(el: any) => (customRequest_importData.importRef = el)}
+                    showFileList={false}
+                    accept=".xlsx"
+                    customRequest={customRequest_importFile}
+                  >
+                    <NButton
+                      type="primary"
+                      onClick={() => {
+                        customRequest_importData.importRef?.clear()
+                      }}
+                    >
+                      导入课件
+                    </NButton>
+                  </NUpload>
+                </div>
               </NSpace>
-            </NFormItem>
-          </SaveForm>
-          <NSpace style={{ paddingBottom: '12px' }}>
-            <NButton
-              type="primary"
-              v-auth="coursewareDetail1607207526805606402"
-              onClick={() => {
-                state.visiableKnowledge = true
-                router.push({
-                  path: '/coursewareDetail'
-                })
-              }}
-            >
-              新增课件
-            </NButton>
-          </NSpace>
+            </NSpace>
 
-          <NDataTable
-            loading={state.loading}
-            columns={columns()}
-            data={state.dataList}
-          ></NDataTable>
-          <Pagination
-            saveKey="courseware-manage-ad-key"
-            v-model:page={state.pagination.page}
-            v-model:pageSize={state.pagination.rows}
-            v-model:pageTotal={state.pagination.pageTotal}
-            onList={getList}
-            sync
-          ></Pagination>
-        </div>
+            <NDataTable
+              loading={state.loading}
+              columns={columns()}
+              data={state.dataList}
+            ></NDataTable>
+            <Pagination
+              saveKey="courseware-manage-ad-key"
+              v-model:page={state.pagination.page}
+              v-model:pageSize={state.pagination.rows}
+              v-model:pageTotal={state.pagination.pageTotal}
+              onList={getList}
+              sync
+            ></Pagination>
+          </div>
+        </NSpin>
       </div>
     )
   }

+ 23 - 1
src/views/teaching-manage/courseware-manage/model/CourseKnowledgePoint.tsx

@@ -20,6 +20,7 @@ import {
   lessonCoursewareDetailUpOrDownKnowledgePoint
 } from '../../api'
 import AddseKnowledge from './AddseKnowledge'
+import TheLink from '@/components/TheLink'
 
 export default defineComponent({
   name: 'CourseKnowledgePoint',
@@ -60,7 +61,28 @@ export default defineComponent({
       },
       {
         title: '知识点名称',
-        key: 'name'
+        key: 'name',
+        render(row: any) {
+          // return row.children ? (
+          //   <>
+          //     {row.name}({row.knowledgePointId})
+          //   </>
+          // ) : (
+          //   <TheLink
+          //     to={{
+          //       path: '/educationalManage/knowledgeManage',
+          //       query: { keyword: row.knowledgePointId }
+          //     }}
+          //   >
+          //     {row.name}({row.knowledgePointId})
+          //   </TheLink>
+          // )
+          return (
+              <>
+                {row.name}({row.knowledgePointId})
+              </>
+          )
+        }
       },
       {
         title: '课程类型',

+ 4 - 1
src/views/teaching-manage/teaching-plan/plan-detail.tsx

@@ -59,7 +59,10 @@ export default defineComponent({
           key: 'name',
           render: (row: any) => (
             <>
-              <TheLink to={{ path: '/coursewareDetail', query: { id: row.lessonCoursewareId } }}>
+              <TheLink
+                authLink="coursewareManage1606856890826199041"
+                to={{ path: '/coursewareDetail', query: { id: row.lessonCoursewareId } }}
+              >
                 {row.name}
               </TheLink>
             </>

+ 2 - 19
src/views/teaching-manage/unit-test/index.module.less

@@ -2,7 +2,6 @@
   .form {
     :global {
       .n-form-item-blank {
-
         .n-input,
         .n-select {
           width: 160px;
@@ -11,45 +10,37 @@
     }
   }
 }
-
 .kaodian {
   :global {
     .n-base-selection-input {
       color: #333 !important;
     }
-
     .n-base-loading.n-base-suffix {
       display: none;
     }
   }
 }
-
 .coustomBank {
   :global {
     .n-tabs-nav {
       display: none;
     }
-
     .n-tab-pane {
       padding-top: 0;
     }
   }
 }
-
 .answerItem {
   display: flex;
   align-items: center;
   justify-content: space-between;
   padding: 10px 0;
-
   &:hover {
     background-color: rgba(0, 0, 0, 0.1);
   }
-
   .handle {
     width: 50px;
   }
-
   .itemContent {
     flex: 1;
     padding: 0 50px 0 0;
@@ -57,43 +48,35 @@
     align-items: center;
   }
 }
-
 .juanWrap {
   margin-bottom: 20px;
 }
-
 .unit-test-index-editAndUpdate {
   .ramdomItem {
     position: relative;
     border-radius: 8px;
-    padding: 30px 10px 0px 10px;
-
+    padding: 10px 10px 0 10px;
     :global {
       .n-form-item-label {
         display: flex;
         flex-direction: row;
         align-items: center;
       }
-
       .n-form-item-label__asterisk {
         display: none;
       }
     }
-
     .kaoLabel {
       span {
         color: var(--n-asterisk-color);
       }
     }
-
     &:hover {
       background-color: rgba(0, 0, 0, 0.1);
-
       .delIcon {
         visibility: visible;
       }
     }
-
     .delIcon {
       position: absolute;
       right: 10px;
@@ -101,4 +84,4 @@
       visibility: hidden;
     }
   }
-}
+}

+ 1 - 1
src/views/teaching-manage/unit-test/index.tsx

@@ -49,7 +49,7 @@ export default defineComponent({
           <div class={styles.unitTest}>
             <NTabs
               v-model:value={data.active}
-              type="line"
+              type="card"
               onUpdate:value={(val: any) => setTabs(val)}
             >
               <NTabPane name="1" tab="阶段自测" v-auth="unitExamination/page1614564155343577090">

+ 48 - 11
src/views/teaching-manage/unit-test/model/addQuestionBank.tsx

@@ -93,6 +93,21 @@ interface ExaminationQuestionAdd {
   answerAnalysis: string | null
 }
 
+const apiUrls = {
+  dev: 'https://dev.kt.colexiu.com',
+  test: 'https://test.kt.colexiu.com',
+  online: 'https://mec.colexiu.com'
+}
+
+const environment = location.origin.includes('//dev')
+  ? 'dev'
+  : location.origin.includes('//test')
+  ? 'test'
+  : location.origin.includes('//mec.colexiu')
+  ? 'online'
+  : 'dev'
+const apiUrl = apiUrls[environment]
+
 export default defineComponent({
   name: 'addQuestionBank',
   emits: ['handleSuccess', 'close'],
@@ -136,6 +151,7 @@ export default defineComponent({
       try {
         const res: any = await examinationQuestionDetail(props.item.id)
         if (res?.data) {
+          console.log(res.data, 'res.data')
           for (let key in saveModel) {
             ;(saveModel as any)[key] = res.data[key] || ''
           }
@@ -148,14 +164,25 @@ export default defineComponent({
               playData.score = _palyData.score
               playData.musicSheetId = _palyData.musicSheetId
               playData.musicName = _palyData.musicName
-              const prefix = /(localhost|192)/.test(location.host)
-                ? 'https://ponline.colexiu.com'
-                : location.origin
+              // const prefix = /(localhost|192)/.test(location.host)
+              //   ? 'https://ponline.colexiu.com'
+              //   : location.origin
+              // musicSheetSrc.value =
+              //   prefix +
+              //   `/orchestra-music-score/?_t=${Date.now()}&id=${
+              //     _palyData.musicSheetId
+              //   }&modelType=practice&Authorization=${userStore.getToken}`
+
+              const prefix = /(localhost)/.test(location.host)
+                ? 'https://test.kt.colexiu.com'
+                : apiUrl
               musicSheetSrc.value =
                 prefix +
-                `/orchestra-music-score/?_t=${Date.now()}&id=${
+                `/instrument/?_t=${Date.now()}&id=${
                   _palyData.musicSheetId
-                }&modelType=practice&Authorization=${userStore.getToken}`
+                }&modelType=practise&modeType=json&Authorization=${
+                  userStore.getToken
+                }&isCbs=true&zoom=0.8`
             } catch (error) {}
           }
           if (saveModel.mediaUrls) {
@@ -560,18 +587,28 @@ export default defineComponent({
           <div>
             <SelectMusicSheet
               onSelect={(row: any) => {
-                // console.log(row)
                 playData.musicSheetId = row.id
-                playData.musicName = row.musicSheetName
+                playData.musicName = row.name
                 modalData.open = false
+                // const prefix = /(localhost|192)/.test(location.host)
+                //   ? 'https://ponline.colexiu.com'
+                //   : location.origin
+                // musicSheetSrc.value =
+                //   prefix +
+                //   `/orchestra-music-score/?_t=${Date.now()}&id=${
+                //     row.id
+                //   }&modelType=practice&Authorization=${userStore.getToken}`
+
                 const prefix = /(localhost|192)/.test(location.host)
-                  ? 'https://ponline.colexiu.com'
-                  : location.origin
+                  ? 'https://test.kt.colexiu.com'
+                  : apiUrl
                 musicSheetSrc.value =
                   prefix +
-                  `/orchestra-music-score/?_t=${Date.now()}&id=${
+                  `/instrument/?_t=${Date.now()}&id=${
                     row.id
-                  }&modelType=practice&Authorization=${userStore.getToken}`
+                  }&modelType=practise&modeType=json&Authorization=${
+                    userStore.getToken
+                  }&isCbs=true&zoom=0.8`
               }}
             />
           </div>

+ 18 - 6
src/views/teaching-manage/unit-test/model/addQuestionList.tsx

@@ -130,10 +130,22 @@ export default defineComponent({
           rows: 1000
         })
         if (Array.isArray(res?.data?.rows)) {
-          data.categorys = res.data.rows
+          data.categorys = formatList(res.data.rows)
         }
       } catch (error) {}
     }
+
+    const formatList = (item: any) => {
+      item.forEach((child: any) => {
+        if (child.children && child.children.length) {
+          formatList(child.children)
+        } else {
+          child.children = null
+        }
+      })
+      return item
+    }
+
     const onSubmit = () => {
       data.pagination.page = 1
       getList()
@@ -153,7 +165,7 @@ export default defineComponent({
           onSetModel={(val: any) => Object.assign(searchForm, val)}
           saveKey="add-question-list-key"
         >
-          <NFormItem path="keyword" label='关键字'>
+          <NFormItem path="keyword" label="关键字">
             <NInput
               placeholder="请输入题目名称/编号"
               v-model:value={searchForm.keyword}
@@ -165,7 +177,7 @@ export default defineComponent({
               clearable
             />
           </NFormItem>
-          <NFormItem path="score" label='分值'>
+          <NFormItem path="score" label="分值">
             <NInput
               placeholder="请输入分值"
               v-model:value={searchForm.score}
@@ -177,7 +189,7 @@ export default defineComponent({
               clearable
             />
           </NFormItem>
-          <NFormItem path="questionTypeCode" label='题目类型'>
+          <NFormItem path="questionTypeCode" label="题目类型">
             <NSelect
               placeholder="请选择题目类型"
               v-model:value={searchForm.questionTypeCode}
@@ -196,7 +208,7 @@ export default defineComponent({
               options={lessonType}
             />
           </NFormItem> */}
-          <NFormItem path="categoryId" label='考点'>
+          <NFormItem path="categoryId" label="考点">
             <NCascader
               placeholder="请选择考点"
               v-model:value={searchForm.categoryId}
@@ -209,7 +221,7 @@ export default defineComponent({
               clearable
             />
           </NFormItem>
-          <NFormItem path="difficultyCoefficient" label='难度'>
+          <NFormItem path="difficultyCoefficient" label="难度">
             <NSelect
               placeholder="请选择难度"
               clearable

+ 28 - 20
src/views/teaching-manage/unit-test/unit-test-index/editAndUpdate.tsx

@@ -176,24 +176,33 @@ export default defineComponent({
             message.error('阶段自测的合格分数高于题目的总分值')
             return
           }
-          const params: any = {
-            ...saveModel,
-            questionList: modalData.selectList
-          }
-          let res: any = null
-          console.log(params)
-          if (saveModel.id) {
-            res = await unitExaminationSave(params)
-          } else {
-            res = await unitExaminationSave(params)
-          }
-          if (res?.code == 200) {
-            message.success('保存成功')
-            gotoBack()
-            // emit('handleSuccess')
-          } else {
-            message.warning('保存失败')
-          }
+          dialog.warning({
+            title: '提示',
+            content: '请确保测验曲目已添加到业务系统',
+            positiveText: '确定',
+            negativeText: '取消',
+            onPositiveClick: async () => {
+              const params: any = {
+                ...saveModel,
+                questionList: modalData.selectList
+              }
+              let res: any = null
+              console.log(params)
+              if (saveModel.id) {
+                res = await unitExaminationSave(params)
+              } else {
+                res = await unitExaminationSave(params)
+              }
+              if (res?.code == 200) {
+                message.success('保存成功')
+                gotoBack()
+                // emit('handleSuccess')
+              } else {
+                message.warning('保存失败')
+              }
+            },
+            onNegativeClick: () => {}
+          })
         }
       })
     }
@@ -577,7 +586,6 @@ export default defineComponent({
                                 default: () => (
                                   <NSelect
                                     multiple
-                                    clearable
                                     options={questions}
                                     v-model:value={item.questionTypeCodes}
                                   />
@@ -603,7 +611,7 @@ export default defineComponent({
                       )
                     })}
                   </NForm>
-                  <NSpace style={{ padding: '10px 10px 0 10px' }}>
+                  <NSpace style={{ padding: '0 10px 0 10px' }}>
                     <NButton
                       type="warning"
                       style={{ width: '170px' }}

+ 26 - 6
src/views/teaching-manage/unit-test/unit-test-index/previewUnit.tsx

@@ -4,6 +4,11 @@ import { computed, defineComponent, reactive } from 'vue'
 import { difficultyCoefficients, questionTypeCode } from '../question-bank'
 import styles from './previewUnit.module.less'
 const items = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'M']
+const difficultyEmun = [
+  { label: '普通级', value: '1' },
+  { label: '进阶级', value: '2' },
+  { label: '大师级', value: '3' }
+]
 export default defineComponent({
   name: 'previewUnit',
   props: {
@@ -30,9 +35,8 @@ export default defineComponent({
           }) || []
         let questionExtendsInfo = ''
         try {
-          questionExtendsInfo = n.questionTypeCode != "PLAY"
-            ? n.questionExtendsInfo
-            : JSON.parse(n.questionExtendsInfo)
+          questionExtendsInfo =
+            n.questionTypeCode != 'PLAY' ? n.questionExtendsInfo : JSON.parse(n.questionExtendsInfo)
         } catch (error) {}
         arr.push({
           ...n,
@@ -73,12 +77,11 @@ export default defineComponent({
                     <div>
                       <div innerHTML={n.questionDetail}></div>
 
-                      {n.questionTypeCode != "PLAY" ? (
+                      {n.questionTypeCode != 'PLAY' ? (
                         <div>
                           <NSpace>
                             {n.mediaUrls.map((media: any) => (
                               <>
-                                {/* <audio src='https://daya.ks3-cn-beijing.ksyun.com/202205/T6doLdd.mp3' controls></audio> */}
                                 {media.type === 'audio' ? (
                                   <audio src={media.src} controls></audio>
                                 ) : (
@@ -119,7 +122,24 @@ export default defineComponent({
                             modalData.music = { id: n.questionExtendsInfo?.musicSheetId }
                           }}
                         >
-                          演奏曲目: {n.questionExtendsInfo?.musicName} (合格分数: {n.questionExtendsInfo?.score})
+                          演奏曲目: {n.questionExtendsInfo?.musicName}
+                          <NSpace style={{ marginLeft: '8px' }}>
+                            <NTag size="small" type="primary">
+                              合格分数: {n.questionExtendsInfo?.score}
+                            </NTag>
+                            <NTag size="small" type="primary">
+                              练习小节:
+                              {n.questionExtendsInfo?.start}-{n.questionExtendsInfo?.end}
+                            </NTag>
+                            <NTag size="small" type="primary">
+                              测验难度:
+                              {
+                                difficultyEmun.find(
+                                  (d: any) => d.value == n.questionExtendsInfo?.difficulty
+                                )?.label
+                              }
+                            </NTag>
+                          </NSpace>
                         </NButton>
                       )}
 

+ 2 - 2
vite.config.ts

@@ -19,9 +19,9 @@ function pathResolve(dir: string) {
 }
 
 // const proxyUrl = 'https://dev.lexiaoya.cn'
-const proxyUrl = 'http://127.0.0.1:7293/'
+// const proxyUrl = 'http://127.0.0.1:7293/'
 // const proxyUrl = 'https://resource.colexiu.com/'
-// const proxyUrl = 'https://dev.resource.colexiu.com'
+const proxyUrl = 'https://test.resource.colexiu.com'
 // https://test.resource.colexiu.com/
 
 export default ({ command, mode }: ConfigEnv): UserConfig => {