ソースを参照

拆分playlist前

xiang 3 週間 前
コミット
370116ce3c

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "axios": "^1.10.0",
     "classnames": "^2.5.1",
     "crypto-js": "^4.2.0",
+    "dayjs": "^1.11.19",
     "dplayer": "^1.27.1",
     "echarts": "^6.0.0",
     "normalize.css": "^8.0.1",

+ 10 - 7
pnpm-lock.yaml

@@ -26,6 +26,9 @@ importers:
       crypto-js:
         specifier: ^4.2.0
         version: 4.2.0
+      dayjs:
+        specifier: ^1.11.19
+        version: 1.11.19
       dplayer:
         specifier: ^1.27.1
         version: 1.27.1
@@ -858,8 +861,8 @@ packages:
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
-  dayjs@1.11.13:
-    resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+  dayjs@1.11.19:
+    resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
 
   debug@4.4.1:
     resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
@@ -2423,7 +2426,7 @@ snapshots:
       '@rc-component/trigger': 2.2.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       classnames: 2.5.1
       copy-to-clipboard: 3.3.3
-      dayjs: 1.11.13
+      dayjs: 1.11.19
       rc-cascader: 3.34.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-checkbox: 3.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-collapse: 3.9.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -2439,7 +2442,7 @@ snapshots:
       rc-motion: 2.9.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-notification: 5.6.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-pagination: 5.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
