mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
feature: dataMask logs dialog
This commit is contained in:
@@ -66,6 +66,22 @@ export type DataMaskStrategyItem = {
|
||||
updater:EntityItem
|
||||
updateTime:string
|
||||
}
|
||||
export type DataMaskLogItem = {
|
||||
id:string
|
||||
service: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
method:string
|
||||
url:string
|
||||
remote_ip:string
|
||||
consumer: {
|
||||
id:string
|
||||
name:string
|
||||
}
|
||||
authorization:string
|
||||
record_time:string
|
||||
}
|
||||
|
||||
|
||||
export type FilterFormField= {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ProtectedRoute } from "@core/components/aoplatform/RenderRoutes";
|
||||
import Login from "@core/pages/Login";
|
||||
import { useLocaleContext } from "./LocaleContext";
|
||||
import Root from "@core/pages/Root"
|
||||
import DataMaskingCompare from "@core/pages/policy/dataMasking/DataMaskingCompare";
|
||||
interface GlobalState {
|
||||
isAuthenticated: boolean;
|
||||
userData: UserData | null;
|
||||
@@ -286,6 +287,7 @@ const globalReducer = (state: GlobalState, action: GlobalAction): GlobalState =>
|
||||
export const DefaultRouteConfig = [
|
||||
{ path: '/', pathMatch: 'full', component: <Root /> ,key:'root',},
|
||||
{ path: '/login', component: <Login /> ,key:'login'},
|
||||
{ path: '/dataMaskCompare/:logId/:serviceId?/:teamId?', component: <DataMaskingCompare /> ,key:'dataMaskCompare'},
|
||||
{ path: '/', pathMatch:'prefix',component:<ProtectedRoute /> ,key:'basciLayout',children:[
|
||||
{ path: '*', component: <ErrorBoundary><NotFound/></ErrorBoundary>, key: 'errorBoundary' }
|
||||
]}
|
||||
|
||||
@@ -975,7 +975,7 @@ p{
|
||||
.ant-drawer-content-wrapper{
|
||||
min-width: 820px !important;
|
||||
.ant-table:not(.ant-table-bordered){
|
||||
border:1px solid var(--border-color) !important;
|
||||
/* border:1px solid var(--border-color) !important; */
|
||||
border-top:0px !important;
|
||||
}
|
||||
.ant-table:not(.ant-table-borderer){
|
||||
@@ -1001,7 +1001,7 @@ p{
|
||||
.ant-modal-wrap:not(.height-fixed-modal){
|
||||
.ant-modal-body{
|
||||
.ant-table:not(.ant-table-bordered){
|
||||
border:1px solid var(--border-color) !important;
|
||||
/* border:1px solid var(--border-color) !important; */
|
||||
border-top:0px !important;
|
||||
}
|
||||
.ant-table:not(.ant-table-borderer){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ActionType } from "@ant-design/pro-components";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { App, Button, message, Switch } from 'antd'
|
||||
import { App, Button, message, Switch, Modal } from 'antd'
|
||||
import PageList, { PageProColumns } from "@common/components/aoplatform/PageList";
|
||||
import { $t } from "@common/locales";
|
||||
import { useGlobalContext } from "@common/contexts/GlobalStateContext";
|
||||
@@ -8,14 +8,14 @@ import { BasicResponse, DELETE_TIPS, RESPONSE_TIPS, STATUS_CODE } from "@common/
|
||||
import { useFetch } from "@common/hooks/http";
|
||||
import WithPermission from "@common/components/aoplatform/WithPermission.tsx";
|
||||
import TableBtnWithPermission from "@common/components/aoplatform/TableBtnWithPermission";
|
||||
import { DATA_MASSKING_TABLE_COLUMNS } from "./DataMaskingColumn";
|
||||
import { DATA_MASKING_TABLE_COLUMNS } from "./DataMaskingColumn";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { PolicyPublishInfoType, PolicyPublishModalHandle, RouterParams } from "@common/const/type";
|
||||
import { DrawerWithFooter } from "@common/components/aoplatform/DrawerWithFooter";
|
||||
import { DataMaskStrategyItem } from "@common/const/policy/type";
|
||||
import {PolicyPublishModalContent} from '@common/components/aoplatform/PolicyPublishModalContent'
|
||||
import { PolicyPublishModalContent } from '@common/components/aoplatform/PolicyPublishModalContent'
|
||||
import { checkAccess } from "@common/utils/permission";
|
||||
|
||||
import DataMaskingLogModal from "./DataMaskingLogModal.tsx";
|
||||
const DataMasking = (props: any) => {
|
||||
|
||||
const {
|
||||
@@ -25,19 +25,21 @@ const DataMasking = (props: any) => {
|
||||
rowOperation = []
|
||||
} = props;
|
||||
const { serviceId, teamId } = useParams<RouterParams>()
|
||||
const { state,accessData } = useGlobalContext()
|
||||
const { state, accessData } = useGlobalContext()
|
||||
const navigator = useNavigate()
|
||||
const [drawerVisible, setDrawerVisible] = useState<boolean>(false)
|
||||
const [drawerData, setDrawerData] = useState<PolicyPublishInfoType >()
|
||||
const [modalVisible, setModalVisible] = useState<boolean>(false);
|
||||
|
||||
const [drawerData, setDrawerData] = useState<PolicyPublishInfoType>()
|
||||
const [isOkToPublish, setIsOkToPublish] = useState<boolean>(false)
|
||||
const drawerRef = useRef<PolicyPublishModalHandle>(null)
|
||||
const { modal } = App.useApp()
|
||||
|
||||
/**
|
||||
* 列表ref
|
||||
*/
|
||||
/**
|
||||
* 列表ref
|
||||
*/
|
||||
const pageListRef = useRef<ActionType>(null);
|
||||
|
||||
|
||||
/**
|
||||
* 请求数据
|
||||
*/
|
||||
@@ -47,27 +49,28 @@ const DataMasking = (props: any) => {
|
||||
* 搜索关键字
|
||||
*/
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
const [strategy, setStrategy] = useState<string>('')
|
||||
|
||||
/**
|
||||
* 获取列数据,国际化变化时重新获取
|
||||
*/
|
||||
const columns = useMemo(() => {
|
||||
const res = DATA_MASSKING_TABLE_COLUMNS.map(x => {
|
||||
const res = DATA_MASKING_TABLE_COLUMNS.map(x => {
|
||||
// 启动列渲染
|
||||
if (x.dataIndex === 'isStop') {
|
||||
x.render = (text: any, record: any) => <WithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} ><Switch checked={!record.isStop} onChange={(e) => { changeOpenApiStatus(e, record) }} /></WithPermission>
|
||||
x.render = (text: any, record: any) => <WithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.edit`} ><Switch checked={!record.isStop} onChange={(e) => { changeOpenApiStatus(e, record) }} /></WithPermission>
|
||||
}
|
||||
// 处理数列渲染
|
||||
if (x.dataIndex === 'treatmentNumber') {
|
||||
x.render = (text: any, record: any) => <span className="w-full block cursor-pointer [&>.ant-typography]:text-theme" onClick={(e) => { openLogsModal(record) }} >{ text }</span>
|
||||
x.render = (text: any, record: any) => <span className="w-full block cursor-pointer [&>.ant-typography]:text-theme" onClick={(e) => { openLogsModal(record) }} >{text}</span>
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title as string) : x.title
|
||||
title: <span title={$t(x.title as string)}>{$t(x.title as string)}</span>
|
||||
}
|
||||
})
|
||||
return res
|
||||
}, [ state.language])
|
||||
}, [state.language])
|
||||
|
||||
/**
|
||||
* 操作列
|
||||
@@ -80,16 +83,21 @@ const DataMasking = (props: any) => {
|
||||
fixed: 'right',
|
||||
valueType: 'option',
|
||||
render: (_: React.ReactNode, entity: any) => [
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} key="edit" btnType="edit" onClick={() => { openEditModal(entity) }} btnTitle="编辑" />] : []),
|
||||
// ...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.view`} key="logs" btnType="logs" onClick={() => { openLogsModal(entity) }} btnTitle="详情" />] : []),
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'edit') ? [<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.edit`} key="edit" btnType="edit" onClick={() => { openEditModal(entity) }} btnTitle="编辑" />] : []),
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'logs') ? [<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.view`} key="logs" btnType="logs" onClick={() => { openLogsModal(entity) }} btnTitle="日志" />] : []),
|
||||
...(rowOperation.length && rowOperation.find((item: string) => item === 'delete') ? [
|
||||
entity.isDelete ? <TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`} key="refresh" btnType="refresh" onClick={() => { restorePolicy(entity) }} btnTitle="恢复" /> :
|
||||
<TableBtnWithPermission access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.delete`} key="delete" btnType="delete" onClick={() => { openModal('delete',entity) }} btnTitle="删除" />
|
||||
] : []),
|
||||
entity.isDelete ? <TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.edit`} key="refresh" btnType="refresh" onClick={() => { restorePolicy(entity) }} btnTitle="恢复" /> :
|
||||
<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.delete`} key="delete" btnType="delete" onClick={() => { openModal('delete', entity) }} btnTitle="删除" />
|
||||
] : []),
|
||||
],
|
||||
}
|
||||
] : []
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setModalVisible(false);
|
||||
// setDetailInvokeError(false)
|
||||
// setDetailInvokeStatic(undefined)
|
||||
// setCompareTotal(false)
|
||||
};
|
||||
/**
|
||||
* 手动刷新表格数据
|
||||
*/
|
||||
@@ -104,12 +112,12 @@ const DataMasking = (props: any) => {
|
||||
*/
|
||||
const changeOpenApiStatus = (enabled: boolean, entity: any) => {
|
||||
fetchData<BasicResponse<null>>(
|
||||
`strategy/${serviceId === undefined? 'global':'service'}/data-masking/${enabled ? 'enable' :'disable' }`,
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/${enabled ? 'enable' : 'disable'}`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
eoParams: {
|
||||
service:serviceId,
|
||||
team:teamId,
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
strategy: entity.id
|
||||
}
|
||||
}
|
||||
@@ -133,44 +141,45 @@ const DataMasking = (props: any) => {
|
||||
pageSize: number;
|
||||
current: number;
|
||||
},
|
||||
sort:Record<string, string>,
|
||||
filter:Record<string, string>) => {
|
||||
sort: Record<string, string>,
|
||||
filter: Record<string, string>) => {
|
||||
let filters
|
||||
if(filter){
|
||||
if (filter) {
|
||||
filters = []
|
||||
if(filter.isStop){
|
||||
if(filter.isStop.indexOf('true')!== -1){
|
||||
filters.push('enable')
|
||||
}
|
||||
if(filter.isStop.indexOf('false')!== -1){
|
||||
filters.push('disable')
|
||||
}
|
||||
if(filter.publishStatus?.length > 0){
|
||||
filters = [...filters, ...filter.publishStatus]
|
||||
}
|
||||
if (filter.isStop) {
|
||||
if (filter.isStop.indexOf('true') !== -1) {
|
||||
filters.push('enable')
|
||||
}
|
||||
if (filter.isStop.indexOf('false') !== -1) {
|
||||
filters.push('disable')
|
||||
}
|
||||
if (filter.publishStatus?.length > 0) {
|
||||
filters = [...filters, ...filter.publishStatus]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fetchData<BasicResponse<{list:DataMaskStrategyItem[], total:number}>>(
|
||||
`strategy/${serviceId === undefined? 'global':'service'}/data-masking/list`,
|
||||
|
||||
return fetchData<BasicResponse<{ list: DataMaskStrategyItem[], total: number }>>(
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/list`,
|
||||
{
|
||||
method: 'GET',
|
||||
eoParams: {
|
||||
order:Object.keys(sort)?.[0],
|
||||
sort:Object.keys(sort)?.length > 0 ? Object.values(sort)?.[0] === 'descend' ? 'desc' : 'asc' : undefined,
|
||||
filters:JSON.stringify(filters),
|
||||
eoParams: {
|
||||
order: Object.keys(sort)?.[0],
|
||||
sort: Object.keys(sort)?.length > 0 ? Object.values(sort)?.[0] === 'descend' ? 'desc' : 'asc' : undefined,
|
||||
filters: JSON.stringify(filters),
|
||||
keyword: searchWord,
|
||||
service:serviceId,
|
||||
team:teamId,},
|
||||
eoTransformKeys: ['is_stop', 'is_delete', 'update_time','publish_status','processed_total']
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
},
|
||||
eoTransformKeys: ['is_stop', 'is_delete', 'update_time', 'publish_status', 'processed_total']
|
||||
}
|
||||
).then(response => {
|
||||
const { code,data, msg } = response
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
// 保存数据
|
||||
return {
|
||||
data:data.list,
|
||||
total:data.total,
|
||||
data: data.list,
|
||||
total: data.total,
|
||||
success: true
|
||||
}
|
||||
} else {
|
||||
@@ -181,7 +190,7 @@ const DataMasking = (props: any) => {
|
||||
return { data: [], success: false }
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,17 +207,17 @@ const DataMasking = (props: any) => {
|
||||
const publish = async () => {
|
||||
message.loading($t(RESPONSE_TIPS.loading));
|
||||
const { code, data, msg } = await fetchData<BasicResponse<PolicyPublishInfoType>>(
|
||||
'strategy/global/data-masking/to-publishs',
|
||||
{ method: 'GET',eoTransformKeys:['opt_time','is_publish','version_name','unpublish_msg'] }
|
||||
'strategy/global/data-masking/to-publishs',
|
||||
{ method: 'GET', eoTransformKeys: ['opt_time', 'is_publish', 'version_name', 'unpublish_msg'] }
|
||||
);
|
||||
message.destroy();
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setDrawerVisible(true)
|
||||
setDrawerData(data)
|
||||
setIsOkToPublish(data.isPublish??true)
|
||||
setDrawerVisible(true)
|
||||
setDrawerData(data)
|
||||
setIsOkToPublish(data.isPublish ?? true)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error));
|
||||
return
|
||||
message.error(msg || $t(RESPONSE_TIPS.error));
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,42 +234,44 @@ const DataMasking = (props: any) => {
|
||||
*/
|
||||
const openLogsModal = (entity: any) => {
|
||||
console.log('日志', entity);
|
||||
setStrategy(entity.id)
|
||||
setModalVisible(true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const openModal =async (type:'delete',entity?:DataMaskStrategyItem)=>{
|
||||
if(entity?.publishStatus === 'online'){
|
||||
return deletePolicy(entity!).then((res)=>{if(res === true) manualReloadTable()})
|
||||
|
||||
const openModal = async (type: 'delete', entity?: DataMaskStrategyItem) => {
|
||||
if (entity?.publishStatus === 'online') {
|
||||
return deletePolicy(entity!).then((res) => { if (res === true) manualReloadTable() })
|
||||
}
|
||||
let title:string = ''
|
||||
let content:string|React.ReactNode = ''
|
||||
switch (type){
|
||||
case 'delete':
|
||||
title=$t('删除')
|
||||
content=$t(DELETE_TIPS.default)
|
||||
break;
|
||||
let title: string = ''
|
||||
let content: string | React.ReactNode = ''
|
||||
switch (type) {
|
||||
case 'delete':
|
||||
title = $t('删除')
|
||||
content = $t(DELETE_TIPS.default)
|
||||
break;
|
||||
}
|
||||
|
||||
modal.confirm({
|
||||
title,
|
||||
content,
|
||||
onOk:()=>{
|
||||
switch (type){
|
||||
case 'delete':
|
||||
return deletePolicy(entity!).then((res)=>{if(res === true) manualReloadTable()})
|
||||
}
|
||||
},
|
||||
width:600,
|
||||
okText:$t('确认'),
|
||||
okButtonProps:{
|
||||
disabled : !checkAccess( `${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`, accessData)
|
||||
},
|
||||
cancelText:$t('取消'),
|
||||
closable:true,
|
||||
icon:<></>,
|
||||
title,
|
||||
content,
|
||||
onOk: () => {
|
||||
switch (type) {
|
||||
case 'delete':
|
||||
return deletePolicy(entity!).then((res) => { if (res === true) manualReloadTable() })
|
||||
}
|
||||
},
|
||||
width: 600,
|
||||
okText: $t('确认'),
|
||||
okButtonProps: {
|
||||
disabled: !checkAccess(`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.edit`, accessData)
|
||||
},
|
||||
cancelText: $t('取消'),
|
||||
closable: true,
|
||||
icon: <></>,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
@@ -268,13 +279,14 @@ const DataMasking = (props: any) => {
|
||||
*/
|
||||
const deletePolicy = (entity: DataMaskStrategyItem) => {
|
||||
return fetchData<BasicResponse<null>>(
|
||||
`strategy/${serviceId === undefined? 'global':'service'}/data-masking`,
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
eoParams: {
|
||||
service:serviceId,
|
||||
team:teamId,
|
||||
strategy:entity.id},
|
||||
eoParams: {
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
strategy: entity.id
|
||||
},
|
||||
}
|
||||
).then(response => {
|
||||
const { code, msg } = response
|
||||
@@ -285,7 +297,7 @@ const DataMasking = (props: any) => {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
return Promise.reject(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).catch((errorInfo)=> Promise.reject(errorInfo))
|
||||
}).catch((errorInfo) => Promise.reject(errorInfo))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,13 +306,14 @@ const DataMasking = (props: any) => {
|
||||
*/
|
||||
const restorePolicy = (entity: any) => {
|
||||
fetchData<BasicResponse<null>>(
|
||||
`strategy/${serviceId === undefined? 'global':'service'}/data-masking/restore`,
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/restore`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
eoParams: {
|
||||
service:serviceId,
|
||||
team:teamId,
|
||||
strategy:entity.id},
|
||||
eoParams: {
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
strategy: entity.id
|
||||
},
|
||||
}
|
||||
).then(response => {
|
||||
const { code, msg } = response
|
||||
@@ -313,13 +326,13 @@ const DataMasking = (props: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
const onSubmit = () => {
|
||||
return drawerRef.current?.publish()?.then((res) => {
|
||||
manualReloadTable();
|
||||
return res;
|
||||
});
|
||||
}
|
||||
return drawerRef.current?.publish()?.then((res) => {
|
||||
manualReloadTable();
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -331,38 +344,51 @@ const DataMasking = (props: any) => {
|
||||
pageSize: number;
|
||||
current: number;
|
||||
},
|
||||
sort:Record<string, string>,
|
||||
filter:Record<string, string>) => getPolicyList(params,sort, filter)}
|
||||
sort: Record<string, string>,
|
||||
filter: Record<string, string>) => getPolicyList(params, sort, filter)}
|
||||
addNewBtnTitle={$t("添加策略")}
|
||||
addNewBtnAccess={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.edit`}
|
||||
addNewBtnAccess={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.edit`}
|
||||
onAddNewBtnClick={() => { addPolicy() }}
|
||||
searchPlaceholder={$t("输入名称、筛选条件查找")}
|
||||
afterNewBtn={
|
||||
publishBtn && [<WithPermission key="removeFromDepPermission" access={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.publish`} >
|
||||
publishBtn && [<WithPermission key="removeFromDepPermission" access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.publish`} >
|
||||
<Button className="mr-btnbase" key="removeFromDep" onClick={() => publish()}>{$t('发布')}</Button>
|
||||
</WithPermission>]
|
||||
</WithPermission>]
|
||||
}
|
||||
onSearchWordChange={(e) => {
|
||||
setSearchWord(e.target.value)
|
||||
}}
|
||||
manualReloadTable={manualReloadTable}
|
||||
/>
|
||||
<DrawerWithFooter
|
||||
destroyOnClose={true}
|
||||
title={$t('申请发布')}
|
||||
width={'60%'}
|
||||
onClose={()=>{setDrawerVisible(false)}}
|
||||
okBtnTitle={$t('发布')}
|
||||
open={drawerVisible}
|
||||
submitDisabled={!isOkToPublish}
|
||||
submitAccess={`${ serviceId === undefined ? 'system.devops':'team.service'}.policy.publish`}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<PolicyPublishModalContent
|
||||
ref={drawerRef}
|
||||
data={drawerData! }
|
||||
/>
|
||||
</DrawerWithFooter>
|
||||
<DrawerWithFooter
|
||||
destroyOnClose={true}
|
||||
title={$t('申请发布')}
|
||||
width={'60%'}
|
||||
onClose={() => { setDrawerVisible(false) }}
|
||||
okBtnTitle={$t('发布')}
|
||||
open={drawerVisible}
|
||||
submitDisabled={!isOkToPublish}
|
||||
submitAccess={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.publish`}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<PolicyPublishModalContent
|
||||
ref={drawerRef}
|
||||
data={drawerData!}
|
||||
/>
|
||||
</DrawerWithFooter>
|
||||
<Modal
|
||||
title={$t('处理日志')}
|
||||
visible={modalVisible}
|
||||
onCancel={handleCloseModal}
|
||||
footer={null}
|
||||
wrapClassName="modal-without-footer"
|
||||
width={1000}
|
||||
maskClosable={true}
|
||||
>
|
||||
<div className="pb-btnybase flex flex-nowrap flex-col h-full w-full items-center justify-between">
|
||||
<DataMaskingLogModal strategy={strategy}></DataMaskingLogModal>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { $t } from "@common/locales";
|
||||
import { StrategyStatusEnum, StrategyStatusColorClass } from "@common/const/policy/consts";
|
||||
|
||||
|
||||
export const DATA_MASSKING_TABLE_COLUMNS: PageProColumns<any>[] = [
|
||||
export const DATA_MASKING_TABLE_COLUMNS: PageProColumns<any>[] = [
|
||||
{
|
||||
title: ('策略名称'),
|
||||
dataIndex: 'name',
|
||||
@@ -67,3 +67,41 @@ export const DATA_MASSKING_TABLE_COLUMNS: PageProColumns<any>[] = [
|
||||
sorter: (a, b) => frontendTimeSorter(a, b, 'updateTime')
|
||||
},
|
||||
];
|
||||
export const DATA_MASKING_TABLE_LOG_COLUMNS: PageProColumns<any>[] = [
|
||||
{
|
||||
title: ('服务'),
|
||||
dataIndex: ['service', 'name'],
|
||||
ellipsis: true,
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: ('调用地址'),
|
||||
dataIndex: 'url',
|
||||
ellipsis: true,
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: ('消费者IP'),
|
||||
dataIndex: 'remote_ip',
|
||||
ellipsis: true,
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: ('消费者'),
|
||||
dataIndex: ['consumer', 'name'],
|
||||
ellipsis: true,
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: ('鉴权名称'),
|
||||
dataIndex: 'authorization',
|
||||
ellipsis: true,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: ('时间'),
|
||||
dataIndex: 'record_time',
|
||||
width: 150,
|
||||
ellipsis: true
|
||||
},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Codebox } 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 { useFetch } from "@common/hooks/http";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LoadingOutlined } from "@ant-design/icons";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
type LogItems = {
|
||||
id: string;
|
||||
origin: string;
|
||||
target: string;
|
||||
}
|
||||
const DataMaskingCompare = () => {
|
||||
const { logId, serviceId, teamId } = useParams();
|
||||
const { fetchData } = useFetch()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [originValue, setOriginValue] = useState('')
|
||||
const [targetValue, settTargetValue] = useState('')
|
||||
const getLogData = () => {
|
||||
setLoading(true)
|
||||
return fetchData<BasicResponse<{ log: LogItems }>>(`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/log`,
|
||||
{
|
||||
method: 'GET',
|
||||
eoParams: {
|
||||
log: logId,
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
}
|
||||
}).then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
const { log } = data
|
||||
setOriginValue(log.origin || '')
|
||||
settTargetValue(log.target || '')
|
||||
setLoading(false)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
}).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)
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
getLogData()
|
||||
}, []);
|
||||
return (
|
||||
<Spin wrapperClassName=" h-full flex-1" indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} spinning={loading}>
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<div className="w-1/2 p-2 h-full">
|
||||
<div className="h-[30px] bg-gray-200 mb-2 flex items-center justify-center">
|
||||
脱敏前
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
language='json'
|
||||
height="100%"
|
||||
width="100%"
|
||||
value={originValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-1/2 p-2 h-full">
|
||||
<div className="h-[30px] bg-green-100 mb-2 flex items-center justify-center">
|
||||
脱敏后
|
||||
</div>
|
||||
<div style={{ height: 'calc(100vh - 50px)' }}>
|
||||
<Codebox
|
||||
language='json'
|
||||
width="100%"
|
||||
height="100%"
|
||||
value={targetValue}
|
||||
sx={{ whiteSpace: 'nowrap' }}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
export default DataMaskingCompare;
|
||||
@@ -0,0 +1,373 @@
|
||||
import React, { useEffect, 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 { DATA_MASKING_TABLE_LOG_COLUMNS, DATA_MASKING_TABLE_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;
|
||||
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 { fetchData } = useFetch()
|
||||
/**
|
||||
* 列表ref
|
||||
*/
|
||||
const pageListRef = useRef<ActionType>(null);
|
||||
/**
|
||||
* 搜索关键字
|
||||
*/
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
/**
|
||||
* 操作列
|
||||
*/
|
||||
const operation: PageProColumns<any>[] = [
|
||||
{
|
||||
title: '操作',
|
||||
key: 'option',
|
||||
btnNums: 1,
|
||||
fixed: 'right',
|
||||
valueType: 'option',
|
||||
render: (_: React.ReactNode, entity: any) => {
|
||||
let url = `/dataMaskCompare/${entity.id}`
|
||||
if (serviceId) {
|
||||
url += `/${serviceId}`
|
||||
}
|
||||
if (teamId) {
|
||||
url += `/${teamId}`
|
||||
}
|
||||
return [
|
||||
<TableBtnWithPermission access={`${serviceId === undefined ? 'system.devops' : 'team.service'}.policy.view`} key="view" btnType="view" onClick={() => { window.open(url,'_blank') }} btnTitle="查看" />
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
/**
|
||||
* 手动刷新表格数据
|
||||
*/
|
||||
const manualReloadTable = () => {
|
||||
pageListRef.current?.reload()
|
||||
};
|
||||
const columns = useMemo(() => {
|
||||
const res = DATA_MASKING_TABLE_LOG_COLUMNS.map(x => {
|
||||
if (x.dataIndex === 'url') {
|
||||
x.render = (text: any, record: any) => <><span className='text-green-500'>{record.method}</span> <span>{text}</span></>
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
title: typeof x.title === 'string' ? $t(x.title as string) : x.title
|
||||
}
|
||||
})
|
||||
return res
|
||||
}, [state.language])
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
* @param dataType
|
||||
* @returns
|
||||
*/
|
||||
const getPolicyList = (params: DataMaskLogItem & {
|
||||
pageSize: number;
|
||||
current: number;
|
||||
}) => {
|
||||
return fetchData<BasicResponse<{ logs: DataMaskLogItem[], total: number }>>(
|
||||
`strategy/${serviceId === undefined ? 'global' : 'service'}/data-masking/list`,
|
||||
{
|
||||
method: 'GET',
|
||||
eoParams: {
|
||||
keyword: searchWord,
|
||||
begin: queryData?.start,
|
||||
end: queryData?.end,
|
||||
page: params.current,
|
||||
page_size: params.pageSize,
|
||||
strategy: strategy,
|
||||
service: serviceId,
|
||||
team: teamId,
|
||||
},
|
||||
eoTransformKeys: ['is_stop', 'is_delete', 'update_time', 'publish_status', 'processed_total']
|
||||
}
|
||||
).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,
|
||||
total: data.total,
|
||||
success: true
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
return { data: [], success: false }
|
||||
}
|
||||
}).catch(() => {
|
||||
return { data: [], success: false }
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
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})
|
||||
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="w-full h-full p-[20px]">
|
||||
<PageList<DataMaskLogItem>
|
||||
id="data_masking_log_list"
|
||||
ref={pageListRef}
|
||||
minVirtualHeight={400}
|
||||
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>
|
||||
</div>
|
||||
</div>]
|
||||
}
|
||||
request={async (params: DataMaskLogItem & {
|
||||
pageSize: number;
|
||||
current: number;
|
||||
}) => getPolicyList(params)}
|
||||
searchPlaceholder={$t("输入调用地址、消费者IP和消费者条件查找")}
|
||||
onSearchWordChange={(e) => {
|
||||
setSearchWord(e.target.value)
|
||||
}}
|
||||
manualReloadTable={manualReloadTable}
|
||||
></PageList>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
};
|
||||
export default DataMaskingLogModal;
|
||||
Reference in New Issue
Block a user