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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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/>&nbsp;&nbsp;添加客服信息</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/>&nbsp;&nbsp;基本信息</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/>&nbsp;&nbsp;自定义信息</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/>&nbsp;&nbsp;客户动态</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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  )
}