antd#Descriptions TypeScript Examples
The following examples show how to use
antd#Descriptions.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: PortAssetPage.tsx From yakit with GNU Affero General Public License v3.0 | 6 votes |
PortAssetDescription: React.FC<PortAssetDescriptionProp> = (props) => {
const {port} = props;
return <Descriptions size={"small"} bordered={true} column={!port.ServiceType ? 1 : 2} title={''}
style={{marginLeft: 20}}>
<Descriptions.Item label={<Tag>状态</Tag>}><CopyableField
text={`${port.State}`}/></Descriptions.Item>
{port.HtmlTitle && <Descriptions.Item label={<Tag>Title</Tag>}><CopyableField
text={`${port.HtmlTitle}`}/></Descriptions.Item>}
{port.ServiceType && <Descriptions.Item span={2} label={<Tag>应用</Tag>}><CopyableField
text={`${port.ServiceType}`}/></Descriptions.Item>}
{port.Reason && <Descriptions.Item span={2} label={<Tag>失败原因</Tag>}><CopyableField
text={`${port.Reason}`}/></Descriptions.Item>}
{port.CPE.join("|") !== "" ? <Descriptions.Item span={2} label={<Tag>CPE</Tag>}>
<Space direction={"vertical"}>
{port.CPE.map(e => {
return <CopyableField
text={`${e}`}
/>
})}
</Space>
</Descriptions.Item> : undefined}
{port.Fingerprint && <Descriptions.Item span={2} label={<Tag>指纹信息</Tag>}>
<div style={{height: 200}}>
<YakEditor value={port.Fingerprint} noLineNumber={true} noMiniMap={true}/>
</div>
</Descriptions.Item>}
</Descriptions>
}
Example #2
Source File: DetailDescription.tsx From mayoor with MIT License | 6 votes |
StyledDescriptions = styled(Descriptions)`
padding: 0 35px;
.ant-descriptions-item-label,
.ant-descriptions-item-content {
font-size: 12px;
}
.anticon {
margin-right: 3px;
}
`
Example #3
Source File: DetailDescription.tsx From mayoor with MIT License | 6 votes |
DetailDescription: React.FC<Props> = ({ createdByName, createdAt, updatedAt }) => {
const { t } = useTranslation();
const { f } = useDateFormatter();
return (
<StyledDescriptions>
<Descriptions.Item label={t('Created By')} key="createdBy">
<UserOutlined />
{createdByName}
</Descriptions.Item>
<Descriptions.Item label={t('Created At')} key="createdAt">
{createdAt && (
<>
<CalendarOutlined /> {f(createdAt, 'datetime')}
</>
)}
</Descriptions.Item>
<Descriptions.Item label={t('Last Updated At')} key="lastUpdatedAt">
{updatedAt && (
<>
<CalendarOutlined /> {f(updatedAt, 'datetime')}
</>
)}
</Descriptions.Item>
</StyledDescriptions>
);
}
Example #4
Source File: index.tsx From jetlinks-ui-antd with MIT License | 6 votes |
Save: React.FC<Props> = (props) => {
return (
<Modal
visible
title={'访问日志详情'}
width={900}
onOk={() => { props.close() }}
onCancel={() => { props.close(); }}
// footer={null}
>
<Descriptions bordered column={2} >
<Descriptions.Item label="URL" span={1}>{props.data.url}</Descriptions.Item>
<Descriptions.Item label="请求方法" span={1}>{props.data.httpMethod}</Descriptions.Item>
<Descriptions.Item label="动作" span={1}>{props.data.action}</Descriptions.Item>
<Descriptions.Item label="类名" span={1}>{props.data.target}</Descriptions.Item>
<Descriptions.Item label="方法名" span={1}>{props.data.method}</Descriptions.Item>
<Descriptions.Item label="IP" span={1}>{props.data.ip}</Descriptions.Item>
<Descriptions.Item label="请求时间" span={1}>{moment(props.data.requestTime).format('YYYY-MM-DD HH:mm:ss')}</Descriptions.Item>
<Descriptions.Item label="请求耗时" span={1}>{(props.data.responseTime || 0) - (props.data.requestTime || 0)}ms</Descriptions.Item>
<Descriptions.Item label="请求头" span={2}>
{JSON.stringify(props.data.httpHeaders)}
</Descriptions.Item>
<Descriptions.Item label="请求参数" span={2}>
{JSON.stringify(props.data.parameters)}
</Descriptions.Item>
<Descriptions.Item label="异常信息" span={2}>
<div
style={{
height: 200,
overflow: 'auto'
}}>
{props.data.exception}
</div>
</Descriptions.Item>
</Descriptions>
</Modal>
)
}
Example #5
Source File: index.tsx From jetlinks-ui-antd with MIT License | 6 votes |
Save: React.FC<Props> = props => (
<Modal
visible
title="系统日志详情"
width={900}
onOk={() => { props.close() }}
onCancel={() => { props.close(); }}
// footer={null}
>
<Descriptions bordered column={2}>
<Descriptions.Item label="线程名称" span={1}>{props.data.threadName}</Descriptions.Item>
<Descriptions.Item label="日志级别" span={1}>{props.data.level}</Descriptions.Item>
<Descriptions.Item label="方法名" span={1}>{props.data.methodName}</Descriptions.Item>
<Descriptions.Item label="行号" span={1}>{props.data.lineNumber}</Descriptions.Item>
<Descriptions.Item label="线程ID" span={1}>{props.data.threadName}</Descriptions.Item>
<Descriptions.Item label="创建时间" span={1}>{moment(props.data.createTime).format('YYYY-MM-DD HH:mm:ss')}</Descriptions.Item>
<Descriptions.Item label="名称" span={2}>{props.data.name}</Descriptions.Item>
<Descriptions.Item label="类名" span={2}>{props.data.className}</Descriptions.Item>
<Descriptions.Item label="消息" span={2}>
<Input.TextArea rows={2} value={props.data.message} />
</Descriptions.Item>
<Descriptions.Item label="上下文" span={2}>
{JSON.stringify(props.data.context)}
</Descriptions.Item>
<Descriptions.Item label="异常栈" span={2}>
<Input.TextArea rows={3} value={props.data.exceptionStack} />
</Descriptions.Item>
</Descriptions>
</Modal>
)
Example #6
Source File: ResolveId.tsx From wildduck-ui with MIT License | 6 votes |
ResolveId: React.FC = () => {
const { Search } = Input;
const { resolveId } = useActions(dkimLogic);
const { domainId } = useValues(dkimLogic);
const onSearch = (value: any) => {
if (value.length > 0) {
resolveId(value);
}
};
const descriptionBox = (
<Card>
<Descriptions bordered>
<Descriptions.Item label='ID'>{domainId}</Descriptions.Item>
</Descriptions>
</Card>
);
const pageBreadcrumb = (
<Breadcrumb>
<Breadcrumb.Item>
<Link to='/dkim'>DKIM</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Resolve DKIM ID</Breadcrumb.Item>
</Breadcrumb>
);
return (
<Page title={pageBreadcrumb}>
<Search placeholder='Enter Alias' allowClear enterButton='Search' size='large' onSearch={onSearch} />
{domainId.length > 0 && descriptionBox}
</Page>
);
}
Example #7
Source File: WalletForm.tsx From subscan-multisig-react with Apache License 2.0 | 6 votes |
function confirmToAdd(accountExist: KeyringAddress, confirm: () => void) {
return Modal.confirm({
cancelText: <Trans>cancel</Trans>,
okText: <Trans>confirm</Trans>,
onOk: (close) => {
if (confirm) {
confirm();
}
close();
},
maskClosable: false,
closeIcon: false,
content: (
<div>
<p className="mb-4">
<Trans>
There is an account configured by the same member and threshold. Confirm to replace it with a new account?
</Trans>
</p>
<Descriptions column={1} size="small" title={<Trans>Origin Account</Trans>}>
<Descriptions.Item label={<Trans>name</Trans>}>{accountExist.meta.name}</Descriptions.Item>
<Descriptions.Item label={<Trans>threshold</Trans>}>
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
{(accountExist.meta as any).threshold}
</Descriptions.Item>
<Descriptions.Item label={<Trans>Create Time</Trans>}>
{format(accountExist.meta.whenCreated || 0, 'yyyy-MM-dd hh:mm:ss')}
</Descriptions.Item>
</Descriptions>
</div>
),
});
}
Example #8
Source File: Info.tsx From jetlinks-ui-antd with MIT License | 6 votes |
Info: React.FC<Props> = (props) => {
return (
<div>
<Card style={{ marginBottom: 20 }}>
<Descriptions style={{ marginBottom: 20 }} bordered column={3} title={<span>固件信息</span>}>
<Descriptions.Item label="固件名称" span={1}>
{props.data.name}
</Descriptions.Item>
<Descriptions.Item label="所属产品" span={1}>
{props.data.productName}
</Descriptions.Item>
<Descriptions.Item label="版本" span={1}>
{props.data.version}
</Descriptions.Item>
<Descriptions.Item label="版本序号" span={1}>
{props.data.versionOrder}
</Descriptions.Item>
<Descriptions.Item label="签名方式" span={1}>
{props.data.signMethod}
</Descriptions.Item>
<Descriptions.Item label="签名" span={1}>
{props.data.sign}
</Descriptions.Item>
<Descriptions.Item label="说明" span={3}>
{props.data.description}
</Descriptions.Item>
</Descriptions>
</Card>
</div>
);
}
Example #9
Source File: index.tsx From scorpio-h5-design with MIT License | 6 votes |
export default function Font() {
const { selectComponent, changeContainerPropsState } = useModel('bridge');
const { color, fontSize, fontWeight } = selectComponent?.containerProps ?? {};
return (
<Descriptions column={1}>
<Descriptions.Item label="颜色">
<div className="font-color-input">
<ColorPicker onChange={(value: string) => { changeContainerPropsState('color', value); }} value={color ?? '#fff'} />
</div>
</Descriptions.Item>
<Descriptions.Item label="字号">
<div className="font-size-weight">
<Select
value={fontWeight ?? 100}
style={{ width: 120 }}
onChange={(value) => { changeContainerPropsState('fontWeight', value); }}
>
<Select.Option value={100}>普通</Select.Option>
<Select.Option value={800}>粗体</Select.Option>
</Select>
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => Number((value ?? '').replace('px', ''))}
value={fontSize ?? 30}
onChange={(value) => { changeContainerPropsState('fontSize', value); }}
/>
</div>
</Descriptions.Item>
</Descriptions>
);
}
Example #10
Source File: index.tsx From scorpio-h5-design with MIT License | 6 votes |
export default function BaseConfig() {
return (
<div className="design-config-base">
<Collapse defaultActiveKey={[1, 2, 3, 4, 5]}>
<Panel header="布局" key={1}>
<Descriptions column={1}>
<Descriptions.Item label="边距">
<MarginPadding />
</Descriptions.Item>
</Descriptions>
</Panel>
<Panel header="文字" key={2}>
<Font />
</Panel>
<Panel header="背景" key={3}>
<Background />
</Panel>
<Panel header="边框" key={4}>
<Border />
</Panel>
<Panel header="阴影" key={5}>
<Shadow />
</Panel>
</Collapse>
</div>
);
}
Example #11
Source File: HotkeyInfo.tsx From jmix-frontend with Apache License 2.0 | 6 votes |
HotkeyInfo = observer(({hotkeyConfigs}: HotkeyInfoProps) => {
const intl = useIntl();
const hotkeysConfigByCategory = groupBy(hotkeyConfigs, 'categoryName');
return (
<div>
{Object.entries(hotkeysConfigByCategory)
.map(([category, categoryHotkeysConfig]) => (
<Descriptions
key={category}
title={intl.formatMessage({id: category})}
column={1}
>
{categoryHotkeysConfig
.map(hotkeyConfig =>
<Descriptions.Item
key={hotkeyConfig.description}
label={hotkeyConfig.hotkey}
>
{intl.formatMessage({id: hotkeyConfig.description})}
</Descriptions.Item>
)
}
</Descriptions>
))
}
</div>
)
})
Example #12
Source File: CartFinalPriceTable.tsx From Shopping-Cart with MIT License | 5 votes |
CartFinalPriceTable: FC<PropTypes> = props => {
const { dataSource, recommend } = props;
const [discountPrice, setDiscountPrice] = useState<number>(0);
const [defaultChecked, setDefaultChecked] = useState('unApplied');
const couponData = useSelector(couponTypeSelector);
const isNotRecommend: boolean = recommend.recommend === 'unApplied';
// 자동 추천 기능
useEffect(() => {
setDefaultChecked(recommend.recommend);
if (recommend.recommend === 'rate') {
setDiscountPrice(dataSource.rateDiscountPrice);
}
if (recommend.recommend === 'amount') {
setDiscountPrice(dataSource.amountDiscountPrice);
}
if (recommend.recommend === 'unApplied') {
setDiscountPrice(0);
}
}, [dataSource, recommend]);
const handleChange = useCallback(
(event: RadioChangeEvent) => {
setDefaultChecked(event.target.value);
if (event.target.value === 'rate') {
setDiscountPrice(dataSource.rateDiscountPrice);
}
if (event.target.value === 'amount') {
setDiscountPrice(dataSource.amountDiscountPrice);
}
if (event.target.value === 'unApplied') {
setDiscountPrice(0);
}
},
[setDiscountPrice, dataSource],
);
return (
<>
{couponData ? (
<Radio.Group
value={defaultChecked}
buttonStyle="solid"
style={{ margin: '25px 50px 0 60px' }}
onChange={handleChange}
>
<Radio value={'unApplied'} disabled={isNotRecommend}>
쿠폰 미적용
</Radio>
<Radio value={couponData.rate.type} disabled={isNotRecommend}>
{couponData.rate.title}
</Radio>
<Radio value={couponData.amount.type} disabled={isNotRecommend}>
{couponData.amount.title}
</Radio>
</Radio.Group>
) : (
''
)}
<Descriptions bordered style={{ margin: '10px 50px 0 50px' }}>
<Descriptions.Item label="총 상품 금액" span={2}>
<PriceLabel value={dataSource.totalPrice} />
</Descriptions.Item>
<Descriptions.Item label="상품 할인 금액">
<PriceLabel value={discountPrice} />
</Descriptions.Item>
<Descriptions.Item label="최종 가격" span={3}>
<PriceLabel
value={dataSource.totalPrice - discountPrice}
large={true}
/>
</Descriptions.Item>
</Descriptions>
</>
);
}
Example #13
Source File: index.tsx From scorpio-h5-design with MIT License | 5 votes |
export default function Background() {
const { selectComponent, changeContainerPropsState } = useModel('bridge');
const { backgroundImage, backgroundColor, backgroundSize, backgroundRepeat } = selectComponent?.containerProps ?? {};
const [backgroundFillType, setBackgroundFillType] = useState(FILL_TYPE.color);
return (
<Descriptions column={1}>
<Descriptions.Item label="填充">
<div className="background">
<Radio.Group
size="small"
options={[
{ label: '颜色填充', value: FILL_TYPE.color },
{ label: '背景图片', value: FILL_TYPE.image },
]}
onChange={(e) => { setBackgroundFillType(e.target.value); }}
value={backgroundFillType}
optionType="button"
buttonStyle="solid"
/>
</div>
</Descriptions.Item>
{backgroundFillType === FILL_TYPE.color && (
<Descriptions.Item label="填充颜色">
<ColorPicker
className="background-color"
onChange={(value: string) => { changeContainerPropsState('backgroundColor', value); }}
value={backgroundColor}
/>
</Descriptions.Item>
)}
{backgroundFillType === FILL_TYPE.image && (
<>
<Descriptions.Item label="图片">
<ImageUpload
value={backgroundImage}
onChange={(value) => { changeContainerPropsState('backgroundImage', value); }}
/>
</Descriptions.Item>
<Descriptions.Item label="尺寸">
<Radio.Group
style={{ marginTop: 4 }}
size="small"
options={[
{ label: '默认', value: 'initial' },
{ label: '充满', value: '100% 100%' },
{ label: '等比填充', value: 'contain' },
{ label: '等比覆盖', value: 'cover' },
]}
onChange={(e) => { changeContainerPropsState('backgroundSize', e.target.value); }}
value={backgroundSize ?? 'initial'}
optionType="button"
buttonStyle="solid"
/>
</Descriptions.Item>
<Descriptions.Item label="重复">
<Radio.Group
style={{ marginTop: 4 }}
size="small"
options={[
{ label: '默认', value: 'initial' },
{ label: '水平重复', value: 'repeat-x' },
{ label: '垂直重复', value: 'repeat-y' },
{ label: '不重复', value: 'no-repeat' },
]}
onChange={(e) => { changeContainerPropsState('backgroundRepeat', e.target.value); }}
value={backgroundRepeat ?? 'initial'}
optionType="button"
buttonStyle="solid"
/>
</Descriptions.Item>
</>
)}
</Descriptions>
);
}
Example #14
Source File: detail.tsx From dashboard with Apache License 2.0 | 5 votes |
CustomerMassMsgDetail: React.FC = () => {
const [currentItem, setCurrentItem] = useState<CustomerMassMsgItem>();
const id = new URLSearchParams(window.location.search).get('id') || '';
useEffect(() => {
Get(id).then((res) => {
if (res.code === 0) {
setCurrentItem(res?.data);
} else {
message.error(res.message);
}
});
}, []);
return (
<PageContainer
onBack={() => history.goBack()}
backIcon={<LeftOutlined />}
header={{
title: '群发详情',
}}
>
<ProCard className={styles.detailContainer}>
<Row gutter={2}>
<Col lg={18} md={14} sm={12}>
<Descriptions title='群发详情' column={1}>
<Descriptions.Item label='创建者'>{currentItem?.created_at}</Descriptions.Item>
<Descriptions.Item label='群发内容'>
<div>
<p>{currentItem?.msg?.text}</p>
{currentItem?.msg?.attachments && currentItem?.msg?.attachments?.length > 0 && (
<>
<p style={{
color: 'rgb(255,133,0)',
fontSize: 13,
}}> [{currentItem?.msg?.attachments?.length || 0}个附件] </p>
</>
)}
</div>
</Descriptions.Item>
<Descriptions.Item
label='群发类型'>{CustomerMassMsgTypeLabels[currentItem?.send_type || 1]}</Descriptions.Item>
<Descriptions.Item
label='发送状态'>{CustomerMassMsgTypeLabels[currentItem?.mission_status || 1]}</Descriptions.Item>
<Descriptions.Item
label='发送时间'>{moment(currentItem?.created_at).format('YYYY-MM-DD HH:mm')}</Descriptions.Item>
</Descriptions>
</Col>
<Col lg={4} md={8} sm={10} className={styles.previewContainer}>
<Typography.Text className={styles.title}>客户收到的消息</Typography.Text>
<div style={{ position: 'absolute', top: 30 }}>
<AutoReplyPreview autoReply={currentItem?.msg} />
</div>
</Col>
</Row>
</ProCard>
<ProCard style={{ marginTop: 12 }} gutter={2}>
</ProCard>
</PageContainer>
);
}
Example #15
Source File: index.tsx From scorpio-h5-design with MIT License | 5 votes |
export default function Border() {
const { selectComponent, changeContainerPropsState } = useModel('bridge');
const { borderColor, borderWidth, borderStyle, borderRadius } = selectComponent?.containerProps ?? {};
return (
<Descriptions column={1}>
<Descriptions.Item label="圆角">
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => Number((value ?? '').replace('px', ''))}
value={borderRadius ?? 0}
onChange={(value) => { changeContainerPropsState('borderRadius', value); }}
/>
</Descriptions.Item>
<Descriptions.Item label="样式">
<Radio.Group
size="small"
options={[
{ label: '无边框', value: 'none' },
{ label: '实线', value: 'solid' },
{ label: '虚线', value: 'dashed' },
{ label: '点线', value: 'dotted' },
]}
onChange={(e) => { changeContainerPropsState('borderStyle', e.target.value); }}
value={borderStyle ?? 'none'}
optionType="button"
buttonStyle="solid"
/>
</Descriptions.Item>
<Descriptions.Item label="宽度">
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => (value ?? '').replace('px', '')}
value={borderWidth ?? 0}
onChange={(value) => { changeContainerPropsState('borderWidth', value); }}
/>
</Descriptions.Item>
<Descriptions.Item label="颜色">
<ColorPicker
onChange={(value: string) => { changeContainerPropsState('borderColor', value); }}
value={borderColor}
/>
</Descriptions.Item>
</Descriptions>
);
}
Example #16
Source File: index.tsx From scorpio-h5-design with MIT License | 5 votes |
export default function Shadow() {
const { selectComponent, changeContainerPropsState } = useModel('bridge');
const { containerProps } = selectComponent || {};
const { boxShadow } = containerProps ?? {};
let computedBoxShadow = boxShadow as string;
if (!boxShadow) {
computedBoxShadow = 'rgba(255,255,255,0) 0px 0px 0px 0px';
}
const arrayBoxShadow = computedBoxShadow.split(' ') as string[];
const boxShadowType = /inset/.test(boxShadow as string) ? BOX_SHADOW_TYPE.inset : BOX_SHADOW_TYPE.outside;
const [color, boxShadowX, boxShadowY, boxShadowRadius] = arrayBoxShadow;
const onBoxShadowTypeChange = function(type: BOX_SHADOW_TYPE) {
let changedBoxShadow;
if (type === BOX_SHADOW_TYPE.outside) {
changedBoxShadow = arrayBoxShadow.slice(0, 4).join(' ');
}
if (type === BOX_SHADOW_TYPE.inset) {
changedBoxShadow = `${arrayBoxShadow.slice(0, 4).join(' ')} inset`;
}
changeContainerPropsState('boxShadow', changedBoxShadow);
};
const changeShadowState = function(index: number, value: string | number | undefined) {
// @ts-expect-error
arrayBoxShadow[index] = index === 0 ? value : `${value ?? 0}px`;
changeContainerPropsState('boxShadow', arrayBoxShadow.join(' '));
};
return (
<Descriptions column={1}>
<Descriptions.Item label="类型">
<Radio.Group
size="small"
options={[
{ label: '外阴影', value: BOX_SHADOW_TYPE.outside },
{ label: '内阴影', value: BOX_SHADOW_TYPE.inset },
]}
onChange={(e) => { onBoxShadowTypeChange(e.target.value); }}
value={boxShadowType}
optionType="button"
buttonStyle="solid"
/>
</Descriptions.Item>
<Descriptions.Item label="颜色">
<ColorPicker
className="background-color"
onChange={(value: string) => { changeShadowState(0, value); }}
value={color}
/>
</Descriptions.Item>
<Descriptions.Item label="X轴">
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => (value ?? '').replace('px', '')}
value={boxShadowX.replace('px', '')}
onChange={(value) => { changeShadowState(1, value); }}
/>
</Descriptions.Item>
<Descriptions.Item label="Y轴">
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => (value ?? '').replace('px', '')}
value={boxShadowY.replace('px', '')}
onChange={(value) => { changeShadowState(2, value); }}
/>
</Descriptions.Item>
<Descriptions.Item label="半径">
<InputNumber
formatter={(value) => `${value}px`}
parser={(value) => (value ?? '').replace('px', '')}
value={boxShadowRadius.replace('px', '')}
onChange={(value) => { changeShadowState(3, value); }}
/>
</Descriptions.Item>
</Descriptions>
);
}
Example #17
Source File: submission.values.tsx From ui with GNU Affero General Public License v3.0 | 5 votes |
SubmissionValues: React.FC<Props> = (props) => {
const { t } = useTranslation()
const columns: ColumnsType<SubmissionFieldFragment> = [
{
title: t('submission:field'),
render(_, row) {
if (row.field) {
return `${row.field.title}${row.field.required ? '*' : ''}`
}
return `${row.id}`
},
},
{
title: t('submission:value'),
render(_, row) {
try {
return fieldTypes[row.type]?.displayValue(row.value)
} catch (e) {
return row.value
}
},
},
]
return (
<div>
<Descriptions title={t('submission:submission')}>
<Descriptions.Item label={t('submission:country')}>
{props.submission.geoLocation.country}
</Descriptions.Item>
<Descriptions.Item label={t('submission:city')}>
{props.submission.geoLocation.city}
</Descriptions.Item>
<Descriptions.Item label={t('submission:device.type')}>
{props.submission.device.type}
</Descriptions.Item>
<Descriptions.Item label={t('submission:device.name')}>
{props.submission.device.name}
</Descriptions.Item>
</Descriptions>
<Table columns={columns} dataSource={props.submission.fields} rowKey={'id'} />
</div>
)
}
Example #18
Source File: DkimDetails.tsx From wildduck-ui with MIT License | 5 votes |
DkimDetails: React.SFC = () => {
const { TabPane } = Tabs;
const params: { id: string } = useParams();
const { data, isLoading } = useDkimDetails(params.id);
const DescriptionBox = () => {
return (
!isLoading && (
<Descriptions size='small' bordered column={1}>
<Descriptions.Item label='id'>{data.id}</Descriptions.Item>
<Descriptions.Item label='domain'>{data.domain}</Descriptions.Item>
<Descriptions.Item label='selector'>{data.selector}</Descriptions.Item>
<Descriptions.Item label='description'>{data.description}</Descriptions.Item>
<Descriptions.Item label='fingerprint'>{data.fingerprint}</Descriptions.Item>
<Descriptions.Item label='DNS name'>{data.dnsTxt.name}</Descriptions.Item>
<Descriptions.Item label=' DNS value'>{data.dnsTxt.value}</Descriptions.Item>
<Descriptions.Item label=' created'>{data.created}</Descriptions.Item>
</Descriptions>
)
);
};
const pageBreadcrumb = (
<Breadcrumb>
<Breadcrumb.Item>
<Link to='/dkim'>DKIM</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>{!isLoading && data.domain}</Breadcrumb.Item>
</Breadcrumb>
);
return (
<Page title={pageBreadcrumb} loading={isLoading}>
<Tabs defaultActiveKey='descriptionBox'>
<TabPane tab='Details' key='descriptionBox'>
<DescriptionBox />
</TabPane>
</Tabs>
</Page>
);
}
Example #19
Source File: HTTPFlowRiskViewer.tsx From yakit with GNU Affero General Public License v3.0 | 5 votes |
HTTPFlowRiskViewer: React.FC<HTTPFlowRiskViewerProp> = (props) => {
const {risk} = props;
const {risk_name, is_https, url, highlight, request, response, fragment, level} = risk;
const [showFragment, setShowFragment] = useState(false);
return <>
<Card
style={{width: "100%"}}
size={"small"} title={<>
<Tag color={LogLevelToCode(level) as any}>{level.toUpperCase()}</Tag>
<span>{risk_name}</span>
<Divider type={"vertical"}/>
{
highlight !== "" && (fragment || []).length > 0 ?
<span style={{color: "#999"}}>详情:<Switch size={"small"} checked={showFragment}
onChange={setShowFragment}/></span> : undefined
}
</>}
bodyStyle={{overflow: "hidden", width: "100%"}}
extra={[
<Button type={"link"} onClick={() => {
showModal({
title: "JSON Object",
width: "50%",
content: <div style={{overflow: "auto"}}>
<ReactJson src={props.risk}/>
</div>
})
}}>JSON</Button>
]}>
<Space direction={"vertical"} style={{width: "100%"}}>
<Descriptions bordered={false} size={"small"} column={2}>
<Descriptions.Item label={<Tag>URL</Tag>} span={2}>
<CopyableField text={url} width={"100%"}/>
</Descriptions.Item>
</Descriptions>
{showFragment && fragment.map(i => <Card
bordered={false} hoverable={true}
bodyStyle={{padding: 8}}
>
<Space direction={"vertical"} style={{width: "100%"}}>
<CopyableField text={highlight}/>
<CodeViewer
mode={"http"}
value={i} highlightKeywords={highlight.split(",")}
width={"100%"} height={300}
/>
</Space>
</Card>)}
</Space>
</Card>
</>
}
Example #20
Source File: Header.tsx From slim with Apache License 2.0 | 5 votes |
handleInfoButtonClick = (): void => {
const browser = detect()
const environment: {
browser: {
name?: string
version?: string
}
os: {
name?: string
}
} = {
browser: {},
os: {}
}
if (browser != null) {
environment.browser = {
name: browser.name != null ? browser.name : undefined,
version: browser.version != null ? browser.version : undefined
}
environment.os = {
name: browser.os != null ? browser.os : undefined
}
}
Modal.info({
title: 'About',
width: 600,
content: (
<>
<Descriptions title='Application' column={1}>
<Descriptions.Item label='Name'>
{this.props.app.name}
</Descriptions.Item>
<Descriptions.Item label='Version'>
{this.props.app.version}
</Descriptions.Item>
<Descriptions.Item label='Homepage'>
{this.props.app.homepage}
</Descriptions.Item>
</Descriptions>
<Descriptions title='Browser' column={1}>
<Descriptions.Item label='Name'>
{environment.browser.name}
</Descriptions.Item>
<Descriptions.Item label='Version'>
{environment.browser.version}
</Descriptions.Item>
</Descriptions>
<Descriptions title='Operating System' column={1}>
<Descriptions.Item label='Name'>
{environment.os.name}
</Descriptions.Item>
</Descriptions>
</>
),
onOk (): void {}
})
}
Example #21
Source File: Description.tsx From slim with Apache License 2.0 | 5 votes |
render (): React.ReactNode {
let layout: 'horizontal' | 'vertical' = 'horizontal'
let labelLineHeight = '14px'
const contentLineHeight = '14px'
if (this.props.hasLongValues !== undefined && this.props.hasLongValues) {
layout = 'vertical'
labelLineHeight = '20px'
}
const items = this.props.attributes.map((item: Attribute, index: number) => {
const uid = generateUUID()
return (
<Descriptions.Item
key={uid}
label={item.name}
labelStyle={{
lineHeight: labelLineHeight
}}
contentStyle={{
fontWeight: 600,
whiteSpace: 'pre-line',
lineHeight: contentLineHeight
}}
span={1}
>
{item.value}
</Descriptions.Item>
)
})
let icon = null
if (this.props.icon !== undefined) {
icon = <this.props.icon />
}
return (
<Card
title={this.props.header}
extra={icon}
size='small'
hoverable={this.props.selectable}
bordered={this.props.header !== undefined}
actions={this.props.methods}
>
<Descriptions
column={1}
size='small'
layout={layout}
bordered={false}
>
{items}
</Descriptions>
{this.props.children}
</Card>
)
}
Example #22
Source File: YakScriptManager.tsx From yakit with GNU Affero General Public License v3.0 | 5 votes |
YakScriptOperator: React.FC<YakScriptOperatorProp> = (props) => {
const {script, target} = props;
let defaultScript:YakScript = cloneDeep(script)
defaultScript.Params = defaultScript.Params.map(item =>{
if(item.Field === "target"){
item.DefaultValue = target || ""
return item
}
return item
})
return <Card title={<Space>
<Text>{script.ScriptName}</Text>
<Tag color={"geekblue"}>{script.Type}</Tag>
</Space>}>
<Descriptions bordered={true} column={2} labelStyle={{
width: 100,
}}>
<Descriptions.Item span={2} label={<Space>
<Tag><Text>{"模块描述"}</Text></Tag>
</Space>}>
{script.Help}
</Descriptions.Item>
{script.Level && <Descriptions.Item label={<Space>
<Tag><Text>{"模块级别"}</Text></Tag>
</Space>}>
{script.Level}
</Descriptions.Item>}
{script.Author && <Descriptions.Item label={<Space>
<Tag><Text>{"模块作者"}</Text></Tag>
</Space>}>
{script.Author}
</Descriptions.Item>}
{script.Tags && <Descriptions.Item label={<Space>
<Tag><Text>{"标签/关键字"}</Text></Tag>
</Space>}>
{script.Tags}
</Descriptions.Item>}
</Descriptions>
<Divider/>
<YakScriptParamsSetter
submitVerbose={"执行该脚本"}
{...defaultScript}
onParamsConfirm={r => {
startExecuteYakScript(script, r)
}}
/>
</Card>
}
Example #23
Source File: BrickDescriptions.spec.tsx From next-basics with GNU General Public License v3.0 | 5 votes |
describe("BrickDescriptions", () => {
it("should work", () => {
const itemList = [
{
id: "0",
text: "Lynette",
label: "UserName",
},
{
id: "1",
text: "18",
label: "Age",
},
];
const wrapper = shallow(<BrickDescriptions itemList={itemList} />);
expect(wrapper.find(Descriptions.Item).length).toBe(2);
});
it("should work when set hideGroups", () => {
const itemList = [
{
id: "0",
text: "Lynette",
label: "UserName",
},
{
id: "1",
text: "18",
label: "Age",
},
{
id: "3",
text: "2022",
label: "year",
group: "a",
},
{
id: "4",
text: "123456",
label: "phone",
group: "a",
},
{
id: "5",
text: "[email protected]",
label: "email",
group: "b",
},
{
id: "6",
text: "street",
label: "address",
group: "b",
},
];
const wrapper = shallow(<BrickDescriptions itemList={itemList} />);
expect(wrapper.find(Descriptions.Item).length).toBe(6);
wrapper.setProps({
hideGroups: "b",
});
wrapper.update();
expect(wrapper.find(Descriptions.Item).length).toBe(4);
wrapper.setProps({
hideGroups: ["a", "b"],
});
wrapper.update();
expect(wrapper.find(Descriptions.Item).length).toBe(2);
});
});
Example #24
Source File: MessageDetails.tsx From wildduck-ui with MIT License | 4 votes |
MessageDetails: React.FC = () => {
const { id }: any = useParams();
const { mailboxId, mailboxName } = useValues(mailboxesLogic);
const { messageId, attachmentId } = useValues(messagesLogic);
const attachment = useDownloadAttachment({
userId: id,
attachment: attachmentId,
mailboxId: mailboxId,
messageId: messageId,
});
const { data, isLoading, isError } = useMessageDetails({ userId: id, mailboxId: mailboxId, messageId: messageId });
const { setMessageDetailsToggle, setAttachmentId } = useActions(messagesLogic);
const { setUpdateMailboxToggle, setShowMailboxMessagesTable } = useActions(mailboxesLogic);
const pageBreadcrumb = (
<Breadcrumb>
<Breadcrumb.Item>
<a
onClick={() => {
setUpdateMailboxToggle(false);
setShowMailboxMessagesTable(false);
}}
>
Mailboxes
</a>
</Breadcrumb.Item>
<Breadcrumb.Item>
<a
onClick={(event) => {
event.stopPropagation();
setMessageDetailsToggle(false);
}}
>
{mailboxName}
</a>
</Breadcrumb.Item>
<Breadcrumb.Item>Message</Breadcrumb.Item>
</Breadcrumb>
);
const MessageTitle = (
<div>
<p>From : {`${_.get(data, 'from.name', '')}<${_.get(data, 'from.address', '')}>`}</p>
<p>To : {`${_.get(data, 'to.0.name', '')}<${_.get(data, 'to.0.address', '')}>`}</p>
<p>Subject : {_.get(data, 'subject', '')}</p>
</div>
);
return (
<Page title={pageBreadcrumb} loading={isLoading} error={isError}>
{_.isUndefined(data) ? null : (
<Card title={MessageTitle} extra={<>{moment(data.date).format(DATE_TIME_FORMAT_AP)}</>}>
<BraftEditor language='en' controls={[]} value={BraftEditor.createEditorState(data.html[0])} />
{_.isEmpty(data.attachments) ? null : (
<Descriptions size='small' bordered column={1}>
<Descriptions.Item label='Attachments'>
{_.map(data.attachments, (attachment, index) => {
return (
<Row key={index}>
<Col>
<p>
Filename: {_.get(attachment, 'filename', '')}
<br />
Content Type: {_.get(attachment, 'contentType', '')}
<br />
Size: {_.get(attachment, 'sizeKb', '')} KB
</p>
</Col>
<Col offset={1}>
<Tooltip title={'Download file'}>
<Button
className='ant-btn-icon'
shape='circle'
onClick={() => {
setAttachmentId(attachment);
}}
>
<DownloadOutlined className={'blue-color'} />
</Button>
</Tooltip>
</Col>
</Row>
);
})}
</Descriptions.Item>
</Descriptions>
)}
</Card>
)}
</Page>
);
}
Example #25
Source File: HTTPFlowDetail.tsx From yakit with GNU Affero General Public License v3.0 | 4 votes |
HTTPFlowDetail: React.FC<HTTPFlowDetailProp> = (props) => {
const [flow, setFlow] = useState<HTTPFlow>();
const [loading, setLoading] = useState(false);
const actionFuzzer = [
{
id: 'send-fuzzer-info',
label: '发送到Fuzzer',
contextMenuGroupId: 'send-fuzzer-info',
run: () => {
ipcRenderer.invoke("send-to-tab", {
type: "fuzzer",
data: {
isHttps: flow?.IsHTTPS,
request: Buffer.from(flow?.Request || []).toString("utf8")
}
})
if (props.onClose) props.onClose()
}
},
{
id: 'send-to-plugin',
label: '发送到数据包扫描',
contextMenuGroupId: 'send-fuzzer-info',
run: () => ipcRenderer.invoke("send-to-packet-hack", {
request: flow?.Request,
ishttps: flow?.IsHTTPS,
response: flow?.Response
})
}
]
useEffect(() => {
if (!props.hash) {
return
}
//
// ipcRenderer.on(props.hash, (e: any, data: HTTPFlow) => {
// setFlow(data)
// setTimeout(() => setLoading(false), 300)
// })
// ipcRenderer.on(`ERROR:${props.hash}`, (e: any, details: any) => {
// failed(`查询该请求失败[${props.hash}]: ` + details)
// })
setLoading(true)
ipcRenderer.invoke("GetHTTPFlowByHash", {Hash: props.hash}).then((data: HTTPFlow) => {
setFlow(data)
}).catch(e => {
failed(`GetHTTPFlow ByHash[${props.hash}] failed`)
}).finally(() => setTimeout(() => setLoading(false), 300))
// ipcRenderer.invoke("get-http-flow", props.hash)
return () => {
// ipcRenderer.removeAllListeners(props.hash)
// ipcRenderer.removeAllListeners(`ERROR:${props.hash}`)
}
}, [props.hash])
return <Spin spinning={loading} style={{width: "100%", marginBottom: 24}}>
{flow ? <>
{props.noHeader ? undefined : <PageHeader
title={`请求详情`} subTitle={props.hash}
extra={
props.fetchRequest ?
<Space>
<Tooltip title={"上一个请求"}>
<Button type="link" disabled={!!props.isFront}
icon={<LeftOutlined/>} onClick={() => {
props?.fetchRequest!(1)
}}></Button>
</Tooltip>
<Tooltip title={"下一个请求"}>
<Button type="link" disabled={!!props.isBehind}
icon={<RightOutlined/>} onClick={() => {
props?.fetchRequest!(2)
}}></Button>
</Tooltip>
</Space>
:
<></>
}/>
}
<Space direction={"vertical"} style={{width: "100%"}}>
<Descriptions column={4} bordered={true} size={"small"}>
<Descriptions.Item key={"method"} span={1} label={"HTTP 方法"}><Tag color={"geekblue"}><Text
style={{maxWidth: 500}}>{flow.Method}</Text></Tag></Descriptions.Item>
<Descriptions.Item key={"url"} span={3} label={"请求 URL"}>
<Text style={{maxWidth: 500}} copyable={true}>{flow.Url}</Text>
</Descriptions.Item>
<Descriptions.Item key={"https"} span={1} label={"HTTPS"}><Tag color={"geekblue"}>
<div
style={{maxWidth: 500}}>{flow.IsHTTPS ? "True" : "False"}</div>
</Tag></Descriptions.Item>
<Descriptions.Item key={"status"} span={1} label={"StatusCode"}><Tag
color={"geekblue"}>{flow.StatusCode}</Tag></Descriptions.Item>
<Descriptions.Item key={"size"} span={1} label={"Body大小"}><Tag color={"geekblue"}>
<div style={{maxWidth: 500}}>{flow.BodySizeVerbose}</div>
</Tag></Descriptions.Item>
<Descriptions.Item key={"type"} span={1} label={"Content-Type"}><Tag color={"geekblue"}>
<div style={{maxWidth: 500}}>{flow.ContentType}</div>
</Tag></Descriptions.Item>
</Descriptions>
<div style={{width: "100%", overflow: "auto"}}>
{flow.GetParams.length > 0 || flow.PostParams.length > 0 || flow.CookieParams.length > 0 ? <Tabs>
{flow.GetParams.length > 0 && <Tabs.TabPane key={"get"} tab={"GET 参数"}>
<FuzzableParamList data={flow.GetParams} sendToWebFuzzer={() => {
if (props.onClose) props.onClose()
}}/>
</Tabs.TabPane>}
{flow.PostParams.length > 0 && <Tabs.TabPane key={"post"} tab={"POST 参数"}>
<FuzzableParamList data={flow.PostParams} sendToWebFuzzer={() => {
if (props.onClose) props.onClose()
}}/>
</Tabs.TabPane>}
{flow.CookieParams.length > 0 && <Tabs.TabPane key={"cookie"} tab={"Cookie 参数"}>
<FuzzableParamList data={flow.CookieParams} sendToWebFuzzer={() => {
if (props.onClose) props.onClose()
}}/>
</Tabs.TabPane>}
</Tabs> : ""}
</div>
<Row gutter={8}>
<Col span={12}>
<Card title={"原始 HTTP 请求"} size={"small"} bodyStyle={{padding: 0}}>
<div style={{height: 350}}>
<YakEditor readOnly={true} type={"http"}//theme={"fuzz-http-theme"}
value={new Buffer(flow.Request).toString("utf-8")}
actions={[...actionFuzzer]}/>
</div>
</Card>
</Col>
<Col span={12}>
<Card title={"原始 HTTP 响应"} size={"small"} bodyStyle={{padding: 0}}>
<div style={{height: 350}}>
<YakEditor readOnly={true} type={"http"}// theme={"fuzz-http-theme"}
value={new Buffer(flow.Response).toString("utf-8")}
/>
</div>
</Card>
</Col>
</Row>
{/*<Collapse>*/}
{/* <Collapse.Panel key={"request-raw"} header={"原始 HTTP 请求数据包内容"}>*/}
{/* </Collapse.Panel>*/}
{/* <Collapse.Panel key={"response-raw"} header={"原始 HTTP 响应数据包内容"}>*/}
{/* </Collapse.Panel>*/}
{/*</Collapse>*/}
<Row gutter={8}>
<Col span={12}>
<Collapse defaultActiveKey={"request"}>
<Collapse.Panel key={"request"} header={"Request Headers"}>
<Descriptions bordered={true} column={1} size={"small"}>
{(flow?.RequestHeader || []).sort((i, e) => {
return i.Header.localeCompare(e.Header)
}).map(i => {
return <Descriptions.Item key={i.Header} label={<Text style={{width: 240}}>
<Tag>{i.Header}</Tag>
</Text>}>
<Text
copyable={true}
style={{maxWidth: 500}}
ellipsis={{tooltip: true}}>{i.Value}</Text>
</Descriptions.Item>
})}
</Descriptions>
</Collapse.Panel>
</Collapse>
</Col>
<Col span={12}>
<Collapse defaultActiveKey={"response"}>
<Collapse.Panel key={"response"} header={"Response Headers"}>
<Descriptions bordered={true} column={1} size={"small"}>
{(flow?.ResponseHeader || []).sort((i, e) => {
return i.Header.localeCompare(e.Header)
}).map(i => {
return <Descriptions.Item key={i.Header} label={<Text style={{width: 240}}>
<Tag>{i.Header}</Tag>
</Text>}>
<Text
copyable={true}
style={{maxWidth: 500}}
ellipsis={{tooltip: true}}>{i.Value}</Text>
</Descriptions.Item>
})}
</Descriptions>
</Collapse.Panel>
</Collapse>
</Col>
</Row>
</Space>
</> : ""}
</Spin>
}
Example #26
Source File: detail.tsx From dashboard with Apache License 2.0 | 4 votes |
CustomerDetail: React.FC = () => {
const queryFormRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [customerDetail, setCustomerDetail] = useState<CustomerItem>()
const [staffMap, setStaffMap] = useState<Dictionary<StaffOption>>({});
const [allCustomerTagGroups, setAllCustomerTagGroups] = useState<CustomerTagGroupItem[]>([]);
const [defaultCustomerTags, setDefaultCustomerTags] = useState<CustomerTag[]>([]);
const [defaultInternalTagsIds, setDefaultInternalTagsIds] = useState<string []>([])
const [personalTagModalVisible, setPersonalTagModalVisible] = useState(false)
const [customerTagModalVisible, setCustomerTagModalVisible] = useState(false)
const [internalTagList, setInternalTagList] = useState<InternalTags.Item[]>([])
const [internalTagListMap, setInternalTagListMap] = useState<Dictionary<InternalTags.Item>>({});
const [initialEvents, setInitialEvents] = useState<CustomerEvents.Item[]>([])
const [currentTab, setCurrentTab] = useState('survey')
const [basicInfoDisplay, setBasicInfoDisplay] = useState({} as any)// 展示哪些基本信息
const [basicInfoValues, setBasicInfoValues] = useState({} as any) // 基本信息取值
const [remarkValues, setRemarkValues] = useState<Remark[]>([])
const [reloadCusDataTimesTamp, setReloadCusDataTimesTamp] = useState(Date.now)
const [formRef] = Form.useForm()
const params = new URLSearchParams(window.location.search);
const currentStaff = localStorage.getItem('extStaffAdminID') as string
const extCustomerID = params.get('ext_customer_id') || "";
if (!extCustomerID) {
message.error('传入参数请带上ID');
}
const extStaff = () => {
const staffs: StaffItem[] = [];
customerDetail?.staff_relations?.forEach((staff_relation) => {
// @ts-ignore
const staff = staffMap[staff_relation.ext_staff_id];
if (staff) {
staffs.push(staff);
}
});
return staffs;
}
const getCustomerDetail = () => {
const hide = message.loading("加载数据中");
GetCustomerDetail(extCustomerID).then(res => {
hide();
if (res?.code !== 0) {
message.error("获取客户详情失败");
return;
}
setCustomerDetail(res?.data);
const cusTags: any[] = [];
const interTagsIds: any[] = []
res?.data?.staff_relations?.forEach((relation: any) => {
if (relation.ext_staff_id === currentStaff) {
relation.customer_staff_tags?.forEach((tag: any) => {
cusTags.push({...tag, name: tag.tag_name, ext_id: tag.ext_tag_id});
});
relation.internal_tags?.forEach((tagId: string) => {
interTagsIds.push(tagId);
})
}
});
setDefaultCustomerTags(cusTags)
setDefaultInternalTagsIds(interTagsIds)
}).catch(() => {
hide();
})
}
const getInternalTags = () => {
QueryInternalTags({page_size: 5000, ext_staff_id: currentStaff}).then(res => {
if (res?.code === 0) {
setInternalTagList(res?.data?.items)
setInternalTagListMap(_.keyBy(res?.data?.items, 'id'))
} else {
message.error(res?.message)
}
})
}
const getCustomerRemark = () => { // 自定义信息id-key
QueryCustomerRemark().then(res => {
if (res?.code === 0) {
console.log('QueryCustomerRemark', res.data)
} else {
message.error(res?.message)
}
})
}
const getBasicInfoDisplay = () => {
GetCustomerBasicInfoDisplay().then(res => {
if (res?.code === 0) {
const displayData = res?.data
delete displayData.id
delete displayData.ext_corp_id
delete displayData.created_at
delete displayData.updated_at
delete displayData.deleted_at
setBasicInfoDisplay(displayData || {})
} else {
message.error(res?.message)
}
})
}
const getBasicInfoAndRemarkValues = () => {
GetBasicInfoAndRemarkValues({
ext_customer_id: extCustomerID,
ext_staff_id: currentStaff,
}).then(res => {
if (res?.code === 0) {
const resData = res?.data
delete resData.id
delete resData.ext_corp_id
delete resData.ext_creator_id
delete resData.ext_customer_id
delete resData.ext_staff_id
delete resData.created_at
delete resData.updated_at
delete resData.deleted_at
delete resData.remark_values
setBasicInfoValues(resData)
setRemarkValues(res?.data?.remark_values || [])
}
})
}
const updateBasicInfoAndRemark = (basicInfoParams: any) => {
UpdateBasicInfoAndRemark({
ext_staff_id: currentStaff,
ext_customer_id: extCustomerID,
...basicInfoParams
}).then(res => {
if (res?.code === 0) {
message.success('客户信息更新成功')
setReloadCusDataTimesTamp(Date.now)
} else {
message.error('客户信息更新失败')
}
})
}
useEffect(() => {
getInternalTags()
getCustomerDetail()
getCustomerRemark()
getBasicInfoDisplay()
getBasicInfoAndRemarkValues()
}, [reloadCusDataTimesTamp])
useEffect(() => {
QueryCustomerTagGroups({page_size: 5000}).then((res) => {
if (res.code === 0) {
setAllCustomerTagGroups(res?.data?.items);
} else {
message.error(res.message);
}
});
}, []);
useEffect(() => {
QuerySimpleStaffs({page_size: 5000}).then((res) => {
if (res.code === 0) {
const staffs = res?.data?.items?.map((item: SimpleStaffInterface) => {
return {
label: item.name,
value: item.ext_id,
...item,
};
}) || [];
setStaffMap(_.keyBy<StaffOption>(staffs, 'ext_id'));
} else {
message.error(res.message);
}
});
}, []);
useEffect(() => {
QueryCustomerEvents({
ext_customer_id: extCustomerID,
ext_staff_id: currentStaff,
page_size: 5
}).then(res => {
console.log('QueryCustomerEventsQueryCustomerEvents', res)
setInitialEvents(res?.data?.items || [])
})
}, [])
useEffect(() => {
formRef.setFieldsValue(basicInfoValues)
}, [basicInfoValues])
return (
<PageContainer
fixedHeader
onBack={() => history.go(-1)}
backIcon={<LeftOutlined/>}
header={{
title: '客户详情',
}}
>
<ProCard>
<Descriptions title="客户信息" column={1}>
<Descriptions.Item>
<div className={'customer-info-field'}>
<div><img src={customerDetail?.avatar} alt={customerDetail?.name} style={{borderRadius: 5}}/></div>
<div style={{fontSize: 16, marginLeft: 10}}>
<p>{customerDetail?.name}</p>
{customerDetail?.corp_name && (
<p style={{color: '#eda150', marginTop: 10}}>@{customerDetail?.corp_name}</p>
)}
{customerDetail?.type === 1 && (
<p style={{
color: '#5ec75d',
fontSize: '13px'
}}>@微信</p>
)}
</div>
</div>
</Descriptions.Item>
<div>
<div style={{width: 70, display: 'inline-block'}}>企业标签:</div>
<div className={styles.tagContainer}>
<Space direction={'horizontal'} wrap={true}>
{
defaultCustomerTags?.length > 0 && defaultCustomerTags?.map((tag) =>
<Tag
key={tag?.id}
className={'tag-item selected-tag-item'}
>
{tag?.name}
</Tag>
)}
</Space>
</div>
<Button
key='addCusTags'
icon={<EditOutlined/>}
type={'link'}
onClick={() => {
setCustomerTagModalVisible(true);
}}
>
编辑
</Button>
</div>
<div>
<div style={{width: 70, display: 'inline-block'}}>个人标签:</div>
<div className={styles.tagContainer}>
<Space direction={'horizontal'} wrap={true}>
{
defaultInternalTagsIds?.length > 0 && defaultInternalTagsIds.map(id => internalTagListMap[id])?.map((tag) =>
<Tag
key={tag?.id}
className={'tag-item selected-tag-item'}
>
{tag?.name}
<span>
</span>
</Tag>
)}
</Space>
</div>
<Button
key='addInternalTags'
icon={<EditOutlined/>}
type={'link'}
onClick={() => {
setPersonalTagModalVisible(true);
}}
>
编辑
</Button>
</div>
</Descriptions>
</ProCard>
<ProCard
tabs={{
onChange: (activeKey: string) => setCurrentTab(activeKey),
activeKey: currentTab
}}
style={{marginTop: 25}}
>
<ProCard.TabPane key="survey" tab="客户概况">
<div className={styles.survey}>
<div className={styles.cusSurveyLeft}>
<div>
<Descriptions title={<div><ContactsFilled/> 添加客服信息</div>} layout="vertical" bordered
column={4}>
<Descriptions.Item label="所属员工">
<CollapsedStaffs limit={2} staffs={extStaff()}/>
</Descriptions.Item>
<Descriptions.Item label="客户来源">
<span>
{customerDetail?.staff_relations?.map((para) => {
return (`${addWayEnums[para.add_way || 0]}\n`);
})}
</span>
</Descriptions.Item>
<Descriptions.Item label="添加时间">
<Space>
{customerDetail?.staff_relations?.map((para) => {
return (
<div className={styles.staffTag}
dangerouslySetInnerHTML={{
__html: moment(para.createtime)
.format('YYYY-MM-DD HH:mm')
.split(' ')
.join('<br />'),
}}
/>
);
})}
</Space>
</Descriptions.Item>
<Descriptions.Item label="更新时间">
<div
dangerouslySetInnerHTML={{
__html: moment(customerDetail?.updated_at)
.format('YYYY-MM-DD HH:mm')
.split(' ')
.join('<br />'),
}}
/>
</Descriptions.Item>
</Descriptions>
</div>
<Form form={formRef} onFinish={(values) => {
console.log('ooooooooooooooovaluesvalues', values)
const basicInfoParams = {...values}
updateBasicInfoAndRemark(basicInfoParams)
}}>
<div style={{paddingTop: 20}} className={styles.baseInfoContainer}>
<Descriptions
title={<div><BookFilled/> 基本信息</div>}
bordered
column={2}
size={'small'}
>
{
Object.keys(basicInfoDisplay).map(key => {
return <Descriptions.Item label={basicInfo[key]}>
<TableInput name={key} />
</Descriptions.Item>
})
}
</Descriptions>
</div>
{
remarkValues.length > 0 && <div style={{paddingTop: 20}} className={styles.customInfoContainer}>
<Descriptions
title={<div><EditFilled/> 自定义信息</div>}
bordered
column={2}
size={'small'}
>
<Descriptions.Item label="sfdsf">
<TableInput name={'aa'}/>
</Descriptions.Item>
<Descriptions.Item label="违法的">
<TableInput name={'bb'}/>
</Descriptions.Item>
<Descriptions.Item label="sdf434">
<TableInput name={'cc'}/>
</Descriptions.Item>
<Descriptions.Item label="yjkyujy">
<TableInput name={'dd'}/>
</Descriptions.Item>
</Descriptions>
</div>
}
<div style={{display: 'flex', justifyContent: 'center', marginTop: 40}}>
<Space>
<Button onClick={() => formRef.setFieldsValue(basicInfoValues)}>重置</Button>
<Button type={"primary"} onClick={() => {
formRef.submit()
}}>提交</Button>
</Space>
</div>
</Form>
</div>
<div className={styles.cusSurveyRight}>
<div className={styles.eventsTitle}>
<span className={styles.titleText}><SoundFilled/> 客户动态</span>
<a onClick={() => setCurrentTab('events')} style={{fontSize: 12}}>查看更多<RightOutlined/></a>
</div>
<Events data={initialEvents.filter(elem => elem !== null)} simpleRender={true} staffMap={staffMap}
extCustomerID={extCustomerID}/>
</div>
</div>
</ProCard.TabPane>
<ProCard.TabPane key="events" tab="客户动态">
<Events staffMap={staffMap} extCustomerID={extCustomerID}/>
</ProCard.TabPane>
<ProCard.TabPane key="room" tab="所在群聊">
<ProTable<GroupChatItem>
search={false}
formRef={queryFormRef}
actionRef={actionRef}
className={'table'}
scroll={{x: 'max-content'}}
columns={columns}
rowKey="id"
toolBarRender={false}
bordered={false}
tableAlertRender={false}
dateFormatter="string"
request={async (originParams: any, sort, filter) => {
return ProTableRequestAdapter(
originParams,
sort,
filter,
QueryCustomerGroupsList,
);
}}
/>
</ProCard.TabPane>
<ProCard.TabPane key="chat" tab="聊天记录">
{
setStaffMap[currentStaff]?.enable_msg_arch === 1 ? <Button
key={'chatSession'}
type={"link"}
icon={<ClockCircleOutlined style={{fontSize: 16, verticalAlign: '-3px'}}/>}
onClick={() => {
window.open(`/staff-admin/corp-risk-control/chat-session?staff=${currentStaff}`)
}}
>
聊天记录查询
</Button>
:
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span>员工暂未开启消息存档</span>}/>
}
</ProCard.TabPane>
</ProCard>
<CustomerTagSelectionModal
type={'customerDetailEnterpriseTag'}
isEditable={true}
withLogicalCondition={false}
width={'630px'}
visible={customerTagModalVisible}
setVisible={setCustomerTagModalVisible}
defaultCheckedTags={defaultCustomerTags}
onFinish={(selectedTags) => {
const removeAry = _.difference(defaultCustomerTags.map(dt => dt.ext_id), selectedTags.map(st => st.ext_id))
UpdateCustomerTags({
// @ts-ignore
add_ext_tag_ids: selectedTags.map((tag) => tag.ext_id),
ext_customer_ids: [extCustomerID],
ext_staff_id: currentStaff,
// @ts-ignore
remove_ext_tag_ids: removeAry
}).then(() => {
getCustomerDetail()
})
}}
allTagGroups={allCustomerTagGroups}
/>
<InternalTagModal
width={560}
allTags={internalTagList}
allTagsMap={internalTagListMap}
setAllTags={setInternalTagList}
visible={personalTagModalVisible}
setVisible={setPersonalTagModalVisible}
defaultCheckedTagsIds={defaultInternalTagsIds}
reloadTags={getInternalTags}
onFinish={(selectedTags) => {
console.log('selectedTags', selectedTags)
const removeAry = _.difference(defaultInternalTagsIds, selectedTags.map(st => st.id))
CustomerInternalTags({
// @ts-ignore
add_ext_tag_ids: selectedTags.map((tag) => tag.id),
ext_customer_id: extCustomerID,
ext_staff_id: currentStaff,
// @ts-ignore
remove_ext_tag_ids: removeAry
}).then(() => {
getCustomerDetail()
})
}
}
/>
</PageContainer>
);
}
Example #27
Source File: RiskTable.tsx From yakit with GNU Affero General Public License v3.0 | 4 votes |
RiskDetails: React.FC<RiskDetailsProp> = React.memo((props) => {
const {info, isShowTime = true} = props
const title = TitleColor.filter((item) => item.key.includes(info.Severity || ""))[0]
return (
<Descriptions
title={
<div className='container-title-body'>
<div className='title-icon'>
<img src={title?.img || infoImg} className='icon-img'/>
</div>
<div className='title-header'>
<div className='header-name text-ellipsis' title={info?.TitleVerbose || info.Title}>
{info?.TitleVerbose || info.Title}
</div>
<div className='header-subtitle'>
<div className={`${title?.tag || "title-background-default"} subtitle-level`}>
{title ? title.name : info.Severity || "-"}
</div>
<div style={{maxWidth: 260}} className='subtitle-spacing text-ellipsis'>
Url
<span className='subtitle-font' title={info?.Url || "-"}>
{info?.Url || "-"}
</span>
</div>
{isShowTime && <div className='subtitle-spacing'>
发现时间
<span className='subtitle-font'>
{info.CreatedAt > 0 ? formatTimestamp(info.CreatedAt) : "-"}
</span>
</div>}
{isShowTime && <div>
最近更新时间
<span className='subtitle-font'>
{info.CreatedAt > 0 ? formatTimestamp(info.CreatedAt) : "-"}
</span>
</div>}
</div>
</div>
</div>
}
bordered
size='small'
>
<Descriptions.Item label='IP'>
<div>{info.IP || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='ID'>
<div>{info.Id || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='端口'>
<div>{info.Port || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='Host'>
<div>{info.Host || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='类型'>
<div>{info?.RiskTypeVerbose || info.RiskType}</div>
</Descriptions.Item>
<Descriptions.Item label='来源'>
<div>{info?.FromYakScript || "漏洞检测"}</div>
</Descriptions.Item>
<Descriptions.Item label='反连Token'>
<div>{info.ReverseToken || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='Hash'>
<div>{info.Hash || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='验证状态'>
<div style={{color: `${!info.WaitingVerified ? "#11AB4E" : "#FAAF2B"}`}}>
{!info.WaitingVerified ? "已验证" : "未验证"}
</div>
</Descriptions.Item>
{!props.shrink && <>
<Descriptions.Item label='Parameter' span={3}>
<div>{info.Parameter || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='Payload' span={3}>
<div>{info.Payload || "-"}</div>
</Descriptions.Item>
<Descriptions.Item label='详情' span={3}>
<div style={{maxHeight: 180, overflow:"auto"}}>{info.Details || "-"}</div>
</Descriptions.Item>
</>}
</Descriptions>
)
})
Example #28
Source File: index.tsx From jetlinks-ui-antd with MIT License | 4 votes |
AuthorizationSetting: React.FC<Props> = (props) => {
const initState: State = {
permissionList: [],
// currentList: [],
mergeData: [],
loading: true,
fieldAccessVisible: false,
checkedPermission: {},
}
const [permissionList, setPermissionList] = useState(initState.permissionList);
// const [currentList, setCurrentList] = useState(initState.currentList);
const [mergeData, setMergeData] = useState(initState.mergeData);
const [loading, setLoading] = useState(initState.loading);
const [fieldAccessVisible, setFieldAccessVisible] = useState(initState.fieldAccessVisible);
const [checkedPermission, setCheckedPermission] = useState(initState.checkedPermission);
useEffect(() => {
setLoading(true);
getPermissionList();
}, [props.dimension]);
const getPermissionList = () => {
apis.permission.listNoPaging().then(p => {
if (p.status === 200) {
if (props.dimension && props.dimension.id) {
const params = {
terms: { dimensionTarget: props.dimension.id, }
};
apis.dimensions.queryAutz(encodeQueryParam(params)).then(e => {
if (e.status === 200) {
const temp = (p.result).map((item: PermissionItem) => {
const autz = (e.result).find((i: DimensionsSetting) => i.permission === item.id);
//增加all选项
if (autz) {
(autz.actions || []).length >= (item.actions || []).length ? autz.actions.push('all') : autz;
}
return autz ? { 'current': autz, ...item } : item;
});
setPermissionList(temp);
}
}).catch(() => {
});
} else {
setPermissionList(p.result);
}
setLoading(false);
}
}).catch(() => {
});
}
const saveFieldsAccess = (permision: PermissionItem) => {
const index = permissionList.findIndex(p => p.id === permision.id);
permissionList[index] = permision;
}
/*
* * checkItem: 选择权限
* * permissionID :权限ID
* * item :权限
* */
const checkItem = (permissionId: string, item?: string) => {
const permission = permissionList.find(e => e.id === permissionId);
if (!permission) return;
const index = permissionList.findIndex(e => e.id === permissionId);
if (permission.current) {
let currentActions = permission.current.actions || [];
//存在current才会有删除的可能
if (item) {
const y = currentActions.find((e: string) => e === item);
if (y) {
//如果存在则删除
permission.current.actions = currentActions.filter((e: string) => e !== item && e !== 'all');
} else {
currentActions.push(item);
}
if (currentActions.length >= (permission.actions || []).length) {
currentActions.push('all');
}
} else {
if (currentActions.find((e: string) => e === 'all')) {
const { current, ...temp } = permission;
permissionList[index] = temp;
} else {
let current = {
actions: ['all', ...((permission.actions || []).map((e: any) => e.action))],
}
permission.current = current
permissionList[index] = permission;
}
}
} else {
if (item) {
let current = {
actions: [item],
}
permissionList[index] = { current, ...permission };
} else {
let current = {
actions: ['all', ...((permission.actions || []).map((e: any) => e.action))],
}
permissionList[index] = { current, ...permission };
}
}
setPermissionList(permissionList);
setMergeData([]);
}
const saveAutzSetting = () => {
//组装成接口所需格式
setLoading(true);
const data: any[] = [];
permissionList.forEach(p => {
let action = ((p.current || {}).actions || []).filter(e => e !== 'all');
data.push({
'id': (p.current || {}).id,
'permission': p.id,
'dimensionType': props.dimension.typeId,
'dimensionTypeName': props.dimension.typeName,
'dimensionTarget': props.dimension.id,
'dimensionTargetName': props.dimension.name,
'state': 1,
'actions': action,
'priority': 10,
'merge': true,
'dataAccesses': p.dataAccesses,
});
});
apis.dimensions.saveAutzSetting(data).then(e => {
if (e.status === 200) {
message.success('保存成功');
} else {
message.error('保存失败');
}
}).finally(() => {
setLoading(false);
setMergeData([]);
getPermissionList();
})
}
return (
<Spin spinning={loading}>
<Card
>
<Descriptions title={(props.dimension || {}).name}>
<Descriptions.Item>{(props.dimension || {}).describe}</Descriptions.Item>
</Descriptions>
<Col span={20}>
{
permissionList.map(permission => {
return (
<Card
id={permission.id}
key={permission.id}
title={permission.name}
bordered={false}
extra={
<span>
{
permission.optionalFields &&
<span>
<Button type="link" onClick={() => { setFieldAccessVisible(true); setCheckedPermission(permission) }}>字段权限</Button>
<Divider type="vertical" />
</span>
}
{/* <Button type="link" onClick={() => message.warn('开发中')}>数据权限</Button> */}
</span>
}
>
<Checkbox.Group style={{ width: '100%' }} value={(permission.current || {}).actions}>
<Col span={6} style={{ marginBottom: 10 }}>
<Checkbox
value="all"
onClick={() => checkItem(permission.id)}
indeterminate={
((permission.current || {}).actions || []).length > 0 &&
((permission.current || {}).actions || []).length < (permission.actions || []).length
}
>全选</Checkbox>
</Col>
{
(permission.actions || []).map((action: any) => {
return (
<Col span={6} style={{ marginBottom: 10 }} key={action.action}>
<Checkbox value={action.action} onClick={() => { checkItem(permission.id, action.action) }}>{action.name}</Checkbox>
</Col>
)
})
}
</Checkbox.Group>
</Card>
)
}
)
}
<Affix offsetBottom={20} style={{ float: "right" }}>
<Button
type="primary"
onClick={() => { saveAutzSetting() }}
>
保存
</Button>
</Affix>
</Col>
{/* <Col span={3} push={1} style={{ height: 600, overflow: 'auto' }}>
<Affix>
<Anchor>
{
permissionList.map(permission =>
<Anchor.Link href={'#' + permission.id} title={permission.name} key={permission.id} />
)
}
</Anchor>
</Affix>
</Col> */}
</Card>
{
fieldAccessVisible &&
<FieldAccess
close={() => setFieldAccessVisible(false)}
data={checkedPermission}
save={(item: PermissionItem) => saveFieldsAccess(item)}
/>
}
</Spin>
);
}
Example #29
Source File: index.tsx From jetlinks-ui-antd with MIT License | 4 votes |
MediaDevice: React.FC<Props> = props => {
const {location: {pathname},} = props;
const service = new Service('media/channel');
const [loading, setLoading] = useState<boolean>(false);
const [deviceId, setDeviceId] = useState<string>("");
const [result, setResult] = useState<any>({});
const [deviceInfo, setDeviceInfo] = useState<any>({});
const [channel, setChannel] = useState<boolean>(false);
const [channelInfo, setChannelInfo] = useState<any>({});
const [playing, setPlaying] = useState<boolean>(false);
const [playback, setPalyback] = useState<boolean>(false)
const [data, setData] = useState<any>({});
const [searchParam, setSearchParam] = useState(initState.searchParam);
const statusMap = new Map();
statusMap.set('online', 'success');
statusMap.set('offline', 'error');
statusMap.set('notActive', 'processing');
const ptzType = new Map();
ptzType.set(0, '未知');
ptzType.set(1, '球体');
ptzType.set(2, '半球体');
ptzType.set(3, '固定枪机');
ptzType.set(4, '遥控枪机');
const deviceDetail = (deviceId: string) => {
service.mediaDevice(deviceId).subscribe((data) => {
setDeviceInfo(data);
},
() => {
},
() => {
})
};
const handleSearch = (params?: any) => {
setSearchParam(params);
setLoading(true);
service.query(encodeQueryParam(params)).subscribe(
data => setResult(data),
() => {
},
() => setLoading(false));
};
const columns: ColumnProps<any>[] = [
{
title: '通道国标编号',
dataIndex: 'channelId',
ellipsis: true,
},
{
title: '通道名称',
dataIndex: 'name',
ellipsis: true,
},
{
title: '厂商',
dataIndex: 'manufacturer',
width: 100,
ellipsis: true,
},
{
title: '安装地址',
dataIndex: 'address',
width: '10%',
ellipsis: true,
},
{
title: '云台类型',
dataIndex: 'ptzType',
width: 100,
render: record => ptzType.get(record?.value || 0),
ellipsis: true,
},
{
title: '在线状态',
dataIndex: 'status',
width: 110,
render: record => record ? <Badge status={statusMap.get(record.value)} text={record.text}/> : '',
filters: [
{
text: '离线',
value: 'offline',
},
{
text: '在线',
value: 'online',
},
],
filterMultiple: false,
},
{
title: '经纬度',
width: 200,
ellipsis: true,
render: (record: any) => (
<span>{record.longitude ? `${record.longitude ? record.longitude : ''},${record.latitude ? record.latitude : ''}` : ''}</span>
)
},
{
title: '子通道数',
dataIndex: 'subCount',
width: 100,
},
{
title: '描述',
dataIndex: 'description',
width: '10%',
ellipsis: true
},
{
title: '操作',
align: 'center',
// fixed: 'right',
render: (record: any) => (
<Fragment>
<a
onClick={() => {
setChannel(true);
setChannelInfo(record);
}}
>
编辑
</a>
<Divider type="vertical"/>
{record.status.value === 'online' ? (
<>
<a
onClick={() => {
setPlaying(true);
setData(record)
}}
>
播放
</a>
<Divider type="vertical"/>
<a
onClick={() => {
setPalyback(true);
setData(record)
}}
>
回放
</a>
</>
) : (
<Popconfirm
placement="topRight"
title="确定删除此通道吗?"
onConfirm={() => {
setLoading(true);
service.remove(record.id).subscribe(
() => {
message.success('通道删除成功');
},
() => {
message.error('通道删除失败');
},
() => {
handleSearch(searchParam);
setLoading(false);
},
);
}}
>
<a>删除</a>
</Popconfirm>
)}
</Fragment>
)
},
];
useEffect(() => {
if (pathname.indexOf('channel') > 0) {
const list = pathname.split('/');
deviceDetail(list[list.length - 1]);
setDeviceId(list[list.length - 1]);
searchParam.terms = {deviceId: list[list.length - 1]};
handleSearch(searchParam);
}
}, [window.location.hash]);
const onTableChange = (
pagination: PaginationConfig,
filters: any,
sorter: SorterResult<DeviceInstance>,
) => {
const {terms} = searchParam;
handleSearch({
pageIndex: Number(pagination.current) - 1,
pageSize: pagination.pageSize,
terms: {...terms, ...filters},
sorts: sorter,
})
};
const content = (
<div style={{marginTop: 30}}>
<Descriptions column={4}>
<Descriptions.Item label="设备名称">
<div>
{deviceInfo.name}
</div>
</Descriptions.Item>
</Descriptions>
</div>
);
const titleInfo = (
<Row>
<div>
<span style={{paddingRight: 20}}>
通道列表:{deviceId}
</span>
<Badge status={statusMap.get(deviceInfo.state?.value)} text={deviceInfo.state?.text}/>
</div>
</Row>
);
return (
<PageHeaderWrapper title={titleInfo} content={content}>
<Card style={{height: 92, marginBottom: 16}}>
<div className={styles.tableList} style={{marginTop: -22}}>
<div>
<SearchForm
search={(params: any) => {
setSearchParam(params);
params ? params.deviceId = deviceId : params = {deviceId: deviceId};
handleSearch({pageSize: 10, terms: {...params}, sorts: {field: 'id', order: 'desc'}});
}}
formItems={[
{
label: '名称',
key: 'name$LIKE',
type: 'string',
},
]}
/>
</div>
</div>
</Card>
<Card>
<div className={styles.StandardTable}>
<Table
loading={loading}
columns={columns}
dataSource={(result || {}).data}
rowKey="id"
onChange={onTableChange}
pagination={{
current: result?.pageIndex + 1,
total: result?.total,
pageSize: result?.pageSize,
showQuickJumper: true,
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: (total: number) =>
`共 ${total} 条记录 第 ${result?.pageIndex + 1}/${Math.ceil(
result?.total / result?.pageSize,
)}页`,
}}
/>
</div>
</Card>
{playing && <Play data={data} close={() => {
setPlaying(false)
}} ok={() => {
setPlaying(false)
}}/>}
{channel && <ChannelEdit data={channelInfo} close={() => {
setChannel(false);
handleSearch(searchParam);
}}/>
}
{playback && <Playback data={data} close={() => {
setPalyback(false)
}} ok={() => {
setPalyback(false)
}} />}
</PageHeaderWrapper>
)
}