Merge branch 'develop_search' into develop
This commit is contained in:
commit
c10799b6d0
Binary file not shown.
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 10 KiB |
|
@ -73,6 +73,10 @@ const EducoderLogin = Loadable({
|
|||
loader: () => import('./modules/login/EducoderLogin'),
|
||||
loading: Loading,
|
||||
})
|
||||
const Search = Loadable({
|
||||
loader: () => import('./modules/search/'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
|
@ -247,6 +251,10 @@ class App extends Component {
|
|||
</Route>
|
||||
{/*404*/}
|
||||
<Route path="/nopage" component={Shixunnopage} />
|
||||
|
||||
{/* 查询 */}
|
||||
<Route path="/search" component={Search} />
|
||||
|
||||
{/* 个人主页 */}
|
||||
<Route path="/users/:username"
|
||||
render={
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import React, { useState } from "react";
|
||||
import { Input ,notification} from "antd";
|
||||
|
||||
const { Search } = Input;
|
||||
export default ({history}) => {
|
||||
const [openSearch, setOpenSearch] = useState(false);
|
||||
|
||||
function onGlobalSearch(value) {
|
||||
history.push('/search?value=' + value);
|
||||
// window.location.href = `search?value=` + value;
|
||||
// history.push({
|
||||
// pathname:'/search',
|
||||
// state:value
|
||||
// })
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
openSearch ?
|
||||
<div
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
setOpenSearch(false)
|
||||
}, 500)
|
||||
}}
|
||||
>
|
||||
<Search placeholder="请输入搜索关键字"
|
||||
className={`search-input mr20`}
|
||||
onSearch={onGlobalSearch}
|
||||
autoFocus={true}
|
||||
style={{width:'260px'}}
|
||||
/>
|
||||
</div>
|
||||
:
|
||||
<i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
|
||||
setOpenSearch(true)
|
||||
}} />
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
};
|
|
@ -43,7 +43,7 @@ function SiderBar() {
|
|||
{
|
||||
list && list.map((i,k)=>{
|
||||
return(
|
||||
<li><a href={`${i.url}`} title={i.question} target="_blank">{i.question}</a></li>
|
||||
<li key={i.question+k}><a href={`${i.url}`} title={i.question} target="_blank">{i.question}</a></li>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import axios from 'axios';
|
|||
import { Input , notification , Dropdown , Menu } from 'antd';
|
||||
|
||||
import LoginDialog from '../../modules/login/LoginDialog';
|
||||
import GotoQQgroup from '../../modal/GotoQQgroup';
|
||||
import HeadSearch from '../Component/HeadSearch';
|
||||
|
||||
import AddProjectModal from './AddProjectModal';
|
||||
import '../../modules/tpm/TPMIndex.css';
|
||||
|
||||
|
@ -76,36 +79,35 @@ class NewHeader extends Component {
|
|||
} catch (e) {}
|
||||
}
|
||||
|
||||
SearchInput = (open,item)=>{
|
||||
if(open){
|
||||
return(
|
||||
<div
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
openSearch:false
|
||||
})
|
||||
}, 300)
|
||||
}}
|
||||
>
|
||||
<Search placeholder="请输入搜索关键字"
|
||||
className={`search-input mr20`}
|
||||
onSearch={(value)=>this.onGlobalSearch(value,item)}
|
||||
autoFocus={true}
|
||||
style={{width:"260px"}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return <i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
|
||||
this.setState({openSearch:true})
|
||||
}} />
|
||||
}
|
||||
}
|
||||
// SearchInput = (open,item)=>{
|
||||
// if(open){
|
||||
// return(
|
||||
// <div
|
||||
// onBlur={() => {
|
||||
// setTimeout(() => {
|
||||
// this.setState({
|
||||
// openSearch:false
|
||||
// })
|
||||
// }, 300)
|
||||
// }}
|
||||
// >
|
||||
// <Search placeholder="实践课程/教学课堂/实践项目/交流问答"
|
||||
// className={`search-input mr20`}
|
||||
// onSearch={(value)=>this.onGlobalSearch(value,item)}
|
||||
// autoFocus={true}
|
||||
// />
|
||||
// </div>
|
||||
// )
|
||||
// }else{
|
||||
// return <i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
|
||||
// this.setState({openSearch:true})
|
||||
// }} />
|
||||
// }
|
||||
// }
|
||||
|
||||
onGlobalSearch=(value,item)=>{
|
||||
window.location.href=`${item}?value=` + value;
|
||||
}
|
||||
// onGlobalSearch=(value,item)=>{
|
||||
// window.location.href=`${item}?value=` + value;
|
||||
// }
|
||||
|
||||
openNotification = (messge) => {
|
||||
notification.open({
|
||||
|
@ -264,7 +266,7 @@ class NewHeader extends Component {
|
|||
{
|
||||
list.map((item,key)=>{
|
||||
return(
|
||||
(item.name !=="加入课堂" && item.name !=="加入开发项目") && <Menu.Item><a href={item.url}>{item.name}</a></Menu.Item>
|
||||
(item.name !=="加入课堂" && item.name !=="加入开发项目") && <Menu.Item key={item.name+key}><a href={item.url}>{item.name}</a></Menu.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -383,7 +385,7 @@ class NewHeader extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
let search_url = settings && settings.common && settings.common.search;
|
||||
// let search_url = settings && settings.common && settings.common.search;
|
||||
let notice_url = settings && settings.common && settings.common.notice;
|
||||
return (
|
||||
<div className="newHeaders" id="nHeader">
|
||||
|
@ -447,7 +449,8 @@ class NewHeader extends Component {
|
|||
}
|
||||
</div>
|
||||
<div className="head-right">
|
||||
{search_url ? this.SearchInput(openSearch,search_url):""}
|
||||
{/* {search_url ? this.SearchInput(openSearch,search_url):""} */}
|
||||
<HeadSearch {...this.props}/>
|
||||
{
|
||||
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
||||
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import './index.scss';
|
||||
export default (props) => {
|
||||
const { list } = props;
|
||||
|
||||
function itemClick(item) {
|
||||
item.url && window.open(item.url);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
list.map((item, i) => {
|
||||
return (
|
||||
<div className="search-item" key={item.id}>
|
||||
<div className="search-item-tit">
|
||||
<h3 className="search-item-title" dangerouslySetInnerHTML={{ __html: item.title }} onClick={() => { itemClick(item) }}></h3>
|
||||
|
||||
{item.type == 1 && <p>
|
||||
<span className="search-icon"><i className="iconfont icon-dianjiliang mr3 font-12" />{item.watchersCount}</span>
|
||||
<span className="search-icon"><i className="iconfont icon-kongxing mr3 font-16" />{item.praisesCount}</span>
|
||||
<span className="search-icon"><i className="iconfont icon-fork mr3 font-16" />{item.forkedCount}</span>
|
||||
</p>}
|
||||
|
||||
</div >
|
||||
<p className="search-item-content" dangerouslySetInnerHTML={{ __html: item.content }}></p>
|
||||
<div>{item.updateTime}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Input, Row, Col, Tabs, Pagination } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { TPMIndexHOC } from '../tpm/TPMIndexHOC';
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
import ItemList from './ItemList';
|
||||
import Nodata from '../../forge/Nodata';
|
||||
import './index.scss';
|
||||
|
||||
const { Search } = Input;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
// const https = 'http://192.168.0.77:8081'; //曾伟内网后台
|
||||
// const https = 'http://192.168.31.104:8081'; //曾伟外网后台
|
||||
// const https='http://106.75.31.211:58081';
|
||||
const https = 'https://test-statistics.trustie.net';
|
||||
|
||||
const GlobalSearch = ({ location, showNotification, history }) => {
|
||||
|
||||
const size = 10;
|
||||
let defaultValue = decodeURI(location.search.split("=")[1] || "");
|
||||
|
||||
const [term, setTerm] = useState(defaultValue);
|
||||
const [searchValue, setSearchValue] = useState(defaultValue);
|
||||
|
||||
const [type, setType] = useState(1);
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [dataList, setDataList] = useState([]);
|
||||
|
||||
const [forcesearch, setForcesearch] = useState(false);
|
||||
|
||||
const [totalType1, setTotalType1] = useState(0);
|
||||
const [totalType2, setTotalType2] = useState(0);
|
||||
const [totalType3, setTotalType3] = useState(0);
|
||||
const [totalType4, setTotalType4] = useState(0);
|
||||
const [totalType5, setTotalType5] = useState(0);
|
||||
|
||||
const [ref, setRef] = useState(undefined);
|
||||
const [focus, setFocus] = useState(0);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
searchDataList();
|
||||
}, [type, page, term, forcesearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref) {
|
||||
ref && ref.input.input.focus();
|
||||
}
|
||||
}, [focus])
|
||||
|
||||
|
||||
function searchFun(val) {
|
||||
setTerm(val);
|
||||
setPage(1);
|
||||
setForcesearch(!forcesearch);
|
||||
}
|
||||
|
||||
function searchDataList() {
|
||||
const url = https + '/search';
|
||||
if (!term) {
|
||||
// showNotification('请输入关键字');
|
||||
setFocus(focus + 1);
|
||||
return;
|
||||
}
|
||||
axios.defaults.withCredentials = true;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
page,
|
||||
size,
|
||||
term,
|
||||
type,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.status === 200 && res.data && res.data.code === '1') {
|
||||
const data = res.data.data;
|
||||
setDataList(data.rows);
|
||||
setTotal(data.total);
|
||||
for (const item of data.searchItemTypes) {
|
||||
if (item.type == 1) {
|
||||
setTotalType1(item.count);
|
||||
} else if (item.type == 2) {
|
||||
setTotalType2(item.count);
|
||||
} else if (item.type == 3) {
|
||||
setTotalType3(item.count);
|
||||
} else if (item.type == 4) {
|
||||
setTotalType4(item.count);
|
||||
} else if (item.type == 5) {
|
||||
setTotalType5(item.count);
|
||||
}
|
||||
}
|
||||
} else if (res && res.data) {
|
||||
showNotification(res.data.data.message);
|
||||
setDataList([]);
|
||||
setTotal(0);
|
||||
} else {
|
||||
showNotification('查询失败!');
|
||||
setDataList([]);
|
||||
setTotal(0);
|
||||
}
|
||||
}).catch(err => {
|
||||
showNotification('查询失败!返回错误');
|
||||
setDataList([]);
|
||||
setTotal(0);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function changeTab(type) {
|
||||
setType(type);
|
||||
setPage(1);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
history.listen(historyLocation => {
|
||||
setSearchValue(historyLocation.search.split("=")[1] || "");
|
||||
setTerm(historyLocation.search.split("=")[1] || "");
|
||||
})
|
||||
}, [history]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="suit-main clearfix">
|
||||
<div className="search-head">
|
||||
|
||||
<Row className="search-box">
|
||||
<Col xs={20} sm={16} lg={13} >
|
||||
<Search
|
||||
placeholder="请输入搜索关键字"
|
||||
enterButton="搜索"
|
||||
size="large"
|
||||
onSearch={searchFun}
|
||||
className={{ 'global-search': true, "required-search": !searchValue }}
|
||||
value={searchValue}
|
||||
onChange={(e) => { setSearchValue(e.target.value) }}
|
||||
ref={(el) => setRef(el)}
|
||||
/>
|
||||
{!searchValue && <span className="ant-form-explain">请输入搜索关键字</span>}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
|
||||
<Tabs defaultActiveKey="1" onChange={changeTab}>
|
||||
<TabPane tab={`项目(${totalType1})`} key={1}>
|
||||
<div className="search-content">
|
||||
<p>{`找到${totalType1}条结果`}</p>
|
||||
<ItemList
|
||||
list={dataList}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
dataList.length ?
|
||||
<Pagination
|
||||
showQuickJumper={dataList.length > size}
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={page}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>
|
||||
: <Nodata _html="暂无数据" className="no-data-box" />
|
||||
}
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab={`帖子(${totalType2})`} key="2">
|
||||
<div className="search-content">
|
||||
<p>{`找到${totalType2}条结果`}</p>
|
||||
<ItemList
|
||||
list={dataList}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
dataList.length ?
|
||||
<Pagination
|
||||
showQuickJumper={dataList.length > size}
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={page}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/> : <Nodata _html="暂无数据" />
|
||||
}
|
||||
</TabPane>
|
||||
|
||||
{/* <TabPane tab={`众包任务(${totalType3})`} key={3}>
|
||||
<div className="search-content">
|
||||
<p>{`找到${totalType3}条结果`}</p>
|
||||
<ItemList
|
||||
list={dataList}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
dataList.length ?
|
||||
<Pagination
|
||||
showQuickJumper={dataList.length > size}
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={page}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/> : <Nodata _html="暂无数据" />
|
||||
}
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab={`资源(${totalType4})`} key="4">
|
||||
<div className="search-content">
|
||||
<p>{`找到${totalType4}条结果`}</p>
|
||||
<ItemList
|
||||
list={dataList}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
dataList.length ?
|
||||
<Pagination
|
||||
showQuickJumper={dataList.length > size}
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={page}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/> : <Nodata _html="暂无数据" />
|
||||
}
|
||||
</TabPane> */}
|
||||
|
||||
<TabPane tab={`易修(${totalType5})`} key="5">
|
||||
<div className="search-content">
|
||||
<p>{`找到${totalType5}条结果`}</p>
|
||||
<ItemList
|
||||
list={dataList}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
dataList.length ?
|
||||
<Pagination
|
||||
showQuickJumper={dataList.length > size}
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={page}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/> : <Nodata _html="暂无数据" />
|
||||
}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default SnackbarHOC()(TPMIndexHOC(GlobalSearch));
|
|
@ -0,0 +1,89 @@
|
|||
.suit-main {
|
||||
.search-head {
|
||||
background: #eef2f5;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 1200px;
|
||||
height: 110px;
|
||||
margin: 0 auto;
|
||||
.ant-form-explain{
|
||||
color: #f5222d;
|
||||
}
|
||||
}
|
||||
|
||||
.global-search {
|
||||
margin-top: 40px;
|
||||
}
|
||||
.required-search{
|
||||
.ant-input{
|
||||
border-color: #f5222d !important;
|
||||
}
|
||||
}
|
||||
.ant-tabs-top {
|
||||
background: #eef2f5;
|
||||
}
|
||||
.ant-tabs-tabpane {
|
||||
background: #fff;
|
||||
}
|
||||
.ant-tabs-bar {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.ant-tabs-tab-active {
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab:hover {
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 列表 */
|
||||
.search-content {
|
||||
width: 1200px;
|
||||
margin: 1.5vw auto;
|
||||
p{
|
||||
margin-bottom: .75em !important;
|
||||
}
|
||||
}
|
||||
.search-item {
|
||||
padding: .75em 0;
|
||||
border-top:1px solid #e1e4e8;
|
||||
.search-item-tit{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.search-item-title{
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: #1890ff;
|
||||
}
|
||||
span{
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
.search-item-content{
|
||||
span{
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
.search-icon{
|
||||
margin-right: 2em;
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-pagination{
|
||||
text-align: center;
|
||||
margin-bottom: 3vw;
|
||||
}
|
||||
|
||||
.none_panels{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: column nowrap;
|
||||
height: 40vh;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue