mirror of
https://github.com/tencentmusic/supersonic.git
synced 2025-12-20 06:34:55 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { Space } from 'antd';
|
||||
export interface IProps {
|
||||
title: string;
|
||||
subTitle?: string;
|
||||
}
|
||||
|
||||
const FormItemTitle: React.FC<IProps> = ({ title, subTitle }) => {
|
||||
return (
|
||||
<Space direction="vertical" size={2}>
|
||||
<span>{title}</span>
|
||||
{subTitle && <span style={{ fontSize: '12px', color: '#6a6a6a' }}>{subTitle}</span>}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormItemTitle;
|
||||
@@ -0,0 +1,39 @@
|
||||
.normalState {
|
||||
position: static;
|
||||
height: 100%;
|
||||
|
||||
.backNormal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.maxState {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
|
||||
.innerWrap {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.backNormal {
|
||||
display: block;
|
||||
height: 30px;
|
||||
padding-right: 20px;
|
||||
color: #02a7f0;
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
text-align: right;
|
||||
|
||||
.fullscreenExitIcon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const formLayout: any = {
|
||||
// labelCol: { span: 13 },
|
||||
// wrapperCol: { span: 13 },
|
||||
layout: 'vertical',
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
.normalState {
|
||||
position: static;
|
||||
height: 100%;
|
||||
|
||||
.backNormal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.maxState {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
|
||||
.innerWrap {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.backNormal {
|
||||
display: block;
|
||||
height: 30px;
|
||||
padding-right: 20px;
|
||||
color: #02a7f0;
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
text-align: right;
|
||||
|
||||
.fullscreenExitIcon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { ReactNode, FC } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useImperativeHandle, useState } from 'react';
|
||||
import { FullscreenExitOutlined } from '@ant-design/icons';
|
||||
import styles from './index.less';
|
||||
|
||||
export interface IProps {
|
||||
children: ReactNode;
|
||||
maxRef?: any;
|
||||
top?: string;
|
||||
isFullScreen: boolean;
|
||||
triggerBackToNormal: () => void;
|
||||
}
|
||||
|
||||
const FullScreen: FC<IProps> = ({
|
||||
children,
|
||||
maxRef,
|
||||
top = '50px',
|
||||
isFullScreen,
|
||||
triggerBackToNormal,
|
||||
}) => {
|
||||
const [wrapCls, setWrapCls] = useState(styles.normalState);
|
||||
const changeToMax = () => {
|
||||
setWrapCls(styles.maxState);
|
||||
};
|
||||
|
||||
const changeToNormal = () => {
|
||||
setWrapCls(styles.normalState);
|
||||
};
|
||||
|
||||
const handleBackToNormal = () => {
|
||||
if (typeof triggerBackToNormal === 'function') {
|
||||
triggerBackToNormal();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isFullScreen) {
|
||||
changeToMax();
|
||||
} else {
|
||||
changeToNormal();
|
||||
}
|
||||
}, [isFullScreen]);
|
||||
|
||||
useImperativeHandle(maxRef, () => ({
|
||||
changeToMax,
|
||||
changeToNormal,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={wrapCls} style={wrapCls === styles.maxState ? { paddingTop: top } : {}}>
|
||||
<div
|
||||
className={styles.innerWrap}
|
||||
style={wrapCls === styles.maxState ? { top } : { height: '100%' }}
|
||||
>
|
||||
<div className={styles.backNormal}>
|
||||
<FullscreenExitOutlined
|
||||
className={styles.fullscreenExitIcon}
|
||||
title="退出全屏"
|
||||
onClick={handleBackToNormal}
|
||||
/>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FullScreen;
|
||||
@@ -0,0 +1,16 @@
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { DropDownProps } from 'antd/es/dropdown';
|
||||
import { Dropdown } from 'antd';
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import styles from './index.less';
|
||||
|
||||
export type HeaderDropdownProps = {
|
||||
overlayClassName?: string;
|
||||
overlay: React.ReactNode | (() => React.ReactNode) | any;
|
||||
placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
|
||||
} & Omit<DropDownProps, 'overlay'>;
|
||||
|
||||
const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => (
|
||||
<Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
|
||||
);
|
||||
|
||||
export default HeaderDropdown;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createFromIconfontCN } from '@ant-design/icons';
|
||||
import defaultSettings from '../../../config/defaultSettings';
|
||||
|
||||
const IconFont = createFromIconfontCN({
|
||||
scriptUrl: defaultSettings.iconfontUrl,
|
||||
});
|
||||
|
||||
export default IconFont;
|
||||
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import { LogoutOutlined } from '@ant-design/icons';
|
||||
import { Menu } from 'antd';
|
||||
import { useModel } from 'umi';
|
||||
import HeaderDropdown from '../HeaderDropdown';
|
||||
import styles from './index.less';
|
||||
import TMEAvatar from '../TMEAvatar';
|
||||
import cx from 'classnames';
|
||||
import { AUTH_TOKEN_KEY } from '@/common/constants';
|
||||
import { history } from 'umi';
|
||||
|
||||
export type GlobalHeaderRightProps = {
|
||||
menu?: boolean;
|
||||
onClickLogin?: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* 并返回到首页
|
||||
*/
|
||||
const loginOut = async () => {
|
||||
localStorage.removeItem(AUTH_TOKEN_KEY);
|
||||
history.push('/login');
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const { APP_TARGET } = process.env;
|
||||
|
||||
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = () => {
|
||||
const { initialState = {}, setInitialState } = useModel('@@initialState');
|
||||
|
||||
const onMenuClick = (event: any) => {
|
||||
const { key } = event;
|
||||
if (key === 'logout' && initialState) {
|
||||
loginOut().then(() => {
|
||||
setInitialState({ ...initialState, currentUser: undefined });
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const { currentUser = {} } = initialState as any;
|
||||
console.log(currentUser, 'currentUser');
|
||||
const menuHeaderDropdown = (
|
||||
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
|
||||
<Menu.Item key="logout">
|
||||
<LogoutOutlined />
|
||||
退出登录
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
return (
|
||||
<HeaderDropdown overlay={menuHeaderDropdown} disabled={APP_TARGET === 'inner'}>
|
||||
<span className={`${styles.action} ${styles.account}`}>
|
||||
<TMEAvatar className={styles.avatar} size="small" staffName={currentUser.staffName} />
|
||||
<span className={cx(styles.name, 'anticon')}>{currentUser.staffName}</span>
|
||||
</span>
|
||||
</HeaderDropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export default AvatarDropdown;
|
||||
@@ -0,0 +1,105 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
@pro-header-hover-bg: rgba(0, 0, 0, 0.025);
|
||||
|
||||
.menu {
|
||||
:global(.anticon) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
:global(.ant-dropdown-menu-item) {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
display: flex;
|
||||
float: right;
|
||||
height: 48px;
|
||||
margin-left: auto;
|
||||
overflow: hidden;
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
padding: 0 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
>span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @pro-header-hover-bg;
|
||||
}
|
||||
|
||||
&:global(.opened) {
|
||||
background: @pro-header-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: 0 12px;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.account {
|
||||
.avatar {
|
||||
margin-right: 8px;
|
||||
color: @primary-color;
|
||||
vertical-align: top;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.action {
|
||||
.download {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menuName {
|
||||
margin-left: 5px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #296df3;
|
||||
}
|
||||
|
||||
&:global(.opened) {
|
||||
background: #252a3d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actionIcon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tooltip {
|
||||
padding-top: 0 !important;
|
||||
font-size: 12px !important;
|
||||
|
||||
:global {
|
||||
.ant-tooltip-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-tooltip-inner {
|
||||
min-height: 0 !important;
|
||||
padding: 3px 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Space } from 'antd';
|
||||
import React from 'react';
|
||||
import { useModel } from 'umi';
|
||||
import Avatar from './AvatarDropdown';
|
||||
|
||||
import styles from './index.less';
|
||||
import cx from 'classnames';
|
||||
|
||||
export type SiderTheme = 'light' | 'dark';
|
||||
|
||||
const GlobalHeaderRight: React.FC = () => {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
|
||||
if (!initialState || !initialState.settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { navTheme, layout } = initialState.settings;
|
||||
let className = styles.right;
|
||||
|
||||
if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
|
||||
className = cx(styles.right, styles.dark);
|
||||
}
|
||||
|
||||
function handleLogin() {}
|
||||
|
||||
return (
|
||||
<Space className={className}>
|
||||
<Avatar onClickLogin={handleLogin} />
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
export default GlobalHeaderRight;
|
||||
340
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.css
Normal file
340
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.css
Normal file
@@ -0,0 +1,340 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2436113 */
|
||||
src: url('iconfont.woff2?t=1659425018463') format('woff2'),
|
||||
url('iconfont.woff?t=1659425018463') format('woff'),
|
||||
url('iconfont.ttf?t=1659425018463') format('truetype'),
|
||||
url('iconfont.svg?t=1659425018463#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconbaobiaokanban:before {
|
||||
content: "\e66b";
|
||||
}
|
||||
|
||||
.iconkanban:before {
|
||||
content: "\e638";
|
||||
}
|
||||
|
||||
.iconyunyingkanban:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.iconshujukanban1:before {
|
||||
content: "\eb66";
|
||||
}
|
||||
|
||||
.iconjingqingqidai01:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icontouzi:before {
|
||||
content: "\e67a";
|
||||
}
|
||||
|
||||
.iconriqi:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.iconyinleren_:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icondapan:before {
|
||||
content: "\e668";
|
||||
}
|
||||
|
||||
.iconbangdan:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.iconshujuwajue:before {
|
||||
content: "\e667";
|
||||
}
|
||||
|
||||
.iconshoucang1:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icontianjiazhibiao:before {
|
||||
content: "\e632";
|
||||
}
|
||||
|
||||
.icontianjiafenzu:before {
|
||||
content: "\e666";
|
||||
}
|
||||
|
||||
.iconyouxiajiaogouxuan:before {
|
||||
content: "\e8b7";
|
||||
}
|
||||
|
||||
.iconxiaoshouzhibiaoshezhi:before {
|
||||
content: "\e665";
|
||||
}
|
||||
|
||||
.iconyingyongbiaoge:before {
|
||||
content: "\e6ae";
|
||||
}
|
||||
|
||||
.iconzhibiao:before {
|
||||
content: "\e66a";
|
||||
}
|
||||
|
||||
.iconsearch:before {
|
||||
content: "\e7c9";
|
||||
}
|
||||
|
||||
.iconfactory-color:before {
|
||||
content: "\e69d";
|
||||
}
|
||||
|
||||
.iconportray-color:before {
|
||||
content: "\e69e";
|
||||
}
|
||||
|
||||
.iconvisualize-color:before {
|
||||
content: "\e69f";
|
||||
}
|
||||
|
||||
.iconamount-color:before {
|
||||
content: "\e68f";
|
||||
}
|
||||
|
||||
.iconapi-color:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.iconcontent-color:before {
|
||||
content: "\e691";
|
||||
}
|
||||
|
||||
.iconbox-color:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.iconchat-color:before {
|
||||
content: "\e693";
|
||||
}
|
||||
|
||||
.iconclient-color:before {
|
||||
content: "\e694";
|
||||
}
|
||||
|
||||
.icondata-process:before {
|
||||
content: "\e695";
|
||||
}
|
||||
|
||||
.iconbi-color:before {
|
||||
content: "\e696";
|
||||
}
|
||||
|
||||
.iconfiled-color:before {
|
||||
content: "\e697";
|
||||
}
|
||||
|
||||
.iconinvoking-color:before {
|
||||
content: "\e698";
|
||||
}
|
||||
|
||||
.iconissue-color:before {
|
||||
content: "\e699";
|
||||
}
|
||||
|
||||
.iconplatform-color:before {
|
||||
content: "\e69a";
|
||||
}
|
||||
|
||||
.iconfile-color:before {
|
||||
content: "\e69b";
|
||||
}
|
||||
|
||||
.iconname-color:before {
|
||||
content: "\e69c";
|
||||
}
|
||||
|
||||
.icondraft:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.iconunknown:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.iconnormal:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.iconfreezed:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.iconlogowenzi:before {
|
||||
content: "\e660";
|
||||
}
|
||||
|
||||
.iconlogobiaoshi:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.iconchaoyinshuxitonglogo:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.iconzanwuquanxiandianjishenqing_1:before {
|
||||
content: "\e662";
|
||||
}
|
||||
|
||||
.iconqingchuangjianmuluhuokanban:before {
|
||||
content: "\e661";
|
||||
}
|
||||
|
||||
.iconzichan:before {
|
||||
content: "\e65f";
|
||||
}
|
||||
|
||||
.iconhangweifenxi:before {
|
||||
content: "\e65e";
|
||||
}
|
||||
|
||||
.iconshujuzichan:before {
|
||||
content: "\e65d";
|
||||
}
|
||||
|
||||
.iconshujukanban:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.iconshujujieru:before {
|
||||
content: "\e65a";
|
||||
}
|
||||
|
||||
.iconshujutansuo:before {
|
||||
content: "\e65b";
|
||||
}
|
||||
|
||||
.iconminjiefenxi:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.iconyanfagongju:before {
|
||||
content: "\e658";
|
||||
}
|
||||
|
||||
.iconshujuanquan:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.iconCE:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.iconkanbantu-shuaxin:before {
|
||||
content: "\e657";
|
||||
}
|
||||
|
||||
.icondaohang-sousuo:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icondaohang-bangzhu:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.iconkanbantu-fenxiang:before {
|
||||
content: "\e640";
|
||||
}
|
||||
|
||||
.iconquanju-riqi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icondaohang-shezhi:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icondaohang-zichangouwuche:before {
|
||||
content: "\e643";
|
||||
}
|
||||
|
||||
.iconquanju-xiazai:before {
|
||||
content: "\e644";
|
||||
}
|
||||
|
||||
.iconkanbantu-quanping:before {
|
||||
content: "\e645";
|
||||
}
|
||||
|
||||
.iconshujuzichan-yewushujuzichan:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.iconshujukanban-tianjiakanban:before {
|
||||
content: "\e647";
|
||||
}
|
||||
|
||||
.iconqingkong:before {
|
||||
content: "\e648";
|
||||
}
|
||||
|
||||
.iconshujuzichan-jishushujuzichan:before {
|
||||
content: "\e649";
|
||||
}
|
||||
|
||||
.iconshujuzichan-zichanfaxian:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icontishi-beizhu1:before {
|
||||
content: "\e64b";
|
||||
}
|
||||
|
||||
.iconshujukanban-tianjiamulu:before {
|
||||
content: "\e64c";
|
||||
}
|
||||
|
||||
.icontubiao-zhuzhuangtu:before {
|
||||
content: "\e64d";
|
||||
}
|
||||
|
||||
.icondaohang-xiaoxitishi:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icontubiao-bingtu:before {
|
||||
content: "\e64f";
|
||||
}
|
||||
|
||||
.icontishi-beizhu2:before {
|
||||
content: "\e650";
|
||||
}
|
||||
|
||||
.iconshezhi-quanxianshezhi:before {
|
||||
content: "\e651";
|
||||
}
|
||||
|
||||
.iconhangweifenxi-mokuaifenxi:before {
|
||||
content: "\e652";
|
||||
}
|
||||
|
||||
.icontubiao-loudoutu:before {
|
||||
content: "\e653";
|
||||
}
|
||||
|
||||
.icontubiao-zhexiantu:before {
|
||||
content: "\e654";
|
||||
}
|
||||
|
||||
.icontubiao-biaoge:before {
|
||||
content: "\e655";
|
||||
}
|
||||
|
||||
.iconhangweifenxi-baobiaoliebiao:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,576 @@
|
||||
{
|
||||
"id": "2436113",
|
||||
"name": "SuperSonic 超音数系统官方图标库",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon",
|
||||
"description": "TME数据中台产品",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "22419559",
|
||||
"name": "报表看板",
|
||||
"font_class": "baobiaokanban",
|
||||
"unicode": "e66b",
|
||||
"unicode_decimal": 58987
|
||||
},
|
||||
{
|
||||
"icon_id": "17815082",
|
||||
"name": "看板",
|
||||
"font_class": "kanban",
|
||||
"unicode": "e638",
|
||||
"unicode_decimal": 58936
|
||||
},
|
||||
{
|
||||
"icon_id": "29598913",
|
||||
"name": "运营看板",
|
||||
"font_class": "yunyingkanban",
|
||||
"unicode": "e608",
|
||||
"unicode_decimal": 58888
|
||||
},
|
||||
{
|
||||
"icon_id": "3868281",
|
||||
"name": "数据看板",
|
||||
"font_class": "shujukanban1",
|
||||
"unicode": "eb66",
|
||||
"unicode_decimal": 60262
|
||||
},
|
||||
{
|
||||
"icon_id": "580614",
|
||||
"name": "敬请期待",
|
||||
"font_class": "jingqingqidai01",
|
||||
"unicode": "e607",
|
||||
"unicode_decimal": 58887
|
||||
},
|
||||
{
|
||||
"icon_id": "845846",
|
||||
"name": "投资",
|
||||
"font_class": "touzi",
|
||||
"unicode": "e67a",
|
||||
"unicode_decimal": 59002
|
||||
},
|
||||
{
|
||||
"icon_id": "7294994",
|
||||
"name": "日期",
|
||||
"font_class": "riqi",
|
||||
"unicode": "e609",
|
||||
"unicode_decimal": 58889
|
||||
},
|
||||
{
|
||||
"icon_id": "2029508",
|
||||
"name": "音乐人_16",
|
||||
"font_class": "yinleren_",
|
||||
"unicode": "e606",
|
||||
"unicode_decimal": 58886
|
||||
},
|
||||
{
|
||||
"icon_id": "9504044",
|
||||
"name": "大盘",
|
||||
"font_class": "dapan",
|
||||
"unicode": "e668",
|
||||
"unicode_decimal": 58984
|
||||
},
|
||||
{
|
||||
"icon_id": "26652200",
|
||||
"name": "榜单",
|
||||
"font_class": "bangdan",
|
||||
"unicode": "e669",
|
||||
"unicode_decimal": 58985
|
||||
},
|
||||
{
|
||||
"icon_id": "4313898",
|
||||
"name": "数据挖掘",
|
||||
"font_class": "shujuwajue",
|
||||
"unicode": "e667",
|
||||
"unicode_decimal": 58983
|
||||
},
|
||||
{
|
||||
"icon_id": "12694976",
|
||||
"name": "KHCFDC_收藏",
|
||||
"font_class": "shoucang1",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "10690834",
|
||||
"name": "添加指标",
|
||||
"font_class": "tianjiazhibiao",
|
||||
"unicode": "e632",
|
||||
"unicode_decimal": 58930
|
||||
},
|
||||
{
|
||||
"icon_id": "21030367",
|
||||
"name": "添加维度",
|
||||
"font_class": "tianjiafenzu",
|
||||
"unicode": "e666",
|
||||
"unicode_decimal": 58982
|
||||
},
|
||||
{
|
||||
"icon_id": "1727419",
|
||||
"name": "203右下角勾选",
|
||||
"font_class": "youxiajiaogouxuan",
|
||||
"unicode": "e8b7",
|
||||
"unicode_decimal": 59575
|
||||
},
|
||||
{
|
||||
"icon_id": "2462841",
|
||||
"name": "销售指标设置",
|
||||
"font_class": "xiaoshouzhibiaoshezhi",
|
||||
"unicode": "e665",
|
||||
"unicode_decimal": 58981
|
||||
},
|
||||
{
|
||||
"icon_id": "8097138",
|
||||
"name": "应用表格",
|
||||
"font_class": "yingyongbiaoge",
|
||||
"unicode": "e6ae",
|
||||
"unicode_decimal": 59054
|
||||
},
|
||||
{
|
||||
"icon_id": "12331689",
|
||||
"name": "指标",
|
||||
"font_class": "zhibiao",
|
||||
"unicode": "e66a",
|
||||
"unicode_decimal": 58986
|
||||
},
|
||||
{
|
||||
"icon_id": "6242439",
|
||||
"name": "search",
|
||||
"font_class": "search",
|
||||
"unicode": "e7c9",
|
||||
"unicode_decimal": 59337
|
||||
},
|
||||
{
|
||||
"icon_id": "25630410",
|
||||
"name": "factory-color",
|
||||
"font_class": "factory-color",
|
||||
"unicode": "e69d",
|
||||
"unicode_decimal": 59037
|
||||
},
|
||||
{
|
||||
"icon_id": "25630419",
|
||||
"name": "portray-color",
|
||||
"font_class": "portray-color",
|
||||
"unicode": "e69e",
|
||||
"unicode_decimal": 59038
|
||||
},
|
||||
{
|
||||
"icon_id": "25630420",
|
||||
"name": "visualize-color",
|
||||
"font_class": "visualize-color",
|
||||
"unicode": "e69f",
|
||||
"unicode_decimal": 59039
|
||||
},
|
||||
{
|
||||
"icon_id": "25630396",
|
||||
"name": "amount-color",
|
||||
"font_class": "amount-color",
|
||||
"unicode": "e68f",
|
||||
"unicode_decimal": 59023
|
||||
},
|
||||
{
|
||||
"icon_id": "25630397",
|
||||
"name": "api-color",
|
||||
"font_class": "api-color",
|
||||
"unicode": "e690",
|
||||
"unicode_decimal": 59024
|
||||
},
|
||||
{
|
||||
"icon_id": "25630398",
|
||||
"name": "content-color",
|
||||
"font_class": "content-color",
|
||||
"unicode": "e691",
|
||||
"unicode_decimal": 59025
|
||||
},
|
||||
{
|
||||
"icon_id": "25630399",
|
||||
"name": "box-color",
|
||||
"font_class": "box-color",
|
||||
"unicode": "e692",
|
||||
"unicode_decimal": 59026
|
||||
},
|
||||
{
|
||||
"icon_id": "25630400",
|
||||
"name": "chat-color",
|
||||
"font_class": "chat-color",
|
||||
"unicode": "e693",
|
||||
"unicode_decimal": 59027
|
||||
},
|
||||
{
|
||||
"icon_id": "25630401",
|
||||
"name": "client-color",
|
||||
"font_class": "client-color",
|
||||
"unicode": "e694",
|
||||
"unicode_decimal": 59028
|
||||
},
|
||||
{
|
||||
"icon_id": "25630402",
|
||||
"name": "data-process",
|
||||
"font_class": "data-process",
|
||||
"unicode": "e695",
|
||||
"unicode_decimal": 59029
|
||||
},
|
||||
{
|
||||
"icon_id": "25630403",
|
||||
"name": "bi-color",
|
||||
"font_class": "bi-color",
|
||||
"unicode": "e696",
|
||||
"unicode_decimal": 59030
|
||||
},
|
||||
{
|
||||
"icon_id": "25630404",
|
||||
"name": "filed-color",
|
||||
"font_class": "filed-color",
|
||||
"unicode": "e697",
|
||||
"unicode_decimal": 59031
|
||||
},
|
||||
{
|
||||
"icon_id": "25630405",
|
||||
"name": "invoking-color",
|
||||
"font_class": "invoking-color",
|
||||
"unicode": "e698",
|
||||
"unicode_decimal": 59032
|
||||
},
|
||||
{
|
||||
"icon_id": "25630406",
|
||||
"name": "issue-color",
|
||||
"font_class": "issue-color",
|
||||
"unicode": "e699",
|
||||
"unicode_decimal": 59033
|
||||
},
|
||||
{
|
||||
"icon_id": "25630407",
|
||||
"name": "platform-color",
|
||||
"font_class": "platform-color",
|
||||
"unicode": "e69a",
|
||||
"unicode_decimal": 59034
|
||||
},
|
||||
{
|
||||
"icon_id": "25630408",
|
||||
"name": "file-color",
|
||||
"font_class": "file-color",
|
||||
"unicode": "e69b",
|
||||
"unicode_decimal": 59035
|
||||
},
|
||||
{
|
||||
"icon_id": "25630409",
|
||||
"name": "name-color",
|
||||
"font_class": "name-color",
|
||||
"unicode": "e69c",
|
||||
"unicode_decimal": 59036
|
||||
},
|
||||
{
|
||||
"icon_id": "21480366",
|
||||
"name": "icon-task-status-draft",
|
||||
"font_class": "draft",
|
||||
"unicode": "e605",
|
||||
"unicode_decimal": 58885
|
||||
},
|
||||
{
|
||||
"icon_id": "21480363",
|
||||
"name": "icon-task-status-system-freeze",
|
||||
"font_class": "unknown",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "21480360",
|
||||
"name": "icon-task-status-normal",
|
||||
"font_class": "normal",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
},
|
||||
{
|
||||
"icon_id": "21480337",
|
||||
"name": "icon-task-status-freezed",
|
||||
"font_class": "freezed",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "20901515",
|
||||
"name": "logo文字",
|
||||
"font_class": "logowenzi",
|
||||
"unicode": "e660",
|
||||
"unicode_decimal": 58976
|
||||
},
|
||||
{
|
||||
"icon_id": "20901503",
|
||||
"name": "logo标识",
|
||||
"font_class": "logobiaoshi",
|
||||
"unicode": "e664",
|
||||
"unicode_decimal": 58980
|
||||
},
|
||||
{
|
||||
"icon_id": "20897340",
|
||||
"name": "超音数系统logo",
|
||||
"font_class": "chaoyinshuxitonglogo",
|
||||
"unicode": "e663",
|
||||
"unicode_decimal": 58979
|
||||
},
|
||||
{
|
||||
"icon_id": "20852244",
|
||||
"name": "暂无权限点击申请",
|
||||
"font_class": "zanwuquanxiandianjishenqing_1",
|
||||
"unicode": "e662",
|
||||
"unicode_decimal": 58978
|
||||
},
|
||||
{
|
||||
"icon_id": "20851776",
|
||||
"name": "请创建目录或看板",
|
||||
"font_class": "qingchuangjianmuluhuokanban",
|
||||
"unicode": "e661",
|
||||
"unicode_decimal": 58977
|
||||
},
|
||||
{
|
||||
"icon_id": "20830143",
|
||||
"name": "资产",
|
||||
"font_class": "zichan",
|
||||
"unicode": "e65f",
|
||||
"unicode_decimal": 58975
|
||||
},
|
||||
{
|
||||
"icon_id": "20829646",
|
||||
"name": "行为分析",
|
||||
"font_class": "hangweifenxi",
|
||||
"unicode": "e65e",
|
||||
"unicode_decimal": 58974
|
||||
},
|
||||
{
|
||||
"icon_id": "20829640",
|
||||
"name": "数据资产",
|
||||
"font_class": "shujuzichan",
|
||||
"unicode": "e65d",
|
||||
"unicode_decimal": 58973
|
||||
},
|
||||
{
|
||||
"icon_id": "20829629",
|
||||
"name": "数据看板",
|
||||
"font_class": "shujukanban",
|
||||
"unicode": "e659",
|
||||
"unicode_decimal": 58969
|
||||
},
|
||||
{
|
||||
"icon_id": "20829630",
|
||||
"name": "数据接入",
|
||||
"font_class": "shujujieru",
|
||||
"unicode": "e65a",
|
||||
"unicode_decimal": 58970
|
||||
},
|
||||
{
|
||||
"icon_id": "20829631",
|
||||
"name": "数据探索",
|
||||
"font_class": "shujutansuo",
|
||||
"unicode": "e65b",
|
||||
"unicode_decimal": 58971
|
||||
},
|
||||
{
|
||||
"icon_id": "20829633",
|
||||
"name": "敏捷分析",
|
||||
"font_class": "minjiefenxi",
|
||||
"unicode": "e65c",
|
||||
"unicode_decimal": 58972
|
||||
},
|
||||
{
|
||||
"icon_id": "19149997",
|
||||
"name": "研发工具",
|
||||
"font_class": "yanfagongju",
|
||||
"unicode": "e658",
|
||||
"unicode_decimal": 58968
|
||||
},
|
||||
{
|
||||
"icon_id": "3977827",
|
||||
"name": "数据安全",
|
||||
"font_class": "shujuanquan",
|
||||
"unicode": "e614",
|
||||
"unicode_decimal": 58900
|
||||
},
|
||||
{
|
||||
"icon_id": "20782797",
|
||||
"name": "CE",
|
||||
"font_class": "CE",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "20624066",
|
||||
"name": "看板图-刷新",
|
||||
"font_class": "kanbantu-shuaxin",
|
||||
"unicode": "e657",
|
||||
"unicode_decimal": 58967
|
||||
},
|
||||
{
|
||||
"icon_id": "20623681",
|
||||
"name": "导航-搜索",
|
||||
"font_class": "daohang-sousuo",
|
||||
"unicode": "e63e",
|
||||
"unicode_decimal": 58942
|
||||
},
|
||||
{
|
||||
"icon_id": "20623682",
|
||||
"name": "导航-帮助",
|
||||
"font_class": "daohang-bangzhu",
|
||||
"unicode": "e63f",
|
||||
"unicode_decimal": 58943
|
||||
},
|
||||
{
|
||||
"icon_id": "20623683",
|
||||
"name": "看板图-分享",
|
||||
"font_class": "kanbantu-fenxiang",
|
||||
"unicode": "e640",
|
||||
"unicode_decimal": 58944
|
||||
},
|
||||
{
|
||||
"icon_id": "20623684",
|
||||
"name": "全局-日期",
|
||||
"font_class": "quanju-riqi",
|
||||
"unicode": "e641",
|
||||
"unicode_decimal": 58945
|
||||
},
|
||||
{
|
||||
"icon_id": "20623685",
|
||||
"name": "导航-设置",
|
||||
"font_class": "daohang-shezhi",
|
||||
"unicode": "e642",
|
||||
"unicode_decimal": 58946
|
||||
},
|
||||
{
|
||||
"icon_id": "20623686",
|
||||
"name": "导航-资产购物车",
|
||||
"font_class": "daohang-zichangouwuche",
|
||||
"unicode": "e643",
|
||||
"unicode_decimal": 58947
|
||||
},
|
||||
{
|
||||
"icon_id": "20623687",
|
||||
"name": "全局-下载",
|
||||
"font_class": "quanju-xiazai",
|
||||
"unicode": "e644",
|
||||
"unicode_decimal": 58948
|
||||
},
|
||||
{
|
||||
"icon_id": "20623688",
|
||||
"name": "看板图-全屏",
|
||||
"font_class": "kanbantu-quanping",
|
||||
"unicode": "e645",
|
||||
"unicode_decimal": 58949
|
||||
},
|
||||
{
|
||||
"icon_id": "20623689",
|
||||
"name": "数据资产-业务数据资产",
|
||||
"font_class": "shujuzichan-yewushujuzichan",
|
||||
"unicode": "e646",
|
||||
"unicode_decimal": 58950
|
||||
},
|
||||
{
|
||||
"icon_id": "20623690",
|
||||
"name": "数据看板-添加看板",
|
||||
"font_class": "shujukanban-tianjiakanban",
|
||||
"unicode": "e647",
|
||||
"unicode_decimal": 58951
|
||||
},
|
||||
{
|
||||
"icon_id": "20623691",
|
||||
"name": "清空",
|
||||
"font_class": "qingkong",
|
||||
"unicode": "e648",
|
||||
"unicode_decimal": 58952
|
||||
},
|
||||
{
|
||||
"icon_id": "20623692",
|
||||
"name": "数据资产-技术数据资产",
|
||||
"font_class": "shujuzichan-jishushujuzichan",
|
||||
"unicode": "e649",
|
||||
"unicode_decimal": 58953
|
||||
},
|
||||
{
|
||||
"icon_id": "20623693",
|
||||
"name": "数据资产-资产发现",
|
||||
"font_class": "shujuzichan-zichanfaxian",
|
||||
"unicode": "e64a",
|
||||
"unicode_decimal": 58954
|
||||
},
|
||||
{
|
||||
"icon_id": "20623695",
|
||||
"name": "提示-备注1",
|
||||
"font_class": "tishi-beizhu1",
|
||||
"unicode": "e64b",
|
||||
"unicode_decimal": 58955
|
||||
},
|
||||
{
|
||||
"icon_id": "20623696",
|
||||
"name": "数据看板-添加目录",
|
||||
"font_class": "shujukanban-tianjiamulu",
|
||||
"unicode": "e64c",
|
||||
"unicode_decimal": 58956
|
||||
},
|
||||
{
|
||||
"icon_id": "20623697",
|
||||
"name": "图表-柱状图",
|
||||
"font_class": "tubiao-zhuzhuangtu",
|
||||
"unicode": "e64d",
|
||||
"unicode_decimal": 58957
|
||||
},
|
||||
{
|
||||
"icon_id": "20623698",
|
||||
"name": "导航-消息提示",
|
||||
"font_class": "daohang-xiaoxitishi",
|
||||
"unicode": "e64e",
|
||||
"unicode_decimal": 58958
|
||||
},
|
||||
{
|
||||
"icon_id": "20623699",
|
||||
"name": "图表-饼图",
|
||||
"font_class": "tubiao-bingtu",
|
||||
"unicode": "e64f",
|
||||
"unicode_decimal": 58959
|
||||
},
|
||||
{
|
||||
"icon_id": "20623700",
|
||||
"name": "提示-备注2",
|
||||
"font_class": "tishi-beizhu2",
|
||||
"unicode": "e650",
|
||||
"unicode_decimal": 58960
|
||||
},
|
||||
{
|
||||
"icon_id": "20623701",
|
||||
"name": "设置-权限设置",
|
||||
"font_class": "shezhi-quanxianshezhi",
|
||||
"unicode": "e651",
|
||||
"unicode_decimal": 58961
|
||||
},
|
||||
{
|
||||
"icon_id": "20623702",
|
||||
"name": "行为分析-模块分析",
|
||||
"font_class": "hangweifenxi-mokuaifenxi",
|
||||
"unicode": "e652",
|
||||
"unicode_decimal": 58962
|
||||
},
|
||||
{
|
||||
"icon_id": "20623703",
|
||||
"name": "图表-漏斗图",
|
||||
"font_class": "tubiao-loudoutu",
|
||||
"unicode": "e653",
|
||||
"unicode_decimal": 58963
|
||||
},
|
||||
{
|
||||
"icon_id": "20623704",
|
||||
"name": "图表-折线图",
|
||||
"font_class": "tubiao-zhexiantu",
|
||||
"unicode": "e654",
|
||||
"unicode_decimal": 58964
|
||||
},
|
||||
{
|
||||
"icon_id": "20623705",
|
||||
"name": "图表-表格",
|
||||
"font_class": "tubiao-biaoge",
|
||||
"unicode": "e655",
|
||||
"unicode_decimal": 58965
|
||||
},
|
||||
{
|
||||
"icon_id": "20623706",
|
||||
"name": "行为分析-报表列表",
|
||||
"font_class": "hangweifenxi-baobiaoliebiao",
|
||||
"unicode": "e656",
|
||||
"unicode_decimal": 58966
|
||||
}
|
||||
]
|
||||
}
|
||||
181
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.svg
Normal file
181
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 97 KiB |
BIN
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.ttf
Normal file
BIN
webapp/packages/supersonic-fe/src/components/S2Icon/iconfont.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
.s2icon {
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { CSSProperties, FC } from 'react';
|
||||
import cx from 'classnames';
|
||||
import iconfont from './iconfont.css';
|
||||
import styles from './index.less';
|
||||
|
||||
export interface S2IconProps {
|
||||
icon: string;
|
||||
color?: string;
|
||||
size?: string | number;
|
||||
style?: CSSProperties;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const S2Icon: FC<S2IconProps> = ({ color, size, icon, style, className }) => {
|
||||
return (
|
||||
<span
|
||||
className={cx(styles.s2icon, iconfont.iconfont, icon, className)}
|
||||
style={{ color, fontSize: size, ...style }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ICON = iconfont;
|
||||
|
||||
export const AssetIcon = <S2Icon icon={ICON.iconzichan} />;
|
||||
|
||||
export default S2Icon;
|
||||
@@ -0,0 +1,156 @@
|
||||
import { Avatar, TreeSelect, Tag } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { getDepartmentTree, getUserByDeptid } from './service';
|
||||
import TMEAvatar from '@/components/TMEAvatar';
|
||||
|
||||
type Props = {
|
||||
type: 'selectedPerson' | 'selectedDepartment';
|
||||
value?: any;
|
||||
onChange?: (value: boolean) => void;
|
||||
treeSelectProps?: Record<string, any>;
|
||||
};
|
||||
|
||||
const isDisableCheckbox = (name: string, type: string) => {
|
||||
const isPersonNode = name.includes('(');
|
||||
if (type === 'selectedPerson') {
|
||||
return !isPersonNode;
|
||||
}
|
||||
if (type === 'selectedDepartment') {
|
||||
if (isPersonNode) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 转化树结构
|
||||
export function changeTreeData(treeData: any = [], type: string) {
|
||||
return treeData.map((item: any) => {
|
||||
return {
|
||||
title: item.name,
|
||||
value: item.key,
|
||||
key: item.key,
|
||||
isLeaf: !!item.emplid,
|
||||
children: item?.subDepartments ? changeTreeData(item.subDepartments, type) : [],
|
||||
disableCheckbox: isDisableCheckbox(item.name, type),
|
||||
checkable: !isDisableCheckbox(item.name, type),
|
||||
icon: item.name.includes('(') && (
|
||||
<Avatar size={18} shape="square" src={`${item.avatarImg}`} alt="avatar" />
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const SelectPartner: React.FC<Props> = ({
|
||||
type = 'selectedPerson',
|
||||
value,
|
||||
onChange,
|
||||
treeSelectProps = {},
|
||||
}) => {
|
||||
const [treeData, setTreeData] = useState([]);
|
||||
|
||||
const getDetpartment = async () => {
|
||||
const res = await getDepartmentTree();
|
||||
const data = changeTreeData(res.data, type);
|
||||
setTreeData(data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getDetpartment();
|
||||
}, []);
|
||||
|
||||
const updateTreeData = (list: any, key: any, children: any) => {
|
||||
return list.map((node: any) => {
|
||||
if (node.key === key) {
|
||||
let childrenData = node.children;
|
||||
if (node.children && !node.children.find((item: any) => item?.key === children[0]?.key)) {
|
||||
childrenData = [...children, ...node.children];
|
||||
}
|
||||
return { ...node, children: childrenData };
|
||||
}
|
||||
if (node.children.length !== 0) {
|
||||
return { ...node, children: updateTreeData(node.children, key, children) };
|
||||
}
|
||||
return node;
|
||||
});
|
||||
};
|
||||
const onLoadData = (target: any) => {
|
||||
const { key } = target;
|
||||
const loadData = async () => {
|
||||
const childData = await getUserByDeptid(key);
|
||||
if (childData.data.length === 0) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
setTreeData((origin) => updateTreeData(origin, key, changeTreeData(childData.data, type)));
|
||||
}, 300);
|
||||
};
|
||||
return new Promise<void>((resolve) => {
|
||||
loadData().then(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = (newValue: any) => {
|
||||
onChange?.(newValue);
|
||||
};
|
||||
const tagRender = (props: any) => {
|
||||
const { label } = props;
|
||||
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
const enEname = label.split('(')[0];
|
||||
return (
|
||||
<Tag
|
||||
onMouseDown={onPreventMouseDown}
|
||||
closable={true}
|
||||
onClose={() => {
|
||||
const { value: propsValue } = props;
|
||||
const newValue = value.filter((code: string) => {
|
||||
return code !== propsValue;
|
||||
});
|
||||
onChange?.(newValue);
|
||||
}}
|
||||
style={{ marginRight: 3, marginBottom: 3 }}
|
||||
>
|
||||
{type === 'selectedPerson' && <TMEAvatar size="small" staffName={enEname} />}
|
||||
<span
|
||||
style={{
|
||||
position: 'relative',
|
||||
top: '2px',
|
||||
left: '5px',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<TreeSelect
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
value={value}
|
||||
loadData={onLoadData}
|
||||
dropdownStyle={{ maxHeight: 800, overflow: 'auto' }}
|
||||
allowClear
|
||||
multiple
|
||||
onChange={handleChange}
|
||||
treeCheckable={true}
|
||||
treeIcon={true}
|
||||
treeData={treeData}
|
||||
tagRender={tagRender}
|
||||
treeNodeFilterProp={'title'}
|
||||
listHeight={500}
|
||||
showCheckedStrategy={TreeSelect.SHOW_PARENT}
|
||||
{...treeSelectProps}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectPartner;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { request } from 'umi';
|
||||
|
||||
export async function getDepartmentTree() {
|
||||
return request<any>('/api/tpp/getDetpartmentTree', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
export async function getUserByDeptid(id: any) {
|
||||
return request<any>(`/api/tpp/getUserByDeptid/${id}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.userAvatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.userText {
|
||||
margin-left: 10px;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { useState } from 'react';
|
||||
import type { FC } from 'react';
|
||||
import { Select, message } from 'antd';
|
||||
import type { UserItem } from './service';
|
||||
import { getAllUser } from './service';
|
||||
|
||||
import styles from './index.less';
|
||||
import { useFetchDataEffect } from '@/utils/curd';
|
||||
import TMEAvatar from '../TMEAvatar';
|
||||
|
||||
interface Props {
|
||||
value?: string[];
|
||||
placeholder?: string;
|
||||
isMultiple?: boolean;
|
||||
onChange?: (owners: string | string[]) => void;
|
||||
}
|
||||
|
||||
const SelectTMEPerson: FC<Props> = ({ placeholder, value, isMultiple = true, onChange }) => {
|
||||
const [userList, setUserList] = useState<UserItem[]>([]);
|
||||
|
||||
useFetchDataEffect(
|
||||
{
|
||||
fetcher: async () => {
|
||||
const res = await getAllUser();
|
||||
if (res.code !== 200) {
|
||||
message.error(res.msg);
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
return res.data || [];
|
||||
},
|
||||
updater: (list) => {
|
||||
const users = list.map((item: UserItem) => {
|
||||
const { enName, chName, name } = item;
|
||||
return {
|
||||
...item,
|
||||
enName: enName || name,
|
||||
chName: chName || name,
|
||||
};
|
||||
});
|
||||
setUserList(users);
|
||||
},
|
||||
cleanup: () => {
|
||||
setUserList([]);
|
||||
},
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={value}
|
||||
placeholder={placeholder ?? '请选择用户名'}
|
||||
mode={isMultiple ? 'multiple' : undefined}
|
||||
allowClear
|
||||
showSearch
|
||||
onChange={onChange}
|
||||
>
|
||||
{userList.map((item) => {
|
||||
return (
|
||||
<Select.Option key={item.enName} value={item.enName}>
|
||||
<TMEAvatar size="small" staffName={item.enName} />
|
||||
<span className={styles.userText}>{item.displayName}</span>
|
||||
</Select.Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectTMEPerson;
|
||||
@@ -0,0 +1,19 @@
|
||||
import request from 'umi-request';
|
||||
|
||||
export type UserItem = {
|
||||
enName?: string;
|
||||
displayName: string;
|
||||
chName?: string;
|
||||
name?: string;
|
||||
email: string;
|
||||
};
|
||||
export type GetAllUserRes = Result<UserItem[]>;
|
||||
|
||||
// 获取所有用户
|
||||
export async function getAllUser(): Promise<GetAllUserRes> {
|
||||
const { APP_TARGET } = process.env;
|
||||
if (APP_TARGET === 'inner') {
|
||||
return request.get('/api/oa/user/all');
|
||||
}
|
||||
return request.get(`${process.env.AUTH_API_BASE_URL}user/getUserList`);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@borderColor: #eee;
|
||||
|
||||
.sqlEditor {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
border: solid 1px @borderColor;
|
||||
|
||||
:global {
|
||||
.ace_editor {
|
||||
font-family: 'Menlo', 'Monaco', 'Ubuntu Mono', 'Consolas', 'source-code-pro' !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fullScreenBtnBox {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
282
webapp/packages/supersonic-fe/src/components/SqlEditor/index.tsx
Normal file
282
webapp/packages/supersonic-fe/src/components/SqlEditor/index.tsx
Normal file
@@ -0,0 +1,282 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import React, { useRef, useEffect, useCallback, useState, useMemo } from 'react';
|
||||
import AceEditor, { IAceOptions } from 'react-ace';
|
||||
import languageTools from 'ace-builds/src-min-noconflict/ext-language_tools';
|
||||
import 'ace-builds/src-min-noconflict/ext-searchbox';
|
||||
import 'ace-builds/src-min-noconflict/theme-sqlserver';
|
||||
import 'ace-builds/src-min-noconflict/theme-monokai';
|
||||
import 'ace-builds/src-min-noconflict/mode-sql';
|
||||
import ReactAce, { IAceEditorProps } from 'react-ace/lib/ace';
|
||||
import { Typography } from 'antd';
|
||||
import { debounce } from 'lodash';
|
||||
import FullScreen from '../FullScreen';
|
||||
import styles from './index.less';
|
||||
|
||||
type TMode = 'sql' | 'mysql' | 'sqlserver';
|
||||
|
||||
enum EHintMeta {
|
||||
table = 'table',
|
||||
variable = 'variable',
|
||||
column = 'column',
|
||||
}
|
||||
const DEFAULT_FONT_SIZE = '14px';
|
||||
// const THEME_DEFAULT = 'sqlserver';
|
||||
const MODE_DEFAULT = 'sql';
|
||||
// const HEIGHT_DEFAULT = '300px';
|
||||
const HEIGHT_DEFAULT = '100%';
|
||||
const EDITOR_OPTIONS: IAceOptions = {
|
||||
behavioursEnabled: true,
|
||||
enableSnippets: false,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
autoScrollEditorIntoView: true,
|
||||
wrap: true,
|
||||
useWorker: false,
|
||||
};
|
||||
export interface ISqlEditorProps {
|
||||
hints?: { [name: string]: string[] };
|
||||
value?: string;
|
||||
height?: string;
|
||||
/**
|
||||
* 需引入对应的包 'ace-builds/src-min-noconflict/mode-${mode}'
|
||||
*/
|
||||
mode?: TMode;
|
||||
/**
|
||||
* 需引入对应的包 'ace-builds/src-min-noconflict/theme-${theme}'
|
||||
*/
|
||||
// theme?: TTheme;
|
||||
isRightTheme?: boolean;
|
||||
editorConfig?: IAceEditorProps;
|
||||
sizeChanged?: number;
|
||||
fullScreenBtnVisible?: boolean;
|
||||
onSqlChange?: (sql: string) => void;
|
||||
onChange?: (sql: string) => void;
|
||||
onSelect?: (sql: string) => void;
|
||||
onCmdEnter?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Editor Component
|
||||
* @param props ISqlEditorProps
|
||||
*/
|
||||
function SqlEditor(props: ISqlEditorProps) {
|
||||
const refEditor = useRef<ReactAce>();
|
||||
const {
|
||||
hints = {},
|
||||
value,
|
||||
height = HEIGHT_DEFAULT,
|
||||
mode = MODE_DEFAULT,
|
||||
isRightTheme = false,
|
||||
sizeChanged,
|
||||
editorConfig,
|
||||
fullScreenBtnVisible = true,
|
||||
onSqlChange,
|
||||
onChange,
|
||||
onSelect,
|
||||
onCmdEnter,
|
||||
} = props;
|
||||
const resize = useCallback(
|
||||
debounce(() => {
|
||||
refEditor.current?.editor.resize();
|
||||
}, 300),
|
||||
[],
|
||||
);
|
||||
|
||||
const change = useCallback((sql: string) => {
|
||||
onSqlChange?.(sql);
|
||||
onChange?.(sql);
|
||||
}, []);
|
||||
|
||||
const selectionChange = useCallback(
|
||||
debounce((selection: any) => {
|
||||
const rawSelectedQueryText: any = refEditor.current?.editor.session.doc.getTextRange(
|
||||
selection.getRange(),
|
||||
);
|
||||
const selectedQueryText = rawSelectedQueryText?.length > 1 ? rawSelectedQueryText : null;
|
||||
onSelect?.(selectedQueryText);
|
||||
}, 300),
|
||||
[],
|
||||
);
|
||||
|
||||
const commands = useMemo(
|
||||
() => [
|
||||
{
|
||||
name: 'execute',
|
||||
bindKey: { win: 'Ctrl-Enter', mac: 'Command-Enter' },
|
||||
exec: onCmdEnter,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
resize();
|
||||
}, [sizeChanged, height]);
|
||||
|
||||
useEffect(() => {
|
||||
setHintsPopover(hints);
|
||||
}, [hints]);
|
||||
|
||||
const [isSqlIdeFullScreen, setIsSqlIdeFullScreen] = useState<boolean>(false);
|
||||
|
||||
const handleNormalScreenSqlIde = () => {
|
||||
setIsSqlIdeFullScreen(false);
|
||||
// setSqlEditorHeight(getDefaultSqlEditorHeight(screenSize));
|
||||
};
|
||||
return (
|
||||
<div className={styles.sqlEditor} style={{ height }}>
|
||||
<FullScreen
|
||||
isFullScreen={isSqlIdeFullScreen}
|
||||
top={`${0}px`}
|
||||
triggerBackToNormal={handleNormalScreenSqlIde}
|
||||
>
|
||||
<AceEditor
|
||||
ref={refEditor}
|
||||
name="aceEditor"
|
||||
width="100%"
|
||||
height="100%"
|
||||
fontSize={DEFAULT_FONT_SIZE}
|
||||
mode={mode}
|
||||
theme={isRightTheme ? 'sqlserver' : 'monokai'}
|
||||
value={value}
|
||||
showPrintMargin={false}
|
||||
highlightActiveLine={true}
|
||||
setOptions={EDITOR_OPTIONS}
|
||||
commands={commands as any}
|
||||
onChange={change}
|
||||
onSelectionChange={selectionChange}
|
||||
// autoScrollEditorIntoView={true}
|
||||
{...editorConfig}
|
||||
/>
|
||||
</FullScreen>
|
||||
{fullScreenBtnVisible && (
|
||||
<span
|
||||
className={styles.fullScreenBtnBox}
|
||||
onClick={() => {
|
||||
setIsSqlIdeFullScreen(true);
|
||||
}}
|
||||
>
|
||||
<Typography.Link>全屏查看</Typography.Link>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ICompleters {
|
||||
value: string;
|
||||
name?: string;
|
||||
caption?: string;
|
||||
meta?: string;
|
||||
type?: string;
|
||||
score?: number;
|
||||
}
|
||||
|
||||
function setHintsPopover(hints: ISqlEditorProps['hints']) {
|
||||
const {
|
||||
textCompleter,
|
||||
keyWordCompleter,
|
||||
// snippetCompleter,
|
||||
setCompleters,
|
||||
} = languageTools;
|
||||
const customHintsCompleter = {
|
||||
identifierRegexps: [/[a-zA-Z_0-9.\-\u00A2-\uFFFF]/],
|
||||
getCompletions: (editor, session, pos, prefix, callback) => {
|
||||
const { tableKeywords, tableColumnKeywords, variableKeywords, columns } =
|
||||
formatCompleterFromHints(hints);
|
||||
if (prefix[prefix.length - 1] === '.') {
|
||||
const tableName = prefix.substring(0, prefix.length - 1);
|
||||
const AliasTableColumnKeywords = genAliasTableColumnKeywords(editor, tableName, hints);
|
||||
const hintList = tableKeywords.concat(
|
||||
variableKeywords,
|
||||
AliasTableColumnKeywords,
|
||||
tableColumnKeywords[tableName] || [],
|
||||
);
|
||||
return callback(null, hintList);
|
||||
}
|
||||
callback(null, tableKeywords.concat(variableKeywords, columns));
|
||||
},
|
||||
};
|
||||
const completers = [
|
||||
textCompleter,
|
||||
keyWordCompleter,
|
||||
// snippetCompleter,
|
||||
customHintsCompleter,
|
||||
];
|
||||
setCompleters(completers);
|
||||
}
|
||||
|
||||
function formatCompleterFromHints(hints: ISqlEditorProps['hints']) {
|
||||
const variableKeywords: ICompleters[] = [];
|
||||
const tableKeywords: ICompleters[] = [];
|
||||
const tableColumnKeywords: { [tableName: string]: ICompleters[] } = {};
|
||||
const columns: ICompleters[] = [];
|
||||
let score = 1000;
|
||||
Object.keys(hints).forEach((key) => {
|
||||
const meta: EHintMeta = isVariable(key) as any;
|
||||
if (!meta) {
|
||||
const { columnWithTableName, column } = genTableColumnKeywords(hints[key], key);
|
||||
tableColumnKeywords[key] = columnWithTableName;
|
||||
columns.push(...column);
|
||||
tableKeywords.push({
|
||||
name: key,
|
||||
value: key,
|
||||
score: score--,
|
||||
meta: isTable(),
|
||||
});
|
||||
} else {
|
||||
variableKeywords.push({ score: score--, value: key, meta });
|
||||
}
|
||||
});
|
||||
|
||||
return { tableKeywords, tableColumnKeywords, variableKeywords, columns };
|
||||
}
|
||||
|
||||
function genTableColumnKeywords(table: string[], tableName: string) {
|
||||
let score = 100;
|
||||
const columnWithTableName: ICompleters[] = [];
|
||||
const column: ICompleters[] = [];
|
||||
table.forEach((columnVal) => {
|
||||
const basis = { score: score--, meta: isColumn() };
|
||||
columnWithTableName.push({
|
||||
caption: `${tableName}.${columnVal}`,
|
||||
name: `${tableName}.${columnVal}`,
|
||||
value: `${tableName}.${columnVal}`,
|
||||
...basis,
|
||||
});
|
||||
column.push({ value: columnVal, name: columnVal, ...basis });
|
||||
});
|
||||
return { columnWithTableName, column };
|
||||
}
|
||||
|
||||
function genAliasTableColumnKeywords(
|
||||
editor,
|
||||
aliasTableName: string,
|
||||
hints: ISqlEditorProps['hints'],
|
||||
) {
|
||||
const content = editor.getSession().getValue();
|
||||
const tableName = Object.keys(hints).find((tableName) => {
|
||||
const reg = new RegExp(`.+${tableName}\\s*(as|AS)?(?=\\s+${aliasTableName}\\s*)`, 'im');
|
||||
return reg.test(content);
|
||||
});
|
||||
if (!tableName) {
|
||||
return [];
|
||||
}
|
||||
const { columnWithTableName } = genTableColumnKeywords(hints[tableName], aliasTableName);
|
||||
return columnWithTableName;
|
||||
}
|
||||
|
||||
function isVariable(key: string) {
|
||||
return key.startsWith('$') && key.endsWith('$') && EHintMeta.variable;
|
||||
}
|
||||
|
||||
function isTable(key?: string) {
|
||||
return EHintMeta.table;
|
||||
}
|
||||
|
||||
function isColumn(key?: string) {
|
||||
return EHintMeta.column;
|
||||
}
|
||||
|
||||
export default SqlEditor;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,15 @@
|
||||
import type { FC } from 'react';
|
||||
import { Avatar } from 'antd';
|
||||
import type { AvatarProps } from 'antd';
|
||||
import avatarIcon from './assets/avatar.gif';
|
||||
|
||||
interface Props extends AvatarProps {
|
||||
staffName?: string;
|
||||
avatarImg?: string;
|
||||
}
|
||||
|
||||
const TMEAvatar: FC<Props> = ({ avatarImg, ...restProps }) => (
|
||||
<Avatar src={`${avatarImg}`} alt="avatar" icon={<img src={avatarIcon} />} {...restProps} />
|
||||
);
|
||||
|
||||
export default TMEAvatar;
|
||||
Reference in New Issue
Block a user