first commit

This commit is contained in:
jerryjzhang
2023-06-12 18:44:01 +08:00
commit dc4fc69b57
879 changed files with 573090 additions and 0 deletions

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,5 @@
export const formLayout: any = {
// labelCol: { span: 13 },
// wrapperCol: { span: 13 },
layout: 'vertical',
};

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -0,0 +1,8 @@
import { createFromIconfontCN } from '@ant-design/icons';
import defaultSettings from '../../../config/defaultSettings';
const IconFont = createFromIconfontCN({
scriptUrl: defaultSettings.iconfontUrl,
});
export default IconFont;

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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;

View 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

View File

@@ -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
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -0,0 +1,3 @@
.s2icon {
line-height: 1;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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',
});
}

View File

@@ -0,0 +1,9 @@
.userAvatar {
width: 24px;
height: 24px;
border-radius: 50%;
}
.userText {
margin-left: 10px;
}

View File

@@ -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;

View File

@@ -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`);
}

View File

@@ -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;
}

View 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

View File

@@ -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;