Skip to content

Commit a8e11bd

Browse files
committed
feat: add MusciDetail component, comment, simi songlist, simi songs logic
1 parent a4d1c1d commit a8e11bd

31 files changed

Lines changed: 1118 additions & 57 deletions

src/apis/comment.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import axios from 'helpers/axios'
2+
3+
enum COMMENT_TYPE {
4+
MUSIC = 0,
5+
MV = 1,
6+
SONGLIST = 2,
7+
ALBUM = 3,
8+
RADIO_STATION = 4,
9+
VIDEO = 5
10+
}
11+
12+
interface ILikeUnlikeCommentRequest {
13+
likeOrUnlike: number,
14+
type?: COMMENT_TYPE,
15+
id: number,
16+
commentId: number
17+
}
18+
19+
type Params = Omit<ILikeUnlikeCommentRequest, 'likeOrUnlike'>
20+
21+
type LikeUnlikeCommentFn = (params: ILikeUnlikeCommentRequest) => Promise<any>
22+
type LikeCommentFn = (params: Params, callback?: Function) => Promise<any>
23+
type UnlikeCommentFn = (params: Params, callback?: Function) => Promise<any>
24+
25+
const likeUnlikeComment: LikeUnlikeCommentFn = async ({ likeOrUnlike, type, id, commentId }) => {
26+
const response = await axios({
27+
method: 'get',
28+
url: '/comment/like',
29+
params: {
30+
id,
31+
type,
32+
t: likeOrUnlike,
33+
cid: commentId
34+
}
35+
})
36+
return response
37+
}
38+
39+
const likeComment: LikeCommentFn = async ({ id, commentId, type = COMMENT_TYPE.MUSIC }) => {
40+
const response = await likeUnlikeComment({
41+
likeOrUnlike: 1,
42+
type,
43+
id,
44+
commentId
45+
})
46+
return response
47+
}
48+
49+
const unlikeComment: UnlikeCommentFn = async ({ id, commentId, type = COMMENT_TYPE.MUSIC }) => {
50+
const response = await likeUnlikeComment({
51+
likeOrUnlike: 2,
52+
type,
53+
id,
54+
commentId
55+
})
56+
return response
57+
}
58+
59+
export default {
60+
likeUnlikeComment,
61+
likeComment,
62+
unlikeComment
63+
}

src/apis/song.ts

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import axios from 'helpers/axios'
2-
import { IMyMusic, IMusic } from 'apis/types/business'
2+
import { IMyMusic, IMusic, ISonglist } from 'apis/types/business'
3+
import { IComment } from 'apis/types/comment'
34

