Commit 0596fdd5 authored by 邓晓峰's avatar 邓晓峰

feat: 优化components

parent 0a54ee72
Pipeline #47273 skipped with stages
/* eslint-disable */ /* eslint-disable */
// const proxyURL = process.env.NODE_ENV !== 'production' ? 'http://192.168.10.150:8777' : window.location.origin; // const proxyURL = process.env.NODE_ENV !== 'production' ? 'http://192.168.10.150:8777' : window.location.origin;
const proxyURL = 'https://work.panda-water.cn'; // const proxyURL = 'https://work.panda-water.cn';
// const proxyURL = 'http://192.168.12.47:8082'; // const proxyURL = 'http://192.168.12.47:8082';
const proxyURL = 'https://panda-water.cn';
module.exports = { module.exports = {
......
...@@ -110,7 +110,7 @@ ...@@ -110,7 +110,7 @@
"@wisdom-map/Map": "^1.0.12-17", "@wisdom-map/Map": "^1.0.12-17",
"@wisdom-map/arcgismap": "^1.0.79-17", "@wisdom-map/arcgismap": "^1.0.79-17",
"@wisdom-map/util": "^1.0.27-0", "@wisdom-map/util": "^1.0.27-0",
"@wisdom-utils/components": "0.0.20", "@wisdom-utils/components": "0.0.29",
"@wisdom-utils/runtime": "0.0.15", "@wisdom-utils/runtime": "0.0.15",
"@wisdom-utils/utils": "0.0.77", "@wisdom-utils/utils": "0.0.77",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
......
import React from 'react';
import { Tabs } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import { ChineseDistricts } from '@wisdom-utils/utils';
import styles from './index.less';
const { TabPane } = Tabs;
const PROVINCE = 'province';
const CITY = 'city';
const DISTRICT = 'district';
const PROJECT = 'project';
class CitySelector extends React.Component {
constructor(props) {
super(props);
this.DEFAULTS = {
simple: false,
Clickable: {},
responsive: false,
placeholder: '请选择省/市/区(包括地级市)',
level: 'project',
province: '',
city: '',
district: '',
project: '',
handEnd() {},
};
this.state = {
currentItem: {},
cityCurrentItem: {},
districtCurrentItem: {},
activeIndex: '1',
};
this.$dropdown = null;
this.options = Object.assign(
{},
this.DEFAULTS,
_.isPlainObject(props.options) ? props.options : {},
);
this.active = false;
this.dems = [];
this.needBlur = false;
}
getProvinceList(data) {
const { simple } = this.props;
const pOptions = this.props.Clickable.proviceOption;
return data.map(item => (
<dl className="clearfix" key={item.code}>
<dt>{item.code}</dt>
<dd>
{item.address.map(k => {
let flag = false;
// eslint-disable-next-line no-plusplus,no-var,vars-on-top
var j = 0;
for (j = 0; j < pOptions.length; j++) {
if (k.address === pOptions[j].proviceName) {
flag = true;
break;
}
}
if (flag) {
return (
<a
title={k.address}
key={k.code}
className={classNames(
styles.clickAble,
k.code === this.state.currentItem.code ? styles.active : '',
)}
onClick={event =>
this.selectHandle(
event,
k,
k.code === this.state.currentItem.code,
)
}
>
{simple ? this.simplize(k.address, PROVINCE) : k.address}
{/* eslint-disable-next-line no-undef,block-scoped-var */}
<b>{this.symbolNumber(pOptions[j].num)}</b>
</a>
);
}
return (
<a title={k.address} key={k.code}>
{simple ? this.simplize(k.address, PROVINCE) : k.address}
</a>
);
})}
</dd>
</dl>
));
}
getList(data, type, flag) {
const { simple } = this.props;
const { cityOption } = this.props.Clickable;
const { siteOption } = this.props.Clickable;
const children = [];
if (type === PROJECT && flag === 'project') {
const { address } = this.state.districtCurrentItem;
const arr = siteOption.filter(item => item.city.indexOf(address) > 0);
return (
<dl className="clearfix">
<dd>
{arr.map(item => (
<a
title={item.city}
className={classNames(
styles.clickAble,
!item.isDeployed ? styles.noData : '',
)}
onClick={event => this.siteHandle(event, item)}
>
{item.groupName}
</a>
))}
</dd>
</dl>
);
}
return (
<dl className="clearfix">
<dd>
{/* eslint-disable-next-line array-callback-return */}
{data.map((item, index) => {
// eslint-disable-next-line no-shadow
const flag = data.filter(
// eslint-disable-next-line no-shadow
item => item.code === this.state.cityCurrentItem.code,
);
if (type === DISTRICT && index === 0 && !flag.length) {
let flag2 = false;
// eslint-disable-next-line no-plusplus
for (let h = 0; h < siteOption.length; h++) {
const arr = siteOption[h].city.split('/');
const lastValue = arr[arr.length - 1];
if (
lastValue.indexOf(this.state.cityCurrentItem.address) > -1
) {
flag2 = true;
break;
}
}
if (!flag2) {
children.push(
<a
title={this.state.cityCurrentItem.address}
datacode={this.state.cityCurrentItem.code}
>
{simple
? this.simplize(this.state.cityCurrentItem.address, type)
: this.state.cityCurrentItem.address}
</a>,
);
} else {
children.push(
<a
title={this.state.cityCurrentItem.address}
className={classNames(
styles.clickAble,
item.code === this.state.districtCurrentItem.code
? styles.active
: '',
)}
onClick={event =>
this.districtHandle(event, this.state.cityCurrentItem)
}
>
{simple
? this.simplize(this.state.cityCurrentItem.address, type)
: this.state.cityCurrentItem.address}
</a>,
);
}
}
if (type === CITY) {
// eslint-disable-next-line no-shadow
let flag = false;
// eslint-disable-next-line no-var,no-plusplus
for (var j = 0; j < cityOption.length; j++) {
if (item.address === cityOption[j].proviceName) {
flag = true;
break;
}
}
if (flag) {
children.push(
<a
title={item.address}
className={classNames(
styles.clickAble,
item.code === this.state.cityCurrentItem.code
? styles.active
: '',
)}
onClick={event => this.selectCityHandle(event, item)}
>
{simple ? this.simplize(item.address, CITY) : item.address}
{/* eslint-disable-next-line no-undef */}
<b>{this.symbolNumber(cityOption[j].num)}</b>
</a>,
);
} else {
children.push(
<a>
{simple ? this.simplize(item.address, CITY) : item.address}
</a>,
);
}
} else {
let flg1 = false;
// eslint-disable-next-line no-plusplus
for (let k = 0; k < siteOption.length; k++) {
if (siteOption[k].city.indexOf(item.address) > -1) {
flg1 = true;
break;
}
}
if (flg1) {
children.push(
<a
title={item.address}
className={classNames(
styles.clickAble,
item.code === this.state.districtCurrentItem.code
? styles.active
: '',
)}
onClick={event =>
type === DISTRICT
? this.districtHandle(event, item, '123')
: null
}
>
{simple ? this.simplize(item.address, type) : item.address}
</a>,
);
} else {
children.push(
<a>
{simple ? this.simplize(item.address, type) : item.address}
</a>,
);
}
}
})}
{children}
</dd>
</dl>
);
}
nextTab() {
// eslint-disable-next-line radix
let key = parseInt(this.state.activeIndex);
// eslint-disable-next-line no-plusplus
key = ++key;
return key.toString();
}
selectHandle = (event, item, status) => {
event.persist();
this.setState({
currentItem: item,
});
this.handleChangeTab(this.nextTab());
};
handleChangeTab = activeKey => {
this.setState({
activeIndex: activeKey,
});
};
selectCityHandle = (event, item, status) => {
event.persist();
this.setState({
cityCurrentItem: item,
});
this.handleChangeTab(this.nextTab());
};
districtHandle = (event, item, status) => {
event.persist();
this.setState({
districtCurrentItem: item,
});
this.handleChangeTab(this.nextTab());
};
siteHandle = (event, item) => {
// eslint-disable-next-line no-unused-expressions
this.props.handEnd && this.props.handEnd(event, item);
};
render() {
return (
<Tabs activeKey={this.state.activeIndex} onChange={this.handleChangeTab}>
<TabPane tab="省份" key="1">
<div className={styles['city-select-content']}>
<div className={classNames(styles['city-select'], styles.province)}>
{this.output(PROVINCE)}
</div>
</div>
</TabPane>
<TabPane tab="城市" key="2">
<div className={styles['city-select-content']}>
<div className={classNames(styles['city-select'], styles.city)}>
{this.output(CITY)}
</div>
</div>
</TabPane>
<TabPane tab="区县" key="3">
<div className={styles['city-select-content']}>
<div className={classNames(styles['city-select'], styles.city)}>
{this.output(DISTRICT)}
</div>
</div>
</TabPane>
<TabPane tab="站点" key="4">
<div className={styles['city-select-content']}>
<div className={classNames(styles['city-select'], styles.city)}>
{this.output(PROJECT, 'project')}
</div>
</div>
</TabPane>
</Tabs>
);
}
refresh() {}
defineDems() {
let stop = false;
// eslint-disable-next-line array-callback-return
[PROVINCE, CITY, DISTRICT, PROJECT].map(item => {
if (stop) {
this.dems.push(item);
}
// eslint-disable-next-line no-undef
if (type === this.options.level) {
stop = true;
}
});
}
includeDem(type) {
return this.dems.findIndex(item => item === type) !== -1;
}
componentDidMount() {
this.output();
}
/* eslint-disable */
output(type = PROVINCE, flag) {
const data = [];
const code =
// eslint-disable-next-line no-nested-ternary
type === PROVINCE
? 86
: type === CITY
? this.state.currentItem.code
: type === DISTRICT
? this.state.cityCurrentItem.code
: type === PROJECT
? this.state.currentItem.code
: null;
const districts = ChineseDistricts[code];
if (_.isPlainObject(districts)) {
Object.keys(districts).forEach((item, index) => {
const ret = districts[item];
data.push({
code: item,
address: ret,
});
});
}
return type === PROVINCE
? this.getProvinceList(data)
: this.getList(data, type, flag);
}
// eslint-disable-next-line consistent-return
simplize(address, type) {
// eslint-disable-next-line no-param-reassign
address = address || '';
if (type === PROVINCE) {
return address.replace(/[省,市,自治区,壮族,回族,维吾尔]/g, '');
}
if (type === CITY) {
return address
.replace(
/[市,地区,回族,蒙古,苗族,白族,傣族,景颇族,藏族,彝族,壮族,傈僳族,布依族,侗族]/g,
'',
)
.replace('哈萨克', '')
.replace('自治州', '')
.replace(/自治县/, '');
}
if (type === DISTRICT) {
return address;
}
}
symbolNumber(num) {
const symbolArr = [
'①',
'②',
'③',
'④',
'⑤',
'⑥',
'⑦',
'⑧',
'⑨',
'⑩',
'⑪',
'⑫',
'⑬',
'⑭',
'⑮',
'⑯',
'⑰',
'⑱',
'⑲',
'⑳',
'㉑',
'㉒',
'㉓',
'㉔',
'㉕',
'㉖',
'㉗',
'㉘',
'㉙',
'㉚',
'㉛',
'㉜',
'㉝',
'㉞',
'㉟',
'㊱',
'㊲',
'㊳',
'㊴',
'㊵',
'㊶',
'㊷',
'㊸',
'㊹',
'㊺',
'㊻',
'㊼',
'㊽',
'㊾',
'㊿',
];
return symbolArr[num - 1];
}
}
export default CitySelector;
.city-select-content {
width: 100%;
min-height: 10px;
background-color: #fff;
// padding: 10px 15px;
box-sizing: border-box;
.city-select {
font-size: 13px;
dl {
line-height: 2;
clear: both;
padding: 3px 0;
margin: 0;
position: relative;
dt {
position: absolute;
width: 2.5em;
font-weight: 500;
text-align: right;
line-height: 2;
}
dd {
line-height: 2;
margin-left: 3em;
}
a {
display: inline-block;
padding: 0 10px;
outline: 0;
text-decoration: none;
white-space: nowrap;
margin-right: 2px;
text-decoration: none;
color: #333;
cursor: pointer;
&.active {
background-color: #46a4ff;
color: #fff !important;
border-radius: 2px;
b {
color: #fff;
margin-left: 3px;
}
&:hover {
background-color: #46a4ff;
color: #fff !important;
}
}
&.clickAble {
color: #46a4ff;
}
&.noData {
color: #ccc;
display: inline;
cursor: pointer;
}
&:hover {
background-color: #f1f8ff;
border-radius: 2px;
color: #46a4ff;
text-decoration: none;
}
}
}
&.city {
dl {
dd {
margin-left: 0 !important;
}
}
}
}
}
import React from 'react';
import { Result } from 'antd';
class ErrorBoundary extends React.Component {
state = { hasError: false, errorInfo: '' };
static getDerivedStateFromError(error) {
return { hasError: true, errorInfo: error.message };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
// eslint-disable-next-line no-console
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<Result
status="error"
title="访问页面发生错误."
extra={this.state.errorInfo}
/>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
...@@ -7,7 +7,7 @@ import classNames from 'classnames'; ...@@ -7,7 +7,7 @@ import classNames from 'classnames';
import { useHistory } from '@wisdom-utils/runtime'; import { useHistory } from '@wisdom-utils/runtime';
import { useIntl } from '@/locales/localeExports'; import { useIntl } from '@/locales/localeExports';
import { actionCreators } from '../../containers/App/store'; import { actionCreators } from '../../containers/App/store';
import HeaderSearch from '../HeaderSearch'; import { HeaderSearch } from '@wisdom-utils/components';
import Avatar from './AvatarDropdown'; import Avatar from './AvatarDropdown';
import styles from './index.less'; import styles from './index.less';
import NoticeIconView from './NoticeIconView'; import NoticeIconView from './NoticeIconView';
......
...@@ -7,7 +7,7 @@ import Icon from '@ant-design/icons'; ...@@ -7,7 +7,7 @@ import Icon from '@ant-design/icons';
import { useIntl } from '@/locales/localeExports'; import { useIntl } from '@/locales/localeExports';
import { actionCreators } from '../../containers/App/store'; import { actionCreators } from '../../containers/App/store';
import HeaderSearch from '../HeaderSearch'; import { HeaderSearch } from '@wisdom-utils/components';
import Avatar from './AvatarDropdown'; import Avatar from './AvatarDropdown';
import styles from './index.less'; import styles from './index.less';
import NoticeIconView from './NoticeIconView'; import NoticeIconView from './NoticeIconView';
......
import React from 'react';
import { Dropdown } from 'antd';
import classNames from 'classnames';
import styles from './index.less';
const HeaderDropdown = ({ overlayClassName: cls, ...restProps }) => (
<Dropdown
overlayClassName={classNames(styles.container, cls)}
{...restProps}
/>
);
export default HeaderDropdown;
@import '~antd/es/style/themes/default.less';
.container > * {
background-color: @popover-bg;
border-radius: 4px;
box-shadow: @shadow-1-down;
}
@media screen and (max-width: @screen-xs) {
.container {
width: 100% !important;
}
.container > * {
border-radius: 0 !important;
}
}
import React, {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import classNames from 'classnames';
import PinyinMatch from 'pinyin-match';
import { useHistory } from '@wisdom-utils/runtime';
import Icon, { RightCircleOutlined } from '@ant-design/icons';
import Modal from '../modal';
import styes from './index.less';
const HistorySvg = () => (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
width="10"
height="10"
>
<path
d="M1016.405333 0h-351.573333a7.594667 7.594667 0 0 0-5.376 12.885333l149.077333 149.674667-244.224 249.770667H434.346667A7.594667 7.594667 0 0 0 426.666667 419.84v169.898667c0 4.266667 3.413333 7.594667 7.594666 7.594666h169.813334c4.266667 0 7.68-3.413333 7.68-7.594666V486.826667l263.253333-257.792 136.106667 135.509333A7.594667 7.594667 0 0 0 1024 359.253333V7.68A7.594667 7.594667 0 0 0 1016.405333 0z"
fill="#C1C1C1"
/>
<path
d="M979.626667 640a45.226667 45.226667 0 0 0-44.202667 46.08v249.258667H88.490667V88.576h245.418666l1.194667-0.085333A45.056 45.056 0 0 0 378.88 44.288 45.056 45.056 0 0 0 333.994667 0H7.68A7.68 7.68 0 0 0 0 7.68v1008.64c0 4.266667 3.413333 7.68 7.68 7.68h1008.64c4.266667 0 7.68-3.413333 7.68-7.68V686.08a45.226667 45.226667 0 0 0-44.373333-46.08z"
fill="#C1C1C1"
/>
</svg>
);
const DelHistory = () => (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
width="12"
height="12"
>
<path
d="M153.6 345.6a38.4 38.4 0 0 1 0-76.8h665.6a38.4 38.4 0 1 1 0 76.8H153.6z"
fill="#888888"
/>
<path
d="M345.6 307.2a38.4 38.4 0 0 1-76.8 0V204.8c0-49.4592 40.1408-89.6 89.6-89.6h256c49.4592 0 89.6 40.1408 89.6 89.6v102.4a38.4 38.4 0 1 1-76.8 0V204.8a12.8 12.8 0 0 0-12.8-12.8H358.4a12.8 12.8 0 0 0-12.8 12.8v102.4zM166.4 460.8a38.4 38.4 0 0 1 76.8 0v358.4c0 7.0656 5.7344 12.8 12.8 12.8h460.8a12.8 12.8 0 0 0 12.8-12.8V460.8a38.4 38.4 0 1 1 76.8 0v358.4A89.6 89.6 0 0 1 716.8 908.8H256A89.6 89.6 0 0 1 166.4 819.2V460.8z"
fill="#888888"
/>
<path
d="M371.2 460.8a38.4 38.4 0 0 1 76.8 0v256a38.4 38.4 0 1 1-76.8 0V460.8zM524.8 460.8a38.4 38.4 0 0 1 76.8 0v256a38.4 38.4 0 1 1-76.8 0V460.8z"
fill="#888888"
/>
</svg>
);
const HistoryHrefIcon = props => <Icon component={HistorySvg} {...props} />;
const DelIcon = props => <Icon component={DelHistory} {...props} />;
const unique = (arr, val) => {
const res = new Map();
return arr.filter(item => !res.has(item[val]) && res.set(item[val], 1));
};
const SearchPanel = props => {
const [visible, setVisible] = useState(false);
// const [disabled, setDisabled] = useState(false);
// const [axis, setAxis] = useState('both');
// const [currentIndex, setCurrentIndex] = useState(-1);
const [eventCounts, setEventCounts] = useState(() => ['resultConsole', -1]);
const featureRef = useRef(null);
const consoleRef = useRef(null);
let recentKeywords = props.recentKeywords.toJS
? props.recentKeywords.toJS()
: props.recentKeywords;
recentKeywords = Array.isArray(recentKeywords)
? recentKeywords
: [recentKeywords];
let recentVisited = props.recentVisited.toJS
? props.recentVisited.toJS()
: props.recentVisited;
recentVisited = Array.isArray(recentVisited)
? recentVisited
: [recentVisited];
let recentProducts = props.recentProducts.toJS
? props.recentProducts.toJS()
: props.recentProducts;
recentProducts = Array.isArray(recentProducts)
? recentProducts
: [recentProducts];
const history = useHistory();
// eslint-disable-next-line consistent-return
function getParents(data, key) {
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const i in data) {
if (data[i].key === key) {
return [];
}
if (data[i].routes) {
const ro = getParents(data[i].routes, key);
if (ro !== undefined) return ro.concat(data[i]);
}
}
}
const goFeature = (path, rect, value) => {
// eslint-disable-next-line no-param-reassign
value = value || props.value;
const findKeywordIndex =
recentKeywords.length > 0
? recentKeywords.findIndex(item => item.data === value)
: -1;
const findRecentVisitedIndex =
recentVisited.length > 0
? recentVisited.findIndex(item => item.data.name === rect.name)
: -1;
if (findKeywordIndex === -1)
props.updateRecentKeywords && props.updateRecentKeywords(value);
if (findRecentVisitedIndex === -1)
props.updateRecentVisited && props.updateRecentVisited(rect);
let parents = getParents(props.menu, rect.key);
parents = parents[parents.length - 1];
const findIndex = props.menu.findIndex(k => k.name === parents.name);
props.updateCurrentIndex && props.updateCurrentIndex(findIndex);
const routes = props.menu[findIndex];
const selectedIndex = routes.routes.findIndex(item => item.name === rect.subSystem);
let currentPath = void 0;
// props.updateOpenKeys && props.updateOpenKeys([parents.key]);
if (rect && rect.routes && rect.routes.length > 0) {
currentPath = rect.routes[0].path;
} else {
currentPath = path;
}
// props.updateSelectedKeys && props.updateSelectedKeys(rect.key);
window.share && window.share.event && window.share.event.emit('event:updateCurrentChildrenRoutes', {
currentPath: currentPath,
currentRoute: rect,
selectedIndex: selectedIndex
});
if(window.__POWERED_BY_QIANKUN__) {
history.push(`/civbase${currentPath}`);
} else {
history.push(currentPath);
}
// props.updatePathname && props.updatePathname(rect.key);
};
const goProduct = (event, item) => {
/* eslint-disable */
event.persist && event.persist();
event && event.stopPropagation();
const findRecentIndex =
recentProducts.length > 0
? recentProducts.findIndex(item => item.data.name === item.name)
: -1;
if (findRecentIndex === -1)
props.updateRecentProduct && props.updateRecentProduct(item);
const findIndex = props.menu.findIndex(k => k.name === item.name);
props.updateCurrentIndex && props.updateCurrentIndex(findIndex);
};
const handlerMore = event => {
event.persist && event.persist();
event && event.nativeEvent.stopImmediatePropagation();
setVisible(!visible);
props.onClose && props.onClose(event);
};
const handlerDelHistory = () => {
props.clearRecentProduct && props.clearRecentProduct();
};
const matchValue = (str, value) => {
const match = PinyinMatch.match(str, value || props.value);
return match;
};
const transformRecentProduct = () =>
unique(recentProducts.map(item => item.data), 'name');
const transformWillSearch = () => {
if (props.willSearch.length === 0) {
return null;
}
return (
<div className={styes.item}>
<div className={styes.title}>你是不是想搜:</div>
<div className={styes.label}>
{(unique(props.willSearch, 'name') || []).map(item => (
// eslint-disable-next-line react/button-has-type
<button
className={styes.btn}
key={item.name}
title={item.title}
onClick={() => props.onWillSearch(item.name)}
>
{item.name}
</button>
))}
</div>
</div>
);
};
const transformConsole = () => {
if (props.console.length === 0) {
return <div className={styes.empty}>没有找到相关内容</div>;
}
return (props.console || []).map((item, index) => {
const match = matchValue(item.name);
const name = match ? (
<span>
{item.name.substring(0, match[0])}
<em>{item.name.substring(match[0], match[1] + 1)}</em>
{item.name.substring(match[1] + 1)}
</span>
) : (
item.name
);
return (
<a
className={styes.featureItem}
key={item.name}
onClick={event => goProduct(event, item)}
tabIndex="1"
onKeyDown={event => event.key === 'Enter' && event.keyCode === 13 && goProduct(event, item)}
>
<span className={styes.text}>{name}</span>
<span className={styes.featIn}>
<RightCircleOutlined />
</span>
</a>
);
});
};
const transformFeature = () => {
if (props.willSearch.length === 0) {
return <div className={styes.empty}>没有找到相关内容</div>;
}
return (unique(props.willSearch.slice(0, 20), 'path') || []).map(
(item, index) => {
const match = matchValue(item.name);
const name = match ? (
<span>
{item.name.substring(0, match[0])}
<em>{item.name.substring(match[0], match[1] + 1)}</em>
{item.name.substring(match[1] + 1)}
</span>
) : (
item.name
);
return (
<a
className={styes.featureItem}
key={index}
onClick={() => goFeature(item.path, item)}
tabIndex="1"
onKeyDown={event => event.key === 'Enter' && event.keyCode === 13 && goFeature(item.path, item)}
>
<span className={styes.text}>
{name}
<HistoryHrefIcon className={styes.href} />
</span>
<span className={styes.featIn}>
{item.parent && item.parent.name}
</span>
</a>
);
},
);
};
useEffect(() => {
setEventCounts(['resultConsole', -1])
}, [props.value]);
const RESULT_KEYS = ['resultConsole', 'resultFeature'];
const getFistKey = (response, key, type) => {
const result = RESULT_KEYS.filter(item => {
const ret = response[item];
return !!(ret && 'success' === ret.type && ret.response.items.length > 0);
});
if(0 === result.length) {
return null;
};
if(!key) {
return "down" === type ? result[0]: type === "left" ? result[0]: type === "right" ? result[result.length - 1]:result[result.length - 1];
}
const index = result.indexOf(key);
return index < 0 ? null: 'down' === type ? index + 1 < result.length ? result[index + 1]: null: index - 1 >= 0 ? result[index - 1]: null;
}
const transfromEventHander = useCallback((children, data, type, handlerKey) => {
if (children === 'none') {
return
}
if (null === children) {
const key = getFistKey(data, null, handlerKey ? handlerKey: type);
if (!key) {
return null;
}
children = key === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
const ret = data[key];
const currentIndex = 'up' === type ? ret.response.items.length - 1 : 0
return 'success' !== ret.type ? null : (
setEventCounts([key, currentIndex]),
'up' === type ? (props.onNavUp && (props.onNavUp(), children[currentIndex].focus())): props.onNavDown && (props.onNavDown(), children[currentIndex].focus())
);
}
let eventsKey = eventCounts[0];
let eventsIndex = eventCounts[1];
let resultData = data[eventsKey];
if(resultData.response.items.length === 0) {
const key = getFistKey(data, null, type);
eventsKey = key;
eventsIndex= -1;
resultData = data[key];
children = key === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
}
if ('success' !== resultData.type) {
return null;
}
const index= "up" === type ? eventsIndex - 1: eventsIndex + 1;
if(index >=0 && index < resultData.response.items.length) {
return setEventCounts([eventsKey, index]), 'up' === type ? (props.onNavUp && (props.onNavUp(), children[index].focus())): props.onNavDown && (props.onNavDown(), children[index].focus())
}
const getKey = getFistKey(data, eventsKey, type);
if(!getKey) {
return null;
}
const result = data[getKey];
if('success' !== result.type) {
return null;
}
if('up' === type) {
children = getKey === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
return setEventCounts([getKey, result.response.items.length - 1]), props.onNavUp && ( props.onNavUp(), children[result.response.items.length - 1].focus())
}
return setEventCounts([getKey, 0]), (props.onNavDown && (props.onNavDown(), featureRef.current.children[0].focus()))
}, [eventCounts, props.console, props.willSearch])
const transfomResponse = (data) => {
return {
query: props.value,
response: {
items: data,
total: data.length
},
type: 'success'
}
}
let children = null;
const eventHander = useCallback((event) => {
const transformData = {
resultConsole: transfomResponse(props.console),
resultFeature: transfomResponse( unique(props.willSearch.slice(0, 20), 'path')),
};
switch (event.key) {
case "Escape":
props.onEsc && ( event.preventDefault(), props.onEsc())
break;
case "ArrowRight":
event.preventDefault();
children = featureRef.current.children;
transfromEventHander(null, transformData, 'down', 'right')
break;
case "ArrowDown":
const type = eventCounts[0]
children = type === 'resultFeature' ? featureRef.current.children: consoleRef.current.children;
event.preventDefault();
transfromEventHander(children, transformData, 'down')
break;
case "ArrowLeft":
event.preventDefault();
// const leftChildren = consoleRef.current.children;
setEventCounts(['resultConsole', -1])
transfromEventHander(null, transformData, 'up', 'left')
break;
case "ArrowUp":
children = eventCounts[0] === 'resultFeature' ? featureRef.current.children: consoleRef.current.children;
event.preventDefault();
transfromEventHander(children, transformData, 'up')
break
}
}, [eventCounts, props.console, props.willSearch]);
useEffect(() => {
props.test && document.addEventListener('keydown', eventHander);
return function() {
return document.removeEventListener('keydown', eventHander)
}
}, [props.test, eventHander, eventCounts])
return (
<div
className={classNames(styes.searchPanel, props.className)}
style={props.style}
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
onFocus={props.onFocusChange}
>
<div className={styes.container} ref={props.wrapperRef}>
{props.value === '' && (
<div className={styes.body} style={{ display: 'flex' }}>
<div className={styes.flexItem}>
{recentKeywords.length > 0 ? (
<>
<h5 className={styes.historyTitle}>
最近搜索
<DelIcon onClick={handlerDelHistory} />
</h5>
<div className={styes.label}>
{(unique(recentKeywords, 'data') || []).map(item => (
// eslint-disable-next-line react/button-has-type
<button
className={styes.btn}
title={item.data}
key={item.data}
onClick={() => props.onWillSearch(item.data)}
>
{item.data}
</button>
))}
</div>
</>
) : null}
<h5
className={styes.historyTitle}
style={{
margin: recentKeywords.length > 0 ? '16px 0px 0px' : '0',
}}
>
最近访问的产品
</h5>
{recentProducts.length > 0 ? (
(transformRecentProduct() || []).map(item => (
<a
title={item.name}
className={styes.historyHref}
key={item.name}
onClick={event => goProduct(event, item)}
onKeyDown={(event => console.log(event))}
>
<span className={styes.title}>{item.name}</span>
<span className={styes.featIn}>
<RightCircleOutlined />
</span>
</a>
))
) : (
<div className={styes.empty}>无最近访问的产品</div>
)}
</div>
<div className={styes.flexItem}>
<div className={styes.title}>关注更多信息</div>
<div className={styes.label}>
<div className={styes.empty}>没有找到相关内容</div>
</div>
</div>
</div>
)}
{props.value !== '' && (
<>
<div className={styes.body}>
{transformWillSearch()}
<div className={styes.features}>
<div className={styes.flex}>
<h5 className={styes.title}>
产品入口({props.console.length})
</h5>
<div className={styes.feature} ref={consoleRef}>{transformConsole()}</div>
</div>
<div className={styes.flex}>
<h5 className={styes.title}>快捷操作</h5>
<div className={styes.feature} ref={featureRef}>{transformFeature()}</div>
</div>
</div>
</div>
{props.willSearch.length > 0 || props.console.length > 0 ? (
<div className={styes.footer}>
<span onClick={handlerMore}>查看全部结果</span>
</div>
) : null}
</>
)}
</div>
<Modal
visible={visible}
triggerElRef={props.target}
{...props}
matchValue={matchValue}
goFeature={goFeature}
goProduct={goProduct}
/>
</div>
);
};
export default SearchPanel;
import React, { useEffect, useRef, useState } from 'react';
import { Input } from 'antd';
import classNames from 'classnames';
import PinyinMatch from 'pinyin-match';
import PropType from 'prop-types';
import { useClickAway } from 'react-use';
import useMergeValue from 'use-merge-value';
import { SearchOutlined } from '@ant-design/icons';
import styles from './index.less';
// eslint-disable-next-line import/no-unresolved
import SearchPanel from './Panel';
import ExtendPanel from './ExtendPanel';
const HeaderSearch = props => {
const {
className,
defaultValue,
onVisibleChange,
placeholder,
open,
defaultOpen,
menu,
...restProps
} = props;
const inputRef = useRef(null);
const wrapperRef = useRef(null);
const allawRef = useRef(null);
const [keyword, setKeyword] = useState('');
const [willSearch, setWillSearch] = useState([]);
const [willMenu, setWillMenu] = useState([]);
const [focus, setFocus] = useState(false);
const [isShowWidget, setIsShowWidget] = useState(false);
const [visiblePanel, setVisiblePanel] = useState(false);
const [targetOffset, setTargetOffset] = useState(0);
const [value, setValue] = useMergeValue(defaultValue, {
value: props.value,
onChange: props.onChange,
});
const [searchMode, setSearchMode] = useMergeValue(defaultOpen || true, {
value: props.open,
onChange: onVisibleChange,
});
const inputClass = classNames(styles.input, styles.search, props.className, {
[styles.show]: searchMode,
});
const onMouseEnter = () => {
// setFocus(true)
// setVisiblePanel(true)
};
const onMouseLeave = () => {
// setVisiblePanel(false)
// setFocus(false)
};
const onFocusChange = event => {
event.persist && event.persist();
event && event.stopPropagation();
setVisiblePanel(true);
// inputRef.current.blur();
// setIsShowWidget(true)
};
const onEsc = () => {
setValue('');
};
const onNavUp = () => {
inputRef.current.blur();
};
const onNavDown = () => {
// console.log('onNavDown');
};
const onSearch = event => {
event.persist && event.persist();
setKeyword(event.target.value);
const ret = [];
// eslint-disable-next-line no-shadow
const menu = [];
(props.flatMenu || []).forEach(item => {
if (PinyinMatch.match(item.name, event.target.value)) {
ret.push(item);
}
});
setWillSearch(ret);
(props.menu || []).forEach(item => {
if (PinyinMatch.match(item.name, event.target.value)) {
menu.push(item);
}
});
setWillMenu(menu);
};
useEffect(() => {
if (wrapperRef) {
setTargetOffset(wrapperRef.current.offsetLeft);
}
window.addEventListener('resize', () => {
// eslint-disable-next-line no-unused-expressions
wrapperRef.current && setTargetOffset(wrapperRef.current.offsetLeft);
});
return () => {
window.removeEventListener('resize', () =>
setTargetOffset(wrapperRef.current.offsetLeft),
);
};
}, [wrapperRef]);
useClickAway(allawRef, () => {
setFocus(false);
});
// eslint-disable-next-line no-shadow
const onWillSearch = keyword => {
// setKeyword(keyword);
onSearch({
target: {
value: keyword,
},
});
};
const onClose = event => {
event.persist && event.persist();
event && event.nativeEvent.stopImmediatePropagation();
inputRef.current.blur();
setFocus(false);
};
return (
<div
className={classNames(className, styles.headerSearch)}
ref={allawRef}
onTransitionEnd={({ propertyName }) => {
if (propertyName === 'width' && !searchMode) {
if (onVisibleChange) {
onVisibleChange(searchMode);
}
}
}}
>
<div ref={wrapperRef}>
<Input
ref={inputRef}
value={keyword}
aria-label={placeholder}
placeholder={placeholder}
className={inputClass}
allowClear
onFocus={() => {
setFocus(true);
}}
onKeyDown={event => {
event.key === 'Escape' &&
(setKeyword(''), setFocus(false), inputRef.current.blur());
wrapperRef.current.focus();
}}
onChange={onSearch}
prefix={<SearchOutlined className="site-form-item-icon" />}
/>
</div>
{
props.mode && props.mode === 'tiled' ? <ExtendPanel
value={keyword}
{...props}
target={wrapperRef}
inputRef={inputRef}
test={focus}
className={focus ? styles.active : styles.hidden}
style={{
left: `${targetOffset}px`,
top: isShowWidget ? '42px' : props.offset || '52px',
}}
onEsc={onEsc}
onNavUp={onNavUp}
onNavDown={onNavDown}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onWillSearch={onWillSearch}
onFocusChange={onFocusChange}
willSearch={willSearch}
onClose={onClose}
console={willMenu}
/>: <SearchPanel
value={keyword}
{...props}
target={wrapperRef}
inputRef={inputRef}
test={focus}
className={focus ? styles.active : styles.hidden}
style={{
left: `${targetOffset}px`,
top: isShowWidget ? '42px' : props.offset || '52px',
}}
onEsc={onEsc}
onNavUp={onNavUp}
onNavDown={onNavDown}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onWillSearch={onWillSearch}
onFocusChange={onFocusChange}
willSearch={willSearch}
onClose={onClose}
console={willMenu}
/>
}
</div>
);
};
HeaderSearch.propTypes = {
onSearch: PropType.func,
onChange: PropType.func,
onSelect: PropType.func,
onVisibleChange: PropType.func,
className: PropType.string,
placeholder: PropType.string,
options: PropType.array,
defaultOpen: PropType.bool,
open: PropType.bool,
defaultValue: PropType.string,
value: PropType.string,
};
export default HeaderSearch;
@import '~antd/es/style/themes/default.less';
.headerSearch {
// position: relative;
// display: block;
margin-right: 0px;
.input {
width: 0;
min-width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
transition: width 0.3s, margin-left 0.3s;
:global(.@{ant-prefix}-select-selection) {
background: transparent;
}
input {
padding-right: 0;
padding-left: 0;
border: 0;
box-shadow: none !important;
}
&,
&:hover,
&:focus {
// border-bottom: 1px solid @border-color-base;
}
&.show {
width: 320px;
margin-left: 8px;
}
}
:global {
.@{ant-prefix}-select-selection-search {
.@{ant-prefix}-input-affix-wrapper {
border: 1px solid #b1b9c7;
border-radius: 28px;
width: 320px !important;
color: #555555;
}
}
.@{ant-prefix}-input-affix-wrapper {
padding-right: 12px;
width: 320px;
min-width: 120px;
max-width: 320px;
border-radius: 28px;
}
.anticon-search {
color: #888888;
}
}
}
.searchPanel {
z-index: 4000;
&.hidden {
display: block;
position: absolute;
visibility: hidden;
opacity: 0;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 3px;
box-sizing: border-box;
background-color: rgb(255, 255, 255);
min-width: 120px;
font-size: 12px;
color: rgb(51, 51, 51);
transition: all 360ms ease 0s;
}
&.active {
display: block;
position: absolute;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 3px;
box-sizing: border-box;
background-color: rgb(255, 255, 255);
min-width: 120px;
font-size: 12px;
color: rgb(51, 51, 51);
transition: all 360ms ease 0s;
visibility: visible;
opacity: 1;
}
.container {
padding: 8px 0px;
outline: none;
.body {
min-width: 480px;
max-width: 600px;
font-size: 12px;
// .content {
// display: flex;
// }
.flexItem {
flex: 1 1 0%;
overflow: hidden;
.historyTitle {
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: justify;
justify-content: space-between;
// margin: 16px 0px 0px;
font-family: 'PingFang SC', sans-serif;
font-weight: 400;
color: rgb(136, 136, 136);
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.historyHref {
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
-webkit-box-align: center;
align-items: center;
outline: none;
text-decoration: none;
color: rgb(85, 85, 85);
transition: all 250ms linear 0s;
&:link,
&:visited {
color: rgb(17, 17, 17);
}
.title {
flex: 1 1 0%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&:hover {
background-color: rgb(247, 247, 247);
text-decoration: none;
color: rgb(17, 17, 17);
}
.featIn {
margin-left: 8px;
color: rgb(193, 193, 193);
}
}
}
.item,
.flexItem {
margin-bottom: 4px;
padding-bottom: 12px;
border-bottom: 1px solid rgb(242, 242, 242);
.title {
padding: 0px 12px;
height: 28px;
line-height: 28px;
color: rgb(136, 136, 136);
}
.label {
display: flex;
flex-wrap: wrap;
-webkit-box-pack: start;
justify-content: flex-start;
margin: 0px -3px -4px;
height: auto;
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-height: 24px;
overflow: hidden;
.btn {
box-sizing: border-box;
outline: medium;
background: none rgb(250, 250, 250);
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
// transition: all 0.3s ease-out 0s;
transition: all 250ms linear 0s;
display: inline-block;
border: 1px solid rgba(0, 0, 0, 0.1);
overflow: hidden;
vertical-align: middle;
text-align: center;
color: rgb(85, 85, 85);
white-space: nowrap;
padding: 0px 8px;
height: 24px;
line-height: 22px;
margin: 4px 3px;
border-radius: 14px;
margin-top: 0px;
margin-bottom: 0px;
&:hover {
background-color: rgb(247, 247, 247);
}
}
}
}
.features {
display: flex;
.flex {
flex: 1 1 0%;
overflow: hidden;
.title {
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: 16px 0px 0px;
font-family: 'PingFang SC', sans-serif;
font-weight: 400;
color: rgb(136, 136, 136);
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: justify;
justify-content: space-between;
&:first-child {
margin-top: 0;
}
}
.feature {
flex: 1 1 0%;
overflow: hidden;
.featureItem {
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
-webkit-box-align: center;
align-items: center;
outline: none;
text-decoration: none;
color: rgb(85, 85, 85);
transition: all 250ms linear 0s;
cursor: pointer;
&:link,
&:visited {
color: rgb(17, 17, 17);
}
&:hover, &:focus {
background-color: rgb(247, 247, 247);
text-decoration: none;
color: rgb(17, 17, 17);
.text {
.href {
opacity: 1;
}
}
}
.text {
flex: 1 1 0%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
em {
font-style: normal;
color: @primary-color;
font-weight: 500;
}
.href {
opacity: 0;
margin-left: 4px;
color: rgb(193, 193, 193);
transition: none 0s ease 0s;
}
}
.featIn {
flex: 0 1 auto;
max-width: 40%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 8px;
color: rgb(193, 193, 193);
}
}
}
}
}
}
.footer {
padding: 8px 12px 0px;
border-top: 1px solid rgb(242, 242, 242);
box-sizing: content-box;
height: 16px;
line-height: 16px;
span {
line-height: 12px;
cursor: pointer;
&:hover {
color: @primary-color;
}
}
}
}
}
.searchOverfy {
box-sizing: border-box;
:global(.@{ant-prefix}-popover-arrow) {
display: none;
}
:global(.@{ant-prefix}-popover-inner) {
width: 100%;
height: 100%;
position: absolute;
top: -19px;
}
}
.empty {
color: rgb(193, 193, 193);
// text-align: center;
padding-left: 4px;
width: 100%;
padding: 0px 12px;
height: 28px;
line-height: 28px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
import React, {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import classNames from 'classnames';
import PinyinMatch from 'pinyin-match';
import { useHistory } from '@wisdom-utils/runtime';
import Icon, { RightCircleOutlined } from '@ant-design/icons';
import Modal from '../modal';
import styes from './index.less';
const HistorySvg = () => (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
width="10"
height="10"
>
<path
d="M1016.405333 0h-351.573333a7.594667 7.594667 0 0 0-5.376 12.885333l149.077333 149.674667-244.224 249.770667H434.346667A7.594667 7.594667 0 0 0 426.666667 419.84v169.898667c0 4.266667 3.413333 7.594667 7.594666 7.594666h169.813334c4.266667 0 7.68-3.413333 7.68-7.594666V486.826667l263.253333-257.792 136.106667 135.509333A7.594667 7.594667 0 0 0 1024 359.253333V7.68A7.594667 7.594667 0 0 0 1016.405333 0z"
fill="#C1C1C1"
/>
<path
d="M979.626667 640a45.226667 45.226667 0 0 0-44.202667 46.08v249.258667H88.490667V88.576h245.418666l1.194667-0.085333A45.056 45.056 0 0 0 378.88 44.288 45.056 45.056 0 0 0 333.994667 0H7.68A7.68 7.68 0 0 0 0 7.68v1008.64c0 4.266667 3.413333 7.68 7.68 7.68h1008.64c4.266667 0 7.68-3.413333 7.68-7.68V686.08a45.226667 45.226667 0 0 0-44.373333-46.08z"
fill="#C1C1C1"
/>
</svg>
);
const DelHistory = () => (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
width="12"
height="12"
>
<path
d="M153.6 345.6a38.4 38.4 0 0 1 0-76.8h665.6a38.4 38.4 0 1 1 0 76.8H153.6z"
fill="#888888"
/>
<path
d="M345.6 307.2a38.4 38.4 0 0 1-76.8 0V204.8c0-49.4592 40.1408-89.6 89.6-89.6h256c49.4592 0 89.6 40.1408 89.6 89.6v102.4a38.4 38.4 0 1 1-76.8 0V204.8a12.8 12.8 0 0 0-12.8-12.8H358.4a12.8 12.8 0 0 0-12.8 12.8v102.4zM166.4 460.8a38.4 38.4 0 0 1 76.8 0v358.4c0 7.0656 5.7344 12.8 12.8 12.8h460.8a12.8 12.8 0 0 0 12.8-12.8V460.8a38.4 38.4 0 1 1 76.8 0v358.4A89.6 89.6 0 0 1 716.8 908.8H256A89.6 89.6 0 0 1 166.4 819.2V460.8z"
fill="#888888"
/>
<path
d="M371.2 460.8a38.4 38.4 0 0 1 76.8 0v256a38.4 38.4 0 1 1-76.8 0V460.8zM524.8 460.8a38.4 38.4 0 0 1 76.8 0v256a38.4 38.4 0 1 1-76.8 0V460.8z"
fill="#888888"
/>
</svg>
);
const HistoryHrefIcon = props => <Icon component={HistorySvg} {...props} />;
const DelIcon = props => <Icon component={DelHistory} {...props} />;
const unique = (arr, val) => {
const res = new Map();
return arr.filter(item => !res.has(item[val]) && res.set(item[val], 1));
};
const SearchPanel = props => {
const [visible, setVisible] = useState(false);
// const [disabled, setDisabled] = useState(false);
// const [axis, setAxis] = useState('both');
// const [currentIndex, setCurrentIndex] = useState(-1);
const [eventCounts, setEventCounts] = useState(() => ['resultConsole', -1]);
const featureRef = useRef(null);
const consoleRef = useRef(null);
let recentKeywords = props.recentKeywords.toJS
? props.recentKeywords.toJS()
: props.recentKeywords;
recentKeywords = Array.isArray(recentKeywords)
? recentKeywords
: [recentKeywords];
let recentVisited = props.recentVisited.toJS
? props.recentVisited.toJS()
: props.recentVisited;
recentVisited = Array.isArray(recentVisited)
? recentVisited
: [recentVisited];
let recentProducts = props.recentProducts.toJS
? props.recentProducts.toJS()
: props.recentProducts;
recentProducts = Array.isArray(recentProducts)
? recentProducts
: [recentProducts];
const history = useHistory();
// eslint-disable-next-line consistent-return
function getParents(data, key) {
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (const i in data) {
if (data[i].key === key) {
return [];
}
if (data[i].routes) {
const ro = getParents(data[i].routes, key);
if (ro !== undefined) return ro.concat(data[i]);
}
}
}
const goFeature = (path, rect, value) => {
// eslint-disable-next-line no-param-reassign
value = value || props.value;
const findKeywordIndex =
recentKeywords.length > 0
? recentKeywords.findIndex(item => item.data === value)
: -1;
const findRecentVisitedIndex =
recentVisited.length > 0
? recentVisited.findIndex(item => item.data.name === rect.name)
: -1;
if (findKeywordIndex === -1)
props.updateRecentKeywords && props.updateRecentKeywords(value);
if (findRecentVisitedIndex === -1)
props.updateRecentVisited && props.updateRecentVisited(rect);
let parents = getParents(props.menu, rect.key);
parents = parents[parents.length - 1];
const findIndex = props.menu.findIndex(k => k.name === parents.name);
props.updateCurrentIndex && props.updateCurrentIndex(findIndex);
props.updateOpenKeys && props.updateOpenKeys([parents.key]);
props.updateComplexConfig && props.updateComplexConfig({});
props.updateComplexPathName && props.updateComplexPathName(null);
if (rect && rect.routes && rect.routes.length > 0) {
props.updateComplexConfig && props.updateComplexConfig(rect);
props.updateComplexPathName &&
props.updateComplexPathName(rect.routes[0].path);
history.push(rect.routes[0].path);
} else {
history.push(path);
}
props.updateSelectedKeys && props.updateSelectedKeys(rect.key);
props.updatePathname && props.updatePathname(rect.key);
};
const goProduct = (event, item) => {
/* eslint-disable */
event.persist && event.persist();
event && event.stopPropagation();
const findRecentIndex =
recentProducts.length > 0
? recentProducts.findIndex(item => item.data.name === item.name)
: -1;
if (findRecentIndex === -1)
props.updateRecentProduct && props.updateRecentProduct(item);
const findIndex = props.menu.findIndex(k => k.name === item.name);
props.updateCurrentIndex && props.updateCurrentIndex(findIndex);
};
const handlerMore = event => {
event.persist && event.persist();
event && event.nativeEvent.stopImmediatePropagation();
setVisible(!visible);
props.onClose && props.onClose(event);
};
const handlerDelHistory = () => {
props.clearRecentProduct && props.clearRecentProduct();
};
const matchValue = (str, value) => {
const match = PinyinMatch.match(str, value || props.value);
return match;
};
const transformRecentProduct = () =>
unique(recentProducts.map(item => item.data), 'name');
const transformWillSearch = () => {
if (props.willSearch.length === 0) {
return null;
}
return (
<div className={styes.item}>
<div className={styes.title}>你是不是想搜:</div>
<div className={styes.label}>
{(unique(props.willSearch, 'name') || []).map(item => (
// eslint-disable-next-line react/button-has-type
<button
className={styes.btn}
key={item.name}
title={item.title}
onClick={() => props.onWillSearch(item.name)}
>
{item.name}
</button>
))}
</div>
</div>
);
};
const transformConsole = () => {
if (props.console.length === 0) {
return <div className={styes.empty}>没有找到相关内容</div>;
}
return (props.console || []).map((item, index) => {
const match = matchValue(item.name);
const name = match ? (
<span>
{item.name.substring(0, match[0])}
<em>{item.name.substring(match[0], match[1] + 1)}</em>
{item.name.substring(match[1] + 1)}
</span>
) : (
item.name
);
return (
<a
className={styes.featureItem}
key={item.name}
onClick={event => goProduct(event, item)}
tabIndex="1"
onKeyDown={event => event.key === 'Enter' && event.keyCode === 13 && goProduct(event, item)}
>
<span className={styes.text}>{name}</span>
<span className={styes.featIn}>
<RightCircleOutlined />
</span>
</a>
);
});
};
const transformFeature = () => {
if (props.willSearch.length === 0) {
return <div className={styes.empty}>没有找到相关内容</div>;
}
return (unique(props.willSearch.slice(0, 20), 'path') || []).map(
(item, index) => {
const match = matchValue(item.name);
const name = match ? (
<span>
{item.name.substring(0, match[0])}
<em>{item.name.substring(match[0], match[1] + 1)}</em>
{item.name.substring(match[1] + 1)}
</span>
) : (
item.name
);
return (
<a
className={styes.featureItem}
key={index}
onClick={() => goFeature(item.path, item)}
tabIndex="1"
onKeyDown={event => event.key === 'Enter' && event.keyCode === 13 && goFeature(item.path, item)}
>
<span className={styes.text}>
{name}
<HistoryHrefIcon className={styes.href} />
</span>
<span className={styes.featIn}>
{item.parent && item.parent.name}
</span>
</a>
);
},
);
};
useEffect(() => {
setEventCounts(['resultConsole', -1])
}, [props.value]);
const RESULT_KEYS = ['resultConsole', 'resultFeature'];
const getFistKey = (response, key, type) => {
const result = RESULT_KEYS.filter(item => {
const ret = response[item];
return !!(ret && 'success' === ret.type && ret.response.items.length > 0);
});
if(0 === result.length) {
return null;
};
if(!key) {
return "down" === type ? result[0]: type === "left" ? result[0]: type === "right" ? result[result.length - 1]:result[result.length - 1];
}
const index = result.indexOf(key);
return index < 0 ? null: 'down' === type ? index + 1 < result.length ? result[index + 1]: null: index - 1 >= 0 ? result[index - 1]: null;
}
const transfromEventHander = useCallback((children, data, type, handlerKey) => {
if (children === 'none') {
return
}
if (null === children) {
const key = getFistKey(data, null, handlerKey ? handlerKey: type);
if (!key) {
return null;
}
children = key === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
const ret = data[key];
const currentIndex = 'up' === type ? ret.response.items.length - 1 : 0
return 'success' !== ret.type ? null : (
setEventCounts([key, currentIndex]),
'up' === type ? (props.onNavUp && (props.onNavUp(), children[currentIndex].focus())): props.onNavDown && (props.onNavDown(), children[currentIndex].focus())
);
}
let eventsKey = eventCounts[0];
let eventsIndex = eventCounts[1];
let resultData = data[eventsKey];
if(resultData.response.items.length === 0) {
const key = getFistKey(data, null, type);
eventsKey = key;
eventsIndex= -1;
resultData = data[key];
children = key === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
}
if ('success' !== resultData.type) {
return null;
}
const index= "up" === type ? eventsIndex - 1: eventsIndex + 1;
if(index >=0 && index < resultData.response.items.length) {
return setEventCounts([eventsKey, index]), 'up' === type ? (props.onNavUp && (props.onNavUp(), children[index].focus())): props.onNavDown && (props.onNavDown(), children[index].focus())
}
const getKey = getFistKey(data, eventsKey, type);
if(!getKey) {
return null;
}
const result = data[getKey];
if('success' !== result.type) {
return null;
}
if('up' === type) {
children = getKey === 'resultConsole' ? consoleRef.current.children: featureRef.current.children
return setEventCounts([getKey, result.response.items.length - 1]), props.onNavUp && ( props.onNavUp(), children[result.response.items.length - 1].focus())
}
return setEventCounts([getKey, 0]), (props.onNavDown && (props.onNavDown(), featureRef.current.children[0].focus()))
}, [eventCounts, props.console, props.willSearch])
const transfomResponse = (data) => {
return {
query: props.value,
response: {
items: data,
total: data.length
},
type: 'success'
}
}
let children = null;
const eventHander = useCallback((event) => {
const transformData = {
resultConsole: transfomResponse(props.console),
resultFeature: transfomResponse( unique(props.willSearch.slice(0, 20), 'path')),
};
switch (event.key) {
case "Escape":
props.onEsc && ( event.preventDefault(), props.onEsc())
break;
case "ArrowRight":
event.preventDefault();
children = featureRef.current.children;
transfromEventHander(null, transformData, 'down', 'right')
break;
case "ArrowDown":
const type = eventCounts[0]
children = type === 'resultFeature' ? featureRef.current.children: consoleRef.current.children;
event.preventDefault();
transfromEventHander(children, transformData, 'down')
break;
case "ArrowLeft":
event.preventDefault();
// const leftChildren = consoleRef.current.children;
setEventCounts(['resultConsole', -1])
transfromEventHander(null, transformData, 'up', 'left')
break;
case "ArrowUp":
children = eventCounts[0] === 'resultFeature' ? featureRef.current.children: consoleRef.current.children;
event.preventDefault();
transfromEventHander(children, transformData, 'up')
break
}
}, [eventCounts, props.console, props.willSearch]);
useEffect(() => {
props.test && document.addEventListener('keydown', eventHander);
return function() {
return document.removeEventListener('keydown', eventHander)
}
}, [props.test, eventHander, eventCounts])
return (
<div
className={classNames(styes.searchPanel, props.className)}
style={props.style}
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
onFocus={props.onFocusChange}
>
<div className={styes.container} ref={props.wrapperRef}>
{props.value === '' && (
<div className={styes.body} style={{ display: 'flex' }}>
<div className={styes.flexItem}>
{recentKeywords.length > 0 ? (
<>
<h5 className={styes.historyTitle}>
最近搜索
<DelIcon onClick={handlerDelHistory} />
</h5>
<div className={styes.label}>
{(unique(recentKeywords, 'data') || []).map(item => (
// eslint-disable-next-line react/button-has-type
<button
className={styes.btn}
title={item.data}
key={item.data}
onClick={() => props.onWillSearch(item.data)}
>
{item.data}
</button>
))}
</div>
</>
) : null}
<h5
className={styes.historyTitle}
style={{
margin: recentKeywords.length > 0 ? '16px 0px 0px' : '0',
}}
>
最近访问的产品
</h5>
{recentProducts.length > 0 ? (
(transformRecentProduct() || []).map(item => (
<a
title={item.name}
className={styes.historyHref}
key={item.name}
onClick={event => goProduct(event, item)}
onKeyDown={(event => console.log(event))}
>
<span className={styes.title}>{item.name}</span>
<span className={styes.featIn}>
<RightCircleOutlined />
</span>
</a>
))
) : (
<div className={styes.empty}>无最近访问的产品</div>
)}
</div>
<div className={styes.flexItem}>
<div className={styes.title}>关注更多信息</div>
<div className={styes.label}>
<div className={styes.empty}>没有找到相关内容</div>
</div>
</div>
</div>
)}
{props.value !== '' && (
<>
<div className={styes.body}>
{transformWillSearch()}
<div className={styes.features}>
<div className={styes.flex}>
<h5 className={styes.title}>
产品入口({props.console.length})
</h5>
<div className={styes.feature} ref={consoleRef}>{transformConsole()}</div>
</div>
<div className={styes.flex}>
<h5 className={styes.title}>快捷操作</h5>
<div className={styes.feature} ref={featureRef}>{transformFeature()}</div>
</div>
</div>
</div>
{props.willSearch.length > 0 || props.console.length > 0 ? (
<div className={styes.footer}>
<span onClick={handlerMore}>查看全部结果</span>
</div>
) : null}
</>
)}
</div>
<Modal
visible={visible}
triggerElRef={props.target}
{...props}
matchValue={matchValue}
goFeature={goFeature}
goProduct={goProduct}
/>
</div>
);
};
export default SearchPanel;
...@@ -7,7 +7,7 @@ import useMergeValue from 'use-merge-value'; ...@@ -7,7 +7,7 @@ import useMergeValue from 'use-merge-value';
import Icon from '@ant-design/icons'; import Icon from '@ant-design/icons';
import HeaderDropdown from '../HeaderDropdown'; import { HeaderDropdown } from '@wisdom-utils/components';
import styles from './index.less'; import styles from './index.less';
import NoticeList from './NoticeList'; import NoticeList from './NoticeList';
......
import { dom } from '@wisdom-utils/utils/lib/helpers';
import styles from './index.less';
class SlideVerify {
init() {
this.initDOM();
this.initImg();
this.bindEvents();
}
render({ container, onSuccess, onFail, onRefresh }) {
// eslint-disable-next-line no-param-reassign
container.style.position = container.style.position || 'relative';
this.slideLong = 42; // 拼图边长
this.slideRadius = 9; // 拼图缺口半径
this.canvasWidth = 310; // canvas宽度
this.canvasHeight = 155; // canvas高度
this.slideTotalWidth = this.slideLong + this.slideRadius * 2 + 3; // 拼图实际边长
this.container = container;
this.onSuccess = onSuccess;
this.onFail = onFail;
this.onRefresh = onRefresh;
this.init();
}
destroy() {
const childs = this.container.childNodes;
// eslint-disable-next-line no-plusplus
for (let i = childs.length - 1; i >= 0; i--) {
this.container.removeChild(childs[i]);
}
}
initDOM() {
const canvas = this.createCanvas(this.canvasWidth, this.canvasHeight); // 画布
const block = canvas.cloneNode(true); // 拼图
const sliderContainer = this.createElement('div', styles.sliderContainer);
const refreshIcon = this.createElement('div', styles.refreshIcon);
const sliderMask = this.createElement('div', styles.sliderMask);
const slider = this.createElement('div', styles.slider);
const sliderIcon = this.createElement('span', styles.sliderIcon);
const text = this.createElement('span', styles.sliderText);
block.className = styles.sliderBlock;
text.innerHTML = '向右滑动填充拼图';
const el = this.container;
el.appendChild(canvas);
el.appendChild(refreshIcon);
el.appendChild(block);
slider.appendChild(sliderIcon);
sliderMask.appendChild(slider);
sliderContainer.appendChild(sliderMask);
sliderContainer.appendChild(text);
el.appendChild(sliderContainer);
Object.assign(this, {
canvas,
block,
sliderContainer,
refreshIcon,
slider,
sliderMask,
sliderIcon,
text,
canvasCtx: canvas.getContext('2d'),
blockCtx: block.getContext('2d'),
});
}
initImg() {
// eslint-disable-next-line no-var
var img = this.createImg(() => {
this.startDraw();
this.canvasCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
this.blockCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
const y = this.slideY - this.slideRadius * 2 - 2;
const ImageData = this.blockCtx.getImageData(
this.slideX - 3,
y,
this.slideTotalWidth,
this.slideTotalWidth,
);
this.block.width = this.slideTotalWidth;
this.blockCtx.putImageData(ImageData, 0, y);
});
this.img = img;
}
startDraw() {
// 随机创建拼图的位置(矩形拼图左上顶点位置)
this.slideX = this.getRandomNumberByRange(
this.slideTotalWidth + 10,
this.canvasWidth - (this.slideTotalWidth + 10),
);
this.slideY = this.getRandomNumberByRange(
10 + this.slideRadius * 2,
this.canvasHeight - (this.slideTotalWidth + 10),
);
this.draw(this.canvasCtx, this.slideX, this.slideY, 'fill');
this.draw(this.blockCtx, this.slideX, this.slideY, 'clip');
}
clean() {
this.canvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.blockCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
this.block.width = this.canvasWidth;
}
bindEvents() {
this.container.onselectstart = () => false;
this.refreshIcon.onclick = () => {
this.reset();
typeof this.onRefresh === 'function' && this.onRefresh();
};
let originX;
let originY;
const trail = [];
let isMouseDown = false;
// eslint-disable-next-line func-names
const handleDragStart = function(e) {
originX = e.clientX || e.touches[0].clientX;
originY = e.clientY || e.touches[0].clientY;
isMouseDown = true;
};
// eslint-disable-next-line consistent-return
const handleDragMove = e => {
if (!isMouseDown) return false;
const eventX = e.clientX || e.touches[0].clientX;
const eventY = e.clientY || e.touches[0].clientY;
const moveX = eventX - originX;
const moveY = eventY - originY;
if (moveX < 0 || moveX + 38 >= this.canvasWidth) return false;
this.slider.style.left = `${moveX}px`; // 按钮的滑动距离
const blockLeft =
((this.canvasWidth - 40 - 20) / (this.canvasWidth - 40)) * moveX; // 按钮与滑块的移动比例相同
this.block.style.left = `${blockLeft}px`;
dom.addClass(this.sliderContainer, styles.sliderContainer_active);
this.sliderMask.style.width = `${moveX}px`;
trail.push(moveY);
};
// eslint-disable-next-line consistent-return
const handleDragEnd = e => {
if (!isMouseDown) return false;
isMouseDown = false;
const eventX = e.clientX || e.changedTouches[0].clientX;
if (eventX === originX) return false;
dom.removeClass(this.sliderContainer, styles.sliderContainer_active);
this.trail = trail;
const { spliced, verified } = this.verify();
if (spliced) {
if (verified) {
dom.addClass(this.sliderContainer, styles.sliderContainer_success);
typeof this.onSuccess === 'function' && this.onSuccess();
} else {
dom.addClass(this.sliderContainer, styles.sliderContainer_fail);
this.text.innerHTML = '再试一次';
this.reset();
}
} else {
dom.addClass(this.sliderContainer, styles.sliderContainer_fail);
typeof this.onFail === 'function' && this.onFail();
setTimeout(() => {
this.reset();
}, 1000);
}
};
this.slider.addEventListener('mousedown', handleDragStart);
this.slider.addEventListener('touchstart', handleDragStart);
document.addEventListener('mousemove', handleDragMove);
document.addEventListener('touchmove', handleDragMove);
document.addEventListener('mouseup', handleDragEnd);
document.addEventListener('touchend', handleDragEnd);
}
verify() {
const arr = this.trail; // 拖动时y轴的移动距离
const average = arr.reduce(this.sum) / arr.length;
const deviations = arr.map(x => x - average);
const stddev = Math.sqrt(
deviations.map(this.square).reduce(this.sum) / arr.length,
); // 总体标准差
// eslint-disable-next-line radix
const left = parseInt(this.block.style.left);
return {
spliced: Math.abs(left - this.slideX) < 10,
verified: stddev !== 0, // 简单验证下拖动轨迹,为零时表示Y轴上下没有波动,可能非人为操作
};
}
reset() {
this.sliderContainer.className = styles.sliderContainer;
this.slider.style.left = 0;
this.block.style.left = 0;
this.sliderMask.style.width = 0;
this.clean();
this.img.src = this.getRandomImg();
}
createCanvas(width, height) {
const canvas = this.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
}
createElement(tagName, className) {
const element = document.createElement(tagName);
element.className = className;
return element;
}
getRandomNumberByRange(start, end) {
return Math.round(Math.random() * (end - start) + start);
}
getRandomImg() {
// eslint-disable-next-line global-require
return require(`../../assets/SlideVerify/${[
`${this.getRandomNumberByRange(1, 8)}.jpg`,
]}`);
}
createImg(onload) {
const img = new Image();
img.setAttribute('crossOrigin', 'Anonymous');
img.src = this.getRandomImg();
img.onload = onload;
img.onerror = () => {
img.src = this.getRandomImg();
};
return img;
}
draw(ctx, x, y, operation) {
const l = this.slideLong; // 滑块边长
const r = this.slideRadius;
const { PI } = Math;
const borderGap = 2;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x + l / 2, y - r + borderGap, r, 0.72 * PI, 2.26 * PI); // 上圆
ctx.lineTo(x + l, y);
ctx.arc(x + l + r - borderGap, y + l / 2, r, 1.21 * PI, 2.78 * PI); // 右圆
ctx.lineTo(x + l, y + l);
ctx.lineTo(x, y + l);
ctx.arc(x + r - borderGap, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true); // 左圆
ctx.lineTo(x, y);
ctx.lineWidth = borderGap;
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
ctx.stroke();
ctx[operation]();
ctx.globalCompositeOperation = 'overlay';
}
sum(x, y) {
return x + y;
}
square(x) {
return x * x;
}
}
export default SlideVerify;
.sliderBlock {
position: absolute;
left: 0;
top: 0;
}
.sliderContainer {
position: relative;
text-align: center;
width: 310px;
height: 40px;
line-height: 40px;
margin-top: 15px;
background: #f7f9fa;
color: #45494c;
border: 1px solid #e4e7eb;
&.sliderContainer_active {
.slider {
height: 38px;
top: -1px;
border: 1px solid #1991fa;
}
.sliderMask {
height: 38px;
border-width: 1px;
}
}
&.sliderContainer_success {
.slider {
height: 38px;
top: -1px;
border: 1px solid #52ccba;
background-color: #52ccba !important;
}
.sliderMask {
height: 38px;
border: 1px solid #52ccba;
background-color: #d2f4ef;
}
.sliderIcon {
background-position: 0 0 !important;
}
}
&.sliderContainer_fail {
.sliderMask {
height: 38px;
border: 1px solid #f57a7a;
background-color: #fce1e1;
}
.sliderIcon {
top: 14px;
background-position: 0 -82px !important;
}
}
&.sliderContainer_active .sliderText,
&.sliderContainer_success .sliderText,
&.sliderContainer_fail .sliderText {
display: none;
}
.sliderMask {
position: absolute;
left: 0;
top: 0;
height: 40px;
border: 0 solid #1991fa;
background: #d1e9fe;
}
.slider {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
background: #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
cursor: pointer;
transition: background 0.2s linear;
&:hover {
background: #1991fa;
.sliderIcon {
background-position: 0 -13px;
}
}
}
.sliderIcon {
position: absolute;
top: 15px;
left: 13px;
width: 14px;
height: 12px;
background: url(https://panda-water.cn/web4/assets/images/SlideVerify/icon.png)
0 -26px;
background-size: 34px 471px;
}
.refreshIcon {
position: absolute;
right: 0;
top: 0;
width: 34px;
height: 34px;
cursor: pointer;
background: url(https://panda-water.cn/web4/assets/images/SlideVerify/icon.png)
0 -437px;
background-size: 34px 471px;
}
}
import React, { useState } from 'react';
import classNames from 'classnames';
import styles from './index.less';
const Categories = props => {
const [currentIndex, setCurrentIndex] = useState(props.currentMenuIndex);
const selectCategories = (event, index) => {
event.preventDefault();
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setCurrentIndex(index);
// eslint-disable-next-line no-unused-expressions
props.onChange && props.onChange(index);
};
return (
<div className={classNames(styles['menu-categories'], {
[styles['min-cateorites']]: props.mode
})}>
{(props.data || []).map((item, index) => {
const categorieCls = classNames(
styles['categorie-name'],
styles.btn,
currentIndex === index ? styles.active : '',
);
return (
<div
className={categorieCls}
key={item.name}
onClick={event => selectCategories(event, index)}
>
{/* eslint-disable-next-line jsx-a11y/alt-text */}
<img src={item.extData.icon} />
<span>{item.extData.label}</span>
</div>
);
})}
</div>
);
};
export default Categories;
import React from 'react';
import styles from './index.less';
const Menu = props => {
const renderTitle = title => <h4 className={styles.title}>{title}</h4>;
const renderMenuItem = data => {
let menuItem = [];
if (!data) {
return;
}
// eslint-disable-next-line no-prototype-builtins
if (!data.hasOwnProperty('routes')) {
menuItem = (
<div
className={styles['main-menus-recentAll-menu-group-items-menu-item']}
onClick={event => props.handleClick(event, data)}
>
<img src={data.extData.icon} alt="" />
<a
className={`${
styles['main-menus-recentAll-menu-group-items-menu-item-name']
} ${styles.pad}`}
>
{data.name}
</a>
</div>
);
} else {
data.routes.forEach((item, index) => {
const render = (
<div
className={
styles['main-menus-recentAll-menu-group-items-menu-item']
}
key={item.name}
onClick={event => props.handleClick(event, item)}
>
<img src={item.extData.icon} alt="" />
<a
className={`${
styles['main-menus-recentAll-menu-group-items-menu-item-name']
} ${styles.pad}`}
>
{item.name}
</a>
</div>
);
menuItem.push(render);
});
}
// eslint-disable-next-line consistent-return
return menuItem;
};
return (
<div className={styles['main-menus']}>
<div className={styles['main-menus-recentAll']}>
<div className={styles['main-menus-recentAll-menu-group']}>
{(props.data.routes || []).map((item, index) => (
<div
className={styles['main-menus-recentAll-menu-group-items']}
key={item.name}
>
{renderTitle(item.name)}
{renderMenuItem(item)}
</div>
))}
</div>
</div>
</div>
);
};
export default Menu;
import React, { useState } from 'react';
import classNames from 'classnames';
import styles from './min.less';
const Categories = props => {
const [currentIndex, setCurrentIndex] = useState(props.currentMenuIndex);
const selectCategories = (event, index) => {
event.preventDefault();
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
setCurrentIndex(index);
// eslint-disable-next-line no-unused-expressions
props.onChange && props.onChange(index);
};
return (
<div className={classNames(styles['menu-categories'], {
[styles['min-cateorites']]: props.mode
})}>
{(props.data || []).filter(item => !item.hideInMenu).map((item, index) => {
const categorieCls = classNames(
styles['categorie-name'],
styles.btn,
currentIndex === index ? styles.active : '',
);
return (
<div
className={categorieCls}
key={item.name}
onClick={event => selectCategories(event, index)}
>
{/* eslint-disable-next-line jsx-a11y/alt-text */}
<img src={item.extData.icon} />
<span>{item.extData.label}</span>
</div>
);
})
}
</div>
);
};
export default Categories;
import React, { useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import propTypes from 'prop-types';
import KeyCode from 'rc-util/lib/KeyCode';
import Icon, { MenuOutlined } from '@ant-design/icons';
import Categories from './MinCategories';
import styles from './min.less';
// eslint-disable-next-line import/extensions
import { events } from './utils/index.js';
const ThLarge = props => (
<svg viewBox="0 0 1024 1024" version="1.1" width="14" height="14">
<path
d="M592 64h384c26.51 0 48 21.49 48 48v320c0 26.51-21.49 48-48 48H592c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48z m-160 0H48C21.49 64 0 85.49 0 112v320c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zM0 592v320c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48V592c0-26.51-21.49-48-48-48H48c-26.51 0-48 21.49-48 48z m592 368h384c26.51 0 48-21.49 48-48V592c0-26.51-21.49-48-48-48H592c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48z"
fill="#737f97"
/>
</svg>
);
const ThLargeIcon = props => <Icon component={ThLarge} {...props} />;
const MinPanel = props => {
const getCategories = () => {
let { data } = props;
// eslint-disable-next-line no-prototype-builtins
data = data.filter(item => item.hasOwnProperty('extData'));
return data;
};
const categories = getCategories();
const wcls = categories.length <= 10 ? styles.w110: styles.w210
const panelCls = classNames(
styles.mainPane,
props.visible ? styles.visible : styles.hidden,
wcls
);
const domRef = useRef();
// eslint-disable-next-line no-debugger;
const [currentMenu, setCurrentMenu] = useState(null);
useEffect(() => {
setCurrentMenu(props.data[props.currentMenuIndex]);
}, [props.data, props.currentMenuIndex]);
// eslint-disable-next-line no-underscore-dangle
let _clickEvents = null;
const handleKeyDown = event => {
if (event.keyCode === KeyCode.ESC) {
const { onClose } = props;
event.stopPropagation();
if (onClose) {
onClose(event);
}
}
};
const domFocus = () => {
if (domRef) {
domRef.current.focus();
}
};
const handleDocumentClick = e => {
if (props.visible) {
const node = domRef && domRef.current;
if (
node &&
(node === e.target ||
node.contains(e.target) ||
(e.target !== document &&
!document.documentElement.contains(e.target)))
) {
return;
}
// eslint-disable-next-line no-unused-expressions
props.onClose && props.onClose(e);
}
};
const addDocumentEvents = () => {
if (props.canCloseByOutSideClick) {
_clickEvents = events.on(document, 'click', handleDocumentClick);
}
};
const removeDocumentEvents = () => {
_clickEvents.off();
_clickEvents = null;
};
const selectItem = (event, item) => {
// eslint-disable-next-line no-unused-expressions
props.onSelect && props.onSelect(item);
};
const handleCategories = index => {
setCurrentMenu(props.data[index]);
// eslint-disable-next-line no-unused-expressions
props.onChange && props.onChange(index);
};
useEffect(() => {
if (props.visible) {
domFocus();
}
addDocumentEvents();
return () => removeDocumentEvents();
}, [props.visible]);
return (
<div
className={panelCls}
tabIndex="-1"
onKeyDown={event =>
props.visible && props.keyboard ? handleKeyDown(event) : undefined
}
ref={domRef}
>
<div className={styles.main}>
<div className={styles['main-left']}>
<Categories
mode="mini"
data={categories}
onChange={handleCategories}
currentMenuIndex={props.currentMenuIndex}
/>
</div>
</div>
</div>
);
};
MinPanel.propTypes = {
visible: propTypes.bool,
keyboard: propTypes.bool,
onClose: propTypes.func,
canCloseByOutSideClick: propTypes.bool,
};
MinPanel.defaultProps = {
visible: false,
keyboard: true,
canCloseByOutSideClick: true,
onClose: () => {},
};
export default MinPanel;
import React, { useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import propTypes from 'prop-types';
import KeyCode from 'rc-util/lib/KeyCode';
import { Spin } from 'antd';
import Icon, { MenuOutlined } from '@ant-design/icons';
import { events } from '@wisdom-utils/utils/lib/helpers';
import Categories from './Categories';
import styles from './index.less';
import Menu from './Menu';
// eslint-disable-next-line import/extensions
const ThLarge = props => (
<svg viewBox="0 0 1024 1024" version="1.1" width="14" height="14">
<path
d="M592 64h384c26.51 0 48 21.49 48 48v320c0 26.51-21.49 48-48 48H592c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48z m-160 0H48C21.49 64 0 85.49 0 112v320c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zM0 592v320c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48V592c0-26.51-21.49-48-48-48H48c-26.51 0-48 21.49-48 48z m592 368h384c26.51 0 48-21.49 48-48V592c0-26.51-21.49-48-48-48H592c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48z"
fill="#737f97"
/>
</svg>
);
const ThLargeIcon = props => <Icon component={ThLarge} {...props} />;
const Panel = props => {
const panelCls = classNames(
styles.mainPane,
props.visible ? styles.visible : styles.hidden,
);
const domRef = useRef();
// eslint-disable-next-line no-debugger;
const [currentMenu, setCurrentMenu] = useState(null);
useEffect(() => {
setCurrentMenu(props.data[props.currentMenuIndex]);
}, [props.data, props.currentMenuIndex]);
// eslint-disable-next-line no-underscore-dangle
let _clickEvents = null;
const handleKeyDown = event => {
if (event.keyCode === KeyCode.ESC) {
const { onClose } = props;
event.stopPropagation();
if (onClose) {
onClose(event);
}
}
};
const domFocus = () => {
if (domRef) {
domRef.current.focus();
}
};
const handleDocumentClick = e => {
if (props.visible) {
const node = domRef && domRef.current;
if (
node &&
(node === e.target ||
node.contains(e.target) ||
(e.target !== document &&
!document.documentElement.contains(e.target)))
) {
return;
}
// eslint-disable-next-line no-unused-expressions
props.onClose && props.onClose(e);
}
};
const addDocumentEvents = () => {
if (props.canCloseByOutSideClick) {
_clickEvents = events.on(document, 'click', handleDocumentClick);
}
};
const removeDocumentEvents = () => {
_clickEvents.off();
_clickEvents = null;
};
const getCategories = () => {
let { data } = props;
// eslint-disable-next-line no-prototype-builtins
data = data.filter(item => item.hasOwnProperty('extData'));
return data;
};
const handleCategories = index => {
setCurrentMenu(props.data[index]);
// eslint-disable-next-line no-unused-expressions
props.onChange && props.onChange(index);
};
const selectItem = (event, item) => {
// eslint-disable-next-line no-unused-expressions
props.onSelect && props.onSelect(item);
};
useEffect(() => {
if (props.visible) {
domFocus();
}
addDocumentEvents();
return () => removeDocumentEvents();
}, [props.visible]);
return (
<div
className={panelCls}
tabIndex="-1"
onKeyDown={event =>
props.visible && props.keyboard ? handleKeyDown(event) : undefined
}
ref={domRef}
>
<div className={styles.header}>
<ThLargeIcon />
<div className={styles['header-title']}>切换子系统</div>
<span className={styles.subheader}>
<MenuOutlined />
子系统功能一览
</span>
<span className={styles.marks}>
<img
src="https://panda-water.cn/web4/assets/images/waterMarks/%E8%8F%9C%E5%8D%95%E6%B0%B4%E5%8D%B0.SVG"
alt=""
/>
</span>
</div>
<div className={styles.main}>
<div className={styles['main-left']}>
<Categories
data={getCategories()}
onChange={handleCategories}
currentMenuIndex={props.currentMenuIndex}
/>
</div>
<div className={styles['main-menus']}>
<Spin spinning={!currentMenu}>
<Menu data={currentMenu || []} handleClick={selectItem} />
</Spin>
</div>
</div>
</div>
);
};
Panel.propTypes = {
visible: propTypes.bool,
keyboard: propTypes.bool,
onClose: propTypes.func,
canCloseByOutSideClick: propTypes.bool,
};
Panel.defaultProps = {
visible: false,
keyboard: true,
canCloseByOutSideClick: true,
onClose: () => {},
};
export default Panel;
import Panel from './Panel';
export { Panel };
@import '~antd/es/style/themes/default.less';
@dark-menu-catatories-color: rgba(255, 255, 255, 0.65);
.mainPane {
position: absolute;
&.hidden {
// display: none;
flex: 1 1 0%;
// position: relative;
z-index: 5;
background-color: rgb(247, 247, 247);
// min-width: 490px;
// max-width: 980px;
width: 0;
overflow: hidden;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
transform: translateX(-1240px);
}
&.visible {
display: block;
flex: 1 1 0%;
position: absolute;
z-index: 30;
background-color: #001529;
min-width: 500px;
max-width: 640px;
overflow: hidden;
height: 100%;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
}
.header {
width: 100%;
height: 40px;
line-height: 20px;
text-align: center;
padding: 0 0 0 18px;
display: inline-flex;
align-items: center;
&-title {
color: #fff;
padding-left: 12px;
}
.subheader {
color: #fff;
display: flex;
align-items: center;
margin-left: 20px;
:global(.@{ant-prefix}icon-menu) {
color: #737f97;
padding-right: 12px;
}
}
.marks {
position: absolute;
right: 12px;
top: 8px;
}
}
.main {
// padding: 32px 0px 0px 32px;
padding: 0px 0px 0px 4px;
height: 100%;
overflow: hidden;
box-sizing: border-box;
display: flex;
&-left {
// padding-top: 32px;
width: 125px;
height: 100%;
overflow: hidden auto;
box-sizing: border-box;
.menu-categories {
&.min-cateorites {
position: relative;
top: 46px;
}
.categorie-name {
border-width: 0px 0px 0px 1px;
border-top-style: initial;
border-right-style: initial;
border-bottom-style: initial;
border-top-color: initial;
border-right-color: initial;
border-bottom-color: initial;
border-image: initial;
border-left-style: solid;
border-left-color: rgb(222, 222, 222);
display: flex;
align-items: center;
&.btn {
box-sizing: border-box;
outline: medium;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
transition: all 0.3s ease-out 0s;
border: 1px solid transparent;
vertical-align: middle;
text-align: left;
color: rgb(85, 85, 85);
// display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0px 12px;
height: 40px;
line-height: 40px;
&:hover {
border-left: 2px solid @primary-color;
span {
color: #fff;
}
}
&:hover,
&:link:hover,
&:visited:hover {
color: #273150;
}
}
img {
width: 17px;
height: 17px;
}
span {
margin-left: 12px;
color: @dark-menu-catatories-color;
}
&.active {
background-color: @primary-color;
// border-left: 2px solid @primary-2;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
}
}
}
}
&-menus {
flex: 1 1 0%;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: row;
margin-left: 12px;
&::-webkit-scrollbar {
width: 0px;
height: 0px;
}
&-recentAll {
flex: 1 1 0%;
padding: 0px 32px 32px 0px;
overflow: auto;
&-menu-group {
margin-bottom: 12px;
columns: 120px 3;
column-gap: 12px;
&-items {
display: inline-block;
margin-bottom: 20px;
width: 100%;
break-inside: avoid;
.title {
margin: 0px 0px 8px 0px;
padding: 0px;
height: 30px;
line-height: 30px;
font-size: 12px;
font-weight: 600;
color: #fff;
transition: all 250ms linear 0s;
}
&-menu-item {
position: relative;
transition: all 300ms ease 0s;
display: flex;
align-items: center;
img {
width: 14px;
height: 14px;
}
&-name {
box-sizing: border-box;
outline: medium;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
transition: all 0.3s ease-out 0s;
border: 1px solid transparent;
vertical-align: middle;
text-align: left;
color: rgba(255, 255, 255, 0.65);
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0px 12px;
height: 32px;
line-height: 30px;
&.pad {
padding: 0px 4px;
}
&:link,
&:visited,
&:hover {
// color: rgb(85, 85, 85);
color: #fff;
}
}
}
}
}
}
}
}
}
@import '~antd/es/style/themes/default.less';
@dark-menu-catatories-color: rgba(255, 255, 255, 0.65);
@primary-color: #1685FF;
.mainPane {
position: absolute;
&.hidden {
// display: none;
flex: 1 1 0%;
// position: relative;
z-index: 5;
background-color: rgb(247, 247, 247);
// min-width: 490px;
// max-width: 980px;
width: 0;
overflow: hidden;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
transform: translateX(-1240px);
}
&.visible {
display: block;
flex: 1;
position: absolute;
z-index: 610;
background-color: rgba(0, 21, 41, 0.99);
min-width: 210px;
max-width: 210px;
overflow: hidden;
height: 100%;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
}
&.w110 {
min-width: 110px;
max-width: 110px;
}
&.w210 {
min-width: 210px;
max-width: 210px;
}
.header {
width: 100%;
height: 40px;
line-height: 20px;
text-align: center;
padding: 0 0 0 18px;
display: inline-flex;
align-items: center;
&-title {
color: #fff;
padding-left: 12px;
}
.subheader {
color: #fff;
display: flex;
align-items: center;
margin-left: 20px;
:global(.@{ant-prefix}icon-menu) {
color: #737f97;
padding-right: 12px;
}
}
.marks {
position: absolute;
right: 12px;
top: 8px;
}
}
.main {
// padding: 32px 0px 0px 32px;
padding: 0px 0px 0px 4px;
height: 100%;
overflow: hidden;
box-sizing: border-box;
display: flex;
&-left {
// padding-top: 32px;
// width: 125px;
height: 100%;
overflow: hidden auto;
box-sizing: border-box;
.menu-categories {
&.min-cateorites {
position: relative;
top: 48px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.categorie-name {
border-width: 0px 0px 0px 1px;
border-top-style: initial;
border-right-style: initial;
border-bottom-style: initial;
border-top-color: initial;
border-right-color: initial;
border-bottom-color: initial;
border-image: initial;
border-left-style: solid;
border-left-color: rgb(222, 222, 222);
display: flex;
align-items: center;
&.btn {
box-sizing: border-box;
outline: medium;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
transition: all 0.3s ease-out 0s;
border: 1px solid transparent;
vertical-align: middle;
text-align: left;
color: #555555;
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 12px 12px;
height: 74px;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 2px;
&:hover {
// border-left: 2px solid @primary-color;
// span {
// color: #fff;
// }
span {
color: #fff;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
}
}
&:hover,
&:link:hover,
&:visited:hover {
color: #273150;
}
}
img {
width: 22px;
height: 22px;
}
span {
// margin-left: 12px;
padding-top: 4px;
color: @dark-menu-catatories-color;
opacity: 1;
transition: opacity .3s cubic-bezier(.645,.045,.355,1),margin .3s,color .3s
}
&.active {
background-color: rgba(0, 0, 0, 0.2);
// border-left: 2px solid @primary-2;
transition: all 0.25s cubic-bezier(0, 0, 0.2, 1) 0s;
span {
color: #fff;
}
}
}
}
}
&-menus {
flex: 1 1 0%;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: row;
margin-left: 12px;
&::-webkit-scrollbar {
width: 0px;
height: 0px;
}
&-recentAll {
flex: 1 1 0%;
padding: 0px 32px 32px 0px;
overflow: auto;
&-menu-group {
margin-bottom: 12px;
columns: 120px 3;
column-gap: 12px;
&-items {
display: inline-block;
margin-bottom: 20px;
width: 100%;
break-inside: avoid;
.title {
margin: 0px 0px 8px 0px;
padding: 0px;
height: 30px;
line-height: 30px;
font-size: 12px;
font-weight: 600;
color: #fff;
transition: all 250ms linear 0s;
}
&-menu-item {
position: relative;
transition: all 300ms ease 0s;
display: flex;
align-items: center;
img {
width: 14px;
height: 14px;
}
&-name {
box-sizing: border-box;
outline: medium;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
transition: all 0.3s ease-out 0s;
border: 1px solid transparent;
vertical-align: middle;
text-align: left;
color: rgba(255, 255, 255, 0.65);
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0px 12px;
height: 32px;
line-height: 30px;
&.pad {
padding: 0px 4px;
}
&:link,
&:visited,
&:hover {
// color: rgb(85, 85, 85);
color: #fff;
}
}
}
}
}
}
}
}
}
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { getKeyName } from '../../utils/utils';
const TabPanes = props => {
const [activeKey, setActiveKey] = useState('');
const [panes, setPanes] = useState([
{
title: '首页',
key: 'home',
closable: false,
path: '/',
},
]);
const [isReload, setIsReload] = useState(false);
const [selectedPanel, setSelectedPanel] = useState({});
const pathRef = useRef(null);
const {
storeData: { curTab, reloadPath },
setStoreData,
defaultActiveKey,
panesItem,
tabActiveKey,
} = props;
const history = useHistory();
const { pathname, search } = useLocation();
const fullPath = pathname + search;
const storeTabs = useCallback(
ps => {
const pathArr = ps.reduce((prev, next) => [...prev, next.path], []);
// setStoreData('SET_CURTAB', pathArr)
},
[setStoreData],
);
const resetTabs = useCallback(() => {
const initPanes = curTab.reduce((prev, next) => {
const { title, tabKey, Content } = getKeyName(next);
return [
...prev,
{
title,
key: tabKey,
content: Content,
closable: tabKey !== 'home',
path: next,
},
];
}, []);
const { tabKey } = getKeyName(pathname);
setPanes(initPanes);
setActiveKey(tabKey);
}, [curTab, pathname]);
useEffect(() => {
resetTabs();
}, [resetTabs]);
const onChange = tabKey => {
setActiveKey(tabKey);
};
const remove = targetKey => {
const delIndex = panes.findIndex(item => item.key === targetKey);
panes.splice(delIndex, 1);
if (targetKey !== activeKey) {
const nextKey = activeKey;
setPanes(panes);
setActiveKey(nextKey);
storeTabs(panes);
return;
}
const nextPath = curTab[delIndex - 1];
const { tabKey } = getKeyName(nextPath);
if (nextPath !== '/') {
remove(tabKey);
history.push(curTab[delIndex - 2]);
} else {
history.push(nextPath);
}
setPanes(panes);
storeTabs(panes);
};
const onEdit = (targetKey, action) =>
action === 'remove' && remove(targetKey);
const onTabClick = targetKey => {
const { path } = panes.filter(item => item.key === targetKey)[0];
history.push({ pathname: path });
};
const refreshTab = () => {
setIsReload(true);
setTimeout(() => {
setIsReload(false);
}, 1000);
setStoreData('SET_RELOADPATH', pathname + search);
setTimeout(() => {
setStoreData('SET_RELOADPATH', 'null');
}, 500);
};
};
import React from 'react';
import ReactDraggable from 'react-draggable';
/* eslint-disable */
import Resize from './resize';
class Draggable extends React.Component {
constructor(props) {
super(props);
this.resizing = false;
this.resizingPosition = {
x: 0,
y: 0,
};
this.offsetFromParent = {
left: 0,
top: 0,
};
this.resizableElement = {
current: null,
};
this.refDraggable = ref => {
ref && (this.draggable = ref);
};
this.refResizable = resize => {
resize &&
((this.resizable = resize),
(this.resizableElement.current = resize.resizable));
};
this.state = {
original: {
x: 0,
y: 0,
},
bounds: {
top: 0,
right: 0,
bottom: 0,
left: 0,
},
maxWidth: props.maxWidth,
maxHeight: props.maxHeight,
};
this.onResizeStart = this.onResizeStart.bind(this);
this.onResize = this.onResize.bind(this);
this.onResizeStop = this.onResizeStop.bind(this);
this.onDragStart = this.onDragStart.bind(this);
this.onDrag = this.onDrag.bind(this);
this.onDragStop = this.onDragStop.bind(this);
this.getMaxSizesFromProps = this.getMaxSizesFromProps.bind(this);
}
componentDidMount() {
this.updateOffsetFromParent();
const { left, top } = this.offsetFromParent;
const { x, y } = this.getDraggablePosition();
this.draggable.setState({
x: x - left,
y: y - top,
});
this.forceUpdate();
}
getDraggablePosition() {
const { state } = this.draggable;
return {
x: state.x,
y: state.y,
};
}
getParent() {
return this.resizable && this.resizable.parentNode;
}
getParentSize() {
return this.resizable.getParentSize();
}
getMaxSizesFromProps() {
return {
maxWidth:
void 0 === this.props.maxWidth
? Number.MAX_SAFE_INTEGER
: this.props.maxWidth,
maxHeight:
void 0 === this.props.maxHeight
? Number.MAX_SAFE_INTEGER
: this.props.maxHeight,
};
}
getSelfElement() {
return this.resizable && this.resizable.resizable;
}
getOffsetHeight(event) {
const { scale } = this.props;
switch (this.props.bounds) {
case 'window':
return window.innerHeight / scale;
case 'body':
return document.body.offsetHeight / scale;
default:
return event.offsetHeight;
}
}
getOffsetWidth(event) {
const { scale } = this.props;
switch (this.props.bounds) {
case 'window':
return window.innerWidth / scale;
case 'body':
return document.body.offsetWidth / scale;
default:
return event.offsetWidth;
}
}
onDragStart(event, position) {
if (
(this.props.onDragStart && this.props.onDragStart(event, position),
this.props.bounds)
) {
const parent = this.getParent();
const { scale } = this.props;
// eslint-disable-next-line no-underscore-dangle
let _parent;
if (this.props.bounds === 'parent') {
_parent = parent;
} else {
if (this.props.bounds === 'body') {
const rect = parent.getBoundingClientRect();
const { left, top } = rect;
const domRect = document.body.getBoundingClientRect();
const deltLeft =
-(left - parent.offsetLeft * scale - domRect.left) / scale;
const deltTop =
-(top - parent.offsetTop * scale - domRect.top) / scale;
const deltRight =
(document.body.offsetWidth - this.resizable.size.width * scale) /
scale +
deltLeft;
const deltBottom =
(document.body.offsetHeight - this.resizable.size.height * scale) /
scale +
deltTop;
return this.setState({
bounds: {
top: deltTop,
right: deltRight,
left: deltLeft,
bottom: deltBottom,
},
});
}
if (this.props.bounds === 'window') {
if (!this.resizable) return;
const rect = parent.getBoundingClientRect();
const deltLeft = -(rect.left - parent.offsetLeft * scale) / scale;
const deltTop = -(rect.top - parent.offsetTop * scale) / scale;
const deltRight =
(window.innerWidth - this.resizable.size.width * scale) / scale +
deltLeft;
const deltBottom =
(window.innerHeight - this.resizable.size.height * scale) / scale +
deltTop;
return this.setState({
bounds: {
top: deltTop,
right: deltRight,
left: deltLeft,
bottom: deltBottom,
},
});
}
_parent = document.querySelector(this.props.bounds);
}
if (_parent instanceof HTMLElement && parent instanceof HTMLElement) {
const rect = _parent.getBoundingClientRect();
const { left, top } = rect;
const parentRect = parent.getBoundingClientRect();
let deltLeft = (left - parentRect.left) / scale;
const deltTop = top - deltLeft.top;
if (this.resizable) {
this.updateOffsetFromParent();
const fromParent = this.offsetFromParent;
this.setState({
bounds: {
top: deltTop - fromParent.top,
right:
deltLeft +
(_parent.offsetWidth - this.resizable.size.width) -
fromParent.left / scale,
bottom:
deltTop +
(_parent.offsetHeight - this.resizable.size.height) -
fromParent.top,
// eslint-disable-next-line no-const-assign
left: (deltLeft = fromParent.left / scale),
},
});
}
}
}
}
onDrag(event, position) {
if (this.props.onDrag) {
const fromParent = this.offsetFromParent;
return this.props.onDrag(
event,
Object.assign(Object.assign({}, position), {
x: position.x - fromParent.left,
y: position.y - fromParent.top,
}),
);
}
}
onDragStop(event, position) {
if (this.props.onDragStop) {
const fromParent = this.offsetFromParent;
return this.props.onDragStop(
event,
Object.assign(Object.assign({}, position), {
x: position.y + fromParent.left,
y: position.y + fromParent.top,
}),
);
}
}
onResizeStart(event, placment, callback) {
event.stopPropagation();
this.resizing = !0;
const { scale } = this.props;
const fromParent = this.offsetFromParent;
const dragPosition = this.getDraggablePosition();
if (
((this.resizingPosition = {
x: dragPosition.x + fromParent.left,
y: dragPosition.y + fromParent.top,
}),
this.setState({
original: dragPosition,
}),
this.props.bounds)
) {
const parent = this.getParent();
let element = void 0;
element =
this.props.bounds === 'parent'
? parent
: this.props.bounds === 'body'
? document.body
: this.props.bounds === 'window'
? window
: document.querySelector(this.props.bounds);
const selfElement = this.getSelfElement();
if (
selfElement instanceof Element &&
(element instanceof HTMLElement || element === window) &&
parent instanceof HTMLElement
) {
const maxSizeProps = this.getMaxSizesFromProps();
const parentSize = this.getParentSize();
let { maxWidth, maxHeight } = maxSizeProps;
if (maxWidth && typeof maxWidth === 'string') {
if (maxWidth.endsWith('%')) {
const delt = Number(maxWidth.replace('%', '')) / 100;
maxWidth = parentSize.width * delt;
} else {
maxWidth.endsWith('px') &&
(maxWidth = Number(maxWidth.replace('px', '')));
}
}
if (maxHeight && typeof maxHeight === 'string') {
if (maxHeight.endsWith('%')) {
const delt = Number(maxHeight.replace('%', '')) / 100;
maxHeight = parentSize.width * delt;
} else {
maxHeight.endsWith('px') &&
(maxHeight = Number(maxHeight.replace('px', '')));
maxHeight.endsWith('px') &&
(maxHeight = Number(maxHeight.replace('px', '')));
}
}
const rect = selfElement.getBoundingClientRect();
// eslint-disable-next-line no-underscore-dangle
const _rect_ =
this.props.bounds === 'window'
? {
left: 0,
top: 0,
}
: element.getBoundingClientRect();
const offsetWidth = this.getOffsetWidth();
const offsetHeight = this.getOffsetHeight();
const convertLeft = placment.toLowerCase().endsWith('left');
const convertRight = placment.toLowerCase().endsWith('right');
if (convertLeft && this.resizable) {
const deltWidth =
(rect.left - _rect_.left) / scale + this.resizable.size.width;
this.setState({
maxWidth: deltWidth > Number(maxWidth) ? maxWidth : deltWidth,
});
}
if (convertRight || (this.props.lockAspectRatio && !convertLeft)) {
const deltWidth = offsetWidth + (_rect_.left - rect.left) / scale;
this.setState({
maxWidth: deltWidth > Number(maxWidth) ? maxWidth : deltWidth,
});
}
if (placment.startsWith('top') && this.resizable) {
const deltHeight = rect.top - _rect_.top + this.resizable.size.height;
this.setState({
maxHeight: deltHeight > Number(maxHeight) ? maxHeight : deltHeight,
});
}
if (
placment.startsWith('bottom') ||
(this.props.lockAspectRatio && !placment.startsWith('top'))
) {
const deltHeight = offsetHeight + (_rect_.top - rect.top) / scale;
this.setState({
maxHeight: deltHeight > Number(maxHeight) ? maxHeight : deltHeight,
});
}
}
} else {
this.setState({
maxWidth: this.props.maxWidth,
maxHeight: this.props.maxHeight,
});
}
this.props.onResizeStart &&
this.props.onResizeStart(event, placment, callback);
}
onResize(event, placment, position, target) {
const original = {
x: this.state.original.x,
y: this.state.original.y,
};
const width = -target.width;
const height = -target.height;
['top', 'left', 'topLeft', 'bottomLeft', 'topRight'].indexOf(placment) !==
-1 &&
(placment === 'bottomLeft'
? (original.x += width)
: (placment === 'topRight' || (original.x += width),
(original.y += height)));
(original.x === this.draggable.state.x &&
original.y === this.draggable.state.y) ||
this.draggable.setState(original);
this.updateOffsetFromParent();
const fromParent = this.offsetFromParent;
const x = this.getDraggablePosition().x + fromParent.left;
const y = this.getDraggablePosition().y + fromParent.top;
this.resizingPosition = {
x,
y,
};
this.props.onResize &&
this.props.onResize(event, placment, position, target, {
x,
y,
});
}
onResizeStop(event, placment, position, target) {
this.resizing = !1;
const { maxWidth, maxHeight } = this.getMaxSizesFromProps();
this.setState({
maxHeight,
maxWidth,
});
this.props.onResizeStop &&
this.props.onResizeStop(
event,
placment,
position,
target,
this.resizingPosition,
);
}
updateSize(target) {
this.resizable &&
this.resizable.updateSize({
width: target.width,
height: target.height,
});
}
updatePosition(position) {
this.draggable.setState(position);
}
updateOffsetFromParent() {
const { scale } = this.props;
const parent = this.getParent();
const selfElement = this.getSelfElement();
if (!parent || selfElement === null) {
return {
top: 0,
left: 0,
};
}
const rect = parent.getBoundingClientRect();
const selfRect = selfElement.getBoundingClientRect();
const dragPosition = this.getDraggablePosition();
this.offsetFromParent = {
left: selfRect.left - rect.left - dragPosition.x * scale,
top: selfRect.top - rect.top - dragPosition.y * scale,
};
}
render() {
const { props } = this;
const {
disableDragging,
style,
dragHandleClassName,
position,
onMouseDown,
onMouseUp,
dragAxis,
dragGrid,
bounds,
enableUserSelectHack,
cancel,
children,
resizeHandleClasses,
resizeHandleComponent,
enableResizing,
resizeGrid,
resizeHandleWrapperClass,
resizeHandleWrapperStyle,
scale = 1,
allowAnyClick,
} = props;
const event = (props.onResize,
props.onResizeStop,
props.onDragStart,
props.onDrag,
props.onDragStop,
props.resizeHandleStyles);
const _ = (function(e, t) {
const n = {};
// eslint-disable-next-line guard-for-in
for (var r in e)
Object.prototype.hasOwnProperty.call(e, r) &&
t.indexOf(r) < 0 &&
(n[r] = e[r]);
if (e != null && typeof Object.getOwnPropertySymbols === 'function') {
let o = 0;
// eslint-disable-next-line block-scoped-var,no-plusplus
for (r = Object.getOwnPropertySymbols(e); o < r.length; o++)
t.indexOf(r[o]) < 0 &&
// eslint-disable-next-line block-scoped-var
Object.prototype.propertyIsEnumerable.call(e, r[o]) &&
// eslint-disable-next-line block-scoped-var
(n[r[o]] = e[r[o]]);
}
return n;
})(props, [
'disableDragging',
'style',
'dragHandleClassName',
'position',
'onMouseDown',
'onMouseUp',
'dragAxis',
'dragGrid',
'bounds',
'enableUserSelectHack',
'cancel',
'children',
'onResizeStart',
'onResize',
'onResizeStop',
'onDragStart',
'onDrag',
'onDragStop',
'resizeHandleStyles',
'resizeHandleClasses',
'resizeHandleComponent',
'enableResizing',
'resizeGrid',
'resizeHandleWrapperClass',
'resizeHandleWrapperStyle',
'scale',
'allowAnyClick',
]);
const defaultPosition = this.props.default
? Object.assign({}, this.props.default)
: void 0;
delete _.default;
let calcPostion;
position &&
(calcPostion = {
x: position.x - this.offsetFromParent.left,
y: position.y - this.offsetFromParent.top,
});
let _enableResizing;
const _position_ = this.resizing ? void 0 : calcPostion;
const styles = Object.assign(
Object.assign(
Object.assign(
{},
{
width: this.props.default.width,
height: this.props.default.height,
display: 'inline-block',
position: 'absolute',
top: 0,
left: 0,
zIndex: 5000,
boxShadow: 'rgba(0, 0, 0, 0.21) 0px 4px 16px 0px',
backgroundColor: 'rgb(255, 255, 255)',
overflow: 'hidden',
},
),
disableDragging || dragHandleClassName
? { cursor: 'auto' }
: { cursor: 'move' },
),
this.props.style,
);
return (
<ReactDraggable
ref={e => this.refDraggable(e)}
handle={dragHandleClassName ? `.${dragHandleClassName}` : void 0}
defaultPosition={defaultPosition}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
onStart={this.onDragStart}
onDrag={this.onDrag}
onStop={this.onDragStop}
axis={dragAxis || 'both'}
grid={dragGrid}
position={_position_}
bounds={bounds ? this.state.bounds : void 0}
enableUserSelectHack={enableUserSelectHack}
cancel={cancel}
scale={scale}
allowAnyClick={allowAnyClick}
nodeRef={this.resizableElement}
>
<Resize
ref={e => this.refResizable(e)}
defaultSize={defaultPosition}
size={this.props.size}
enable={
typeof enableResizing === 'boolean'
? ((_enableResizing = enableResizing),
{
bottom: _enableResizing,
bottomLeft: _enableResizing,
bottomRight: _enableResizing,
left: _enableResizing,
right: _enableResizing,
top: _enableResizing,
topLeft: _enableResizing,
topRight: _enableResizing,
})
: enableResizing
}
onResizeStart={this.onResizeStart}
onResize={this.onResize}
onResizeStop={this.onResizeStop}
style={styles}
minWidth={this.props.minWidth}
minHeight={this.props.minHeight}
maxWidth={this.resizing ? this.state.maxWidth : this.props.maxWidth}
maxHeight={
this.resizing ? this.state.maxHeight : this.props.maxHeight
}
grid={dragGrid}
handleWrapperClass={resizeHandleWrapperClass}
handleWrapperStyle={resizeHandleWrapperStyle}
lockAspectRatio={this.props.lockAspectRatio}
lockAspectRatioExtraWidth={this.props.lockAspectRatioExtraWidth}
lockAspectRatioExtraHeight={this.props.lockAspectRatioExtraHeight}
handleStyles={event}
handleClasses={resizeHandleClasses}
handleComponent={resizeHandleComponent}
scale={this.props.scale}
>
{props.children}
</Resize>
</ReactDraggable>
);
}
}
Draggable.defaultProps = {
maxWidth: Number.MAX_SAFE_INTEGER,
maxHeight: Number.MAX_SAFE_INTEGER,
scale: 1,
onResizeStart() {},
onResize() {},
onResizeStop() {},
onDragStart() {},
onDrag() {},
onDragStop() {},
};
export default Draggable;
import React, { useEffect, useRef, useState, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { AutoComplete, Input, Pagination, Tabs } from 'antd';
import classNames from 'classnames';
import PinyinMatch from 'pinyin-match';
import Icon, {
CloseOutlined,
RightCircleOutlined,
SearchOutlined,
} from '@ant-design/icons';
import Draggable from './draggable';
import styles from './index.less';
//
// const { TabPane } = Tabs;
const HistorySvg = () => (
<svg
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
width="10"
height="10"
>
<path
d="M1016.405333 0h-351.573333a7.594667 7.594667 0 0 0-5.376 12.885333l149.077333 149.674667-244.224 249.770667H434.346667A7.594667 7.594667 0 0 0 426.666667 419.84v169.898667c0 4.266667 3.413333 7.594667 7.594666 7.594666h169.813334c4.266667 0 7.68-3.413333 7.68-7.594666V486.826667l263.253333-257.792 136.106667 135.509333A7.594667 7.594667 0 0 0 1024 359.253333V7.68A7.594667 7.594667 0 0 0 1016.405333 0z"
fill="#C1C1C1"
/>
<path
d="M979.626667 640a45.226667 45.226667 0 0 0-44.202667 46.08v249.258667H88.490667V88.576h245.418666l1.194667-0.085333A45.056 45.056 0 0 0 378.88 44.288 45.056 45.056 0 0 0 333.994667 0H7.68A7.68 7.68 0 0 0 0 7.68v1008.64c0 4.266667 3.413333 7.68 7.68 7.68h1008.64c4.266667 0 7.68-3.413333 7.68-7.68V686.08a45.226667 45.226667 0 0 0-44.373333-46.08z"
fill="#C1C1C1"
/>
</svg>
);
const HistoryHrefIcon = props => <Icon component={HistorySvg} {...props} />;
const Empty = () => (
<div className={styles.empty}>
<img
src="https://panda-water.cn/web4/assets/images/dataNull/暂无数据大.png"
alt=""
/>
<p>非常抱歉,找不到和您查询相关的内容或信息</p>
</div>
);
function itemRender(current, type, originalElement) {
if (type === 'prev') {
return <a>上一页</a>;
}
if (type === 'next') {
return <a>下一页</a>;
}
return originalElement;
}
const Modal = props => {
const dragRef = useRef(null);
const searchRef = useRef(null);
const [isWidgetShow, setIsWidgetShow] = useState(props.visible);
const [keyword, setKeyWord] = useState(props.value);
const [searchProduct, setSearchProduct] = useState([]);
const [eventCounts, setEventCounts] = useState(() => ['resultConsole', -1]);
// const [tabIndex]
const [pageCurrent, setPageCurrent] = useState(1);
const [fasts, setFasts] = useState(
props.console.concat(props.willSearch) || [],
);
const [searchProductList, setSearchProductList] = useState([]);
const recentKeywords = props.recentKeywords.toJS
? props.recentKeywords.toJS()
: props.recentKeywords;
const { triggerElRef } = props;
// eslint-disable-next-line consistent-return,func-names
const target = (function() {
if (triggerElRef.current) {
const rect = triggerElRef.current.getBoundingClientRect();
return {
y: rect.top,
x: rect.left,
};
}
})();
const rawData = props.menu.concat(props.flatMenu);
useEffect(() => {
const ret = [];
const searchResult = [];
// eslint-disable-next-line array-callback-return
props.menu.map(item => {
const match = PinyinMatch.match(item.name, keyword);
if (match) {
ret.push(item);
}
});
setSearchProduct(ret);
rawData.forEach(item => {
if (keyword !== '' && PinyinMatch.match(item.name, keyword)) {
searchResult.push(item);
}
});
setFasts(searchResult);
}, [keyword]);
useEffect(() => {
setKeyWord(props.value);
}, [props.value]);
const onNavUp = () => {};
const onNavDown = () => {};
const RESULT_KEYS = ['resultConsole'];
const getFistKey = (response, key, type) => {
/* eslint-disable */
const result = RESULT_KEYS.filter(item => {
const ret = response[item];
return !!(ret && 'success' === ret.type && ret.response.items.length > 0);
});
if(0 === result.length) {
return null;
};
if(!key) {
return 'down' === type ? result[0]:result[result.length - 1];
}
const index = result.indexOf(key);
return index < 0 ? null: 'down' === type ? index + 1 < result.length ? result[index + 1]: null: index - 1 >= 0 ? result[index - 1]: null;
}
const transfromEventHander = useCallback((children, data, type) => {
if (children === 'none') {
return
}
if (null === children) {
const key = getFistKey(data, null, type);
if (!key) {
return null;
}
const ret = data[key];
const currentIndex = 'up' === type ? ret.response.items.length - 1 : 0
return 'success' !== ret.type ? null : (
setEventCounts([key, currentIndex]),
'up' === type ? (children[currentIndex].focus()): (children[currentIndex].focus())
);
}
let eventsKey = eventCounts[0];
let eventsIndex = eventCounts[1];
let resultData = data[eventsKey];
if ('success' !== resultData.type) {
return null;
}
const index= "up" === type ? eventsIndex - 1: eventsIndex + 1;
if(index >=0 && index < resultData.response.items.length) {
return setEventCounts([eventsKey, index]), 'up' === type ? children[index].focus(): children[index].focus()
}
const getKey = getFistKey(data, eventsKey, type);
if(!getKey) {
return null;
}
const result = data[getKey];
if('success' !== result.type) {
return null;
}
if('up' === type) {
return setEventCounts([getKey, result.response.items.length - 1]), children[result.response.items.length - 1].focus()
}
return setEventCounts([getKey, 0]), searchRef.current.children[0].focus()
}, [eventCounts, fasts])
const transfomResponse = (data) => {
return {
query: props.value,
response: {
items: data,
total: data.length
},
type: 'success'
}
}
const eventHander = useCallback(
event => {
// eslint-disable-next-line default-case
const data = {
resultConsole: transfomResponse(searchRef.current.children)
};
switch (event.code) {
case 'ArrowDown':
event.preventDefault();
transfromEventHander(searchRef.current.children, data, 'down')
break;
case 'ArrowUp':
event.preventDefault();
transfromEventHander(searchRef.current.children, data, 'up')
break;
}
},
[fasts, eventCounts],
);
useEffect(() => {
props.visible && document.addEventListener('keydown', eventHander);
return function() {
return document.removeEventListener('keydown', eventHander);
};
}, [props.visible, fasts, eventCounts]);
useEffect(() => {
setIsWidgetShow(props.visible);
}, [props.visible]);
const transformSearchHistory = () => {
const label = keyword !== '' ? '你是不是想搜:' : '搜索历史:';
const data = keyword !== '' ? searchProduct : recentKeywords;
const ret = [
{
value: '搜索历史:',
label: (
<li className={styles['group-label']} title={label} tabIndex={-1}>
<div className={styles['item-inner']}>搜索历史:</div>
</li>
),
},
];
// eslint-disable-next-line array-callback-return
data.map((item, index) => {
ret.push({
value: item.name || item.data,
label: (
<li
className={styles['group-item']}
title={item.data || item.name}
dataindex={index}
>
<div className={styles['item-inner']}>
<span className={styles['item-text']}>
{item.data || item.name}
</span>
</div>
</li>
),
});
});
return ret.length > 0 ? ret : [];
};
const goFeature = (event, item) => {
event.persist && event.persist();
event && event.stopPropagation();
props.goFeature(item.path, item, keyword);
};
const goProduct = (event, item) => {
event.persist && event.persist();
event && event.stopPropagation();
props.goProduct && props.goProduct(event, item, keyword);
};
const paginationProps = {
total: fasts.length,
current: pageCurrent,
pageSize: 20,
onChange: page => {
setPageCurrent(page);
},
};
const largestPage = Math.ceil(paginationProps.total / 20);
if (paginationProps.current > largestPage) {
paginationProps.current = largestPage;
}
const paginationContent = () => {
if (paginationProps.total < 20) {
return null;
}
return (
<div className={styles.footer}>
<Pagination
{...paginationProps}
showSizeChanger={false}
itemRender={itemRender}
size="small"
/>
</div>
);
};
const transformSearchFasts = () => {
if (fasts.length === 0) {
return <Empty />;
}
let splitDataSource = [...fasts];
if (
fasts.length >
(paginationProps.current - 1) * paginationProps.pageSize
) {
splitDataSource = [...fasts].splice(
(paginationProps.current - 1) * paginationProps.pageSize,
paginationProps.pageSize,
);
}
return (
<div className={styles.resultContainer} ref={searchRef}>
{splitDataSource.map((item, index) => {
const match = props.matchValue(item.name, keyword);
const name =
keyword !== '' && match ? (
<div className={styles.withHightLight}>
{item.name.substring(0, match[0])}
<em>{item.name.substring(match[0], match[1] + 1)}</em>
{item.name.substring(match[1] + 1)}
</div>
) : (
item.name
);
return (
<a
className={styles.item}
key={item.name + index}
tabIndex="1"
onClick={event => {
item.parent ? goFeature(event, item) : goProduct(event, item);
}}
onKeyDown={event => event.key === 'Enter' && event.keyCode === 13 && item.parent ? goFeature(event, item) : goProduct(event, item)}
>
<span className={styles.title}>
{name}
{item.parent ? (
<HistoryHrefIcon className={styles.href} />
) : (
<RightCircleOutlined />
)}
</span>
<span className={styles.subtitle}>
{item.parent ? item.parent.name : '产品功能入口'}
</span>
</a>
);
})}
{paginationContent()}
</div>
);
};
const handleChange = value => {
setKeyWord(value);
};
const handleSearch = value => {
setKeyWord(value);
};
const handleFocus = event => {
event.persist && event.persist();
event && event.nativeEvent.stopImmediatePropagation();
};
const onSelect = value => {
setKeyWord(value);
};
const onClose = () => {
setIsWidgetShow(false);
};
if (!isWidgetShow) {
return null;
}
if (props.visible) {
const children = (
<Draggable
dragHandleClassName={styles.header}
default={Object.assign(
Object.assign({}, target),
{},
{
width: 420,
height: 680,
},
)}
bounds="window"
minHeight={400}
minWidth={360}
enableUserSelectHack={false}
>
<div className={styles['base-wedget']} ref={dragRef}>
<div className={styles.header}>
搜索更多
{/* eslint-disable-next-line react/button-has-type */}
<button
className={classNames(styles.btn, styles.close)}
onClick={onClose}
>
<CloseOutlined />
</button>
</div>
<div className={styles.body}>
<div className={styles.search}>
<AutoComplete
options={transformSearchHistory()}
dropdownClassName={styles.searchList}
value={keyword}
onSelect={onSelect}
onSearch={handleSearch}
onChange={handleChange}
onFocus={handleFocus}
>
<Input
size="middle"
placeholder="请输入"
allowClear
suffix={<SearchOutlined className="site-form-item-icon" />}
/>
</AutoComplete>
</div>
<div className={styles.result}>{transformSearchFasts()}</div>
</div>
</div>
</Draggable>
);
return ReactDOM.createPortal(children, document.body);
}
};
export default Modal;
@import '~antd/es/style/themes/default.less';
.base-wedget {
cursor: move;
display: flex;
flex-direction: column;
height: 100%;
.header {
display: flex;
flex: 0 0 auto;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
padding: 6px;
box-sizing: border-box;
background-color: rgb(242, 242, 242);
height: 32px;
cursor: move;
font-size: 12px;
font-weight: 400;
.btn {
box-sizing: border-box;
outline: medium;
background: none;
cursor: pointer;
font-family: inherit;
font-size: inherit;
text-decoration: none;
transition: all 0.3s ease-out 0s;
display: inline-block;
border: 1px solid transparent;
overflow: hidden;
vertical-align: middle;
text-align: center;
color: rgb(85, 85, 85);
white-space: nowrap;
padding: 0px 12px;
height: 32px;
line-height: 30px;
}
.close {
position: absolute;
right: 8px;
cursor: pointer;
top: -2px;
}
}
.body {
flex: 1 1 auto;
min-height: 0px;
margin: 0;
line-height: 1.15;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
font-size: 100%;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC,
Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial,
simsun, sans-serif;
font-size: 12px;
line-height: 1.28571;
color: #111;
.search {
margin-bottom: 0px;
padding-right: 16px;
padding-bottom: 8px;
padding-left: 16px;
background-color: rgb(242, 242, 242);
-webkit-box-flex: 0;
flex: 0 0 auto;
:global(.@{ant-prefix}-select-auto-complete) {
width: 100%;
}
:global(.@{ant-prefix}-input-suffix) {
color: #888888;
}
:global(.@{ant-prefix}-input) {
font-size: 12px;
}
}
.result {
-webkit-box-flex: 1;
flex: 1 1 auto;
display: -webkit-box;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
min-height: 120px;
overflow: hidden;
height: 100%;
:global(.@{ant-prefix}-tabs-nav) {
-webkit-box-flex: 0;
flex: 0 0 auto;
margin-left: 16px;
margin-right: 16px;
margin-bottom: 0px;
}
:global(.@{ant-prefix}-tabs) {
overflow: hidden;
height: 100%;
}
:global(.@{ant-prefix}-tabs-tab-btn) {
font-size: 12px !important;
padding: 0px 16px;
}
:global(.@{ant-prefix}-tabs-tabpane) {
display: flex;
overflow: hidden;
height: 100%;
}
:global(.@{ant-prefix}-tabs-content) {
overflow: hidden;
height: 100%;
}
}
}
.empty {
-webkit-box-flex: 1;
flex: 1 1 auto;
display: -webkit-box;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
img {
border-style: none;
}
p {
margin-bottom: 6px;
font-size: 12px;
font-weight: 400;
line-height: 20px;
}
}
}
.searchList {
.group-label {
padding: 0 12px;
color: #888;
}
.group-item {
position: relative;
padding: 0 12px;
-webkit-transition: background 0.2s ease;
transition: background 0.2s ease;
color: #333;
cursor: pointer;
}
.item-inner {
height: 32px;
line-height: 32px;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
}
.item-text {
vertical-align: middle;
color: #333;
}
:global(.@{ant-prefix}-select-item-option) {
padding: 0 2px !important;
}
:global(.rc-virtual-list-scrollbar) {
width: 0 !important;
}
}
.resultContainer {
padding: 8px 16px;
-webkit-box-flex: 1;
flex: 1 1 auto;
min-height: 0;
overflow: auto;
.item {
display: flex;
-webkit-box-pack: justify;
justify-content: space-between;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
flex-direction: row;
flex-wrap: nowrap;
height: 28px;
line-height: 28px;
font-size: 12px;
color: inherit;
padding: 0 0;
text-decoration: none;
&:hover, &:focus {
background-color: #f7f7f7;
cursor: pointer;
:global(.@{ant-prefix}icon-right-circle) {
opacity: 1 !important;
}
.href {
opacity: 1;
}
}
.title {
-webkit-box-flex: 0;
flex: 0 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
:global(.@{ant-prefix}icon-right-circle) {
margin-left: 8px;
color: #c1c1c1;
opacity: 0;
-webkit-transition: opacity none;
transition: opacity none;
font-size: 14px;
}
}
.href {
opacity: 0;
margin-left: 4px;
color: rgb(193, 193, 193);
transition: none 0s ease 0s;
}
.subtitle {
color: #c1c1c1;
-webkit-box-flex: 0;
flex: 0 0 auto;
margin-left: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.footer {
margin-top: 4px;
float: right;
:global(li.@{ant-prefix}-pagination-item:not(.@{ant-prefix}-pagination-item-active)),
:global(.@{ant-prefix}-pagination-prev),
:global(.@{ant-prefix}-pagination-next) {
// padding: 0 6px;
border-width: 1px;
border-radius: 0;
border: 1px solid #dedede;
background: #fff !important;
min-width: 24px;
margin: 0 0 0 -1px !important;
color: #333;
height: 24px;
line-height: 22px;
font-size: 12px;
border-color: #dedede;
}
:global(.@{ant-prefix}-pagination-prev),
:global(.@{ant-prefix}-pagination-next) {
padding: 0 6px;
}
:global(.@{ant-prefix}-pagination-item-active) {
border-color: @primary-color!important;
border-radius: 0;
box-shadow: none;
background: #fff;
z-index: 1;
position: relative;
}
}
}
.withHightLight {
display: inline-block;
em {
color: @primary-color;
font-style: inherit;
font-weight: 500;
}
}
import React from 'react';
/* eslint-disable */
const pickProps = [
'as',
'style',
'className',
'grid',
'snap',
'bounds',
'size',
'defaultSize',
'minWidth',
'minHeight',
'maxWidth',
'maxHeight',
'lockAspectRatio',
'lockAspectRatioExtraWidth',
'lockAspectRatioExtraHeight',
'enable',
'handleStyles',
'handleClasses',
'handleWrapperStyle',
'handleWrapperClass',
'children',
'onResizeStart',
'onResize',
'onResizeStop',
'handleComponent',
'scale',
'resizeRatio',
'snapGap',
];
/* eslint-disable */
class Resize extends React.Component {
constructor(props) {
super(props);
this.ratio = 1;
this.resizable = null;
this.parentLeft = 0;
this.parentTop = 0;
this.resizableLeft = 0;
this.resizableTop = 0;
this.targetLeft = 0;
this.targetTop = 0;
this.state = {
isResizing: !1,
width:
void 0 === (this.propsSize && this.propsSize.width)
? 'auto'
: this.propsSize && this.propsSize.width,
height:
void 0 === (this.propsSize && this.propsSize.height)
? 'auto'
: this.propsSize && this.propsSize.height,
direction: 'right',
original: {
x: 0,
y: 0,
width: 0,
height: 0,
},
backgroundStyle: {
height: '100%',
width: '100%',
backgroundColor: 'rgba(0,0,0,0)',
cursor: 'auto',
opacity: 0,
position: 'fixed',
zIndex: 9999,
top: '0',
left: '0',
bottom: '0',
right: '0',
},
flexBasis: void 0,
};
this.appendBase = () => {
if (!this.resizable || !window) {
return null;
}
const { parentNode } = this;
if (!parentNode) {
return null;
}
const newDiv = window.document.createElement('div');
newDiv.style.width = '100%';
newDiv.style.height = '100%';
newDiv.style.position = 'absolute';
newDiv.style.transform = 'scale(0, 0)';
newDiv.style.left = '0';
newDiv.style.flex = '0';
newDiv.classList
? newDiv.classList.add('__resizable_base__')
: (newDiv.className += '__resizable_base__');
parentNode.appendChild(newDiv);
};
}
removeBase(child) {
const { parentNode } = this;
parentNode && parentNode.removeChild(child);
}
ref = e => {
e && (this.resizable = e);
};
get parentNode() {
return this.resizable ? this.resizable.parentNode : null;
}
get window() {
return this.resizable && this.resizable.ownerDocument
? this.resizable.ownerDocument.defaultView
: null;
}
get propsSize() {
return (
this.props.size ||
this.props.defaultSize || {
width: 'auto',
height: 'auto',
}
);
}
/* eslint-disable */
get size() {
let width = 0;
let height = 0;
if (this.resizable && this.window) {
const { offsetWidth } = this.resizable;
const { offsetHeight } = this.resizable;
const { position } = this.resizable.style;
position !== 'relative' && (this.resizable.style.position = 'relative'),
(width =
this.resizable.style.width !== 'auto'
? this.resizable.offsetWidth
: offsetWidth), (height =
this.resizable.style.height !== 'auto'
? this.resizable.offsetHeight
: offsetHeight),
(this.resizable.style.position = position);
}
return {
width,
height,
};
}
sizeStyle() {
const { size } = this.props;
const covertSize = key => {
if (void 0 === this.state[key] || this.state[key] === 'auto') {
return 'auto';
}
return this.state[key];
};
return {
width:
size && void 0 !== size.width && !this.state.isResizing
? size.width
: covertSize('width'),
height:
size && void 0 !== size.height && !this.state.isResizing
? size.height
: covertSize('height'),
};
}
getParentSize() {}
bindEvents() {}
unbindEvents() {}
componentDidMount() {
if (this.resizable && this.window) {
const computedStyle = this.window.getComputedStyle(this.resizable);
this.setState({
// eslint-disable-next-line react/no-access-state-in-setstate
width: this.state.width || this.size.width,
// eslint-disable-next-line react/no-access-state-in-setstate
height: this.state.height || this.size.height,
flexBasis:
computedStyle.flexBasis !== 'auto' ? computedStyle.flexBasis : void 0,
});
}
}
componentWillUnmount() {}
createSizeForCssProperty() {}
calculateNewMaxFromBoundary() {}
calculateNewSizeFromDirection() {}
calculateNewSizeFromAspectRatio() {}
setBoundingClientRect() {}
onResizeStart() {}
onMouseMove() {}
onMouseUp() {}
updateSize() {}
renderResizer() {}
render() {
const pick = Object.keys(this.props).reduce(
(item, key) => (
pickProps.indexOf(key) !== -1 || (item[key] = this.props[key]), item
),
{},
);
const style = Object.assign(
Object.assign(
Object.assign(
{
position: 'relative',
userSelect: this.state.isResizing ? 'none' : 'auto',
},
this.props.style,
),
this.sizeStyle,
),
{
maxWidth: this.props.maxWidth,
maxHeight: this.props.maxWidth,
minWidth: this.props.minWidth,
minHeight: this.props.minHeight,
boxSizing: 'border-box',
flexShrink: 0,
},
);
this.state.flexBasis && (style.flexBasis = this.state.flexBasis);
const Element = this.props.as || 'div';
return (
<Element
{...Object.assign(
{
ref: this.ref,
style,
className: this.props.className,
},
pick,
)}
>
{this.props.children}
</Element>
);
}
}
Resize.defaultProps = {
as: 'div',
onResizeStart() {},
onResize() {},
onResizeStop() {},
enable: {
top: !0,
right: !0,
bottom: !0,
left: !0,
topRight: !0,
bottomRight: !0,
bottomLeft: !0,
topLeft: !0,
},
style: {},
grid: [1, 1],
lockAspectRatio: !1,
lockAspectRatioExtraWidth: 0,
lockAspectRatioExtraHeight: 0,
scale: 1,
resizeRatio: 1,
snapGap: 0,
};
export default Resize;
...@@ -23,7 +23,7 @@ import ProLayout, { getPageTitle } from '@ant-design/pro-layout'; ...@@ -23,7 +23,7 @@ import ProLayout, { getPageTitle } from '@ant-design/pro-layout';
import { getMatchMenu } from '@umijs/route-utils'; import { getMatchMenu } from '@umijs/route-utils';
import { useHistory } from '@wisdom-utils/runtime'; import { useHistory } from '@wisdom-utils/runtime';
import RightContent from '@/components/GlobalHeader/RightContent'; import RightContent from '@/components/GlobalHeader/RightContent';
import { Panel } from '@/components/SliderPanel'; import { Panel } from '@wisdom-utils/components';
import { actionCreators } from '@/containers/App/store'; import { actionCreators } from '@/containers/App/store';
import Authorized from '@/utils/Authorized'; import Authorized from '@/utils/Authorized';
import { findPathByLeafId, getBaseName } from '@/utils/utils'; import { findPathByLeafId, getBaseName } from '@/utils/utils';
......
...@@ -34,7 +34,8 @@ import { useHistory } from '@wisdom-utils/runtime'; ...@@ -34,7 +34,8 @@ import { useHistory } from '@wisdom-utils/runtime';
import KeepAlive from 'react-activation'; import KeepAlive from 'react-activation';
import AMapLoader from '@amap/amap-jsapi-loader'; import AMapLoader from '@amap/amap-jsapi-loader';
import RightContent from '@/components/GlobalHeader/ExtendRightContent'; import RightContent from '@/components/GlobalHeader/ExtendRightContent';
import Panel from '@/components/SliderPanel/MinPanel'; // import Panel from '@/components/SliderPanel/MinPanel';
import { MinPanel as Panel } from '@wisdom-utils/components'
import { actionCreators } from '@/containers/App/store'; import { actionCreators } from '@/containers/App/store';
import { ArcgisMap, AMap, CesiumMap } from '../pages/map'; import { ArcgisMap, AMap, CesiumMap } from '../pages/map';
import { WEB_GIS_TYPE } from '../constants'; import { WEB_GIS_TYPE } from '../constants';
......
...@@ -8,7 +8,7 @@ import Cookies from 'js-cookie'; ...@@ -8,7 +8,7 @@ import Cookies from 'js-cookie';
import { cityJson } from '@wisdom-utils/utils'; import { cityJson } from '@wisdom-utils/utils';
import { appService } from '../api'; import { appService } from '../api';
import CitySelector from '../components/CitySelector'; import { CitySelector } from '@wisdom-utils/components';
import Login from '../pages/user/login/login'; import Login from '../pages/user/login/login';
import styles from './UserLayout.less'; import styles from './UserLayout.less';
import { initMicroApps } from '@/micro'; import { initMicroApps } from '@/micro';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment