|
@@ -1,79 +1,186 @@
|
|
|
import React, { Component } from 'react';
|
|
|
import './index.less';
|
|
|
import { Icon } from 'antd';
|
|
|
+import { Link } from 'react-router-dom';
|
|
|
import Page from '@src/containers/Page';
|
|
|
+import { getMap, formatPercent, formatSeconds } from '@src/services/Tools';
|
|
|
import Button from '../../../components/Button';
|
|
|
import Tabs from '../../../components/Tabs';
|
|
|
import UserAction from '../../../components/UserAction';
|
|
|
import UserPagination from '../../../components/UserPagination';
|
|
|
|
|
|
+import { refreshQuestionType, refreshStruct } from '../index';
|
|
|
+import { User } from '../../../stores/user';
|
|
|
+import { Question } from '../../../stores/question';
|
|
|
+
|
|
|
+import { QuestionType, QuestionDifficult } from '../../../../Constant';
|
|
|
+import { My } from '../../../stores/my';
|
|
|
+
|
|
|
+const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
|
|
|
+// const QuestionDifficultMap = getMap(QuestionDifficult, 'value', 'label');
|
|
|
+
|
|
|
export default class extends Page {
|
|
|
initState() {
|
|
|
+ this.searchNo = 0;
|
|
|
return {
|
|
|
- list: [{}, {}, {}],
|
|
|
- searchList: [123, 123, 123],
|
|
|
- historyList: [321, 321, 321],
|
|
|
- searchValue: '',
|
|
|
- search: false,
|
|
|
- tab: '1',
|
|
|
+ list: [],
|
|
|
+ searchList: [],
|
|
|
+ keyword: '',
|
|
|
+ subject: 'verbal',
|
|
|
filterMap: {},
|
|
|
sortMap: {},
|
|
|
focus: false,
|
|
|
+ difficultSelect: QuestionDifficult.map(row => {
|
|
|
+ return {
|
|
|
+ title: row.label,
|
|
|
+ key: row.value,
|
|
|
+ };
|
|
|
+ }),
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- onTabChange(tab) {
|
|
|
- this.setState({ tab });
|
|
|
+ initData() {
|
|
|
+ const data = Object.assign(this.state, this.state.search);
|
|
|
+ data.filterMap = this.state.search;
|
|
|
+ if (data.order) {
|
|
|
+ data.sortMap = { [data.order]: data.direction };
|
|
|
+ }
|
|
|
+ if (data.subject) {
|
|
|
+ data.filterMap.subject = data.subject;
|
|
|
+ }
|
|
|
+ this.setState(data);
|
|
|
+ refreshQuestionType(this, data.subject, data.questionType, { needSentence: false, allSubject: true, excludeAwa: true })
|
|
|
+ .then(({ questionTypes }) => {
|
|
|
+ return refreshStruct(this, 'exercise', data.one, data.two, {
|
|
|
+ all: true,
|
|
|
+ }).then(({ structIds }) => {
|
|
|
+ Question.searchStem(
|
|
|
+ Object.assign(
|
|
|
+ { questionTypes, structIds, module: 'exercise' },
|
|
|
+ this.state.search,
|
|
|
+ {
|
|
|
+ order: Object.keys(data.sortMap)
|
|
|
+ .map(key => {
|
|
|
+ return `${key} ${data.sortMap[key]}`;
|
|
|
+ })
|
|
|
+ .join(','),
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ).then(result => {
|
|
|
+ this.setState({ list: result.list, total: result.total, page: data.page, searchResult: !!data.keyword });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ onRefreshFilter(query) {
|
|
|
+ // this.changeQuery(query);
|
|
|
+ // this.setState(query);
|
|
|
+ this.refreshQuery(query);
|
|
|
+ // this.initData();
|
|
|
+ }
|
|
|
+
|
|
|
+ onFilter(value) {
|
|
|
+ this.search(value);
|
|
|
+ // this.initData();
|
|
|
+ }
|
|
|
+
|
|
|
+ onSearch() {
|
|
|
+ const { keyword } = this.state;
|
|
|
+ User.addSearch(keyword);
|
|
|
+ // this.search({ keyword }, false);
|
|
|
+ // this.changeQuery({ keyword });
|
|
|
+ // this.setState({ keyword });
|
|
|
+ this.refreshQuery({ keyword });
|
|
|
+ // this.initData();
|
|
|
+ }
|
|
|
+
|
|
|
+ onSort(value) {
|
|
|
+ const keys = Object.keys(value);
|
|
|
+ // this.search({ order: keys.length ? keys.join('|') : null, direction: keys.length ? Object.values(value).join('|') : null });
|
|
|
+ const { sortMap } = this.state;
|
|
|
+ const index = keys.length > 1 && sortMap[keys[0]] ? 1 : 0;
|
|
|
+ this.search({ order: keys.length ? keys[index] : null, direction: keys.length ? value[keys[index]] : null }, false);
|
|
|
+ this.initData();
|
|
|
+ }
|
|
|
+
|
|
|
+ onChangePage(page) {
|
|
|
+ this.search({ page }, false);
|
|
|
+ this.initData();
|
|
|
}
|
|
|
|
|
|
- onChangeSearch(value) {
|
|
|
- this.setState({ searchValue: value });
|
|
|
+ onChangeSearch(keyword, force = false) {
|
|
|
+ if (!force) {
|
|
|
+ this.searchNo += 1;
|
|
|
+ const no = this.searchNo;
|
|
|
+ Question.searchNo({ keyword, module: 'exercise', page: 1, size: 5 })
|
|
|
+ .then((result) => {
|
|
|
+ if (no !== this.searchNo) return;
|
|
|
+ this.setState({ searchList: result.list.map(row => row.title) });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.setState({ keyword });
|
|
|
+ }
|
|
|
+
|
|
|
+ addSearchHistory(id) {
|
|
|
+ My.addSearchHistory(id);
|
|
|
}
|
|
|
|
|
|
renderView() {
|
|
|
- const { search } = this.state;
|
|
|
+ const { searchResult } = this.state;
|
|
|
return (
|
|
|
<div>
|
|
|
{this.renderSearch()}
|
|
|
- {search ? this.renderResult() : this.renderFilter()}
|
|
|
+ {searchResult ? this.renderResult() : this.renderFilter()}
|
|
|
</div>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
renderSearch() {
|
|
|
- const { searchList, searchValue, historyList, focus } = this.state;
|
|
|
+ const { searchHistoryList = [] } = this.props.user;
|
|
|
+ const { searchList = [], keyword, focus, tip } = this.state;
|
|
|
+ // console.log(focus, tip, searchHistoryList);
|
|
|
return (
|
|
|
<div className="search-layout">
|
|
|
<div className="search-wrapper">
|
|
|
<input
|
|
|
- value={searchValue}
|
|
|
+ value={keyword}
|
|
|
onChange={e => this.onChangeSearch(e.target.value)}
|
|
|
onFocus={() => this.setState({ focus: true })}
|
|
|
onBlur={() => this.setState({ focus: false })}
|
|
|
/>
|
|
|
- <Button width={150}>
|
|
|
+ <Button width={150} onClick={() => this.onSearch()}>
|
|
|
<Icon className="m-r-5" type="search" />
|
|
|
搜索题目
|
|
|
</Button>
|
|
|
- {focus && (
|
|
|
- <div hidden={!searchValue} className="search-tip-wrapper">
|
|
|
+ {(focus || tip) && (
|
|
|
+ <div hidden={!keyword || searchList.length === 0} className="search-tip-wrapper" onMouseEnter={() => this.setState({ tip: true })} onMouseLeave={() => this.setState({ tip: false })}>
|
|
|
{searchList.map(item => {
|
|
|
- return <div className="t-2 t-s-16">{item}</div>;
|
|
|
+ return <div className="t-2 t-s-16" onClick={() => {
|
|
|
+ this.onChangeSearch(item, true);
|
|
|
+ this.onSearch();
|
|
|
+ }}>{item}</div>;
|
|
|
})}
|
|
|
</div>
|
|
|
)}
|
|
|
- {focus && (
|
|
|
- <div hidden={searchValue} className="search-tip-wrapper">
|
|
|
- {historyList.map(item => {
|
|
|
+ {(focus || tip) && (
|
|
|
+ <div hidden={keyword || searchHistoryList.length === 0} className="search-tip-wrapper" onMouseEnter={() => this.setState({ tip: true })} onMouseLeave={() => this.setState({ tip: false })}>
|
|
|
+ {searchHistoryList.map((item, index) => {
|
|
|
return (
|
|
|
- <div className="t-2 t-s-16">
|
|
|
+ <div className="t-2 t-s-16" onClick={() => {
|
|
|
+ this.onChangeSearch(item, true);
|
|
|
+ this.onSearch();
|
|
|
+ }}>
|
|
|
{item}
|
|
|
- <div className="f-r t-4 t-s-12 c-p">删除</div>
|
|
|
+ <div className="f-r t-4 t-s-12 c-p" onClick={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ User.removeSearchIndex(index);
|
|
|
+ }}>删除</div>
|
|
|
</div>
|
|
|
);
|
|
|
})}
|
|
|
<div className="all-del t-r">
|
|
|
- <span className="t-4 t-s-12 c-p">删除历史</span>
|
|
|
+ <span className="t-4 t-s-12 c-p" onClick={() => User.clearSearch()}>删除历史</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
)}
|
|
@@ -83,7 +190,20 @@ export default class extends Page {
|
|
|
}
|
|
|
|
|
|
renderFilter() {
|
|
|
- const { tab, filterMap, sortMap } = this.state;
|
|
|
+ const { filterMap, sortMap } = this.state;
|
|
|
+ const {
|
|
|
+ subject,
|
|
|
+ questionSubjectSelect,
|
|
|
+ questionSubjectMap = {},
|
|
|
+ difficultSelect,
|
|
|
+ oneSelect,
|
|
|
+ twoSelectMap = {},
|
|
|
+ list = [],
|
|
|
+ total,
|
|
|
+ page,
|
|
|
+ } = this.state;
|
|
|
+ const { login } = this.props.user;
|
|
|
+ console.log(this.props.user);
|
|
|
return (
|
|
|
<div className="filter-layout">
|
|
|
<div className="content">
|
|
@@ -94,30 +214,31 @@ export default class extends Page {
|
|
|
size="small"
|
|
|
space={5}
|
|
|
width={220}
|
|
|
- active={tab}
|
|
|
- tabs={[{ key: '1', title: 'Verval' }, { key: '2', title: 'Quant' }, { key: '3', title: 'IR' }]}
|
|
|
- onChange={key => this.onTabChange(key)}
|
|
|
+ active={subject}
|
|
|
+ tabs={questionSubjectSelect}
|
|
|
+ onChange={key => this.onRefreshFilter({ subject: key })}
|
|
|
/>
|
|
|
+ <div hidden={!login}><Link to="/question/search/history">浏览历史</Link></div>
|
|
|
<UserAction
|
|
|
selectList={[
|
|
|
{
|
|
|
key: 'questionType',
|
|
|
placeholder: '题型',
|
|
|
- select: [],
|
|
|
+ select: questionSubjectMap[subject] || [],
|
|
|
},
|
|
|
{
|
|
|
label: '范围',
|
|
|
children: [
|
|
|
{
|
|
|
- key: 'rang1',
|
|
|
+ key: 'one',
|
|
|
placeholder: '全部',
|
|
|
- select: [],
|
|
|
+ select: oneSelect,
|
|
|
},
|
|
|
{
|
|
|
placeholder: '全部',
|
|
|
- key: 'rang2',
|
|
|
- be: 'rang1',
|
|
|
- selectMap: {},
|
|
|
+ key: 'two',
|
|
|
+ be: 'one',
|
|
|
+ selectMap: twoSelectMap,
|
|
|
},
|
|
|
],
|
|
|
},
|
|
@@ -125,35 +246,41 @@ export default class extends Page {
|
|
|
right: true,
|
|
|
placeholder: '难度',
|
|
|
key: 'level',
|
|
|
- select: [],
|
|
|
+ select: difficultSelect,
|
|
|
},
|
|
|
]}
|
|
|
sortList={[
|
|
|
- { key: '1', label: '全站用时', fixed: true, right: true },
|
|
|
- { key: '2', label: '平均正确率', fixed: true, right: true },
|
|
|
- { key: '3', label: '收藏人数', fixed: true, right: true },
|
|
|
+ { key: 'time', label: '全站用时', fixed: true, right: true },
|
|
|
+ { key: 'correct', label: '平均正确率', fixed: true, right: true },
|
|
|
+ { key: 'collect_number', label: '收藏人数', fixed: true, right: true },
|
|
|
]}
|
|
|
filterMap={filterMap}
|
|
|
sortMap={sortMap}
|
|
|
+ onSort={value => this.onSort(value)}
|
|
|
onFilter={value => this.onFilter(value)}
|
|
|
/>
|
|
|
{this.renderList()}
|
|
|
- <UserPagination />
|
|
|
+ {total > 0 && list.length > 0 && (
|
|
|
+ <UserPagination total={total} current={page} pageSize={this.state.search.size} onChange={p => this.onChangePage(p)} />
|
|
|
+ )}
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
renderResult() {
|
|
|
+ const { total, list, page } = this.state;
|
|
|
return (
|
|
|
<div className="result-layout">
|
|
|
<div className="content">
|
|
|
<div className="m-b-1">
|
|
|
<span className="t-1 t-s-24">搜索结果:</span>
|
|
|
- <span className="t-2 t-s-18">共12条</span>
|
|
|
+ <span className="t-2 t-s-18">共{total}条</span>
|
|
|
</div>
|
|
|
{this.renderList()}
|
|
|
- <UserPagination jump />
|
|
|
+ {total > 0 && list.length > 0 && (
|
|
|
+ <UserPagination total={total} current={page} pageSize={this.state.search.size} onChange={p => this.onChangePage(p)} />
|
|
|
+ )}
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
@@ -162,31 +289,27 @@ export default class extends Page {
|
|
|
renderList() {
|
|
|
const { list } = this.state;
|
|
|
return list.map(item => {
|
|
|
- return <SearchItem data={item} />;
|
|
|
+ return <SearchItem data={item} onClick={() => this.addSearchHistory(item.id)} />;
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class SearchItem extends Component {
|
|
|
render() {
|
|
|
+ const { data = {}, onClick } = this.props;
|
|
|
return (
|
|
|
<div className="search-item">
|
|
|
<div className="search-item-head">
|
|
|
- <span className="t-15 t-s-16 m-r-1">阅读RC</span>
|
|
|
- <span className="t-1 t-s-16">PREP07#124、PREP08#332、PREP07#124、PREP08#332、PREP07#124</span>
|
|
|
+ <span className="t-15 t-s-16 m-r-1">{QuestionTypeMap[data.question.questionType]}</span>
|
|
|
+ <a className="t-1 t-s-16" href={`/question/detail/${data.id}`} target="_blank" onClick={() => onClick()}>{data.title}</a>
|
|
|
<div className="f-r t-15 t-s-14">
|
|
|
- <span className="m-r-1">Medium</span>
|
|
|
- <span className="m-r-1">用时: 1m 39s</span>
|
|
|
- <span className="m-r-1">80% </span>
|
|
|
- <span>收藏 20313</span>
|
|
|
+ <span className="m-r-1">{data.question.difficult}</span>
|
|
|
+ <span className="m-r-1">用时: {formatSeconds(data.totalTime / data.totalNumer)}</span>
|
|
|
+ <span className="m-r-1">{formatPercent(data.totalCorrect, data.totalNumber, false)}</span>
|
|
|
+ <span>收藏 {data.collectNumber}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className="t-1 p-20">
|
|
|
- Margaret Mead, the best-known anthropologist of the twentieth century, helped shape public opinion on
|
|
|
- fundamentally important areas like attitudes toward children and families, along with the relative merits of
|
|
|
- competition and cooperation. A. shape public opinion on fundamentally important areas like attitudes toward
|
|
|
- children and families, along with
|
|
|
- </div>
|
|
|
+ <div className="t-1 p-20">{data.question.description}</div>
|
|
|
</div>
|
|
|
);
|
|
|
}
|