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

feat: 优化components

parent 0a54ee72
Pipeline #47273 skipped with stages
/* eslint-disable */
// 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 = 'https://panda-water.cn';
module.exports = {
......
......@@ -110,7 +110,7 @@
"@wisdom-map/Map": "^1.0.12-17",
"@wisdom-map/arcgismap": "^1.0.79-17",
"@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/utils": "0.0.77",
"animate.css": "^4.1.1",
......
This diff is collapsed.
.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';
import { useHistory } from '@wisdom-utils/runtime';
import { useIntl } from '@/locales/localeExports';
import { actionCreators } from '../../containers/App/store';
import HeaderSearch from '../HeaderSearch';
import { HeaderSearch } from '@wisdom-utils/components';
import Avatar from './AvatarDropdown';
import styles from './index.less';
import NoticeIconView from './NoticeIconView';
......
......@@ -7,7 +7,7 @@ import Icon from '@ant-design/icons';
import { useIntl } from '@/locales/localeExports';
import { actionCreators } from '../../containers/App/store';
import HeaderSearch from '../HeaderSearch';
import { HeaderSearch } from '@wisdom-utils/components';
import Avatar from './AvatarDropdown';
import styles from './index.less';
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;
}
}
This diff is collapsed.
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;
}
This diff is collapsed.
......@@ -7,7 +7,7 @@ import useMergeValue from 'use-merge-value';
import Icon from '@ant-design/icons';
import HeaderDropdown from '../HeaderDropdown';
import { HeaderDropdown } from '@wisdom-utils/components';
import styles from './index.less';
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);
};
};
This diff is collapsed.
This diff is collapsed.
@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;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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