mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
Merge branch 'feature/dataLogPage' into 'main'
feat: integrate global policy API and implement data log page See merge request apipark/APIPark!115
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Radio, DatePicker, GetProps, RadioChangeEvent } from 'antd';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
||||
@@ -12,64 +12,74 @@ export type RangeValue = [Dayjs | null, Dayjs | null] | null;
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
export type TimeRange = {
|
||||
start:number|null
|
||||
end:number|null
|
||||
start: number | null
|
||||
end: number | null
|
||||
}
|
||||
|
||||
export type TimeRangeButton = ''| 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
export type TimeRangeButton = '' | 'hour' | 'day' | 'threeDays' | 'sevenDays';
|
||||
|
||||
type TimeRangeSelectorProps = {
|
||||
initialTimeButton?:TimeRangeButton,
|
||||
initialDatePickerValue?:RangeValue
|
||||
onTimeRangeChange?:(timeRange:TimeRange) =>void
|
||||
hideTitle?:boolean
|
||||
onTimeButtonChange:(time:TimeRangeButton) =>void
|
||||
labelSize?:'small'|'default'
|
||||
}
|
||||
const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
const {initialTimeButton,initialDatePickerValue,onTimeRangeChange,hideTitle,onTimeButtonChange,labelSize='default'} = props
|
||||
initialTimeButton?: TimeRangeButton,
|
||||
initialDatePickerValue?: RangeValue
|
||||
onTimeRangeChange?: (timeRange: TimeRange) => void
|
||||
hideTitle?: boolean
|
||||
onTimeButtonChange: (time: TimeRangeButton) => void
|
||||
labelSize?: 'small' | 'default'
|
||||
bindRef?: any
|
||||
}
|
||||
const TimeRangeSelector = (props: TimeRangeSelectorProps) => {
|
||||
const { initialTimeButton, initialDatePickerValue, onTimeRangeChange, hideTitle, onTimeButtonChange, labelSize = 'default', bindRef } = props
|
||||
const [timeButton, setTimeButton] = useState(initialTimeButton || '');
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null,null]);
|
||||
|
||||
const [datePickerValue, setDatePickerValue] = useState<RangeValue>(initialDatePickerValue || [null, null]);
|
||||
useEffect(() => {
|
||||
if (bindRef) {
|
||||
bindRef({ reset });
|
||||
}
|
||||
}, [bindRef])
|
||||
// 根据选择的时间范围计算开始和结束时间
|
||||
const calculateTimeRange = (curBtn:'hour'|'day'|'threeDays'|'sevenDays') => {
|
||||
const calculateTimeRange = (curBtn: 'hour' | 'day' | 'threeDays' | 'sevenDays') => {
|
||||
const currentSecond = new Date().getTime() // 当前毫秒数时间戳
|
||||
const currentMin = currentSecond - (currentSecond % (60 * 1000)) // 当前分钟数时间戳
|
||||
let startMin = currentMin - 60 * 60 * 1000
|
||||
switch (curBtn) {
|
||||
case 'hour': {
|
||||
startMin = currentMin - 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentMin - 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
2 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
6 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'hour': {
|
||||
startMin = currentMin - 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'day': {
|
||||
startMin = currentMin - 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'threeDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
2 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
case 'sevenDays': {
|
||||
startMin =
|
||||
new Date(new Date().setHours(0, 0, 0, 0)).getTime() -
|
||||
6 * 24 * 60 * 60 * 1000
|
||||
break
|
||||
}
|
||||
}
|
||||
if (onTimeRangeChange) {
|
||||
onTimeRangeChange({ start: startMin / 1000, end: currentMin / 1000 });
|
||||
onTimeRangeChange({ start: startMin / 1000, end: currentMin / 1000 });
|
||||
}
|
||||
};
|
||||
|
||||
// 处理单选按钮的变化
|
||||
const handleRadioChange = (e:RadioChangeEvent) => {
|
||||
const handleRadioChange = (e: RadioChangeEvent) => {
|
||||
setTimeButton(e.target.value);
|
||||
onTimeButtonChange?.(e.target.value)
|
||||
setDatePickerValue(null)
|
||||
calculateTimeRange(e.target.value);
|
||||
};
|
||||
const reset = () => {
|
||||
setTimeButton('hour')
|
||||
calculateTimeRange('hour')
|
||||
setDatePickerValue(null)
|
||||
}
|
||||
|
||||
// 处理日期选择器的变化
|
||||
const handleDatePickerChange = (dates: RangeValue) => {
|
||||
@@ -84,34 +94,37 @@ const TimeRangeSelector = (props:TimeRangeSelectorProps) => {
|
||||
onTimeRangeChange({ start, end });
|
||||
}
|
||||
}
|
||||
if (!dates) {
|
||||
calculateTimeRange('hour')
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
|
||||
|
||||
const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
||||
// Can not select days before today and today
|
||||
return current && current.valueOf() > dayjs().startOf('day').valueOf();
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-nowrap items-center pt-btnybase mr-btnybase">
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
<Radio.Button value="hour">{$t('近1小时')}</Radio.Button>
|
||||
<Radio.Button value="day">{$t('近24小时')}</Radio.Button>
|
||||
<Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>
|
||||
<Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>
|
||||
</Radio.Group>
|
||||
{!hideTitle && <label className={`whitespace-nowrap `}>{$t('时间')}:</label>}
|
||||
<Radio.Group className="whitespace-nowrap" value={timeButton} onChange={handleRadioChange} buttonStyle="solid">
|
||||
<Radio.Button value="hour">{$t('近1小时')}</Radio.Button>
|
||||
<Radio.Button value="day">{$t('近24小时')}</Radio.Button>
|
||||
<Radio.Button value="threeDays">{$t('近3天')}</Radio.Button>
|
||||
<Radio.Button className="rounded-e-none" value="sevenDays">{$t('近7天')}</Radio.Button>
|
||||
</Radio.Group>
|
||||
<DatePicker.RangePicker
|
||||
value={datePickerValue}
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
className="rounded-s-none ml-[-1px]"
|
||||
disabledDate={disabledDate}
|
||||
onChange={handleDatePickerChange}
|
||||
onOpenChange={(open)=>{
|
||||
if(!open && datePickerValue && datePickerValue.length > 2){
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
onOpenChange={(open) => {
|
||||
if (!open && datePickerValue && datePickerValue.length > 2) {
|
||||
setTimeButton('')
|
||||
onTimeButtonChange?.('')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CodeboxApiRef {
|
||||
formatCode: () => void
|
||||
}
|
||||
|
||||
export type codeBoxLanguagesType = 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
interface CodeboxProps {
|
||||
options?: MonacoEditor.IStandaloneEditorConstructionOptions
|
||||
value?: string
|
||||
@@ -22,7 +23,7 @@ interface CodeboxProps {
|
||||
height?: string | null
|
||||
readOnly?: boolean
|
||||
apiRef?: RefObject<CodeboxApiRef>
|
||||
language?: 'html' | 'json' | 'xml' | 'javascript' | 'css' | 'plaintext'|'yaml'
|
||||
language?: codeBoxLanguagesType
|
||||
extraContent?:React.ReactNode
|
||||
sx?:Record<string,unknown>
|
||||
editorTheme?:'vs' | 'vs-dark' | 'hc-black'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { codeBoxLanguagesType } from "@common/components/postcat/api/Codebox";
|
||||
|
||||
export const MatchRules = [
|
||||
{ value: 'inner', label: '数据格式' },
|
||||
@@ -54,4 +55,34 @@ export const StrategyStatusEnum = {
|
||||
"offline":'text-status_fail',
|
||||
"delete":'text-status_offline',
|
||||
}
|
||||
|
||||
export const contentTypeToLanguageMap: Record<string, codeBoxLanguagesType> = {
|
||||
// JSON
|
||||
"application/json": "json",
|
||||
|
||||
// XML
|
||||
"application/xml": "xml",
|
||||
"text/xml": "xml",
|
||||
|
||||
// HTML
|
||||
"text/html": "html",
|
||||
|
||||
// Plain text
|
||||
"text/plain": "plaintext",
|
||||
|
||||
// JavaScript
|
||||
"application/javascript": "javascript",
|
||||
"text/javascript": "javascript",
|
||||
|
||||
// CSS
|
||||
"text/css": "css",
|
||||
|
||||
// YAML
|
||||
"application/x-yaml": "yaml",
|
||||
"text/yaml": "yaml",
|
||||
|
||||
// Others (fallback)
|
||||
"*/*": "plaintext", // 任意类型默认处理为普通文本
|
||||
};
|
||||
|
||||
|
||||
@@ -2,114 +2,133 @@
|
||||
import { EntityItem } from "@common/const/type";
|
||||
|
||||
export type PartitionConfigFieldType = {
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
prefix?:string
|
||||
url?:string
|
||||
managerAddress?:string
|
||||
canDelete?:boolean
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
prefix?: string
|
||||
url?: string
|
||||
managerAddress?: string
|
||||
canDelete?: boolean
|
||||
};
|
||||
|
||||
export type PartitionCertTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
domains:string[];
|
||||
notAfter:string;
|
||||
notBefore:string;
|
||||
updater:EntityItem;
|
||||
updateTime:string;
|
||||
id: string;
|
||||
name: string;
|
||||
domains: string[];
|
||||
notAfter: string;
|
||||
notBefore: string;
|
||||
updater: EntityItem;
|
||||
updateTime: string;
|
||||
};
|
||||
|
||||
export type PartitionCertConfigFieldType = {
|
||||
id?:string
|
||||
key:string
|
||||
pem:string
|
||||
id?: string
|
||||
key: string
|
||||
pem: string
|
||||
};
|
||||
|
||||
export type PartitionCertConfigProps = {
|
||||
type:'add'|'edit'
|
||||
entity?:PartitionCertConfigFieldType
|
||||
type: 'add' | 'edit'
|
||||
entity?: PartitionCertConfigFieldType
|
||||
}
|
||||
|
||||
export type PartitionCertConfigHandle = {
|
||||
save:()=>Promise<boolean|string>
|
||||
save: () => Promise<boolean | string>
|
||||
}
|
||||
|
||||
export type PartitionClusterFieldType = {
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
address?:string;
|
||||
protocol?:'http'|'https'
|
||||
name?: string;
|
||||
id?: string;
|
||||
description?: string;
|
||||
address?: string;
|
||||
protocol?: 'http' | 'https'
|
||||
};
|
||||
|
||||
export type ClusterConfigProps = {
|
||||
mode:'config' | 'retry' | 'result' | 'edit',
|
||||
clusterId?:string
|
||||
initFormValue?:{[k:string]:string|number}
|
||||
mode: 'config' | 'retry' | 'result' | 'edit',
|
||||
clusterId?: string
|
||||
initFormValue?: { [k: string]: string | number }
|
||||
}
|
||||
|
||||
export type ClusterConfigHandle = {
|
||||
save:()=>Promise<boolean|string>
|
||||
check:()=>Promise<boolean>
|
||||
save: () => Promise<boolean | string>
|
||||
check: () => Promise<boolean>
|
||||
}
|
||||
|
||||
export type PartitionClusterTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
status:0|1;
|
||||
description:string;
|
||||
id: string;
|
||||
name: string;
|
||||
status: 0 | 1;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type PartitionClusterNodeTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
managerAddress:string[];
|
||||
serviceAddress:string[];
|
||||
peerAddress:string[];
|
||||
status:0|1;
|
||||
id: string;
|
||||
name: string;
|
||||
managerAddress: string[];
|
||||
serviceAddress: string[];
|
||||
peerAddress: string[];
|
||||
status: 0 | 1;
|
||||
};
|
||||
|
||||
export type PartitionClusterNodeModalTableListItem = {
|
||||
id: string,
|
||||
name: string,
|
||||
managerAddress: [],
|
||||
serviceAddress: [],
|
||||
peerAddress: string,
|
||||
status: string
|
||||
id: string,
|
||||
name: string,
|
||||
managerAddress: [],
|
||||
serviceAddress: [],
|
||||
peerAddress: string,
|
||||
status: string
|
||||
}
|
||||
|
||||
export type NodeModalFieldType = {
|
||||
address:string
|
||||
address: string
|
||||
}
|
||||
|
||||
|
||||
export type NodeModalHandle = {
|
||||
save:()=>void
|
||||
save: () => void
|
||||
}
|
||||
export type NodeModalPropsType = {
|
||||
changeStatus:(status:ClusterPageShowStatus)=>void
|
||||
getClusterInfo:()=>void
|
||||
status:ClusterPageShowStatus
|
||||
changeStatus: (status: ClusterPageShowStatus) => void
|
||||
getClusterInfo: () => void
|
||||
status: ClusterPageShowStatus
|
||||
}
|
||||
|
||||
export type ClusterPageShowStatus = 'view'|'preview'|'edit'
|
||||
export type ClusterPageShowStatus = 'view' | 'preview' | 'edit'
|
||||
export type PartitionTableListItem = {
|
||||
id:string;
|
||||
name: string;
|
||||
clusterNum:number;
|
||||
updater:EntityItem;
|
||||
updateTime:string;
|
||||
id: string;
|
||||
name: string;
|
||||
clusterNum: number;
|
||||
updater: EntityItem;
|
||||
updateTime: string;
|
||||
};
|
||||
|
||||
export type SimplePartition = EntityItem & { clusters: (EntityItem & {description:string})[] }
|
||||
export type SimplePartition = EntityItem & { clusters: (EntityItem & { description: string })[] }
|
||||
|
||||
export type PartitionDashboardConfigFieldType = {
|
||||
driver:string
|
||||
config:{
|
||||
org:string
|
||||
token:string
|
||||
addr:string
|
||||
driver: string
|
||||
config: {
|
||||
org: string
|
||||
token: string
|
||||
addr: string
|
||||
}
|
||||
}
|
||||
export type PartitionDataLogConfigFieldType = {
|
||||
create_time: string
|
||||
id: string
|
||||
update_time: string
|
||||
updater: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
creator: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
config: {
|
||||
headers: {
|
||||
[k: string]: string
|
||||
}
|
||||
url: string
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { PartitionDataLogConfigFieldType } from "@core/const/partitions/types"
|
||||
|
||||
export type DashboardPageShowStatus = 'view'|'edit'
|
||||
export type DashboardSettingEditProps = {
|
||||
changeStatus:(status:DashboardPageShowStatus)=>void
|
||||
refreshData:()=>void
|
||||
data?:PartitionDataLogConfigFieldType
|
||||
}
|
||||
const DataLogSettingEdit = (props:DashboardSettingEditProps) => {
|
||||
const {changeStatus,refreshData,data} = props
|
||||
return (
|
||||
<div>
|
||||
222
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DataLogSettingEdit;
|
||||
@@ -1,93 +1,177 @@
|
||||
import { FC, useEffect, useState} from "react";
|
||||
import {useBreadcrumb} from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import {App, Button, Card, Col, Row, Spin, Tag} from "antd";
|
||||
import {BasicResponse, RESPONSE_TIPS, STATUS_CODE} from "@common/const/const.tsx";
|
||||
import {useFetch} from "@common/hooks/http.ts";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { useBreadcrumb } from "@common/contexts/BreadcrumbContext.tsx";
|
||||
import { App, Button, Card, Col, Row, Spin, Tag } from "antd";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const.tsx";
|
||||
import { useFetch } from "@common/hooks/http.ts";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
import InsidePage from "@common/components/aoplatform/InsidePage.tsx";
|
||||
import { $t } from "@common/locales/index.ts";
|
||||
import DashboardSettingEdit, { DashboardPageShowStatus } from "./DashboardSettingEdit.tsx";
|
||||
import { PartitionDashboardConfigFieldType } from "@core/const/partitions/types.ts";
|
||||
import { PartitionDashboardConfigFieldType, PartitionDataLogConfigFieldType } from "@core/const/partitions/types.ts";
|
||||
import PageList from "@common/components/aoplatform/PageList.tsx";
|
||||
import DataLogSettingEdit from "./DataLogSettingEdit.tsx";
|
||||
|
||||
const PartitionInsideDashboardSetting:FC = ()=> {
|
||||
const {setBreadcrumb} = useBreadcrumb()
|
||||
const {message} = App.useApp()
|
||||
const {fetchData} = useFetch()
|
||||
const [data, setData] = useState<PartitionDashboardConfigFieldType>()
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [showStatus, setShowStatus] = useState<DashboardPageShowStatus>('view')
|
||||
const PartitionInsideDashboardSetting: FC = () => {
|
||||
const { setBreadcrumb } = useBreadcrumb()
|
||||
const { message } = App.useApp()
|
||||
const { fetchData } = useFetch()
|
||||
const [data, setData] = useState<PartitionDashboardConfigFieldType>()
|
||||
const [dataLogData, setDataLogData] = useState<PartitionDataLogConfigFieldType>()
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [dataLogLoading, setDataLogLoading] = useState<boolean>(false)
|
||||
const [showGraphStatus, setShowGraphStatus] = useState<DashboardPageShowStatus>('view')
|
||||
const [showDataLogStatus, setShowDataLogStatus] = useState<DashboardPageShowStatus>('view')
|
||||
|
||||
const getDashboardSettingInfo = () => {
|
||||
setLoading(true)
|
||||
return fetchData<BasicResponse<{ nodes:PartitionDashboardConfigFieldType[] }>>('monitor/config', {method: 'GET',eoTransformKeys:[]}).then(response => {
|
||||
const {code, data, msg} = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
data?.info?.driver && setData(data.info)
|
||||
setShowStatus('view')
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch(() => {
|
||||
return {data: [], success: false}
|
||||
}).finally(()=>{
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
const getDashboardSettingInfo = () => {
|
||||
setLoading(true)
|
||||
return fetchData<BasicResponse<{ nodes: PartitionDashboardConfigFieldType[] }>>('monitor/config', { method: 'GET', eoTransformKeys: [] }).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
data?.info?.driver && setData(data.info)
|
||||
setShowGraphStatus('view')
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch(() => {
|
||||
return { data: [], success: false }
|
||||
}).finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
const getDataLogSettingInfo = () => {
|
||||
setDataLogLoading(true)
|
||||
return fetchData<BasicResponse<{ nodes: PartitionDataLogConfigFieldType[] }>>('log/loki', { method: 'GET', eoTransformKeys: [] }).then(response => {
|
||||
const { code, data, msg } = response
|
||||
console.log('data====', data);
|
||||
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
data?.info && setDataLogData(data.info)
|
||||
setShowDataLogStatus('view')
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch(() => {
|
||||
return { data: [], success: false }
|
||||
}).finally(() => {
|
||||
setDataLogLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumb([
|
||||
{title: $t('数据源')}
|
||||
])
|
||||
getDashboardSettingInfo()
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
setBreadcrumb([
|
||||
{ title: $t('数据源') }
|
||||
])
|
||||
getDashboardSettingInfo()
|
||||
getDataLogSettingInfo()
|
||||
}, []);
|
||||
|
||||
const setDashboardSettingBtn = ()=>{
|
||||
return (<>
|
||||
{showStatus === 'view' && <WithPermission access="system.devops.data_source.edit" key="changeClusterConfig">
|
||||
<Button type="primary" onClick={() => setShowStatus('edit')}>{$t('修改配置')}</Button>
|
||||
</WithPermission> }</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<InsidePage
|
||||
pageTitle={$t('数据源')}
|
||||
description={$t("设置监控报表的数据来源,设置完成之后即可获得详细的API调用统计图表。")}
|
||||
showBorder={false}
|
||||
scrollPage={true}
|
||||
>
|
||||
<div className="flex flex-col h-full overflow-auto pb-PAGE_INSIDE_B pr-PAGE_INSIDE_X">
|
||||
<Spin wrapperClassName=" h-full flex-1" indicator={<LoadingOutlined style={{ fontSize: 24 }} spin/>} spinning={loading}>
|
||||
<div className="h-full overflow-auto">
|
||||
<Card
|
||||
classNames={{
|
||||
body: `overflow-auto ${(!data || !data?.driver) && showStatus === 'view' ? 'hidden': ''}`,
|
||||
}}
|
||||
className="overflow-hidden w-full max-h-full flex flex-col justify-between"
|
||||
title={<div><span className="text-MAIN_TEXT my-btnybase mr-btnbase" > {$t('统计图表')}</span>
|
||||
{!loading && !data?.driver && <Tag color='#f50'>{ $t('未配置')}
|
||||
</Tag>}</div>}
|
||||
|
||||
extra={setDashboardSettingBtn()}>
|
||||
{showStatus === 'view'&& data && data.driver && DashboardConfigPreview(data) }
|
||||
{showStatus !== 'view' && <DashboardSettingEdit data={data} changeStatus={setShowStatus} refreshData={getDashboardSettingInfo} />}
|
||||
</Card>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</InsidePage>
|
||||
</>
|
||||
const setDashboardSettingBtn = (type: string) => {
|
||||
return (<>
|
||||
{showGraphStatus === 'view' && <WithPermission access="system.devops.data_source.edit" key="changeClusterConfig">
|
||||
<Button type="primary" onClick={() => type === 'graph' ? setShowGraphStatus('edit') : setShowDataLogStatus('edit')}>{$t('修改配置')}</Button>
|
||||
</WithPermission>}</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<InsidePage
|
||||
pageTitle={$t('数据源')}
|
||||
description={$t("设置监控报表的数据来源,设置完成之后即可获得详细的API调用统计图表。")}
|
||||
showBorder={false}
|
||||
scrollPage={true}
|
||||
>
|
||||
<div className="flex flex-col overflow-auto pb-PAGE_INSIDE_B pr-PAGE_INSIDE_X">
|
||||
<Spin wrapperClassName="flex-1" indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={loading}>
|
||||
<div className="h-full overflow-auto">
|
||||
<Card
|
||||
classNames={{
|
||||
body: `overflow-auto ${(!data || !data?.driver) && showGraphStatus === 'view' ? 'hidden' : ''}`,
|
||||
}}
|
||||
className="overflow-hidden w-full max-h-full flex flex-col justify-between"
|
||||
title={<div><span className="text-MAIN_TEXT my-btnybase mr-btnbase" > {$t('统计图表')}</span>
|
||||
{!loading && !data?.driver && <Tag color='#f50'>{$t('未配置')}
|
||||
</Tag>}</div>}
|
||||
|
||||
extra={setDashboardSettingBtn('graph')}>
|
||||
{showGraphStatus === 'view' && data && data.driver && DashboardConfigPreview(data)}
|
||||
{showGraphStatus !== 'view' && <DashboardSettingEdit data={data} changeStatus={setShowGraphStatus} refreshData={getDashboardSettingInfo} />}
|
||||
</Card>
|
||||
</div>
|
||||
</Spin>
|
||||
<Spin wrapperClassName="flex-1" indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={dataLogLoading}>
|
||||
<div className="h-full overflow-auto">
|
||||
<Card
|
||||
classNames={{
|
||||
body: `overflow-auto ${(!dataLogData) && showDataLogStatus === 'view' ? 'hidden' : ''}`,
|
||||
}}
|
||||
className="overflow-hidden mt-[30px] w-full max-h-full flex flex-col justify-between"
|
||||
title={<div><span className="text-MAIN_TEXT my-btnybase mr-btnbase" > {$t('数据日志')}</span>
|
||||
{!dataLogLoading && !dataLogData && <Tag color='#f50'>{$t('未配置')}
|
||||
</Tag>}</div>}
|
||||
|
||||
extra={setDashboardSettingBtn('log')}>
|
||||
{showDataLogStatus === 'view' && dataLogData && DataLogConfigPreview(dataLogData)}
|
||||
{showDataLogStatus !== 'view' && <DataLogSettingEdit data={dataLogData} changeStatus={setShowDataLogStatus} refreshData={getDataLogSettingInfo} />}
|
||||
</Card>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</InsidePage>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function DashboardConfigPreview (x:PartitionDashboardConfigFieldType){
|
||||
return <div className="flex flex-col gap-[4px] ">
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('数据源')}:</Col><Col>{x?.driver}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('地址(IP:端口)')}:</Col><Col>{x?.config?.addr}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('组织(Organization)')}:</Col><Col>{x?.config?.org}</Col></Row>
|
||||
</div>}
|
||||
export function DashboardConfigPreview(x: PartitionDashboardConfigFieldType) {
|
||||
return <div className="flex flex-col gap-[4px] ">
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('数据源')}:</Col><Col>{x?.driver}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('地址(IP:端口)')}:</Col><Col>{x?.config?.addr}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('组织(Organization)')}:</Col><Col>{x?.config?.org}</Col></Row>
|
||||
</div>
|
||||
}
|
||||
export function DataLogConfigPreview(x: PartitionDataLogConfigFieldType) {
|
||||
const columns = [
|
||||
{
|
||||
title: '标签',
|
||||
dataIndex: 'tag',
|
||||
},
|
||||
{
|
||||
title: '内容',
|
||||
dataIndex: 'content'
|
||||
}
|
||||
]
|
||||
const getTableList = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
data: x?.config?.headers ? Object.keys(x?.config?.headers).map((key) => {
|
||||
return {
|
||||
tag: key,
|
||||
content: x?.config?.headers[key]
|
||||
}
|
||||
}) : [],
|
||||
success: true
|
||||
})
|
||||
})
|
||||
}
|
||||
console.log(getTableList());
|
||||
|
||||
return <div className="flex flex-col gap-[4px] ">
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('请求前缀')}:</Col><Col>{x?.config?.url}</Col></Row>
|
||||
<Row className=""><Col className="font-bold text-right pr-[4px]">{$t('HTTP 头部')}:</Col><Col className="w-full">
|
||||
<div className="w-full h-full p-[20px]">
|
||||
<PageList
|
||||
id="global_role"
|
||||
tableClass="role_table mb-btnrbase"
|
||||
primaryKey="'tag'"
|
||||
columns={[...columns]}
|
||||
request={() => getTableList()}
|
||||
showPagination={false}
|
||||
noScroll={true}
|
||||
/>
|
||||
</div>
|
||||
</Col></Row>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default PartitionInsideDashboardSetting
|
||||
@@ -79,7 +79,7 @@ const DataMasking = (props: any) => {
|
||||
{
|
||||
title: '',
|
||||
key: 'option',
|
||||
btnNums: rowOperation.length -1,
|
||||
btnNums: rowOperation.length,
|
||||
fixed: 'right',
|
||||
valueType: 'option',
|
||||
render: (_: React.ReactNode, entity: any) => [
|
||||
@@ -379,10 +379,11 @@ const DataMasking = (props: any) => {
|
||||
<Modal
|
||||
title={$t('处理日志')}
|
||||
visible={modalVisible}
|
||||
destroyOnClose={true}
|
||||
onCancel={handleCloseModal}
|
||||
footer={null}
|
||||
wrapClassName="modal-without-footer"
|
||||
width={1000}
|
||||
width={1100}
|
||||
maskClosable={true}
|
||||
>
|
||||
<div className="pb-btnybase flex flex-nowrap flex-col h-full w-full items-center justify-between">
|
||||
|
||||
@@ -86,7 +86,7 @@ export const DATA_MASKING_TABLE_LOG_COLUMNS: PageProColumns<any>[] = [
|
||||
title: ('消费者IP'),
|
||||
dataIndex: 'remote_ip',
|
||||
ellipsis: true,
|
||||
width: 150
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: ('消费者'),
|
||||
@@ -96,7 +96,7 @@ export const DATA_MASKING_TABLE_LOG_COLUMNS: PageProColumns<any>[] = [
|
||||
},
|
||||
{
|
||||
title: ('鉴权名称'),
|
||||
dataIndex: 'authorization',
|
||||
dataIndex: ['authorization', 'name'],
|
||||
ellipsis: true,
|
||||
width: 100
|
||||
},
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Codebox } from "@common/components/postcat/api/Codebox";
|
||||
import { Codebox, codeBoxLanguagesType } from "@common/components/postcat/api/Codebox";
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from "@common/const/const";
|
||||
import { RouterParams } from "@common/const/type";
|
||||
import { $t } from "@common/locales";
|
||||
import { App, Button, message, Switch, Modal, Spin } from 'antd'
|
||||
import { message, Spin } from 'antd'
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import { contentTypeToLanguageMap } from "@common/const/policy/consts";
|
||||
type LogItems = {
|
||||
id: string;
|
||||
origin: string;
|
||||
@@ -18,7 +17,15 @@ const DataMaskingCompare = () => {
|
||||
const { fetchData } = useFetch()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [originValue, setOriginValue] = useState('')
|
||||
const [targetValue, settTargetValue] = useState('')
|
||||
const [targetValue, setTargetValue] = useState('')
|
||||
const [language, setLanguage] = useState<codeBoxLanguagesType>('json')
|
||||
const getMonacoEditorLanguage = (contentType: string): codeBoxLanguagesType => {
|
||||
// 提取主类型,忽略参数(如 "; charset=utf-8")
|
||||
const mainType = contentType.split(";")[0].trim().toLowerCase();
|
||||
|
||||
// 根据映射表获取语言,默认返回 "plaintext"
|
||||
return contentTypeToLanguageMap[mainType] || "json";
|
||||
};
|
||||
const getLogData = () => {
|
||||
setLoading(true)
|
||||
return fetchData<BasicResponse<{ log: LogItems }>>(`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/log`,
|
||||
@@ -33,8 +40,10 @@ const DataMaskingCompare = () => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
const { log } = data
|
||||
setOriginValue(log.origin || '')
|
||||
settTargetValue(log.target || '')
|
||||
const docLanguage = getMonacoEditorLanguage(log.content_type)
|
||||
setLanguage(docLanguage)
|
||||
setOriginValue(docLanguage === 'json' ? JSON.stringify(JSON.parse(log.origin || ''), null, 2) : log.origin || '')
|
||||
setTargetValue(docLanguage === 'json' ? JSON.stringify(JSON.parse(log.target || ''), null, 2) : log.target || '')
|
||||
setLoading(false)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
@@ -42,17 +51,6 @@ const DataMaskingCompare = () => {
|
||||
}).catch(() => {
|
||||
return { data: [], success: false }
|
||||
}).finally(() => {
|
||||
const aa = `{
|
||||
"code": {
|
||||
"gg": "gg",
|
||||
"gg1": "gg",
|
||||
"gg2": "gg",
|
||||
"gg3": "gg",
|
||||
"gg4": "gg"
|
||||
}
|
||||
}`
|
||||
setOriginValue(JSON.stringify(JSON.parse(aa), null, 2))
|
||||
settTargetValue(JSON.stringify(JSON.parse(aa), null, 2))
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
@@ -68,10 +66,12 @@ const DataMaskingCompare = () => {
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
language='json'
|
||||
language={language}
|
||||
height="100%"
|
||||
width="100%"
|
||||
value={originValue}
|
||||
sx={{ whiteSpace: 'nowrap' }}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +81,7 @@ const DataMaskingCompare = () => {
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
language='json'
|
||||
language={language}
|
||||
width="100%"
|
||||
height="100%"
|
||||
value={targetValue}
|
||||
|
||||
@@ -1,40 +1,57 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { DataMaskLogItem } from "@common/const/policy/type";
|
||||
import PageList, { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { $t } from "@common/locales";
|
||||
import { App, Button, message, DatePicker, Modal } from 'antd'
|
||||
import { Button, message } from 'antd'
|
||||
|
||||
import { DATA_MASKING_TABLE_LOG_COLUMNS, DATA_MASKING_TABLE_COLUMNS } from './DataMaskingColumn';
|
||||
import { DATA_MASKING_TABLE_LOG_COLUMNS } from './DataMaskingColumn';
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext';
|
||||
import { ActionType } from '@ant-design/pro-components';
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { RouterParams } from '@common/const/type';
|
||||
import { useFetch } from '@common/hooks/http';
|
||||
import WithPermission from '@common/components/aoplatform/WithPermission';
|
||||
import TimeRangeSelector, { TimeRange } from '@common/components/aoplatform/TimeRangeSelector';
|
||||
import { SearchBody } from '@dashboard/const/type';
|
||||
import TableBtnWithPermission from '@common/components/aoplatform/TableBtnWithPermission';
|
||||
const { RangePicker } = DatePicker;
|
||||
import { getTime } from '@dashboard/utils/dashboard';
|
||||
const DataMaskingLogModal = (props: any) => {
|
||||
const { strategy } = props;
|
||||
const { state, accessData } = useGlobalContext()
|
||||
const { serviceId, teamId } = useParams<RouterParams>()
|
||||
const [datePickerValue, setDatePickerValue] = useState<any>();
|
||||
const [queryData, setQueryData] = useState<SearchBody>({})
|
||||
|
||||
const defaultTime = getTime('hour', datePickerValue)
|
||||
const [queryData, setQueryData] = useState<SearchBody>({
|
||||
start: defaultTime.startTime,
|
||||
end: defaultTime.endTime
|
||||
})
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
const { fetchData } = useFetch()
|
||||
/**
|
||||
* 列表ref
|
||||
*/
|
||||
* 列表ref
|
||||
*/
|
||||
const pageListRef = useRef<ActionType>(null);
|
||||
/**
|
||||
* 搜索关键字
|
||||
*/
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
/**
|
||||
* 重置时间范围
|
||||
*/
|
||||
let resetTimeRange = () => {}
|
||||
/**
|
||||
* 时间按钮
|
||||
*/
|
||||
const [timeButton, setTimeButton] = useState<'' | 'hour' | 'day' | 'threeDays' | 'sevenDays'>('hour');
|
||||
/**
|
||||
* 绑定时间范围组件
|
||||
* @param instance
|
||||
*/
|
||||
const bindRef = (instance: any) => {
|
||||
resetTimeRange = instance.reset
|
||||
};
|
||||
/**
|
||||
* 操作列
|
||||
*/
|
||||
@@ -54,7 +71,7 @@ const DataMaskingLogModal = (props: any) => {
|
||||
url += `/${teamId}`
|
||||
}
|
||||
return [
|
||||
<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.view`} key="view" btnType="view" onClick={() => { window.open(url,'_blank') }} btnTitle="查看" />
|
||||
<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.view`} key="view" btnType="view" onClick={() => { window.open(url, '_blank') }} btnTitle="查看" />
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -88,7 +105,7 @@ const DataMaskingLogModal = (props: any) => {
|
||||
current: number;
|
||||
}) => {
|
||||
return fetchData<BasicResponse<{ logs: DataMaskLogItem[], total: number }>>(
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/list`,
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/logs`,
|
||||
{
|
||||
method: 'GET',
|
||||
eoParams: {
|
||||
@@ -106,204 +123,9 @@ const DataMaskingLogModal = (props: any) => {
|
||||
).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
const mockData: any = [
|
||||
{
|
||||
id: '12334',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff1',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff2',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff3',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff4',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff5',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff6',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff7',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff8',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff9',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff11',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:12',
|
||||
},
|
||||
{
|
||||
id: 'fff22',
|
||||
service: {
|
||||
id: 'xxx',
|
||||
name: 'xxx'
|
||||
},
|
||||
url: 'url',
|
||||
remote_ip: '9234923',
|
||||
consumer: {
|
||||
id: 'yyy',
|
||||
name: 'yyy'
|
||||
},
|
||||
method: 'GET',
|
||||
authorization: 'authorization',
|
||||
record_time: '2021-09-09 12:12:11',
|
||||
}
|
||||
|
||||
]
|
||||
// 保存数据
|
||||
return {
|
||||
data: mockData,
|
||||
data: data.logs || [],
|
||||
total: data.total,
|
||||
success: true
|
||||
}
|
||||
@@ -320,24 +142,13 @@ const DataMaskingLogModal = (props: any) => {
|
||||
const handleTimeRangeChange = (timeRange: TimeRange) => {
|
||||
setQueryData(pre => ({ ...pre, ...timeRange } as SearchBody))
|
||||
manualReloadTable()
|
||||
|
||||
|
||||
};
|
||||
const handleDatePickerChange = (dates: any) => {
|
||||
if (dates && Array.isArray(dates) && dates.length === 2) {
|
||||
const [startDate, endDate] = dates;
|
||||
const start = startDate!.startOf('day').unix(); // 开始日期的00:00:00
|
||||
const end = endDate!.endOf('day').unix(); // 结束日期的23:59:59
|
||||
handleTimeRangeChange({ start, end });
|
||||
} else {
|
||||
handleTimeRangeChange({ start: null, end: null})
|
||||
}
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
setDatePickerValue(null)
|
||||
handleTimeRangeChange({ start: null, end: null})
|
||||
|
||||
resetTimeRange()
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full h-full p-[20px]">
|
||||
@@ -348,11 +159,15 @@ const DataMaskingLogModal = (props: any) => {
|
||||
columns={[...columns, ...operation]}
|
||||
afterNewBtn={
|
||||
[<div className="flex items-center flex-wrap p-[10px] px-btnbase content-before bg-MAIN_BG ">
|
||||
<RangePicker
|
||||
onChange={handleDatePickerChange}
|
||||
value={datePickerValue} />
|
||||
<div className="flex [&>.reset-btn]:!h-auto flex-nowrap items-center ml-[10px]">
|
||||
<Button className="reset-btn" onClick={resetQuery}>{$t('重置')}</Button>
|
||||
<TimeRangeSelector
|
||||
labelSize="small"
|
||||
bindRef={bindRef}
|
||||
initialTimeButton={timeButton}
|
||||
onTimeButtonChange={setTimeButton}
|
||||
initialDatePickerValue={datePickerValue}
|
||||
onTimeRangeChange={handleTimeRangeChange} />
|
||||
<div className="flex flex-nowrap items-center pt-btnybase">
|
||||
<Button onClick={resetQuery}>{$t('重置')}</Button>
|
||||
</div>
|
||||
</div>]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user