Skip to content

Commit

Permalink
feat: add search Result Page
Browse files Browse the repository at this point in the history
  • Loading branch information
uniquemo committed May 6, 2020
1 parent e0010aa commit f2cf52f
Show file tree
Hide file tree
Showing 17 changed files with 376 additions and 8 deletions.
21 changes: 19 additions & 2 deletions src/apis/search.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import axios from 'helpers/axios'
import { ISearchHot, ISearchSuggestRequest, ISearchSuggestResponse } from './types/search'
import { ISearchHot, ISearchSuggestRequest, ISearchSuggestResponse, ISearchRequest, SEARCH_TYPE } from './types/search'

type SearchHotFn = () => Promise<ISearchHot[]>
type SearchSuggestFn = (params: ISearchSuggestRequest) => Promise<ISearchSuggestResponse>
type SearchFn = (params: ISearchRequest) => Promise<any>

const searchHot: SearchHotFn = async () => {
const response = await axios({
Expand All @@ -25,7 +26,23 @@ const searchSuggest: SearchSuggestFn = async ({ keywords }) => {
return response.result
}

const search: SearchFn = async ({ keywords, type = SEARCH_TYPE.MUSIC, limit = 30, offset = 0 }) => {
const response = await axios({
method: 'get',
url: '/search',
params: {
keywords,
type,
limit,
offset
}
})

return response.result
}

export default {
searchHot,
searchSuggest
searchSuggest,
search
}
12 changes: 6 additions & 6 deletions src/apis/types/business.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ export interface IMusic {
album: IAlbum,
alias: string[],
artists: IArtist[],
copyrightId: number,
copyrightId?: number,
duration: number,
fee: number,
ftype: number,
fee?: number,
ftype?: number,
id: number,
mark: number,
mvid: number,
mark?: number,
mvid?: number,
name: string,
status: number
status?: number
}
20 changes: 20 additions & 0 deletions src/apis/types/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,23 @@ export interface ISearchSuggestResponse {
mvs: IMV[],
songs: IMusic[]
}

// 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频
export enum SEARCH_TYPE {
MUSIC = 1,
ALBUM = 10,
ARTIST = 100,
SONG_LIST = 1000,
USER = 1002,
MV = 1004,
LYRIC = 1006,
BROADCASTING_STATION = 1009,
VIDEO = 1014
}

export interface ISearchRequest {
keywords: string,
type?: SEARCH_TYPE,
limit?: number,
offset?: number
}
4 changes: 4 additions & 0 deletions src/components/Layout/Header/Searcher/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { Icon } from '@blueprintjs/core'
import { useHistory } from 'react-router-dom'
import cn from 'classnames'

import Words from './Words'
Expand All @@ -8,11 +9,13 @@ import useAsyncFn from 'hooks/useAsyncFn'
import searchApis from 'apis/search'
import { setSearchHistory, getSearchHistory } from 'helpers/search'
import { debounce } from 'helpers/fn'
import ROUTES from 'constants/routes'
import styles from './style.module.css'

const { useEffect, useState, useMemo } = React

const Searcher = () => {
const history = useHistory()
const [showResult, setShowResult] = useState(false)
const [keyword, setKeyword] = useState('')
const [state, searchHotFn] = useAsyncFn(searchApis.searchHot)
Expand All @@ -34,6 +37,7 @@ const Searcher = () => {

const handleInputKeyPress = async (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
history.push(`${ROUTES.SEARCH}?keyword=${keyword}`)
setSearchHistory(keyword)
}
}
Expand Down
72 changes: 72 additions & 0 deletions src/components/MusicList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react'
import { Icon } from '@blueprintjs/core'

import Table, { IColumn } from 'components/Table'
import { IMusic, IArtist, IAlbum } from 'apis/types/business'
import { formatTime } from 'helpers/time'
import styles from './style.module.css'

interface IProps {
data: IMusic[]
}

const columns: IColumn<IMusic, keyof IMusic>[] = [
{
title: '',
key: 'name',
width: '100px',
render: (name: string, record: IMusic, index?: number) => {
return (
<div className={styles.operations}>
<span className={styles.index}>{(index || 0) + 1}</span>
<Icon icon='heart' iconSize={14} />
<Icon icon='import' iconSize={14} />
</div>
)
}
},
{
title: '音乐标题',
key: 'name',
width: '45%',
render: (name: string, { alias }: IMusic) => {
return (
<>
<div>{name}</div>
{alias?.length ? <div className={styles.alias}>{alias.join(' ')}</div> : null}
</>
)
}
},
{
title: '歌手',
key: 'artists',
width: '15%',
render: (artists: IArtist[]) => artists?.map(({ name }) => name).join(' / ')
},
{
title: '专辑',
key: 'album',
width: '15%',
render: (album: IAlbum) => album?.name
},
{
title: '时长',
key: 'duration',
width: '10%',
render: (duration: number) => formatTime(duration / 1000)
}
]

const MusicList: React.FC<IProps> = ({ data }) => {
return (
<div>
<Table<IMusic>
columns={columns}
data={data}
/>
</div>
)
}

export default MusicList
28 changes: 28 additions & 0 deletions src/components/MusicList/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@value colors: "~styles/colors.module.css";
@value tipsColor, tipsHoverColor from colors;

.alias {
margin-top: 10px;
color: tipsColor;
}

.operations {
display: flex;
justify-content: space-between;
padding-right: 10px;
color: tipsColor;

.index {
width: 40px;
margin-right: 6px;
text-align: right;
}

span:nth-child(2), span:nth-child(3) {
cursor: pointer;

&:hover {
color: tipsHoverColor;
}
}
}
38 changes: 38 additions & 0 deletions src/components/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { ReactElement } from 'react'

import styles from './style.module.css'

export interface IColumn<RecordType, Key extends keyof RecordType> {
title?: string,
key: Key,
width?: string,
render: (value: any, record: RecordType, index?: number) => string | ReactElement
}

interface IProps<RecordType> {
columns: IColumn<RecordType, keyof RecordType>[],
data: RecordType[]
}

function Table<RecordType extends object = any>({ columns, data }: IProps<RecordType>) {
return (
<div className={styles.root}>
<div className={styles.header}>
{columns.map(({ title, key, width }, index) => {
return <div key={index} style={{ width }}>{title}</div>
})}
</div>
<div className={styles.content}>
{data?.map((item, index) => {
return <div className={styles.row} key={index}>
{columns.map(({ key, width, render }, idx) => {
return <div key={idx} style={{ width }}>{render(item[key], item, index)}</div>
})}
</div>
})}
</div>
</div>
)
}

export default Table
27 changes: 27 additions & 0 deletions src/components/Table/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@value colors: "~styles/colors.module.css";
@value tipsHoverColor, bgColor from colors;

.root {
font-size: 0.9em;
}

.header {
display: flex;
padding: 10px 0;
color: tipsHoverColor;
}

.content {
.row {
display: flex;
padding: 10px 0;
}

.row:nth-child(2n) {
background-color: #fafafa;
}

.row:hover {
background-color: bgColor;
}
}
3 changes: 3 additions & 0 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const VIDEOS: string = '/videos'
const VIDEO: string = `${VIDEOS}/video`
const MV: string = `${VIDEOS}/mv`

const SEARCH: string = '/search'

const DOWNLOAD: string = '/download'
const CLOUD: string = '/cloud'
const COLLECTION: string = '/collection'
Expand All @@ -29,6 +31,7 @@ const ROUTES = {
VIDEOS,
VIDEO,
MV,
SEARCH,
DOWNLOAD,
CLOUD,
COLLECTION
Expand Down
19 changes: 19 additions & 0 deletions src/hooks/useQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useLocation } from 'react-router-dom'

const useQuery = () => {
const { search } = useLocation()
const result: IDictionary<string> = {}

search
.substr(1)
.split('&')
.reduce((prev, curr) => {
const [key, value] = curr.split('=')
prev[key] = decodeURIComponent(value)
return prev
}, result)

return result
}

export default useQuery
3 changes: 3 additions & 0 deletions src/pages/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import Layout from 'components/Layout'
import Discovery from './Discovery'
import Videos from './Videos'
import Search from './Search'

import ROUTES from 'constants/routes'
import playMusicReducer, {
initialState,
Expand All @@ -26,6 +28,7 @@ const App = () => {
<Switch>
<Route path={ROUTES.DISCOVERY} component={Discovery} />
<Route path={ROUTES.VIDEOS} component={Videos} />
<Route exact path={ROUTES.SEARCH} component={Search} />
<Redirect from={ROUTES.ROOT} to={ROUTES.DEFAULT_ROUTE} />
</Switch>
</Layout>
Expand Down
19 changes: 19 additions & 0 deletions src/pages/Search/MusicList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'

import MusicListBase from 'components/MusicList'
import { IMusic } from 'apis/types/business'

interface IProps {
data: IMusic[],
total: number
}

const MusicList: React.FC<IProps> = ({ data, total }) => {
return (
<div>
<MusicListBase data={data} />
</div>
)
}

export default MusicList

0 comments on commit f2cf52f

Please sign in to comment.