liushengqiang 1 年之前
父節點
當前提交
8c99602799

+ 1 - 3
src/components/TheSearch/index.tsx

@@ -25,9 +25,7 @@ export default defineComponent({
         placeholder="请输入搜索关键词"
         clearable
         v-model:value={searchData.value}
-        onClear={() =>
-          emit('search', searchData.value ? searchData.value.trim() : '')
-        }
+        onClear={() => emit('search', '')}
         onKeyup={(e: KeyboardEvent) => {
           e.stopPropagation();
           if (e.code === 'Enter') {

+ 23 - 1
src/views/xiaoku-ai/api.ts

@@ -1,8 +1,30 @@
 import request from '@/utils/request';
 
 /**
- * 老师列表
+ * 曲谱分类列表
  */
 export const api_musicTagTree = () => {
   return request.get('/edu-app/musicTag/tree');
 };
+/**
+ * 曲谱教材列表分页
+ */
+export const api_musicSheetCategoriesPage = (params: any) => {
+  return request.post('/edu-app/musicSheetCategories/page', {
+    data: params
+  });
+};
+/**
+ * 乐器列表
+ */
+export const api_subjectList = () => {
+  return request.post('/edu-app/subject/list');
+};
+/**
+ * 曲谱列表分页
+ */
+export const api_musicSheetPage = (params: any) => {
+  return request.post('/edu-app/musicSheet/page', {
+    data: params
+  });
+};

+ 1 - 0
src/views/xiaoku-ai/index.module.less

@@ -33,6 +33,7 @@
 
         :global {
             .n-button {
+                min-width: 102px;
                 height: 37px;
                 padding: 0 24px;
                 font-size: 18px;

+ 164 - 55
src/views/xiaoku-ai/index.tsx

@@ -1,54 +1,111 @@
-import {
-  TransitionGroup,
-  computed,
-  defineComponent,
-  onMounted,
-  reactive,
-  ref
-} from 'vue';
+import { defineComponent, onMounted, reactive } from 'vue';
 import styles from './index.module.less';
 import TheSearch from '@/components/TheSearch';
-import { NButton, NImage, NSpace } from 'naive-ui';
+import { NButton, NImage, NSpace, NSpin } from 'naive-ui';
 import { useRouter } from 'vue-router';
-import mock from './mock.json';
-import { api_musicTagTree } from './api';
+import { api_musicSheetCategoriesPage, api_musicTagTree } from './api';
 
 export default defineComponent({
   name: 'XiaokuAi',
   setup() {
     const router = useRouter();
+    const forms = reactive({
+      musicTagIds: [] as any[],
+      keyword: '',
+      page: 1,
+      rows: 9999
+    });
     const data = reactive({
       tags: [] as any[],
-      tagIndex: 0,
+      tagChildren: [] as any[],
+      tagActiveId: '',
       tagActive: {} as any,
-      list: mock.list
+      list: [] as any,
+      loading: false
     });
     const getTags = async () => {
       const res = await api_musicTagTree();
-      if (Array.isArray(res?.data)) {
+      if (Array.isArray(res?.data) && res.data.length) {
         data.tags = res.data;
-        const list = renderTag(res.data);
-        console.log(list);
+        data.tagActiveId = res.data[0].id;
+        const list: any[] = [];
+        renderTag(res.data[0].children, list);
+        data.tagChildren = list;
+      }
+    };
+
+    const getList = async () => {
+      data.loading = true;
+      const res = await api_musicSheetCategoriesPage({
+        ...forms,
+        musicTagIds: [data.tagActiveId, ...forms.musicTagIds].filter(Boolean)
+      });
+      if (Array.isArray(res?.data?.rows)) {
+        data.list = res.data.rows;
       }
+      data.loading = false;
     };
 
     // 递归渲染标签
-    const renderTag = (_data: any[]): any => {
+    const renderTag = (_data: any[], _list: any[]): any => {
       const item = {
         columnName: _data[0].columnName,
-        list: _data.map((item: any) => {
-          return {
-            name: item.name,
-            list: Array.isArray(item.children) ? renderTag(item.children) : []
-          };
-        })
+        list: [] as any[]
       };
-
-      return item;
+      const childrens = [];
+      for (let i = 0; i < _data.length; i++) {
+        item.list.push({
+          name: _data[i].name,
+          id: _data[i].id,
+          activeIndex: -1
+        });
+        if (_data[i].children) {
+          childrens.push(..._data[i].children);
+        }
+      }
+      _list.push(item);
+      if (childrens.length) {
+        renderTag(childrens, _list);
+      }
     };
-    onMounted(() => {
-      getTags();
+    onMounted(async () => {
+      await getTags();
+      getList();
     });
+
+    /** 改变顶级分类 */
+    const changeTag = (item: any, index: number) => {
+      data.tagActiveId = item.id;
+      forms.musicTagIds = [];
+      const list: any[] = [];
+      renderTag(data.tags[index].children, list);
+      data.tagChildren = list;
+      getList();
+    };
+
+    /** 选中子选项 */
+    const selectChildTag = (columnIndex: number, index: number) => {
+      const oldActiveItem =
+        data.tagChildren[columnIndex].list[
+          data.tagChildren[columnIndex].activeIndex
+        ];
+      const activeItem = data.tagChildren[columnIndex].list[index];
+      if (oldActiveItem && oldActiveItem.id !== activeItem.id) {
+        forms.musicTagIds = forms.musicTagIds.filter(
+          item => item !== oldActiveItem.id
+        );
+      }
+      if (forms.musicTagIds.includes(activeItem.id)) {
+        forms.musicTagIds = forms.musicTagIds.filter(
+          item => item !== activeItem.id
+        );
+        data.tagChildren[columnIndex].activeIndex = -1;
+      } else {
+        forms.musicTagIds.push(activeItem.id);
+        data.tagChildren[columnIndex].activeIndex = index;
+      }
+      getList();
+    };
     return () => (
       <div class={styles.container}>
         <div class={styles.tools}>
@@ -62,7 +119,13 @@ export default defineComponent({
                 {data.tags.map((item: any, index: number) => {
                   return (
                     <>
-                      <NButton round secondary type={'default'}>
+                      <NButton
+                        round
+                        secondary
+                        type={
+                          data.tagActiveId === item.id ? 'primary' : 'default'
+                        }
+                        onClick={() => changeTag(item, index)}>
                         {item.name}
                       </NButton>
                     </>
@@ -70,37 +133,83 @@ export default defineComponent({
                 })}
               </NSpace>
             </div>
-          </div>
-          <TheSearch round />
-        </div>
-        {/* <div class={styles.content}>
-          <NSpace size={[50, 40]}>
-            {data.list.map((item, index) => {
+
+            {data.tagChildren.map((column: any, columnIndex: number) => {
               return (
-                <div
-                  class={styles.item}
-                  key={`item-${index}`}
-                  onClick={() => router.push({ path: '/xiaoku-music' })}>
-                  <div class={styles.cover}>
-                    <div class={styles.itemImg}>
-                      <div class={styles.itemBg}></div>
-                      <NImage
-                        objectFit="cover"
-                        src={item.src}
-                        lazy
-                        previewDisabled={true}
-                        onLoad={e => {
-                          (e.target as any).dataset.loaded = 'true';
-                        }}
-                      />
-                    </div>
-                  </div>
-                  <div class={styles.itemName}>{item.name}</div>
+                <div class={styles.tags}>
+                  <NSpace size={[24, 12]}>
+                    <NButton quaternary disabled>
+                      {column.columnName}
+                    </NButton>
+
+                    {column.list.map((item: any, index: number) => {
+                      return (
+                        <>
+                          <NButton
+                            round
+                            secondary
+                            type={
+                              column.activeIndex === index
+                                ? 'primary'
+                                : 'default'
+                            }
+                            onClick={() => selectChildTag(columnIndex, index)}>
+                            {item.name}
+                          </NButton>
+                        </>
+                      );
+                    })}
+                  </NSpace>
                 </div>
               );
             })}
-          </NSpace>
-        </div> */}
+          </div>
+          <TheSearch
+            round
+            onSearch={val => {
+              forms.keyword = val;
+              getList();
+            }}
+          />
+        </div>
+        <NSpin show={data.loading}>
+          <div class={styles.content}>
+            <NSpace size={[50, 40]}>
+              {data.list.map((item: any, index: number) => {
+                return (
+                  <div
+                    class={styles.item}
+                    key={`item-${index}`}
+                    onClick={() =>
+                      router.push({
+                        path: '/xiaoku-music',
+                        query: {
+                          id: item.id,
+                          name: item.name
+                        }
+                      })
+                    }>
+                    <div class={styles.cover}>
+                      <div class={styles.itemImg}>
+                        <div class={styles.itemBg}></div>
+                        <NImage
+                          objectFit="cover"
+                          src={item.coverImg}
+                          lazy
+                          previewDisabled={true}
+                          onLoad={e => {
+                            (e.target as any).dataset.loaded = 'true';
+                          }}
+                        />
+                      </div>
+                    </div>
+                    <div class={styles.itemName}>{item.name}</div>
+                  </div>
+                );
+              })}
+            </NSpace>
+          </div>
+        </NSpin>
       </div>
     );
   }

+ 0 - 124
src/views/xiaoku-ai/mock.json

@@ -1,124 +0,0 @@
-{
-    "list": [
-        {
-            "name": "一年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879396909941.png"
-        },
-        {
-            "name": "一年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397066202.png"
-        },
-        {
-            "name": "一年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399237211.png"
-        },
-        {
-            "name": "一年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399268072.png"
-        },
-        {
-            "name": "二年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397152383.png"
-        },
-        {
-            "name": "二年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397257464.png"
-        },
-        {
-            "name": "三年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397333805.png"
-        },
-        {
-            "name": "三年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397403546.png"
-        },
-        {
-            "name": "四年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397449747.png"
-        },
-        {
-            "name": "四年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397477658.png"
-        },
-        {
-            "name": "三年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399375956.png"
-        },
-        {
-            "name": "四年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399407587.png"
-        },
-        {
-            "name": "四年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399431318.png"
-        },
-        {
-            "name": "五年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399462639.png"
-        },
-        {
-            "name": "五年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879397501719.png"
-        },
-        {
-            "name": "五年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793975222810.png"
-        },
-        {
-            "name": "六年级上册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793975447311.png"
-        },
-        {
-            "name": "六年级下册(简谱)",
-            "category": "1",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793975664712.png"
-        },
-        {
-            "name": "二年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399291733.png"
-        },
-        {
-            "name": "二年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399318924.png"
-        },
-        {
-            "name": "三年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/16879399348525.png"
-        },
-        {
-            "name": "五年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793994852610.png"
-        },
-        {
-            "name": "六年级上册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793995083811.png"
-        },
-        {
-            "name": "六年级下册",
-            "category": "2",
-            "src": "https://daya.ks3-cn-beijing.ksyuncs.com/168793995297612.png"
-        }
-    ]
-}

+ 1 - 3
src/views/xiaoku-music/component/play-item/index.tsx

@@ -15,8 +15,6 @@ import icon_next from '../../images/icon_next.svg';
 import icon_play from '../../images/icon_play.svg';
 import icon_pause from '../../images/icon_pause.svg';
 import { getSecondRPM } from '/src/utils';
-import icon_favitor from '/src/common/images/icon-collect-default.png';
-import icon_favitorActive from '/src/common/images/icon-collect-active.png';
 import TheNoticeBar from '/src/components/TheNoticeBar';
 
 export default defineComponent({
@@ -173,7 +171,7 @@ export default defineComponent({
             <div class={styles.time}>{time.value}</div>
             <audio
               ref={audioRef}
-              src={props.item.audioFileUrl}
+              src={props.item.audioFileUrl || props.item.metronomeUrl}
               onLoadedmetadata={onLoadedmetadata}
               onTimeupdate={() => {
                 if (timer) return;

+ 45 - 12
src/views/xiaoku-music/index.module.less

@@ -1,4 +1,6 @@
 .container {
+    display: flex;
+    flex-direction: column;
     height: 100%;
 
     :global {
@@ -33,6 +35,7 @@
 
     &> :global(.n-space) {
         height: 36Px;
+        flex-shrink: 0;
     }
 
     .separator {
@@ -43,11 +46,15 @@
 
 .wrap {
     padding-top: 20Px;
-    height: calc(100% - 36Px);
+    flex: 1;
+    transition: padding .3s;
+    overflow: hidden;
 }
 
 .content {
-    height: calc(100% - 20Px);
+    display: flex;
+    flex-direction: column;
+    height: 100%;
     background: #DDF2FF;
     border-radius: 20Px;
 }
@@ -58,10 +65,6 @@
     align-items: center;
     flex-shrink: 0;
 
-    .tags {
-        margin-right: 15Px;
-    }
-
     :global {
         .n-input {
             margin-left: auto;
@@ -71,10 +74,10 @@
 }
 
 .contentWrap {
-    height: calc(100% - 82Px);
+    flex: 1;
     display: flex;
     padding: 0 20Px 20Px;
-    transition: padding .3s;
+    overflow: hidden;
 }
 
 .musicList {
@@ -92,9 +95,29 @@
     .wrapList {
         width: 512px;
         min-width: 294Px;
+        min-height: 300Px;
         background: #fff;
         border-radius: 16Px;
-        padding: 8Px;
+    }
+
+    .empty {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        min-height: 300Px;
+    }
+}
+
+.itemContainer {
+    border-radius: 16Px;
+    padding: 4Px 8Px;
+
+    &:first-child {
+        padding-top: 8Px;
+    }
+
+    &:last-child {
+        padding-bottom: 8Px;
     }
 }
 
@@ -103,8 +126,8 @@
     display: flex;
     align-items: center;
     padding: 10Px;
-    margin: 4Px 0;
     border-radius: 12Px;
+
     cursor: pointer;
 
     &:hover {
@@ -152,6 +175,7 @@
         display: flex;
         flex-direction: column;
         align-items: flex-start;
+
         .titleName {
             font-size: 16Px;
             font-weight: 600;
@@ -183,6 +207,7 @@
         flex-shrink: 0;
         min-width: 62Px;
         min-height: 30Px;
+
         :global {
             .n-button__content {
                 &>img {
@@ -199,12 +224,19 @@
         transform: translate(124%, -50%);
         opacity: 0;
     }
-    .showPlayLoading{
+
+    .showPlayLoading {
         opacity: 0;
     }
 
 }
 
+.loadingWrap {
+    display: flex;
+    justify-content: center;
+    min-height: 80Px;
+}
+
 .musicStaff {
     display: flex;
     flex-direction: column;
@@ -239,7 +271,8 @@
         height: 48px;
         cursor: pointer;
         transition: all .3s;
-        &:hover{
+
+        &:hover {
             transform: scale(1.1);
         }
 

+ 176 - 84
src/views/xiaoku-music/index.tsx

@@ -3,7 +3,10 @@ import {
   TransitionGroup,
   computed,
   defineComponent,
-  reactive
+  nextTick,
+  onMounted,
+  reactive,
+  ref
 } from 'vue';
 import styles from './index.module.less';
 import icon_back from './images/icon_back.svg';
@@ -12,11 +15,12 @@ import {
   NBreadcrumb,
   NBreadcrumbItem,
   NButton,
+  NEmpty,
   NImage,
-  NSpace
+  NSpace,
+  NSpin
 } from 'naive-ui';
 import TheSearch from '/src/components/TheSearch';
-import listData from './data.json';
 import { IMusicItem } from './type';
 import icon_arrow from './images/icon_arrow.svg';
 import icon_play from './images/icon_play.svg';
@@ -24,30 +28,89 @@ import icon_pause from './images/icon_pause.svg';
 import icon_goXiaoku from './images/icon_goXiaoku.svg';
 import icon_favitor from '/src/common/images/icon-collect-default.png';
 import icon_favitorActive from '/src/common/images/icon-collect-active.png';
-import { useRouter } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 import PlayItem from './component/play-item';
 import PlayLoading from './component/play-loading';
 import TheNoticeBar from '/src/components/TheNoticeBar';
+import { api_musicSheetPage, api_subjectList } from '../xiaoku-ai/api';
 
 export default defineComponent({
   name: 'XiaokuMusic',
   setup() {
+    const route = useRoute();
     const router = useRouter();
+    const forms = reactive({
+      page: 1,
+      rows: 20,
+      status: true,
+      keyword: '' // 关键词
+      // musicSheetCategoriesId: route.query.id || ''
+    });
     const data = reactive({
-      tags: [
-        { name: '全部', id: 0 },
-        { name: '竖笛', id: 1 },
-        { name: '排箫', id: 2 },
-        { name: '口风琴', id: 3 },
-        { name: '陶笛', id: 4 },
-        { name: '葫芦丝', id: 5 }
-      ],
+      loading: false,
+      finshed: false,
+      reshing: false,
+      tags: [] as any[],
       tagIndex: 0,
-      list: listData.rows as unknown as IMusicItem[],
+      list: [] as unknown as IMusicItem[],
       listActive: 0,
       playState: 'pause' as 'play' | 'pause',
       showPlayer: false
     });
+    const getSubjects = async () => {
+      const res = await api_subjectList();
+      if (Array.isArray(res?.data)) {
+        data.tags = [{ name: '全部', id: 0 }, ...res.data];
+      }
+    };
+    const getList = async () => {
+      data.loading = true;
+      let res = {} as any;
+      try {
+        res = await api_musicSheetPage({
+          ...forms,
+          musicSubject: data.tagIndex ? data.tagIndex : ''
+        });
+      } catch (error) {
+        console.log(error);
+      }
+      if (data.reshing) {
+        data.list = [];
+        data.reshing = false;
+      }
+      if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
+        data.list = [...data.list, ...res.data.rows];
+        data.finshed = res.data.rows.length < forms.rows;
+        console.log('🚀 ~ data.finshed:', data.finshed);
+      }
+      data.loading = false;
+    };
+
+    const handleGetList = () => {
+      forms.page = 1;
+      data.finshed = false;
+      getList();
+    };
+    const spinRef = ref();
+    const handleResh = () => {
+      console.log(data.finshed);
+      if (data.loading || data.finshed) return;
+      forms.page = forms.page + 1;
+      getList();
+    };
+
+    onMounted(async () => {
+      getSubjects();
+      await getList();
+      const obv = new IntersectionObserver(entries => {
+        if (entries[0].intersectionRatio > 0) {
+          handleResh();
+        }
+      });
+      nextTick(() => {
+        obv.observe(spinRef.value);
+      });
+    });
 
     /** 改变模仿的曲谱 */
     const handleChange = (item: IMusicItem) => {
@@ -114,90 +177,115 @@ export default defineComponent({
               曲谱列表
             </NBreadcrumbItem>
             <img class={styles.separator} src={icon_separator} />
-            <NBreadcrumbItem>一年级上册人教版(2013版)</NBreadcrumbItem>
+            <NBreadcrumbItem>{route.query.name}</NBreadcrumbItem>
           </NBreadcrumb>
         </NSpace>
-        <div class={styles.wrap}>
+        <div
+          class={styles.wrap}
+          style={{ paddingBottom: data.showPlayer ? '108Px' : '' }}>
           <div class={styles.content}>
             <div class={styles.tools}>
-              <div class={styles.tags}>
-                <NSpace size={[24, 12]} wrap={false}>
-                  {data.tags.map((item, index) => (
-                    <NButton
-                      round
-                      textColor={data.tagIndex === index ? '#fff' : '#000'}
-                      color={data.tagIndex === index ? '#198CFE' : '#fff'}
-                      onClick={() => (data.tagIndex = index)}>
-                      {item.name}
-                    </NButton>
-                  ))}
-                </NSpace>
-              </div>
-              <TheSearch round />
+              <NSpace
+                style={{ width: '100%' }}
+                size={[24, 12]}
+                wrapItem={false}>
+                {data.tags.map(item => (
+                  <NButton
+                    round
+                    textColor={data.tagIndex === item.id ? '#fff' : '#000'}
+                    color={data.tagIndex === item.id ? '#198CFE' : '#fff'}
+                    onClick={() => {
+                      data.tagIndex = item.id;
+                      data.reshing = true;
+                      handleGetList();
+                    }}>
+                    {item.name}
+                  </NButton>
+                ))}
+              </NSpace>
+              <TheSearch
+                style={{ marginLeft: 'auto' }}
+                round
+                onSearch={val => {
+                  forms.keyword = val;
+                  data.reshing = true;
+                  handleGetList();
+                }}
+              />
             </div>
 
-            <div
-              class={styles.contentWrap}
-              style={{ paddingBottom: data.showPlayer ? '90px' : '' }}>
+            <div class={styles.contentWrap}>
               <div class={styles.musicList}>
                 <div class={styles.wrapList}>
                   {data.list.map((item: IMusicItem, index) => {
                     return (
-                      <div
-                        class={[
-                          styles.item,
-                          data.listActive === index && styles.active
-                        ]}
-                        onClick={() => handleChange(item)}>
-                        <div class={styles.img}>
-                          <NImage
-                            lazy
-                            objectFit="cover"
-                            previewDisabled={true}
-                            src={item.titleImg}
-                            onLoad={e => {
-                              (e.target as any).dataset.loaded = 'true';
-                            }}
-                          />
-                          <PlayLoading
-                            class={[
-                              data.listActive === index &&
-                              data.playState === 'play'
-                                ? ''
-                                : styles.showPlayLoading
-                            ]}
-                          />
-                        </div>
-                        <div class={styles.title}>
-                          <div class={styles.titleName}>
-                            <TheNoticeBar text={item.musicSheetName} />
+                      <div class={styles.itemContainer}>
+                        <div
+                          class={[
+                            styles.item,
+                            data.listActive === index && styles.active
+                          ]}
+                          onClick={() => handleChange(item)}>
+                          <div class={styles.img}>
+                            <NImage
+                              lazy
+                              objectFit="cover"
+                              previewDisabled={true}
+                              src={item.titleImg}
+                              onLoad={e => {
+                                (e.target as any).dataset.loaded = 'true';
+                              }}
+                            />
+                            <PlayLoading
+                              class={[
+                                data.listActive === index &&
+                                data.playState === 'play'
+                                  ? ''
+                                  : styles.showPlayLoading
+                              ]}
+                            />
+                          </div>
+                          <div class={styles.title}>
+                            <div class={styles.titleName}>
+                              <TheNoticeBar text={item.musicSheetName} />
+                            </div>
+                            <div class={styles.titleDes}>{item.composer}</div>
                           </div>
-                          <div class={styles.titleDes}>{item.composer}</div>
+                          <NButton
+                            color="#259CFE"
+                            textColor="#fff"
+                            round
+                            class={styles.btn}
+                            type="primary"
+                            onClick={(e: Event) => {
+                              e.stopPropagation();
+                              handlePlay(item);
+                            }}>
+                            试听
+                            <img
+                              src={
+                                data.listActive === index &&
+                                data.playState === 'play'
+                                  ? icon_pause
+                                  : icon_play
+                              }
+                            />
+                          </NButton>
+                          <img class={styles.arrow} src={icon_arrow} />
                         </div>
-                        <NButton
-                          color="#259CFE"
-                          textColor="#fff"
-                          round
-                          class={styles.btn}
-                          type="primary"
-                          onClick={(e: Event) => {
-                            e.stopPropagation();
-                            handlePlay(item);
-                          }}>
-                          试听
-                          <img
-                            src={
-                              data.listActive === index &&
-                              data.playState === 'play'
-                                ? icon_pause
-                                : icon_play
-                            }
-                          />
-                        </NButton>
-                        <img class={styles.arrow} src={icon_arrow} />
                       </div>
                     );
                   })}
+                  {!data.finshed && (
+                    <div ref={spinRef} class={styles.loadingWrap}>
+                      <NSpin show={true}></NSpin>
+                    </div>
+                  )}
+                  {!data.loading && data.list.length === 0 && (
+                    <div class={styles.empty}>
+                      <NEmpty />
+                    </div>
+                  )}
                 </div>
               </div>
 
@@ -206,18 +294,22 @@ export default defineComponent({
                   {activeItem.value.musicSheetName}
                 </div>
                 <img
+                  style={{ display: activeItem.value.id ? '' : 'none' }}
                   class={styles.goBtn}
                   src={icon_goXiaoku}
                   onClick={() => {
                     handleChangeAudio('pause');
                     const origin = /(localhost|192)/.test(location.host)
-                      ? 'https://dev.kt.colexiu.com'
+                      ? 'https://test.lexiaoya.cn'
                       : location.origin;
                     const src = `${origin}/instrument?platform=pc&id=${activeItem.value.id}`;
                     window.open(src);
                   }}
                 />
-                <div class={styles.favitor} onClick={() => handleFavitor()}>
+                <div
+                  style={{ display: activeItem.value.id ? '' : 'none' }}
+                  class={styles.favitor}
+                  onClick={() => handleFavitor()}>
                   <Transition name="favitor" mode="out-in">
                     {activeItem.value.delFlag ? (
                       <img src={icon_favitorActive} key="1" />

+ 2 - 0
src/views/xiaoku-music/type.ts

@@ -5,6 +5,8 @@ export interface IMusicItem {
   composer: string;
   titleImg: string;
   audioFileUrl: string;
+  /** 伴奏 */
+  metronomeUrl: string;
   /** 首调 */
   firstTone: string;
   delFlag: boolean;