-      rc-picker: 4.11.3(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+      rc-picker: 4.11.3(dayjs@1.11.19)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-progress: 4.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-rate: 2.13.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
       rc-resize-observer: 1.4.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -2557,7 +2560,7 @@ snapshots:
 
   csstype@3.1.3: {}
 
-  dayjs@1.11.13: {}
+  dayjs@1.11.19: {}
 
   debug@4.4.1:
     dependencies:
@@ -3119,7 +3122,7 @@ snapshots:
       react: 19.1.0
       react-dom: 19.1.0(react@19.1.0)
 
-  rc-picker@4.11.3(dayjs@1.11.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+  rc-picker@4.11.3(dayjs@1.11.19)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
     dependencies:
       '@babel/runtime': 7.27.6
       '@rc-component/trigger': 2.2.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -3130,7 +3133,7 @@ snapshots:
       react: 19.1.0
       react-dom: 19.1.0(react@19.1.0)
     optionalDependencies:
-      dayjs: 1.11.13
+      dayjs: 1.11.19
 
   rc-progress@4.0.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
     dependencies:

+ 1 - 3
src/apis/album.ts

@@ -6,9 +6,7 @@ export const albumAddapi = (data: any) => {
 export const albumQueryapi = (id: number) => {
   return request.get('/album/list', { params: { id: id } })
 }
-export const getSongListApi = (data: any) => {
-  return request.post(`/song/list`, data)
-}
+
 export const albumdetailapi = (id: number) => {
   return request.get('/album/listDetail', { params: { id: id } })
 }

+ 3 - 7
src/apis/login.ts

@@ -12,20 +12,16 @@ export type loginResType = {
 export const loginByPasswordApi = (data: loginType) => {
   // 添加固定参数
   const params = new URLSearchParams({
-    client_id: 'XcWebApp',
-    client_secret: 'XcWebApp',
+    client_id: 'wyMusic',
+    client_secret: 'wyMusic',
     grant_type: 'password',
     username: JSON.stringify({
       ...data,
       authType: 'password'
     })
-  });
-
-  // 将参数作为查询字符串发送,而不是请求体
-  // 明确指定返回类型为 loginResType 而不是 AxiosResponse<loginResType>
+  })
   return request.post<loginResType>(`/oauth/token?${params.toString()}`);
 }
-// 在 src/apis/login.ts 中添加以下代码
 export const loginByWechat = (data: { code: string; state: string }) => {
   return request.post<loginResType>(`/auth/wxLogin`, data);
 }

+ 4 - 1
src/apis/musician.ts

@@ -1,9 +1,12 @@
 import { request } from "@/utils"
-export const applyMusicianApis = (data:any) => {
+export const applyMusicianApis = (data: any) => {
   return request.post('/artist/apply', data)
 }
 
 
 export const applyMusicianStatusApis = () => {
   return request.get('/artist/status')
+}
+export const applicationInfo = (userId) => {
+  return request.get('/artist/application-info', { params: { userId } })
 }

+ 12 - 0
src/apis/payList.ts

@@ -0,0 +1,12 @@
+import { request } from "@/utils"
+export const addplayList = (data: any) => {
+  return request.post('/playlist/add', data)
+}
+
+export const getPaylistApi = () => {
+  return request.get('/playlist/list')
+}
+
+export const getPayListDetail = (id: number) => {
+  return request.get('/playlist/payListDetail', { params: { id } })
+}

+ 9 - 2
src/apis/song.ts

@@ -3,9 +3,16 @@ export const songAddapi = (data: any) => {
   return request.post('/song/add', data)
 }
 
+export const getSongListApi = (data: any) => {
+  return request.post(`/song/list`, data)
+}
 export const songQueryapi = () => {
   return request.get('/song/list')
 }
-export const deleteSongApi = (id:number) => {
-  return request.get('/song/delete',{params:{id}})
+export const deleteSongApi = (id: number) => {
+  return request.get('/song/delete', { params: { id } })
 }
+
+export const songUpdateApi = (id, status) => {
+  return request.put('/song/updateSongStatus', { id, status })
+}

+ 3 - 0
src/apis/wlyrics.ts

@@ -1,4 +1,7 @@
 import { request } from "@/utils"
 export const getwlyrics = (data) => {
   return request.post(`/content/getlyric`, data)
+}
+export const auditLyrici = (id, status, value) => {
+  return request.post(`/content/audit`, { id, status, value })
 }

+ 1 - 1
src/pages/layout/components/LoginContent/components/AuthCallback.tsx

@@ -47,7 +47,7 @@ const AuthCallback = () => {
       loginByGitee({ code, state }).then(async response => {
         if (response) {
           setToken(response);
-          setUserinfo(response.access_token)
+          setUserinfo(response.user_info)
           setLoginStatus('success');
           window.dispatchEvent(new CustomEvent('user-info-updated'));
           startCountdown("/find/recommend"); // 登录成功,开始倒计时跳转到首页

+ 5 - 3
src/pages/layout/components/LoginContent/index.tsx

@@ -21,7 +21,7 @@ import { useNavigate } from 'react-router-dom';
 import { loginByPasswordApi, type loginResType } from '@/apis/login';
 import type { loginType } from '@/type/login';
 import { loginByWechat } from '@/apis/login';
-import { setToken, setUserinfo as setUserInfoUtil } from '@/utils';
+import { setToken, setUserinfo } from '@/utils';
 import GiteeLogin from '@/pages/layout/components/LoginContent/components/GiteeLogin';
 import './index.css'
 interface LoginContentProps {
@@ -67,9 +67,10 @@ const LoginContent: React.FC<LoginContentProps> = ({
   const LoginByPassword: FormProps<loginType>['onFinish'] = async (values) => {
     try {
       const res = await loginByPasswordApi(values);
+      console.log(res);
       if (res && res.access_token) {
         setToken(res);
-        setUserInfoUtil(res.access_token);
+        setUserinfo(res.user_info);
         onLoginSuccess?.();
       } else {
         console.log('登录失败');
@@ -174,8 +175,9 @@ const LoginContent: React.FC<LoginContentProps> = ({
       const res: loginResType = response.data;
 
       if (res && res.access_token) {
+        console.log(res);
         setToken(res);
-        setUserInfoUtil(res.access_token);
+        setUserinfo(res.user_info);
         setType(0);
         onLoginSuccess?.();
         window.dispatchEvent(new CustomEvent('user-info-updated'));

+ 7 - 4
src/pages/layout/components/Wy_Content/index.tsx

@@ -1,10 +1,13 @@
 import { Outlet } from 'react-router-dom'
 import './index.css'
-const Wy_Content=()=>{
+
+const Wy_Content = () => {
   return (
-  <div>
-      <Outlet />
-  </div>
+    <div>
+
+        <Outlet />
+
+    </div>
   )
 }
 

+ 138 - 54
src/pages/layout/pages/mine/index.tsx

@@ -1,41 +1,41 @@
 import './index.css'
-import React, { useState, useEffect } from 'react';
-import { Menu } from 'antd';
+import { useState, useEffect } from 'react';
+import { Button, Checkbox, Flex, Image, Input, Menu, Modal } from 'antd';
 import type { MenuProps } from 'antd';
-import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons';
+import { AppstoreOutlined, MailOutlined, PlusOutlined, SettingOutlined } from '@ant-design/icons';
 import { Outlet, useNavigate } from 'react-router-dom';
-
-// 定义菜单项类型
+import { message } from 'antd';
+import { addplayList, getPaylistApi } from '@/apis/payList';
 type MenuItem = Required<MenuProps>['items'][number];
-
-// 模拟API请求获取歌单数据
-const fetchPlaylists = async () => {
-  // 这里应该是真实的API调用
-  return [
-    { id: '1', name: '我喜欢的音乐', count: 906 },
-    { id: '2', name: '2025、8、21', count: 19 },
-    { id: '3', name: 'dj', count: 55 },
-    { id: '4', name: '奥斯卡', count: 35 },
-    { id: '5', name: '131313', count: 4 },
-  ];
-};
 const fetchCollectionists = async () => {
-  // 这里应该是真实的API调用
   return [
     { id: '6', name: '我喜欢的音乐', count: 906 },
     { id: '7', name: '2025、8、21', count: 19 },
     { id: '8', name: 'dj', count: 55 },
     { id: '9', name: '奥斯卡', count: 35 },
     { id: '10', name: '131313', count: 4 },
-  ];
-};
-// 构建菜单项数据
+  ]
+}
 const Mine = () => {
-  const navigate = useNavigate();
-  const [selectedKey, setSelectedKey] = useState('artist');
-  const [playlists, setPlaylists] = useState<any[]>([]);
-  const [collectonList, setCollectonList] = useState<any[]>([]);
-  const [loading, setLoading] = useState(true);
+  const navigate = useNavigate()
+  const [selectedKey, setSelectedKey] = useState('artist')
+  const [playlists, setPlaylists] = useState<any[]>([])
+  const [collectonList, setCollectonList] = useState<any[]>([])
+  const [loading, setLoading] = useState(true)
+  const [isModalOpen, setIsModalOpen] = useState(false)
+  const [payName, setPayName] = useState('')
+  const [messageApi, contextHolder] = message.useMessage()
+  const [checked, setChecked] = useState(false)
+  const showModal = () => {
+    setIsModalOpen(true);
+  };
+
+
+
+  const handleCancel = () => {
+    setIsModalOpen(false);
+  };
+
   // 标题映射对象
   const titleMap = {
     artist: '我的歌手',
@@ -44,28 +44,57 @@ const Mine = () => {
     playlist: '新建创建的歌单',
     collection: '收藏的歌单'
   };
+  const loadPlaylists = async () => {
+    try {
+      setLoading(true);
+      const res = await getPaylistApi();
+      setPlaylists(res.data);
+      const data1 = await fetchCollectionists();
+      setCollectonList(data1);
+    } catch (error) {
+      console.error('获取歌单失败:', error);
+    } finally {
+      setLoading(false);
+    }
+  };
   // 获取歌单数据
   useEffect(() => {
-    const loadPlaylists = async () => {
-      try {
-        setLoading(true);
-        const data = await fetchPlaylists();
-        setPlaylists(data);
-        const data1 = await fetchCollectionists();
-        setCollectonList(data1);
-      } catch (error) {
-        console.error('获取歌单失败:', error);
-      } finally {
-        setLoading(false);
-      }
-    };
+
 
     loadPlaylists();
   }, []);
-
+  const handleOk = async () => {
+    if (payName === '') {
+      // 提示用户输入歌单名称
+      messageApi.open({
+        type: 'error',
+        content: '请输入歌单名',
+      });
+      return;
+    }
+    const res = await addplayList({ playlistName: payName, status: checked })
+    console.log(res)
+    if (res.code != 200) {
+      messageApi.open({
+        type: 'error',
+        content: res.message,
+      });
+    }
+    setChecked(false)
+    setPayName('')
+    setIsModalOpen(false)
+    console.log(payName)
+    messageApi.open({
+      type: 'success',
+      content: '歌单创建成功',
+    });
+    loadPlaylists()
+  };
   // 处理菜单项点击事件
-  const onClick: MenuProps['onClick'] = ({ key }) => {
-    console.log(key);
+  const onClick: MenuProps['onClick'] = (e) => {
+    const { key } = e;
+
+    console.log(e);
 
     setSelectedKey(key);
 
@@ -75,26 +104,32 @@ const Mine = () => {
       return;
     }
 
-
-    if (key === 'playlist' || key === 'collection') {
-      navigate(`/mine/playlist`);
-      return;
-    }
     navigate(`/mine/${key}`);
   };
 
   // 构建动态菜单项
   const buildPlaylistItems = (value) => {
     if (loading) {
-      return [{ key: 'loading', label: '加载中...' }];
+      return [{
+        key: `loading-${Math.random().toString(36).substr(2, 9)}`,
+        label: '加载中...'
+      }];
     }
-
     return value.map(playlist => ({
       key: `playlist-${playlist.id}`,
       label: (
-        <div>
-          <span>{playlist.name}</span>
-          <span style={{ fontSize: '12px', color: '#999' }}>{playlist.count}首</span>
+        <div style={{ display: 'flex', alignItems: 'center', padding: '8px 0' }}>
+          <div style={{ marginRight: 12 }}>
+            <Image preview={false} width={40} height={40} src={playlist.coverUrl || 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'} />
+          </div>
+          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
+            <div style={{ fontSize: 14, lineHeight: 1.5, whiteSpace: 'nowrap' }}>
+              {playlist.playlistName}
+            </div>
+            <div style={{ color: '#999', fontSize: 12, lineHeight: 1.5 }}>
+              {playlist.songCount}首
+            </div>
+          </div>
         </div>
       ),
     }));
@@ -119,7 +154,23 @@ const Mine = () => {
     {
       key: 'playlist',
       icon: <MailOutlined />,
-      label: '新建创建的歌单',
+      label: (
+        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
+          <span>创建的歌单</span>
+          <Button
+            type="link"
+            icon={<PlusOutlined />}
+            onClick={(e) => {
+              e.stopPropagation();
+              showModal()
+            }}
+            style={{ margin: 0, width: '80px', height: '30px', marginLeft: '10px', padding: '5px' }}
+            color="primary" variant="outlined"
+          >
+            新建
+          </Button>
+        </div>
+      ),
       children: buildPlaylistItems(playlists),
     },
     {
@@ -133,6 +184,7 @@ const Mine = () => {
 
   return (
     <div className='Mine'>
+      {contextHolder}
       <div className='Mine_tabs'>
         <Menu
           mode="inline"
@@ -145,11 +197,43 @@ const Mine = () => {
       <div className='Mine_Content'>
         {/* 动态标题 */}
         <div className='Mine_Content_title'>
-          {titleMap[selectedKey] || '我的歌手'}
+          {titleMap[selectedKey]}
         </div>
         <div className='Mine_Content_hr' />
         <Outlet />
       </div>
+      <Modal
+        title="新建歌单"
+        closable
+        open={isModalOpen}
+        onOk={handleOk}
+        onCancel={handleCancel}
+        width={500}
+        centered
+        destroyOnHidden
+        cancelText={"取消"}
+        okText={"确定"}
+      >
+        <div style={{ padding: '20px 0' }}>
+          <div style={{ marginBottom: '24px' }}>
+            <label style={{ display: 'inline-block', width: '60px', verticalAlign: 'middle', marginRight: '10px' }}>
+              歌单名:
+            </label>
+            <Input onChange={(e) => setPayName(e.target.value)} value={payName} placeholder="请输入歌单名称" style={{ width: '300px' }} />
+            <Checkbox style={{ paddingLeft: 10 }} onChange={(e) => {
+              setChecked(e.target.checked); console.log(e.target.checked);
+            }}>公开</Checkbox>
+          </div>
+          <p style={{
+            color: '#999',
+            fontSize: '12px',
+            textAlign: 'center',
+            marginBottom: '0'
+          }}>
+            可通过"收藏"将音乐添加到新歌单中
+          </p>
+        </div>
+      </Modal>
     </div>
   );
 };

+ 154 - 83
src/pages/layout/pages/mine/playlist/index.tsx

@@ -1,93 +1,161 @@
-// src/pages/layout/pages/mine/playlist/index.tsx
 import React, { useState, useEffect } from 'react';
 import { useParams } from 'react-router-dom';
-import './index.css'; // 假设使用 less 样式文件
-
-interface Song {
-  id: string;
-  name: string;
-  artist: string;
-  duration: string;
-  album: string;
-}
+import './index.css';
+import { getPayListDetail } from '@/apis/payList';
+import { Image, Spin } from 'antd';
+import { LoadingOutlined } from '@ant-design/icons';
 
+// 定义API返回的数据结构
 interface Playlist {
-  id: string;
-  name: string;
-  cover: string;
-  description: string;
-  creator: string;
+  id: number;
+  userId: number;
+  playlistName: string;
+  coverUrl: string | null;
+  description: string | null;
+  tag: string | null;
+  songCount: number;
+  playCount: number;
   createTime: string;
+  updateTime: string;
+  status: boolean;
+}
+
+interface Song {
+  id: number;
+  songName: string;
+  artistId: number;
+  albumId: number | null;
+  duration: number;
+  fileUrl: string;
+  coverUrl: string;
+  releaseTime: string;
+  lyrics: string;
   playCount: number;
+  isPaid: number;
+  price: number;
+  createTime: string;
+  updateTime: string;
+  status: number;
+  auditReason: string | null;
+  auditTime: string | null;
+  publishTime: string | null;
+  shelfTime: string | null;
+  offShelfTime: string | null;
+  deleteFlag: number;
+  deleteTime: string | null;
+  songType: string | null;
+  version: string | null;
+  workType: string | null;
+  genre: string | null;
+  language: string | null;
+  lyricist: string | null;
+  composer: string | null;
+  arranger: string | null;
+  singerName: string | null;
+}
+
+interface PlaylistData {
+  playlist: Playlist;
   songs: Song[];
 }
 
 const Mine_Playlist = () => {
-  const { id } = useParams<{ id: string }>(); // 获取路由参数
-  const [playlist, setPlaylist] = useState<Playlist | null>(null);
+  const { id } = useParams<{ id: string }>();
+  const [playlistData, setPlaylistData] = useState<PlaylistData | null>(null);
   const [loading, setLoading] = useState(true);
+  const [error, setError] = useState<string | null>(null);
 
-  // 模拟请求歌单详情
-  const fetchPlaylistDetails = async (playlistId: string) => {
-    try {
-      setLoading(true);
-
-      // 模拟从 API 获取数据(实际项目中替换为 axios 或 fetch)
-      const mockData: Playlist = {
-        id: playlistId,
-        name: '我喜欢的音乐',
-        cover: '	https://p1.music.126.net/viEFZrxTnTWkXweF5TdbyQ==/109951164281883574.jpg?param=200y200', // 替换为真实封面 URL
-        description: '我的收藏歌单',
-        creator: '生活在经验里_q',
-        createTime: '2017-04-02',
-        playCount: 2258,
-        songs: [
-          { id: '1', name: '拉个勾说永远爱我', artist: 'DJ', duration: '03:08', album: '经典过时了吗' },
-          { id: '2', name: '半点心', artist: '草蜢', duration: '03:52', album: '潘源良二五精神永不忘' },
-          { id: '3', name: '美丽的神话 - (Endless Love 2)', artist: '孙楠/韩红', duration: '04:52', album: '忘不了你' },
-          { id: '4', name: '全是爱', artist: '凤凰传奇', duration: '04:14', album: '最炫民族风' },
-          { id: '5', name: '路边的野花不要采', artist: '邓丽君', duration: '02:03', album: '世纪10星 - 难忘篇' },
-          { id: '6', name: 'Gimme! Gimme! Gimme! (A Man After Midnight)', artist: 'ABBA', duration: '04:49', album: 'ABBA Gold: Greatest Hits' },
-          { id: '7', name: '为你我受冷风吹', artist: '林忆莲', duration: '04:19', album: 'Love, Sandy' },
-          { id: '8', name: 'Old Time Rock and Roll', artist: 'Bob Seger', duration: '03:14', album: 'Stranger in Town' },
-          { id: '9', name: '别看我只是一只羊(喜羊羊与灰太狼)动画片主题曲', artist: '古倩敏', duration: '02:44', album: '喜羊羊与灰太狼' },
-          { id: '10', name: '你是我的玫瑰花', artist: '庞龙', duration: '03:49', album: '你是我的玫瑰花' },
-          { id: '11', name: '快乐女孩 - (动画《甜心格格》主题曲)', artist: '刘惜君', duration: '02:55', album: '快乐女孩' },
-        ],
-      };
-
-      setPlaylist(mockData);
-    } catch (error) {
-      console.error('获取歌单失败:', error);
-    } finally {
-      setLoading(false);
-    }
+  // 格式化时间为 YYYY-MM-DD 格式
+  const formatDate = (dateString: string) => {
+    const date = new Date(dateString);
+    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
   };
 
+  // 将秒数转换为 mm:ss 格式
+  const formatDuration = (seconds: number) => {
+    const mins = Math.floor(seconds / 60);
+    const secs = seconds % 60;
+    return `${mins}:${secs.toString().padStart(2, '0')}`;
+  };
+
+  // 请求歌单详情
   useEffect(() => {
+    const fetchPlaylistDetails = async () => {
+      try {
+        setLoading(true);
+        setError(null);
+
+        if (!id) {
+          throw new Error('缺少歌单ID');
+        }
+
+        // 调用API获取真实数据
+        const response = await getPayListDetail(Number(id));
+
+        if (response.code === 200) {
+          // 直接使用返回的数据,不再需要解析JSON字符串
+          setPlaylistData(response.data);
+        } else {
+          throw new Error(response.message || '获取歌单失败');
+        }
+      } catch (err: any) {
+        console.error('获取歌单失败:', err);
+        setError(err.message || '获取歌单失败');
+      } finally {
+        setLoading(false);
+      }
+    };
+
     if (id) {
-      fetchPlaylistDetails(id);
+      fetchPlaylistDetails();
     }
   }, [id]);
 
   if (loading) {
-    return <div className="loading">加载中...</div>;
+    return (
+      <div className="loading" style={{
+        display: 'flex',
+        justifyContent: 'center',
+        alignItems: 'center',
+        height: '100vh',
+        width: '100vw',
+        position: 'fixed',
+        top: 0,
+        left: 0,
+        backgroundColor: 'rgba(255, 255, 255, 0.8)',
+        zIndex: 9999
+      }}>
+        <Spin indicator={<LoadingOutlined style={{ fontSize: 48 }} spin />} />
+      </div>
+    );
   }
 
-  if (!playlist) {
+  if (error) {
+    return <div className="error">错误: {error}</div>;
+  }
+
+  if (!playlistData || !playlistData.playlist) {
     return <div className="not-found">歌单不存在</div>;
   }
 
+  const { playlist, songs } = playlistData;
+
+  // 确保 songs 是数组,如果不是则默认为空数组
+  const validSongs = Array.isArray(songs) ? songs : [];
+
   return (
     <div className="playlist-page">
       {/* 歌单头部 */}
       <div className="playlist-header">
-        <img src={playlist.cover} alt="歌单封面" className="cover-img" />
+        <img
+          src={playlist.coverUrl || 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'}
+          alt={playlist.playlistName}
+          className="cover-img"
+        />
         <div className="playlist-info">
-          <h1>{playlist.name}</h1>
+          <h1>{playlist.playlistName}</h1>
           <div className="meta">
-            <span className="creator">{playlist.creator}</span>
-            <span className="create-time"> {playlist.createTime} 创建</span>
+            <span className="create-time"> {formatDate(playlist.createTime)} 创建</span>
           </div>
           <div className="actions">
             <button className="play-btn">播放</button>
@@ -104,31 +172,34 @@ const Mine_Playlist = () => {
       </div>
 
       {/* 歌曲列表 */}
-      <div className="song-list-container">
-        <div className="song-list-header">
-          <div className="song-number">序号</div>
-          <div className="song-title">歌曲标题</div>
-          <div className="song-duration">时长</div>
-          <div className="song-artist">歌手</div>
-          <div className="song-album">专辑</div>
-        </div>
+      {validSongs.length > 0 ? (
+        <div className="song-list-container">
+          <div className="song-list-header">
+            <div className="song-number">序号</div>
+            <div className="song-title">歌曲标题</div>
+            <div className="song-duration">时长</div>
+            <div className="song-artist">歌手</div>
+          </div>
 
-        <ul className="song-list">
-          {playlist?.songs.map((song, index) => (
-            <li key={song.id} className="song-item">
-              <div className="song-number">{index + 1}</div>
-              <div className="song-title">
-                <span className="play-icon">▶</span>
-                {song.name}
-                {song.album && <span className="album-tag">({song.album})</span>}
-              </div>
-              <div className="song-duration">{song.duration}</div>
-              <div className="song-artist">{song.artist}</div>
-              <div className="song-album">{song.album}</div>
-            </li>
-          ))}
-        </ul>
-      </div>
+          <ul className="song-list">
+            {validSongs.map((song, index) => (
+              <li key={song.id} className="song-item">
+                <div className="song-number">{index + 1}</div>
+                <div className="song-title">
+                  <span className="play-icon">▶</span>
+                  {song.songName}
+                </div>
+                <div className="song-duration">{formatDuration(song.duration)}</div>
+                <div className="song-artist">{song.singerName || '未知歌手'}</div>
+              </li>
+            ))}
+          </ul>
+        </div>
+      ) : (
+        <div>
+          <Image preview={false} src="http://117.72.120.45:9000/public/musician/playlist/songNull.png" />
+        </div>
+      )}
     </div>
   );
 };

+ 80 - 15
src/pages/layout/pages/musician/ApplyMusicianPage/index.tsx

@@ -4,11 +4,17 @@ import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
 import './index.css';
 import { uploadFile } from '@/apis/upload';
 import { applyMusicianApis } from '@/apis/musician';
-
+import { useState, useEffect } from 'react';
+import { applicationInfo } from '@/apis/musician';
+import { getUserinfo } from '@/utils';
+import dayjs from 'dayjs';
 const { TextArea } = Input;
 const { Option } = Select;
-
-const ApplyMusicianPage = () => {
+interface ApplyMusicianPageProps {
+  applyType?: number;
+}
+const ApplyMusicianPage: React.FC<ApplyMusicianPageProps> = ({ applyType }) => {
+  console.log(applyType);
   // 定义表单字段类型
   type FieldType = {
     artistName?: string;
@@ -34,11 +40,50 @@ const ApplyMusicianPage = () => {
     fanCount?: number;
     agreeTerms?: boolean;
   };
+  const [applicationData, setApplicationData] = useState<any>(null);
+  const [loadingData, setLoadingData] = useState<boolean>(true);
   const [messageApi, contextHolder] = message.useMessage();
-
+  const [loading, setLoading] = useState(false);
+  const userinfo = getUserinfo()
+  const [form] = Form.useForm()
+  useEffect(() => {
+    const fetchApplicationInfo = async () => {
+      try {
+        const id = userinfo.id
+        const res = await applicationInfo(id);
+        if (res.code === 200) {
+          setApplicationData(res.data);
+          // 数据获取成功后,使用 form.setFieldsValue 设置表单值
+          form.setFieldsValue({
+            ...res.data,
+            phone: userinfo?.phone,
+            // 关键:将生日字符串转换为 dayjs 对象
+            birthday: res.data.birthday ? dayjs(res.data.birthday) : null,
+          });
+        }
+      } catch (error) {
+        console.error('获取申请信息失败:', error);
+      } finally {
+        setLoadingData(false);
+      }
+    };
+
+    // 只有在重新申请时才需要获取之前的数据
+    if (applyType === 3) {
+      fetchApplicationInfo();
+    } else {
+      setLoadingData(false);
+      // 即使不获取历史数据,也要设置基本信息
+      form.setFieldsValue({
+        phone: userinfo?.phone,
+      });
+    }
+  }, [applyType, form]);
   const onFinish: (values: FieldType) => Promise<void> = async (values) => {
     console.log(values);
+    setLoading(true);
     const res = await applyMusicianApis(values);
+    setLoading(false);
     if (res.code === 200) {
       // 显示成功消息
       messageApi.open({
@@ -46,6 +91,9 @@ const ApplyMusicianPage = () => {
         content: '申请已提交',
       })
     }
+    setTimeout(() => {
+      window.location.reload();
+    }, 1500);
   };
 
   const onFinishFailed: (errorInfo: any) => void = (errorInfo) => {
@@ -77,7 +125,14 @@ const ApplyMusicianPage = () => {
   const refreshQRCode = () => {
     console.log('刷新二维码');
   };
-
+  if (loadingData) {
+    return (
+      <div className="musician-loading">
+        <div className="spinner"></div>
+        <p className="loading-text">正在加载申请信息...</p>
+      </div>
+    );
+  }
   return (
 
     <div className="musician_Mine">
@@ -94,17 +149,11 @@ const ApplyMusicianPage = () => {
       <div className="musician_title">
         <h1>音乐人实名认证</h1>
         <Form
+          form={form}
           name="artistRegistration"
           labelCol={{ span: 6 }}
           wrapperCol={{ span: 16 }}
           style={{ maxWidth: 800 }}
-          initialValues={{
-            remember: true,
-            gender: '男',
-            region: '中国',
-            genre: '流行',
-            phone: '147****2671',
-          }}
           onFinish={onFinish}
           onFinishFailed={onFinishFailed}
           autoComplete="off"
@@ -142,6 +191,12 @@ const ApplyMusicianPage = () => {
               onChange={handleAvatarChange}
               maxCount={1}
               accept=".jpg,.jpeg,.png"
+              fileList={applicationData?.avatar ? [{
+                uid: '-1',
+                name: 'avatar.png',
+                status: 'done',
+                url: applicationData.avatar,
+              }] : []}
             >
               <div>
                 <PlusOutlined />
@@ -173,6 +228,12 @@ const ApplyMusicianPage = () => {
               onChange={handleAvatarChange}
               maxCount={1}
               accept=".jpg,.jpeg,.png"
+              fileList={applicationData?.headerImage ? [{
+                uid: '-1',
+                name: 'header.png',
+                status: 'done',
+                url: applicationData.headerImage,
+              }] : []}
             >
               <div>
                 <UploadOutlined />
@@ -308,7 +369,6 @@ const ApplyMusicianPage = () => {
           <Form.Item<FieldType>
             label="身份认证"
             name="qrCode"
-            valuePropName="fileList"
             getValueFromEvent={(e) => {
               if (Array.isArray(e)) {
                 return e;
@@ -410,8 +470,13 @@ const ApplyMusicianPage = () => {
 
           {/* 提交按钮 */}
           <Form.Item wrapperCol={{ offset: 6, span: 16 }}>
-            <Button type="primary" htmlType="submit" style={{ width: '100%', backgroundColor: '#ff4d4f', borderColor: '#ff4d4f' }}>
-              提交申请
+            <Button
+              type="primary"
+              htmlType="submit"
+              loading={loading}
+              style={{ width: '100%', backgroundColor: '#ff4d4f', borderColor: '#ff4d4f' }}
+            >
+              {loading ? '提交中...' : applyType === 3 ? '重新提交' : '提交申请'}
             </Button>
           </Form.Item>
         </Form>

+ 11 - 3
src/pages/layout/pages/musician/MusicianDashboardPage/works/songup/index.tsx

@@ -50,7 +50,7 @@ const Songup = () => {
 
 
   const [submitLoading, setSubmitLoading] = useState(false);
-  
+
   // 文件上传处理
   const customUploadAvatar = async (options: any) => {
     const { file, onSuccess, onError, onProgress, data } = options
@@ -266,7 +266,8 @@ const Songup = () => {
       const submitValues = {
         ...values,
         coverUrl: coverUrl || values.cover_url,
-        artistId: artinfo.id
+        artistId: artinfo.id,
+        artistName: artinfo.artistName,
       };
       const res = await albumAddapi(submitValues)
       console.log(res);
@@ -682,7 +683,14 @@ const Songup = () => {
               </span>
             </div>
           </Form.Item>
-
+          {/* 编曲 */}
+          <Form.Item
+            label="歌词名"
+            name="lyricName"
+            rules={[{ required: true, message: '请输入歌词名' }]}
+          >
+            <Input placeholder="输入歌词名" onKeyDown={handleKeyDown} />
+          </Form.Item>
           {/* 歌词录入区域 */}
           <Form.Item label="歌词录入">
             <div className="lyrics-container">

+ 91 - 30
src/pages/layout/pages/musician/MusicianDashboardPage/works/wlyrics/index.tsx

@@ -2,7 +2,7 @@ import { Button, Drawer, Image, Table, Tabs, notification, Space } from 'antd';
 import './index.css';
 import { useEffect, useState } from 'react';
 import { getArtinfo } from '@/utils/artlist';
-import { getwlyrics } from '@/apis/wlyrics';
+import { auditLyrici, getwlyrics } from '@/apis/wlyrics';
 
 const Wlyrics = () => {
   const [lyrics, setLyrics] = useState<any[]>([]);
@@ -10,7 +10,7 @@ const Wlyrics = () => {
   const [openDrawer, setOpenDrawer] = useState(false);
   const [lyricStatus, setLyricStatus] = useState(0);
   const [api, contextHolder] = notification.useNotification();
-
+  const [value, setValue] = useState('');
   const lyricStatusContent = [
     { key: '0', label: '审核中' },
     { key: '1', label: '审核失败' },
@@ -32,7 +32,21 @@ const Wlyrics = () => {
     'acoustic': '原声版',
     'remix': '混音版'
   } as const;
-
+  const auditLyriciAPi = async (record, status, value) => {
+    const res = await auditLyrici(record.id, status, value)
+    if (res.code === 200) {
+      api.success({
+        message: '操作成功',
+        description: res.message
+      });
+      fetchLyrics()
+    } else {
+      api.error({
+        message: '操作失败',
+        description: res.message
+      });
+    }
+  }
   const lyricColumns = [
     {
       title: '语言',
@@ -73,7 +87,23 @@ const Wlyrics = () => {
           <Button size="small" onClick={() => showLyricDetail(record)}>
             查看详情
           </Button>
+          {(record.status === 2 || record.status === 4) && (
+            <Button size="small" onClick={() => auditLyriciAPi(record, 3, null)}>
+              上架
+            </Button>
+          )}
+          {record.status === 3 && (
+            <Button size="small" onClick={() => auditLyriciAPi(record, 4, null)}>
+              下架
+            </Button>
+          )}
+          {record.status === 1 && (
+            <Button size="small" onClick={() => showLyricDetail(record)}>
+              修改内容
+            </Button>
+          )}
         </Space>
+
       ),
     }
   ];
@@ -90,25 +120,29 @@ const Wlyrics = () => {
   const onClose = () => {
     setOpenDrawer(false);
   };
-
+  const fetchLyrics = async () => {
+    try {
+      const artistId = getArtinfo().id;
+      const res = await getwlyrics({ id: artistId, status: lyricStatus });
+      console.log(res);
+      setLyrics(res.data || []);
+    } catch (error) {
+      api.error({
+        message: '获取歌词列表失败',
+        description: error.message || '未知错误'
+      });
+    }
+  };
   useEffect(() => {
-    const fetchLyrics = async () => {
-      try {
-        const artistId = getArtinfo().id;
-        const res = await getwlyrics({ id: artistId, status: lyricStatus });
-        console.log(res);
-        setLyrics(res.data || []);
-      } catch (error) {
-        api.error({
-          message: '获取歌词列表失败',
-          description: error.message || '未知错误'
-        });
-      }
-    };
+
 
     fetchLyrics();
   }, [lyricStatus]);
-
+  useEffect(() => {
+    if (currentLyric) {
+      setValue(currentLyric.lyrics || '');
+    }
+  }, [currentLyric]);
   return (
     <div className="wlyrics-container">
       {contextHolder}
@@ -247,18 +281,45 @@ const Wlyrics = () => {
 
             <div className="detail-section">
               <h4>歌词内容</h4>
-              <div style={{
-                padding: 12,
-                backgroundColor: '#f5f5f5',
-                borderRadius: 4,
-                marginTop: 8,
-                maxHeight: 300,
-                overflowY: 'auto',
-                whiteSpace: 'pre-wrap',
-                fontFamily: 'monospace'
-              }}>
-                {currentLyric.lyrics || '暂无歌词'}
-              </div>
+              {currentLyric?.status === 1 ? (
+                <>
+                  <textarea
+                    value={value}
+                    onChange={(e) => setValue(e.target.value)}
+                    defaultValue={currentLyric.lyrics}
+                    style={{
+                      width: '95%',
+                      minHeight: 300,
+                      padding: 12,
+                      borderRadius: 4,
+                      border: '1px solid #d9d9d9',
+                      fontFamily: 'monospace',
+                      resize: 'vertical'
+                    }}
+                  />
+                  <div style={{ marginTop: 12, textAlign: 'right' }}>
+                    <Button
+                      type="primary"
+                      onClick={() => auditLyriciAPi(currentLyric, 0, value)}
+                    >
+                      提交修改
+                    </Button>
+                  </div>
+                </>
+              ) : (
+                <div style={{
+                  padding: 12,
+                  backgroundColor: '#f5f5f5',
+                  borderRadius: 4,
+                  marginTop: 8,
+                  maxHeight: 300,
+                  overflowY: 'auto',
+                  whiteSpace: 'pre-wrap',
+                  fontFamily: 'monospace'
+                }}>
+                  {currentLyric?.lyrics || '暂无歌词'}
+                </div>
+              )}
             </div>
           </div>
         )}

+ 58 - 27
src/pages/layout/pages/musician/MusicianDashboardPage/works/wsongs/index.tsx

@@ -5,21 +5,20 @@ import type { NotificationPlacement } from 'antd/es/notification/interface';
 import { useNavigate } from 'react-router-dom';
 import { getAlbumListApi } from '@/apis/wsongs';
 import { getArtinfo } from '@/utils/artlist';
-import { albumdetailapi, deleteAlbumApi, getSongListApi } from '@/apis/album';
+import { albumdetailapi, deleteAlbumApi } from '@/apis/album';
 import { PlayCircleOutlined, PauseCircleOutlined } from '@ant-design/icons';
-import { deleteSongApi } from '@/apis/song';
-
+import { deleteSongApi, getSongListApi, songUpdateApi } from '@/apis/song';
 const Wsongs = () => {
-  const navigate = useNavigate();
-  const [mode, setMode] = useState('1');
-  const [songStatus, setsongStatus] = useState(0);
+  const navigate = useNavigate()
+  const [mode, setMode] = useState('1')
+  const [songStatus, setsongStatus] = useState(0)
   // 修改 useState 添加数据存储
-  const [songs, setSongs] = useState<any[]>([]);
-  const [albums, setAlbums] = useState<any[]>([]);
-  const [songList, setSongList] = useState<any[]>([]);
-  const [playingSongId, setPlayingSongId] = useState<number | null>(null);
-  const [audioElement, setAudioElement] = useState<HTMLAudioElement | null>(null);
-
+  const [songs, setSongs] = useState<any[]>([])
+  const [albums, setAlbums] = useState<any[]>([])
+  const [songList, setSongList] = useState<any[]>([])
+  const [playingSongId, setPlayingSongId] = useState<number | null>(null)
+  const [audioElement, setAudioElement] = useState<HTMLAudioElement | null>(null)
+  const id = getArtinfo().id
   const handleModeChange = (e: RadioChangeEvent) => {
     setMode(e.target.value);
   };
@@ -58,7 +57,24 @@ const Wsongs = () => {
   //   }
   // };
 
-
+  const handleShelfAction = async (info, value) => {
+    const res = await songUpdateApi(info.id, value)
+    getSongListFun(id)
+    if (res.code === 200) {
+      notification.success({
+        message: '操作成功',
+        description: res.message,
+      });
+    } else {
+      notification.error({
+        message: '操作失败',
+        description: res.message,
+      });
+    }
+  }
+  const reapplyMusician = (value) => {
+    console.log(value);
+  }
   const [deleteSongId, setDeleteSongId] = useState<number>(null)
   const handleDelete = (record: any) => {
     setIsModalOpen(true);
@@ -94,7 +110,7 @@ const Wsongs = () => {
           2: '发布中',
           3: '已上架',
           4: '已下架'
-        };
+        }
         return statusMap[status] || '未知';
       }
     },
@@ -116,12 +132,26 @@ const Wsongs = () => {
       key: 'action',
       render: (_: any, record: any) => (
         <Space size="middle">
-          {/* <Button type="primary" size="small" onClick={() => handleEdit(record)}>
-            编辑
-          </Button> */}
-          <Button size="small" onClick={() => handleViewDetails(record)}>
-            查看详情
-          </Button>
+          {record.status === 0 && (
+            <Button size="small" onClick={() => handleViewDetails(record)}>
+              查看详情
+            </Button>
+          )}
+          {(record.status === 1) && (
+            <Button size="small" onClick={() => reapplyMusician(record)}>
+              重新申请
+            </Button>
+          )}
+          {(record.status === 2 || record.status === 4) && (
+            <Button size="small" onClick={() => handleShelfAction(record, 3)}>
+              上架
+            </Button>
+          )}
+          {record.status === 3 && (
+            <Button size="small" onClick={() => handleShelfAction(record, 4)}>
+              下架
+            </Button>
+          )}
           <Button danger size="small" onClick={() => handleDelete(record)}>
             删除
           </Button>
@@ -205,14 +235,16 @@ const Wsongs = () => {
       placement,
     });
   };
+  const getSongListFun = async (id) => {
+    const result = await getSongListApi({ id, status: songStatus });
+    setSongs(result.data || []);
+  }
   const handleOk = async () => {
     try {
       await deleteSongApi(deleteSongId);
       // 删除成功后重新获取数据
-      const id = getArtinfo().id;
       if (mode === '1') {
-        const result = await getSongListApi({ id, status: songStatus });
-        setSongs(result.data || []);
+        getSongListFun(id)
       }
       setIsModalOpen(false);
     } catch (error) {
@@ -226,13 +258,12 @@ const Wsongs = () => {
   // 修改 useEffect 中的数据获取逻辑
   useEffect(() => {
     const fetchData = async () => {
-      const id = getArtinfo().id
+
       console.log("获取数据 - mode:", mode, "songStatus:", songStatus);
 
       try {
         if (mode === '1') {
-          const result = await getSongListApi({ id, status: songStatus });
-          setSongs(result.data || []);
+          getSongListFun(id)
         } else {
           const result = await getAlbumListApi({ id, status: songStatus });
           setAlbums(result.data || []);
@@ -244,6 +275,7 @@ const Wsongs = () => {
 
     fetchData();
   }, [mode, songStatus]);
+
   //右边抽屉
   const [openalbum, setOpenalbum] = useState(false);
   const [currentRecord, setCurrentRecord] = useState<any>(null);
@@ -305,7 +337,6 @@ const Wsongs = () => {
     try {
       await deleteAlbumApi(DeleteAlbumId, IsDeleteAll);
       // 删除成功后重新获取数据
-      const id = getArtinfo().id;
       if (mode === '2') { // 专辑模式
         const result = await getAlbumListApi({ id, status: songStatus });
         setAlbums(result.data || []);

+ 10 - 7
src/pages/layout/pages/musician/index.tsx

@@ -8,9 +8,10 @@ import { setArtinfo } from '@/utils/artlist';
 const Musician = () => {
   const navigate = useNavigate();
   const [loading, setLoading] = useState(true);
-  const [userStatus, setUserStatus] = useState<'unlogged' | 'notApplied' | 'pending' | 'approved' | 'rejected' | 'frozen'>('unlogged');
+  const [userStatus, setUserStatus] = useState<'unlogged' | 'notApplied' | 'pending' | 'approved' | 'rejected' | 'frozen' | 'reapplying'>('unlogged');
   const [rejectReason, setRejectReason] = useState('');
   const [freezeReason, setFreezeReason] = useState('');
+
   useEffect(() => {
     const token = localStorage.getItem('token');
     if (!token) {
@@ -77,11 +78,13 @@ const Musician = () => {
     return null;
   }
 
-  if (userStatus === 'notApplied') {
+  else if (userStatus === 'notApplied') {
     return <ApplyMusicianPage />;
   }
-
-  if (userStatus === 'pending') {
+  else if (userStatus === 'reapplying') {
+    return <ApplyMusicianPage applyType={3} />;
+  }
+  else if (userStatus === 'pending') {
     return (
       <div className="status-page pending-page">
         <h2>申请审核中</h2>
@@ -90,7 +93,7 @@ const Musician = () => {
     );
   }
 
-  if (userStatus === 'rejected') {
+  else if (userStatus === 'rejected') {
     return (
       <div className="status-page rejected-page">
         <h2>申请被拒绝</h2>
@@ -101,14 +104,14 @@ const Musician = () => {
             <p>{rejectReason}</p>
           </div>
         )}
-        <button onClick={() => navigate('/musician/apply')}>
+        <button onClick={() => { setUserStatus("reapplying") }}>
           重新申请
         </button>
       </div>
     );
   }
 
-  if (userStatus === 'frozen') {
+  else if (userStatus === 'frozen') {
     return (
       <div className="status-page frozen-page">
         <h2>账号已冻结</h2>

+ 6 - 6
src/pages/layout/pages/testPage/index.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useRef, useEffect } from 'react';
+import React, { useState, useRef } from 'react';
 import AudioPlayer from 'react-h5-audio-player';
 import 'react-h5-audio-player/lib/styles.css';
 import './index.css';
@@ -23,7 +23,7 @@ const playlist: Song[] = [
     id: 1,
     title: '奇妙能力歌',
     artist: '陈粒',
-    url: 'https://music.163.com/song/media/outer/url?id=28539182.mp3',
+    url: 'http://117.72.120.45:9000/song-audio/1765437295748_123.mp3',
     cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
     duration: '03:18',
     album: '如也',
@@ -35,7 +35,7 @@ const playlist: Song[] = [
     id: 2,
     title: '南山南',
     artist: '马頔',
-    url: 'https://music.163.com/song/media/outer/url?id=28248294.mp3',
+    url: 'http://117.72.120.45:9000/song-audio/1765437295748_123.mp3',
     cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
     duration: '04:32',
     album: '孤岛',
@@ -47,7 +47,7 @@ const playlist: Song[] = [
     id: 3,
     title: '董小姐',
     artist: '宋冬野',
-    url: 'https://music.163.com/song/media/outer/url?id=26460053.mp3',
+    url: 'http://117.72.120.45:9000/song-audio/1765437295748_123.mp3',
     cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
     duration: '04:15',
     album: '摩登天空7',
@@ -59,7 +59,7 @@ const playlist: Song[] = [
     id: 4,
     title: '玫瑰',
     artist: '贰佰',
-    url: 'https://music.163.com/song/media/outer/url?id=28539183.mp3',
+    url: 'http://117.72.120.45:9000/song-audio/1765437295748_123.mp3',
     cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
     duration: '04:38',
     album: '玫瑰',
@@ -71,7 +71,7 @@ const playlist: Song[] = [
     id: 5,
     title: '理想三旬',
     artist: '陈鸿宇',
-    url: 'https://music.163.com/song/media/outer/url?id=407954569.mp3',
+    url: 'http://117.72.120.45:9000/song-audio/1765437295748_123.mp3',
     cover: 'https://p1.music.126.net/6y-UleORITEDbvrOLV0Q8A==/5639395138885805.jpg',
     duration: '04:26',
     album: '浓烟下的诗歌电台',

+ 3 - 19
src/utils/userinfo.ts

@@ -1,36 +1,20 @@
-// src/utils/userinfo.ts
 const USERINFO_KEY = 'userinfo'
 
-/**
- * 保存用户信息到本地存储
- * @param token 包含access_token的JWT令牌
- */
 function setUserinfo(token: string) {
   try {
-    // 解析JWT token获取用户信息
-    const base64Payload = token.split('.')[1]
-    const payload = JSON.parse(atob(base64Payload))
-    
-    // 解析username字段中的JSON字符串
-    const userData = JSON.parse(payload.user_name)   
-    localStorage.setItem(USERINFO_KEY, JSON.stringify(userData))
+    localStorage.setItem(USERINFO_KEY, JSON.stringify(token))
   } catch (error) {
     console.error('解析JWT token失败:', error)
   }
 }
 
-/**
- * 从本地存储获取用户信息
- * @returns 用户信息对象或null
- */
+
 function getUserinfo() {
   const data = localStorage.getItem(USERINFO_KEY)
   return data ? JSON.parse(data) : null
 }
 
-/**
- * 移除本地存储的用户信息
- */
+
 function removeUserinfo() {
   localStorage.removeItem(USERINFO_KEY)
 }