45
export enum SONG_TYPE {
56
ALL = 0,
@@ -9,9 +10,30 @@ export enum SONG_TYPE {
910
KOREAN = 16
1011
}
1112

13+
interface IParams {
14+
id: number,
15+
offset?: number,
16+
limit?: number
17+
}
18+
19+
interface IGetCommentsResponse {
20+
comments: IComment[],
21+
hotComments?: IComment[],
22+
isMusician: boolean,
23+
more: boolean,
24+
moreHot: boolean,
25+
topComments: IComment[],
26+
total: number,
27+
userId: number
28+
}
29+
1230
type GetSongDetailFn = (ids: number[]) => Promise<any>
1331
type GetTopSongsFn = (type?: SONG_TYPE) => Promise<IMyMusic[]>
1432
type GetRecommendSongsFn = () => Promise<IMusic[]>
33+
type GetSimiSonglistFn = (params: IParams) => Promise<ISonglist[]>
34+
type GetgetSimiSongFn = (params: IParams) => Promise<IMusic[]>
35+
type GetCommentsFn = (params: IParams) => Promise<IGetCommentsResponse>
36+
type GetgetLyricFn = (id: number) => Promise<any>
1537

1638
const getSongDetail: GetSongDetailFn = async (ids) => {
1739
const response = await axios({
@@ -46,8 +68,66 @@ const getRecommendSongs: GetRecommendSongsFn = async () => {
4668
return response.recommend
4769
}
4870

71+
const getSimiSonglist: GetSimiSonglistFn = async ({ id, offset, limit }) => {
72+
const response = await axios({
73+
method: 'get',
74+
url: '/simi/playlist',
75+
params: {
76+
id,
77+
offset,
78+
limit
79+
}
80+
})
81+
82+
return response.playlists
83+
}
84+
85+
const getSimiSong: GetgetSimiSongFn = async ({ id, offset, limit }) => {
86+
const response = await axios({
87+
method: 'get',
88+
url: '/simi/song',
89+
params: {
90+
id,
91+
offset,
92+
limit
93+
}
94+
})
95+
96+
return response.songs
97+
}
98+
99+
const getComments: GetCommentsFn = async ({ id, offset, limit }) => {
100+
const response = await axios({
101+
method: 'get',
102+
url: '/comment/music',
103+
params: {
104+
id,
105+
offset,
106+
limit
107+
}
108+
})
109+
110+
return response
111+
}
112+
113+
const getLyric: GetgetLyricFn = async (id) => {
114+
const response = await axios({
115+
method: 'get',
116+
url: '/lyric',
117+
params: {
118+
id
119+
}
120+
})
121+
122+
return response
123+
}
124+
49125
export default {
50126
getSongDetail,
51127
getTopSongs,
52-
getRecommendSongs
128+
getRecommendSongs,
129+
getSimiSonglist,
130+
getSimiSong,
131+
getComments,
132+
getLyric
53133
}

src/apis/types/comment.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export interface IUser {
2+
anonym: number,
3+
authStatus: number,
4+
avatarUrl: string,
5+
nickname: string,
6+
userId: number,
7+
userType: number,
8+
vipType: number
9+
}
10+
11+
export interface IReply {
12+
beRepliedCommentId: number,
13+
content: string,
14+
status: number,
15+
user: IUser
16+
}
17+
18+
export interface IComment {
19+
beReplied: IReply[],
20+
commentId: number,
21+
commentLocationType: number,
22+
content: string,
23+
liked: boolean,
24+
likedCount: number,
25+
parentCommentId: number,
26+
status: number,
27+
time: number,
28+
user: IUser
29+
}

src/assets/image/play-bar.png

26.5 KB
Loading

src/assets/image/play-cd.png

9.45 KB
Loading

src/components/Comment/index.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react'
2+
import { Icon } from '@blueprintjs/core'
3+
import cn from 'classnames'
4+
5+
import { IComment } from 'apis/types/comment'
6+
import { formatDatetime } from 'helpers/time'
7+
import styles from './style.module.css'
8+
9+
interface IProps {
10+
data: IComment,
11+
onLikeChange: (comment: IComment) => void
12+
}
13+
14+
const Comment: React.FC<IProps> = ({ data, onLikeChange }) => {
15+
const { user, content, beReplied, time, likedCount, liked } = data
16+
17+
const likeUnlike = async () => {
18+
await onLikeChange(data)
19+
}
20+
21+
return (
22+
<div className={styles.root}>
23+
<div className={styles.avatar}>
24+
<img src={`${user.avatarUrl}?param=35y35`} loading='lazy' />
25+
</div>
26+
27+
<div className={styles.info}>
28+
<div className={styles.comment}>
29+
<span className={styles.nickname}>{user.nickname}: </span>
30+
<span>{content}</span>
31+
</div>
32+
33+
<div className={styles.reply}>
34+
{beReplied.map(({ content, user }, index) => {
35+
return (
36+
<div className={styles.item} key={index}>
37+
<span className={styles.nickname}>{user.nickname}: </span>
38+
<span>{content}</span>
39+
</div>
40+
)
41+
})}
42+
</div>
43+
44+
<div className={styles.others}>
45+
<div className={styles.time}>
46+
{formatDatetime(time, true)}
47+
</div>
48+
<div className={styles.operations}>
49+
<div className={cn(styles.like, liked && 'active')} onClick={likeUnlike}>
50+
<Icon icon='thumbs-up' iconSize={14} />&nbsp;
51+
{!!likedCount && <span>{likedCount}</span>}
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
</div>
57+
)
58+
}
59+
60+
export default Comment
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
@value colors: "~styles/colors.module.css";
2+
@value blue, tipsHoverColor from colors;
3+
4+
.root {
5+
display: flex;
6+
}
7+
8+
.avatar {
9+
width: 35px;
10+
height: 35px;
11+
margin-right: 20px;
12+
background-color: rgba(0, 0, 0, 0.5);
13+
border-radius: 50%;
14+
15+
img {
16+
border-radius: 50%;
17+
}
18+
}
19+
20+
.info {
21+
flex: 1;
22+
padding-bottom: 10px;
23+
margin-bottom: 10px;
24+
border-bottom: 1px solid #ededed;
25+
26+
.comment {
27+
margin-bottom: 8px;
28+
font-size: 0.95em;
29+
}
30+
31+
.reply {
32+
margin-bottom: 10px;
33+
font-size: 0.9em;
34+
.item {
35+
width: 100%;
36+
padding: 8px 10px;
37+
border-radius: 3px;
38+
background-color: #f0f0f0;
39+
}
40+
}
41+
42+
.nickname {
43+
color: blue;
44+
}
45+
46+
.others {
47+
display: flex;
48+
align-items: center;
49+
justify-content: space-between;
50+
font-size: 0.9em;
51+
color: tipsHoverColor;
52+
53+
.operations {
54+
display: flex;
55+
56+
.like {
57+
display: flex;
58+
align-items: center;
59+
cursor: pointer;
60+
}
61+
}
62+
}
63+
}

src/components/Layout/Footer/index.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import { Icon, Tooltip } from '@blueprintjs/core'
3+
import cn from 'classnames'
34

45
import Artists from 'components/Artists'
56
import AudioTimer from './AudioTimer'
@@ -8,18 +9,31 @@ import PlayRecord from './PlayRecord'
89
import PlayMode from './PlayMode'
910
import PlayOperations from './PlayOperations'
1011
import PlayVolume from './PlayVolume'
11-
import { PlayMusicStateContext } from 'reducers/playMusic'
12+
import { PlayMusicStateContext, PlayMusicDispatchContext, ACTIONS } from 'reducers/playMusic'
1213
import styles from './style.module.css'
1314

1415
const { useContext, useState } = React
1516

1617
const Footer = () => {
1718
const [showPlayRecord, setShowPlayRecord] = useState(false)
19+
const dispatch = useContext(PlayMusicDispatchContext)
1820
const state = useContext(PlayMusicStateContext)
19-
const { musicId, music } = state
21+
const { musicId, music, showLyric } = state
2022

2123
const togglePlayRecord = () => setShowPlayRecord(!showPlayRecord)
2224

25+
const handleShowLyric = () => {
26+
dispatch({
27+
type: ACTIONS.SHOW_LYRIC
28+
})
29+
}
30+
31+
const handleHideLyric = () => {
32+
dispatch({
33+
type: ACTIONS.HIDE_LYRIC
34+
})
35+
}
36+
2337
return (
2438
<div className={styles.root}>
2539
{musicId ? (
@@ -29,7 +43,15 @@ const Footer = () => {
2943
) : null}
3044

3145
<div className={styles.songWrap}>
32-
<img src={music?.picUrl ? `${music?.picUrl}?param=40y40` : undefined} loading='lazy' />
46+
<div className={cn(styles.pic, !showLyric && styles.showLyric)}>
47+
<img src={music?.picUrl ? `${music?.picUrl}?param=40y40` : undefined} loading='lazy' />
48+
{!showLyric && <div className={styles.mask} onClick={handleShowLyric}>
49+
<Icon icon='double-chevron-up' />
50+
</div>}
51+
{showLyric && <div className={cn(styles.mask, styles.hideLyric)} onClick={handleHideLyric}>
52+
<Icon icon='double-chevron-down' />
53+
</div>}
54+
</div>
3355
<div>
3456
<div className={styles.info}>
3557
<div className={styles.name}>{`${music?.name || '--'} -`}</div>

0 commit comments

Comments
 (0)