Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-bi
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-bi
Commits
b5a25e0b
提交
b5a25e0b
authored
3月 24, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore: update
上级
28abbff8
全部展开
显示空白字符变更
内嵌
并排
正在显示
44 个修改的文件
包含
1042 行增加
和
162 行删除
+1042
-162
base.ts
src/api/base.ts
+0
-0
data.ts
src/api/data.ts
+36
-0
ChartWrap.tsx
src/components/chart/ChartWrap.tsx
+4
-3
ViewDataButtonModal.tsx
src/components/data/ViewDataButtonModal.tsx
+2
-2
ViewMyDataButtonModal.tsx
src/components/data/ViewMyDataButtonModal.tsx
+32
-0
useQuery.ts
src/hooks/useQuery.ts
+52
-3
Index.tsx
src/modules/data/chart/bar/views/Index.tsx
+1
-1
Index.tsx
src/modules/data/chart/line/views/Index.tsx
+1
-1
Index.tsx
src/modules/data/chart/pie/views/Index.tsx
+1
-1
Index.tsx
src/modules/data/chart/radar/views/Index.tsx
+1
-1
ButtonModal.tsx
src/modules/data/preprocess/error/components/ButtonModal.tsx
+4
-4
ButtonModal.tsx
src/modules/data/preprocess/max/components/ButtonModal.tsx
+4
-4
ButtonModal.tsx
src/modules/data/preprocess/min/components/ButtonModal.tsx
+4
-4
api.ts
src/modules/data/preprocess/null/api.ts
+7
-0
ButtonModal.tsx
src/modules/data/preprocess/null/components/ButtonModal.tsx
+63
-52
query.ts
src/modules/data/preprocess/null/query.ts
+24
-0
types.ts
src/modules/data/preprocess/null/types.ts
+7
-0
ButtonModal.tsx
src/modules/data/preprocess/space/components/ButtonModal.tsx
+4
-4
ButtonModal.tsx
src/modules/data/preprocess/split/components/ButtonModal.tsx
+4
-4
ButtonModal.tsx
...modules/data/preprocess/symbol/components/ButtonModal.tsx
+4
-4
api.ts
src/modules/data/process/binning/api.ts
+7
-0
ButtonModal.tsx
src/modules/data/process/binning/components/ButtonModal.tsx
+0
-0
query.ts
src/modules/data/process/binning/query.ts
+24
-0
types.ts
src/modules/data/process/binning/types.ts
+7
-0
api.ts
src/modules/data/process/date/api.ts
+7
-0
ButtonModal.tsx
src/modules/data/process/date/components/ButtonModal.tsx
+281
-0
query.ts
src/modules/data/process/date/query.ts
+24
-0
types.ts
src/modules/data/process/date/types.ts
+11
-0
Index.tsx
src/modules/data/process/date/views/Index.tsx
+3
-2
api.ts
src/modules/data/process/desensitization/api.ts
+7
-0
ButtonModal.tsx
...s/data/process/desensitization/components/ButtonModal.tsx
+0
-0
query.ts
src/modules/data/process/desensitization/query.ts
+24
-0
types.ts
src/modules/data/process/desensitization/types.ts
+11
-0
Index.tsx
src/modules/data/process/desensitization/views/Index.tsx
+3
-2
api.ts
src/modules/data/process/group/api.ts
+7
-0
ButtonModal.tsx
src/modules/data/process/group/components/ButtonModal.tsx
+247
-0
query.ts
src/modules/data/process/group/query.ts
+24
-0
types.ts
src/modules/data/process/group/types.ts
+6
-0
Index.tsx
src/modules/data/process/group/views/Index.tsx
+3
-2
api.ts
src/modules/data/process/mapping/api.ts
+7
-0
ButtonModal.tsx
src/modules/data/process/mapping/components/ButtonModal.tsx
+51
-65
query.ts
src/modules/data/process/mapping/query.ts
+24
-0
types.ts
src/modules/data/process/mapping/types.ts
+6
-0
axios.ts
src/utils/axios.ts
+3
-3
没有找到文件。
src/api/base.ts
浏览文件 @
b5a25e0b
差异被折叠。
点击展开。
src/api/data.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
// 我的数据集列表
export
function
getMyList
(
params
?:
Partial
<
{
page
:
number
;
'per-page'
:
number
}
>
)
{
return
httpRequest
.
get
(
'/api/resource/bi/v1/data/my/list'
,
{
params
})
}
// 查看字段详情
export
function
getMyField
()
{
return
httpRequest
.
get
(
'/api/resource/bi/v1/data/my/field-detail'
)
}
// 进度查询
export
function
getProcessProgress
(
params
:
{
function_name
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/bi/v1/processing/processing/progress'
,
{
params
})
}
// 数据可视化组件列表
export
function
getComponentList
(
params
?:
Partial
<
{
page
:
number
;
'per-page'
:
number
;
type
:
string
}
>
)
{
return
httpRequest
.
get
(
'/api/resource/bi/v1/reporting/component/list'
,
{
params
})
}
// 更新数据可视化组件
export
function
updateComponent
(
data
:
{
id
:
string
;
name
:
string
;
type
:
string
;
content
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/reporting/component/list'
,
data
)
}
// 删除数据可视化组件
export
function
deleteComponent
(
data
:
{
id
:
string
})
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/reporting/component/list'
,
data
)
}
// 数据可视化组件详情
export
function
getComponent
(
params
:
{
id
:
string
})
{
return
httpRequest
.
get
(
'/api/resource/bi/v1/reporting/component/list'
,
{
params
})
}
src/components/
data
/ChartWrap.tsx
→
src/components/
chart
/ChartWrap.tsx
浏览文件 @
b5a25e0b
import
{
Button
,
Card
,
Flex
}
from
'antd'
import
{
ReactNode
}
from
'react'
import
AppList
,
{
AppListProps
}
from
'@/components/AppList'
import
{
getChartList
}
from
'@/api/base'
import
ViewDataButtonModal
from
'../data/ViewMyDataButtonModal'
import
{
getComponentList
}
from
'@/api/data'
export
default
function
DataWrap
({
title
,
buttons
}:
{
title
:
string
;
buttons
:
ReactNode
;
children
?:
ReactNode
})
{
const
listOptions
:
AppListProps
=
{
fetchApi
:
async
(
params
)
=>
{
const
{
data
}
=
await
getC
har
tList
(
params
)
const
{
data
}
=
await
getC
omponen
tList
(
params
)
return
{
...
data
}
},
columns
:
[
...
...
@@ -54,7 +55,7 @@ export default function DataWrap({ title, buttons }: { title: string; buttons: R
<
Flex
wrap
gap=
{
10
}
>
{
buttons
}
</
Flex
>
<
Button
>
查看我的数据集
</
Button
>
<
ViewDataButtonModal
></
ViewDataButtonModal
>
</
Flex
>
<
AppList
{
...
listOptions
}
/>
</
Card
>
...
...
src/components/data/ViewDataButtonModal.tsx
浏览文件 @
b5a25e0b
import
{
useEffect
,
useState
}
from
'react'
import
{
Button
,
Flex
,
Modal
}
from
'antd'
import
axios
from
'axios'
import
DataRender
from
'./DataRender'
import
{
read
,
utils
}
from
'xlsx'
import
{
uniqueId
}
from
'lodash-es'
import
axios
from
'axios'
import
DataRender
from
'./DataRender'
export
default
function
ViewDataButtonModal
({
data
}:
{
data
:
any
})
{
const
[
open
,
setOpen
]
=
useState
(
false
)
...
...
src/components/data/ViewMyDataButtonModal.tsx
0 → 100644
浏览文件 @
b5a25e0b
import
{
useState
}
from
'react'
import
{
Button
,
Flex
,
Modal
}
from
'antd'
import
{
useDataQuery
}
from
'@/hooks/useQuery'
import
DataRender
from
'./DataRender'
export
default
function
ViewDataButtonModal
()
{
const
[
open
,
setOpen
]
=
useState
(
false
)
const
{
data
,
isPending
}
=
useDataQuery
()
const
columns
:
any
=
data
.
title
.
map
((
item
:
any
)
=>
{
return
{
title
:
item
.
name
,
dataIndex
:
item
.
english_name
,
align
:
'center'
,
minWidth
:
120
,
}
})
return
(
<>
<
Button
onClick=
{
()
=>
setOpen
(
true
)
}
>
查看我的数据集
</
Button
>
<
Modal
title=
"查看我的数据集"
width=
{
'80%'
}
open=
{
open
}
footer=
{
null
}
onCancel=
{
()
=>
setOpen
(
false
)
}
>
<
Flex
justify=
"space-between"
style=
{
{
marginBottom
:
20
}
}
>
<
div
>
数据集名称:
{
data
.
info
?.
name
}
</
div
>
<
div
>
共计:
{
data
.
total
}
条数据
</
div
>
</
Flex
>
<
DataRender
rowKey=
{
'pk_id'
}
loading=
{
isPending
}
dataSource=
{
data
.
list
}
columns=
{
columns
}
/>
</
Modal
>
</>
)
}
src/hooks/useQuery.ts
浏览文件 @
b5a25e0b
import
{
useEffect
}
from
'react'
import
{
useEffect
,
useState
}
from
'react'
import
{
useQuery
}
from
'@tanstack/react-query'
import
{
getUser
,
getMapList
,
getMyList
,
getMyField
}
from
'@/api/base'
import
{
getUser
,
getMapList
,
getMyList
,
getMyField
,
getProcessProgress
}
from
'@/api/base'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useMapStore
}
from
'@/stores/map'
import
axios
from
'axios'
import
{
read
,
utils
}
from
'xlsx'
// 用户信息
export
function
useUserQuery
()
{
const
{
setUser
}
=
useUserStore
()
...
...
@@ -20,6 +21,7 @@ export function useUserQuery() {
return
query
}
// 字典
export
function
useMapQuery
()
{
const
{
setMap
}
=
useMapStore
()
...
...
@@ -53,6 +55,7 @@ export function useDataQuery() {
return
query
}
// 读取excel文件
export
function
useExcelQuery
(
url
:
string
)
{
const
query
=
useQuery
({
queryKey
:
[
'excel'
,
url
],
...
...
@@ -80,6 +83,7 @@ interface DataField {
type
:
string
}
// 字段
export
function
useDataFieldQuery
()
{
const
query
=
useQuery
({
queryKey
:
[
'dataFiled'
],
...
...
@@ -89,6 +93,51 @@ export function useDataFieldQuery() {
return
{
data
:
[]
}
},
})
const
fields
=
query
.
data
?.
map
((
item
)
=>
{
return
{
...
item
,
label
:
item
.
name
,
value
:
item
.
english_name
}
})
||
[]
return
query
const
getFieldName
=
(
value
:
string
)
=>
{
return
fields
.
find
((
item
)
=>
item
.
value
===
value
)?.
label
||
value
}
const
getFieldNames
=
(
values
:
string
[])
=>
{
return
values
.
map
((
value
)
=>
getFieldName
(
value
))
}
return
{
...
query
,
fields
,
fieldOptions
:
fields
,
getFieldName
,
getFieldNames
}
}
// 进度查询
export
function
useProcessProgressQuery
(
params
:
{
function_name
:
string
})
{
const
[
enabled
,
setEnabled
]
=
useState
(
false
)
const
query
=
useQuery
({
queryKey
:
[
'processProgress'
,
params
],
queryFn
:
()
=>
{
return
getProcessProgress
(
params
)
},
select
:
(
res
)
=>
res
.
data
,
enabled
,
refetchInterval
:
enabled
?
1000
:
false
,
})
// 开始轮询的方法
const
start
=
()
=>
{
setEnabled
(
true
)
}
// 结束轮询的方法
const
stop
=
()
=>
{
setEnabled
(
false
)
}
// 组件卸载时清理
useEffect
(()
=>
{
return
()
=>
{
stop
()
}
},
[])
return
{
...
query
,
start
,
stop
}
}
src/modules/data/chart/bar/views/Index.tsx
浏览文件 @
b5a25e0b
import
{
lazy
}
from
'react'
import
ChartWrap
from
'@/components/
data
/ChartWrap'
import
ChartWrap
from
'@/components/
chart
/ChartWrap'
const
ButtonModal
=
lazy
(()
=>
import
(
'../components/ButtonModal'
))
...
...
src/modules/data/chart/line/views/Index.tsx
浏览文件 @
b5a25e0b
import
ChartWrap
from
'@/components/
data
/ChartWrap'
import
ChartWrap
from
'@/components/
chart
/ChartWrap'
import
{
Button
}
from
'antd'
export
default
function
DataProcess
()
{
...
...
src/modules/data/chart/pie/views/Index.tsx
浏览文件 @
b5a25e0b
import
ChartWrap
from
'@/components/
data
/ChartWrap'
import
ChartWrap
from
'@/components/
chart
/ChartWrap'
import
{
Button
}
from
'antd'
export
default
function
DataProcess
()
{
...
...
src/modules/data/chart/radar/views/Index.tsx
浏览文件 @
b5a25e0b
import
ChartWrap
from
'@/components/
data
/ChartWrap'
import
ChartWrap
from
'@/components/
chart
/ChartWrap'
import
{
Button
}
from
'antd'
export
default
function
DataProcess
()
{
...
...
src/modules/data/preprocess/error/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -27,7 +27,7 @@ export default function ButtonModal() {
})
}
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
useEffect
(()
=>
{
...
...
@@ -59,9 +59,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择逻辑错误值字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/preprocess/max/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -27,7 +27,7 @@ export default function ButtonModal() {
})
}
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
useEffect
(()
=>
{
...
...
@@ -59,9 +59,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择过大值字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/preprocess/min/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -27,7 +27,7 @@ export default function ButtonModal() {
})
}
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
useEffect
(()
=>
{
...
...
@@ -59,9 +59,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择过小值字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/preprocess/null/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 缺省值处理
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/pre-processing/missing'
,
data
)
}
src/modules/data/preprocess/null/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -5,6 +5,22 @@ import AppProgressSteps from '@/components/AppProgressSteps'
import
{
useSearchParams
}
from
'react-router'
import
{
useAI
}
from
'@/hooks/useAI'
import
prompt
from
'@/utils/prompt'
import
{
useProcessData
}
from
'../query'
const
actionOptions
=
[
{
label
:
'统一规则处理'
,
value
:
'统一规则处理'
},
{
label
:
'逐个配置规则处理'
,
value
:
'逐个配置规则处理'
},
]
const
ruleOptions
=
[
{
label
:
'不处理'
,
value
:
'不处理'
},
{
label
:
'AI智能填充'
,
value
:
'AI智能填充'
},
{
label
:
'删除'
,
value
:
'删除'
},
{
label
:
'平均值填充'
,
value
:
'平均值填充'
},
{
label
:
'特殊值填充'
,
value
:
'特殊值填充'
},
{
label
:
'热卡填充(上)'
,
value
:
'热卡填充(上)'
},
{
label
:
'热卡填充(下)'
,
value
:
'热卡填充(下)'
},
]
export
default
function
ButtonModal
()
{
const
[
searchParams
]
=
useSearchParams
()
...
...
@@ -14,13 +30,12 @@ export default function ButtonModal() {
try
{
const
parse
=
JSON
.
parse
(
message
.
content
)
console
.
log
(
parse
)
if
(
parse
.
results
.
length
)
form
.
setFieldValue
(
'
checkedList
'
,
parse
.
results
.
map
((
item
:
any
)
=>
item
.
name
)
||
[])
if
(
parse
.
results
.
length
)
form
.
setFieldValue
(
'
fields
'
,
parse
.
results
.
map
((
item
:
any
)
=>
item
.
name
)
||
[])
}
catch
(
error
)
{
console
.
error
(
error
)
}
},
})
const
handleSearch
=
()
=>
{
post
({
response_format
:
{
type
:
'json_object'
},
...
...
@@ -28,7 +43,7 @@ export default function ButtonModal() {
})
}
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
,
getFieldName
,
getFieldNames
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
useEffect
(()
=>
{
...
...
@@ -36,46 +51,48 @@ export default function ButtonModal() {
setOpen
(
true
)
}
},
[
searchParams
])
const
[
current
,
setCurrent
]
=
useState
(
0
)
const
[
form
]
=
Form
.
useForm
()
const
initialValues
=
{
checkedList
:
searchParams
.
get
(
'results'
)?.
split
(
','
)
||
[],
method
:
'unified
'
,
rule
:
'
1
'
,
fields
:
searchParams
.
get
(
'results'
)?.
split
(
','
)
||
[],
action
:
'统一规则处理
'
,
rule
:
'
不处理
'
,
}
const
checkedList
:
string
[]
=
Form
.
useWatch
(
'checkedList
'
,
form
)
||
[]
const
method
=
Form
.
useWatch
(
'method
'
,
form
)
const
fields
:
string
[]
=
Form
.
useWatch
(
'fields
'
,
form
)
||
[]
const
action
=
Form
.
useWatch
(
'action
'
,
form
)
const
rule
=
Form
.
useWatch
(
'rule'
,
form
)
const
rules
=
Form
.
useWatch
(
'rules'
,
form
)
||
{}
const
methodOptions
=
[
{
label
:
'统一规则处理'
,
value
:
'unified'
},
{
label
:
'逐个配置规则处理'
,
value
:
'individual'
},
]
const
ruleOptions
=
[
{
label
:
'不处理'
,
value
:
'1'
},
{
label
:
'AI智能填充'
,
value
:
'2'
},
{
label
:
'删除'
,
value
:
'3'
},
{
label
:
'平均值填充'
,
value
:
'4'
},
{
label
:
'特殊值填充'
,
value
:
'5'
},
{
label
:
'热卡填充(上)'
,
value
:
'6'
},
{
label
:
'热卡填充(下)'
,
value
:
'7'
},
]
const
{
mutate
,
isPending
,
progress
,
message
}
=
useProcessData
()
// 开始处理
const
handleStart
=
()
=>
{
form
.
validateFields
().
then
((
values
)
=>
{
const
params
=
{
...
values
,
fields
:
values
.
fields
.
join
(
','
),
rules
:
JSON
.
stringify
(
values
.
rules
)
}
mutate
(
params
,
{
onSuccess
:
handleClose
,
})
})
}
const
[
step
,
setStep
]
=
useState
<
number
>
(
-
1
)
// 关闭并重置
const
handleClose
=
()
=>
{
setOpen
(
false
)
setCurrent
(
0
)
form
.
resetFields
()
}
const
steps
=
[
{
title
:
'请选择缺失值字段'
,
content
:
(
<
Form
.
Item
name=
"
checkedList
"
>
<
Form
.
Item
name=
"
fields
"
>
<
Checkbox
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Checkbox
value=
{
item
.
name
}
>
{
item
.
name
}
</
Checkbox
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Checkbox
value=
{
item
.
value
}
>
{
item
.
label
}
</
Checkbox
>
</
Col
>
))
}
</
Row
>
...
...
@@ -87,18 +104,17 @@ export default function ButtonModal() {
title
:
'配置处理规则'
,
content
:
(
<>
<
Form
.
Item
label=
"缺失值字段处理方法"
name=
"
method
"
>
<
Radio
.
Group
options=
{
method
Options
}
/>
<
Form
.
Item
label=
"缺失值字段处理方法"
name=
"
action
"
>
<
Radio
.
Group
options=
{
action
Options
}
/>
</
Form
.
Item
>
{
/* 统一规则处理 */
}
{
method
===
'unified'
&&
(
{
action
===
'统一规则处理'
&&
(
<>
<
Form
.
Item
label=
"缺失值字段处理规则"
name=
"rule"
>
<
Select
options=
{
ruleOptions
}
/>
</
Form
.
Item
>
{
rule
===
'
5
'
&&
(
{
rule
===
'
特殊值填充
'
&&
(
<
Form
.
Item
label=
"请填写特殊值"
name=
"special"
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
...
...
@@ -106,16 +122,17 @@ export default function ButtonModal() {
</>
)
}
{
/* 逐个配置规则处理 */
}
{
method
===
'individual'
&&
checkedList
.
map
((
field
)
=>
(
{
action
===
'逐个配置规则处理'
&&
fields
.
map
((
field
,
index
)
=>
(
<
div
key=
{
field
}
style=
{
{
marginBottom
:
10
}
}
>
<
Form
.
Item
label=
"字段"
>
{
field
}
</
Form
.
Item
>
<
Form
.
Item
label=
"缺失值字段处理规则"
name=
{
[
'rules'
,
field
,
'rule'
]
}
>
<
Form
.
Item
label=
"字段"
name=
{
[
'rules'
,
index
,
'field'
]
}
initialValue=
{
field
}
>
<
span
>
{
getFieldName
(
field
)
}
</
span
>
</
Form
.
Item
>
<
Form
.
Item
label=
"缺失值字段处理规则"
name=
{
[
'rules'
,
index
,
'rule'
]
}
>
<
Select
options=
{
ruleOptions
}
/>
</
Form
.
Item
>
{
rules
[
field
]?.
rule
===
'5
'
&&
(
<
Form
.
Item
label=
"请填写特殊值"
name=
{
[
'rules'
,
field
,
'special'
]
}
>
{
rules
[
index
]?.
rule
===
'特殊值填充
'
&&
(
<
Form
.
Item
label=
"请填写特殊值"
name=
{
[
'rules'
,
index
,
'special'
]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
)
}
...
...
@@ -129,14 +146,14 @@ export default function ButtonModal() {
title
:
'处理执行'
,
content
:
(
<>
<
p
>
缺失值处理字段:
{
checkedList
.
join
(
',
'
)
}
</
p
>
<
p
>
缺失值处理字段:
{
getFieldNames
(
fields
).
join
(
'、
'
)
}
</
p
>
<
Flex
vertical
align=
"center"
style=
{
{
marginTop
:
'20px'
}
}
>
<
Button
type=
"primary"
onClick=
{
()
=>
setStep
(
1
)
}
>
<
Button
type=
"primary"
loading=
{
isPending
}
onClick=
{
handleStart
}
>
开始处理
</
Button
>
<
AppProgressSteps
style=
{
{
margin
:
'80px'
}
}
current=
{
step
}
current=
{
progress
}
items=
{
[
{
title
:
(
...
...
@@ -164,13 +181,7 @@ export default function ButtonModal() {
处理结果
</>
),
description
:
(
<>
累计处理XX个字段
<
br
/>
累计处理XX条记录
</>
),
description
:
<>
{
message
[
3
]
}
</>,
},
]
}
/>
...
...
@@ -197,12 +208,12 @@ export default function ButtonModal() {
)
}
{
current
>
0
&&
<
Button
onClick=
{
()
=>
setCurrent
(
current
-
1
)
}
>
上一步
</
Button
>
}
{
current
<
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
()
=>
setCurrent
(
current
+
1
)
}
disabled=
{
!
checkedList
.
length
}
>
<
Button
type=
"primary"
onClick=
{
()
=>
setCurrent
(
current
+
1
)
}
disabled=
{
!
fields
.
length
}
>
下一步
</
Button
>
)
}
{
current
===
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
()
=>
setOpen
(
false
)
}
>
<
Button
type=
"primary"
disabled=
{
isPending
}
onClick=
{
handleClose
}
>
关闭
</
Button
>
)
}
...
...
@@ -210,7 +221,7 @@ export default function ButtonModal() {
}
destroyOnClose
width=
{
800
}
onCancel=
{
()
=>
setOpen
(
false
)
}
>
onCancel=
{
handleClose
}
>
<
div
style=
{
{
minHeight
:
300
,
padding
:
'20px 0'
}
}
>
<
Form
form=
{
form
}
labelCol=
{
{
span
:
5
}
}
preserve=
{
false
}
initialValues=
{
initialValues
}
>
{
steps
.
map
((
item
,
index
)
=>
(
...
...
src/modules/data/preprocess/null/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'missing'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/preprocess/null/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
fields
:
string
action
:
string
rules
:
string
rule
:
string
specify
:
string
}
src/modules/data/preprocess/space/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -24,7 +24,7 @@ export default function ButtonModal() {
})
}
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
...
...
@@ -53,9 +53,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择数据去空格字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/preprocess/split/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -4,7 +4,7 @@ import { useDataFieldQuery } from '@/hooks/useQuery'
import
AppProgressSteps
from
'@/components/AppProgressSteps'
export
default
function
ButtonModal
()
{
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
...
...
@@ -34,9 +34,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择数据拆分字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/preprocess/symbol/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
...
...
@@ -4,7 +4,7 @@ import { useDataFieldQuery } from '@/hooks/useQuery'
import
AppProgressSteps
from
'@/components/AppProgressSteps'
export
default
function
ButtonModal
()
{
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
fieldOptions
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
...
...
@@ -26,9 +26,9 @@ export default function ButtonModal() {
<
Form
.
Item
name=
"checked"
rules=
{
[{
required
:
true
,
message
:
'请选择去标点字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
6
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
src/modules/data/process/binning/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 数据分箱
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/processing/binning'
,
data
)
}
src/modules/data/process/binning/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
差异被折叠。
点击展开。
src/modules/data/process/binning/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'mapping'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/process/binning/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
name
:
string
english_name
:
string
field
:
string
rule
:
string
action
:
string
}
src/modules/data/process/date/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 数据分箱
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/processing/anonymization'
,
data
)
}
src/modules/data/process/date/components/ButtonModal.tsx
0 → 100644
浏览文件 @
b5a25e0b
import
{
useState
}
from
'react'
import
{
Button
,
Flex
,
Modal
,
Radio
,
Input
,
Form
,
Row
,
Col
,
Space
,
Select
}
from
'antd'
import
{
useDataFieldQuery
}
from
'@/hooks/useQuery'
import
AppProgressSteps
from
'@/components/AppProgressSteps'
import
{
useProcessData
}
from
'../query'
const
functionShortcutOptions
=
[
{
label
:
'获取“年份”信息'
,
value
:
'YEAR'
,
demo
:
'如:“2025年”'
,
},
// {
// label: '获取“季度”信息',
// value: 'YEAR',
// demo: '如:“一季度”',
// },
// {
// label: '获取“年季度”信息',
// value: 'YEAR',
// demo: '如:“2025年一季度”',
// },
{
label
:
'获取“月份”信息'
,
value
:
'MONTH'
,
demo
:
'如:“3月”'
,
},
{
label
:
'获取“年月份”信息'
,
value
:
'DATE'
,
demo
:
'如:“2025年3月”'
,
},
{
label
:
'获取“周”信息'
,
value
:
'NETWORKDAYS'
,
demo
:
'如:“12周”'
,
},
// {
// label: '获取“年周”信息',
// value: 'YEAR',
// demo: '如:“2025年12周”',
// },
{
label
:
'获取“日”信息'
,
value
:
'DAY'
,
demo
:
'如:“21日”'
,
},
{
label
:
'获取“小时”信息'
,
value
:
'HOUR'
,
demo
:
'如:“12时”'
,
},
{
label
:
'获取“分钟”信息'
,
value
:
'MINUTE'
,
demo
:
'如:“21分”'
,
},
{
label
:
'获取“秒”信息'
,
value
:
'SECOND'
,
demo
:
'如:“18秒”'
,
},
]
const
functionOptions
=
[
{
label
:
'DATE:组合年、月、日为标准日期'
,
value
:
'DATE'
},
{
label
:
'DATEDIF:计算两个日期间的年/月/日差值'
,
value
:
'DATEDIF'
},
{
label
:
'DATEVALUE:将文本日期转换为 Excel 可识别的序列号'
,
value
:
'DATEVALUE'
},
{
label
:
'DAY:提取日期中的“日”部分'
,
value
:
'DAY'
},
{
label
:
'EDATE:返回指定日期之前/之后几个月的日期'
,
value
:
'EDATE'
},
{
label
:
'EMONTH:返回指定日期之前/之后几个月的最后一天'
,
value
:
'EMONTH'
},
{
label
:
'HOUR:提取时间中的“小时”部分'
,
value
:
'HOUR'
},
{
label
:
'MINUTE:提取时间中的“分钟”部分'
,
value
:
'MINUTE'
},
{
label
:
'MONTH:提取日期中的“月”部分'
,
value
:
'MONTH'
},
{
label
:
'NETWORKDAYS:计算两个日期之间的工作日天数(排除周末和节假日)'
,
value
:
'NETWORKDAYS'
},
{
label
:
'NOW:返回当前日期和时间(精确到秒)'
,
value
:
'NOW'
},
{
label
:
'SECOND:提取时间中的“秒”部分'
,
value
:
'SECOND'
},
{
label
:
'TIME:组合时、分、秒为标准时间'
,
value
:
'TIME'
},
{
label
:
'TIMEVALUE:将文本时间转换为小数'
,
value
:
'TIMEVALUE'
},
{
label
:
'TODAY:返回当前系统日期(无参数)'
,
value
:
'TODAY'
},
{
label
:
'WEEKDAY:返回日期对应的星期几(数字形式)'
,
value
:
'WEEKDAY'
},
{
label
:
'WORKDAY:计算指定工作日天数后的日期(跳过周末和节假日)'
,
value
:
'WORKDAY'
},
{
label
:
'YEAR:提取日期中的“年”部分'
,
value
:
'YEAR'
},
]
export
default
function
ButtonModal
()
{
const
{
fieldOptions
,
getFieldName
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
current
,
setCurrent
]
=
useState
(
0
)
const
[
form
]
=
Form
.
useForm
()
const
action
=
Form
.
useWatch
(
'action'
,
form
)
// 处理下一步按钮逻辑
const
handleNext
=
async
()
=>
{
if
(
current
===
0
)
{
// 第一步验证表单
await
form
.
validateFields
([
'name'
,
'english_name'
])
}
else
if
(
current
===
1
)
{
await
form
.
validateFields
()
}
setCurrent
(
current
+
1
)
}
const
{
mutate
,
isPending
,
progress
,
message
}
=
useProcessData
()
// 开始处理
const
handleStart
=
()
=>
{
const
values
=
form
.
getFieldsValue
()
const
params
=
{
...
values
,
rules
:
JSON
.
stringify
(
values
.
rules
),
action
:
'固定步长分箱'
}
mutate
(
params
,
{
onSuccess
:
handleClose
,
})
}
// 关闭并重置
const
handleClose
=
()
=>
{
setOpen
(
false
)
setCurrent
(
0
)
}
// 步骤定义
const
steps
=
[
{
title
:
'请选择日期计算字段'
,
content
:
(
<>
<
Form
.
Item
label=
"日期计算字段名称"
name=
"name"
rules=
{
[{
required
:
true
,
message
:
'请输入字段名称'
}]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"日期计算字段英文名称"
name=
"english_name"
rules=
{
[{
required
:
true
,
message
:
'请输入英文名称'
}]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
</>
),
},
{
title
:
'配置日期计算规则'
,
content
:
(
<>
<
Form
.
Item
label=
"请选择日期计算方法"
name=
"action"
>
<
Radio
.
Group
options=
{
[
'快速日期计算'
,
'日期函数计算'
]
}
/>
</
Form
.
Item
>
{
action
===
'快速日期计算'
&&
(
<>
<
Form
.
Item
label=
"请选择快速日期计算方法"
name=
"function"
>
<
Radio
.
Group
style=
{
{
width
:
'100%'
}
}
>
{
functionShortcutOptions
.
map
((
item
)
=>
(
<
Flex
>
<
Radio
value=
{
item
.
value
}
>
<
Space
key=
{
item
.
value
}
>
<
p
style=
{
{
minWidth
:
200
}
}
>
{
item
.
label
}
</
p
>
<
p
style=
{
{
color
:
'#999'
}
}
>
{
item
.
demo
}
</
p
>
</
Space
>
</
Radio
>
</
Flex
>
))
}
</
Radio
.
Group
>
</
Form
.
Item
>
</>
)
}
{
action
===
'日期函数计算'
&&
(
<>
<
Form
.
Item
label=
"请选择函数"
name=
"function"
>
<
Select
options=
{
functionOptions
}
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"请输入函数公式"
>
<
Flex
gap=
{
10
}
>
<
Form
.
Item
name=
"content"
noStyle
>
<
Input
.
TextArea
rows=
{
4
}
/>
</
Form
.
Item
>
<
Button
type=
"primary"
style=
{
{
height
:
100
}
}
>
添加字段
</
Button
>
</
Flex
>
</
Form
.
Item
>
</>
)
}
</>
),
},
{
title
:
'处理执行'
,
content
:
(
<>
<
Flex
vertical
align=
"center"
style=
{
{
marginTop
:
'20px'
}
}
>
<
Button
type=
"primary"
onClick=
{
handleStart
}
loading=
{
isPending
}
>
开始处理
</
Button
>
<
AppProgressSteps
style=
{
{
margin
:
'80px'
}
}
current=
{
progress
}
items=
{
[
{
title
:
(
<>
第一步
<
br
/>
新建字段
</>
),
},
{
title
:
(
<>
第二步
<
br
/>
复制数据
</>
),
},
{
title
:
(
<>
第三步
<
br
/>
日期计算处理
</>
),
},
{
title
:
(
<>
第四步
<
br
/>
处理结果
</>
),
description
:
<>
{
message
[
3
]
}
</>,
},
]
}
/>
</
Flex
>
</>
),
},
]
return
(
<>
<
Button
type=
"primary"
onClick=
{
()
=>
setOpen
(
true
)
}
>
日期计算
</
Button
>
<
Modal
title=
{
steps
[
current
]?.
title
}
open=
{
open
}
footer=
{
<
Flex
justify=
"center"
gap=
{
20
}
>
{
current
===
1
&&
action
===
'日期函数计算'
&&
<
Button
type=
"primary"
>
AI智能建议
</
Button
>
}
{
current
>
0
&&
<
Button
onClick=
{
()
=>
setCurrent
(
current
-
1
)
}
>
上一步
</
Button
>
}
{
current
<
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
handleNext
}
>
下一步
</
Button
>
)
}
{
current
===
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
handleClose
}
disabled=
{
isPending
}
>
关闭
</
Button
>
)
}
</
Flex
>
}
destroyOnClose
width=
{
800
}
onCancel=
{
handleClose
}
>
<
div
style=
{
{
minHeight
:
300
,
padding
:
'20px 0'
}
}
>
<
Form
form=
{
form
}
labelCol=
{
{
span
:
5
}
}
preserve=
{
false
}
initialValues=
{
{
action
:
'快速日期计算'
}
}
>
{
steps
.
map
((
item
,
index
)
=>
(
<
div
key=
{
index
}
hidden=
{
current
!==
index
}
style=
{
{
marginTop
:
'20px'
}
}
>
{
item
.
content
}
</
div
>
))
}
</
Form
>
</
div
>
</
Modal
>
</>
)
}
src/modules/data/process/date/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'anonymization'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/process/date/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
name
:
string
english_name
:
string
field
:
string
action
:
string
function
:
string
char
?:
string
sm_fun
?:
string
start
?:
string
end
?:
string
}
src/modules/data/process/date/views/Index.tsx
浏览文件 @
b5a25e0b
import
{
lazy
}
from
'react'
import
DataWrap
from
'@/components/data/DataWrap'
import
{
Button
}
from
'antd'
const
ButtonModal
=
lazy
(()
=>
import
(
'../components/ButtonModal'
))
export
default
function
DataProcess
()
{
return
<
DataWrap
title=
"数据加工:日期计算"
buttons=
{
<
Button
type=
"primary"
>
日期计算
</
Button
>
}
></
DataWrap
>
return
<
DataWrap
title=
"数据加工:日期计算"
buttons=
{
<
Button
Modal
/
>
}
></
DataWrap
>
}
src/modules/data/process/desensitization/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 数据分箱
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/processing/anonymization'
,
data
)
}
src/modules/data/process/desensitization/components/ButtonModal.tsx
0 → 100644
浏览文件 @
b5a25e0b
差异被折叠。
点击展开。
src/modules/data/process/desensitization/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'anonymization'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/process/desensitization/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
name
:
string
english_name
:
string
field
:
string
action
:
string
function
:
string
char
?:
string
sm_fun
?:
string
start
?:
string
end
?:
string
}
src/modules/data/process/desensitization/views/Index.tsx
浏览文件 @
b5a25e0b
import
{
lazy
}
from
'react'
import
DataWrap
from
'@/components/data/DataWrap'
import
{
Button
}
from
'antd'
const
ButtonModal
=
lazy
(()
=>
import
(
'../components/ButtonModal'
))
export
default
function
DataProcess
()
{
return
<
DataWrap
title=
"数据加工:数据脱敏"
buttons=
{
<
Button
type=
"primary"
>
数据脱敏
</
Button
>
}
></
DataWrap
>
return
<
DataWrap
title=
"数据加工:数据脱敏"
buttons=
{
<
Button
Modal
/
>
}
></
DataWrap
>
}
src/modules/data/process/group/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 数据分箱
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/processing/grouping'
,
data
)
}
src/modules/data/process/group/components/ButtonModal.tsx
0 → 100644
浏览文件 @
b5a25e0b
import
{
useEffect
,
useState
}
from
'react'
import
{
Button
,
Flex
,
Modal
,
Radio
,
Input
,
Form
,
Row
,
Col
,
Select
}
from
'antd'
import
{
useDataQuery
,
useDataFieldQuery
}
from
'@/hooks/useQuery'
import
AppProgressSteps
from
'@/components/AppProgressSteps'
import
{
useProcessData
}
from
'../query'
import
{
MinusCircleOutlined
}
from
'@ant-design/icons'
import
{
uniqBy
}
from
'lodash-es'
export
default
function
ButtonModal
()
{
const
{
data
=
{
list
:
[]
}
}
=
useDataQuery
()
const
{
fieldOptions
,
getFieldName
}
=
useDataFieldQuery
()
// 数字类型字段
const
currentFieldOptions
=
fieldOptions
.
filter
((
item
)
=>
item
.
type
.
includes
(
'VARCHAR'
))
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
current
,
setCurrent
]
=
useState
(
0
)
const
[
form
]
=
Form
.
useForm
()
const
[
dataSource
,
setDataSource
]
=
useState
<
{
key
:
number
;
label
:
string
;
value
:
string
}[]
>
([])
const
field
=
Form
.
useWatch
(
'field'
,
form
)
const
rules
=
Form
.
useWatch
(
'rules'
,
form
)
||
[]
useEffect
(()
=>
{
if
(
field
&&
data
.
list
?.
length
)
{
const
uniqList
=
uniqBy
(
data
.
list
,
field
)
setDataSource
(
uniqList
.
map
((
item
:
any
,
index
)
=>
({
key
:
index
+
1
,
label
:
item
[
field
]
||
''
,
value
:
item
[
field
]
||
''
,
}))
)
}
},
[
field
,
data
.
list
])
// 处理下一步按钮逻辑
const
handleNext
=
async
()
=>
{
if
(
current
===
0
)
{
// 第一步验证表单
await
form
.
validateFields
([
'name'
,
'english_name'
,
'field'
])
}
else
if
(
current
===
1
)
{
await
form
.
validateFields
()
}
setCurrent
(
current
+
1
)
}
const
{
mutate
,
isPending
,
progress
,
message
}
=
useProcessData
()
// 开始处理
const
handleStart
=
()
=>
{
const
values
=
form
.
getFieldsValue
()
const
params
=
{
...
values
,
rules
:
JSON
.
stringify
(
values
.
rules
.
map
((
item
:
any
)
=>
{
return
{
...
item
,
fields
:
item
.
fields
.
join
(
','
),
}
})
),
}
mutate
(
params
,
{
onSuccess
:
handleClose
,
})
}
// 关闭并重置
const
handleClose
=
()
=>
{
setOpen
(
false
)
setCurrent
(
0
)
}
const
[
groupName
,
setGroupName
]
=
useState
(
''
)
// 步骤定义
const
steps
=
[
{
title
:
'请选择数据分组字段'
,
content
:
(
<>
<
Form
.
Item
label=
"数据分组字段名称"
name=
"name"
rules=
{
[{
required
:
true
,
message
:
'请输入字段名称'
}]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"数据分组字段英文名称"
name=
"english_name"
rules=
{
[{
required
:
true
,
message
:
'请输入英文名称'
}]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"请选择数据分组字段"
name=
"field"
rules=
{
[{
required
:
true
,
message
:
'请选择数据分组字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
currentFieldOptions
.
map
((
item
)
=>
(
<
Col
span=
{
8
}
key=
{
item
.
value
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
</
Radio
.
Group
>
</
Form
.
Item
>
</>
),
},
{
title
:
'配置数据分组规则'
,
content
:
(
<>
<
Form
.
Item
label=
"数据分组操作字段"
>
{
getFieldName
(
field
)
}
</
Form
.
Item
>
<
Form
.
List
name=
"rules"
>
{
(
fields
,
{
add
,
remove
})
=>
(
<>
<
Form
.
Item
label=
"数据分组名称"
>
<
Flex
gap=
{
10
}
align=
"center"
>
<
Input
placeholder=
"请输入"
value=
{
groupName
}
onChange=
{
(
e
)
=>
setGroupName
(
e
.
target
.
value
)
}
style=
{
{
width
:
'60%'
}
}
/>
<
Button
type=
"primary"
onClick=
{
()
=>
{
if
(
!
groupName
)
return
add
({
name
:
groupName
,
fields
:
[]
})
// 添加新分组
setGroupName
(
''
)
}
}
>
添加分组
</
Button
>
</
Flex
>
</
Form
.
Item
>
{
fields
.
map
(({
key
,
name
,
...
restField
})
=>
(
<
Form
.
Item
{
...
restField
}
label=
{
rules
[
name
]?.
name
}
style=
{
{
flex
:
1
}
}
key=
{
key
}
>
<
Flex
gap=
{
10
}
>
<
Form
.
Item
name=
{
[
name
,
'fields'
]
}
noStyle
>
<
Select
options=
{
dataSource
}
mode=
"multiple"
style=
{
{
width
:
'60%'
}
}
/>
</
Form
.
Item
>
<
MinusCircleOutlined
onClick=
{
()
=>
remove
(
name
)
}
/>
</
Flex
>
</
Form
.
Item
>
))
}
</>
)
}
</
Form
.
List
>
</>
),
},
{
title
:
'处理执行'
,
content
:
(
<>
<
Flex
vertical
align=
"center"
style=
{
{
marginTop
:
'20px'
}
}
>
<
Button
type=
"primary"
onClick=
{
handleStart
}
loading=
{
isPending
}
>
开始处理
</
Button
>
<
AppProgressSteps
style=
{
{
margin
:
'80px'
}
}
current=
{
progress
}
items=
{
[
{
title
:
(
<>
第一步
<
br
/>
新建字段
</>
),
},
{
title
:
(
<>
第二步
<
br
/>
复制数据
</>
),
},
{
title
:
(
<>
第三步
<
br
/>
数据分组处理
</>
),
},
{
title
:
(
<>
第四步
<
br
/>
处理结果
</>
),
description
:
<>
{
message
[
3
]
}
</>,
},
]
}
/>
</
Flex
>
</>
),
},
]
return
(
<>
<
Button
type=
"primary"
onClick=
{
()
=>
setOpen
(
true
)
}
>
数据分组
</
Button
>
<
Modal
title=
{
steps
[
current
]?.
title
}
open=
{
open
}
footer=
{
<
Flex
justify=
"center"
gap=
{
20
}
>
{
current
===
1
&&
<
Button
type=
"primary"
>
AI智能建议
</
Button
>
}
{
current
>
0
&&
<
Button
onClick=
{
()
=>
setCurrent
(
current
-
1
)
}
>
上一步
</
Button
>
}
{
current
<
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
handleNext
}
>
下一步
</
Button
>
)
}
{
current
===
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
handleClose
}
disabled=
{
isPending
}
>
关闭
</
Button
>
)
}
</
Flex
>
}
destroyOnClose
width=
{
800
}
onCancel=
{
handleClose
}
>
<
div
style=
{
{
minHeight
:
300
,
padding
:
'20px 0'
}
}
>
<
Form
form=
{
form
}
labelCol=
{
{
span
:
5
}
}
preserve=
{
false
}
>
{
steps
.
map
((
item
,
index
)
=>
(
<
div
key=
{
index
}
hidden=
{
current
!==
index
}
style=
{
{
marginTop
:
'20px'
}
}
>
{
item
.
content
}
</
div
>
))
}
</
Form
>
</
div
>
</
Modal
>
</>
)
}
src/modules/data/process/group/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'grouping'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/process/group/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
name
:
string
english_name
:
string
field
:
string
rules
:
string
}
src/modules/data/process/group/views/Index.tsx
浏览文件 @
b5a25e0b
import
{
lazy
}
from
'react'
import
DataWrap
from
'@/components/data/DataWrap'
import
{
Button
}
from
'antd'
const
ButtonModal
=
lazy
(()
=>
import
(
'../components/ButtonModal'
))
export
default
function
DataProcess
()
{
return
<
DataWrap
title=
"数据加工:数据分组"
buttons=
{
<
Button
type=
"primary"
>
数据分组
</
Button
>
}
></
DataWrap
>
return
<
DataWrap
title=
"数据加工:数据分组"
buttons=
{
<
Button
Modal
/
>
}
></
DataWrap
>
}
src/modules/data/process/mapping/api.ts
0 → 100644
浏览文件 @
b5a25e0b
import
httpRequest
from
'@/utils/axios'
import
type
{
ProcessDataParams
}
from
'./types'
// 值映射
export
function
processData
(
data
:
ProcessDataParams
)
{
return
httpRequest
.
post
(
'/api/resource/bi/v1/processing/processing/mapping'
,
data
)
}
src/modules/data/process/mapping/components/ButtonModal.tsx
浏览文件 @
b5a25e0b
import
{
useEffect
,
useState
}
from
'react'
import
{
Button
,
Flex
,
Modal
,
Radio
,
Input
,
Form
,
Row
,
Col
,
Table
,
message
}
from
'antd'
import
{
Button
,
Flex
,
Modal
,
Radio
,
Input
,
Form
,
Row
,
Col
,
Table
}
from
'antd'
import
{
useDataQuery
,
useDataFieldQuery
}
from
'@/hooks/useQuery'
import
AppProgressSteps
from
'@/components/AppProgressSteps'
import
{
uniqBy
}
from
'lodash-es'
import
{
useProcessData
}
from
'../query'
export
default
function
ButtonModal
()
{
const
{
data
=
{
list
:
[]
}
}
=
useDataQuery
()
// 添加默认值防止 data 为 undefined
const
{
data
:
fields
=
[]
}
=
useDataFieldQuery
()
const
{
data
=
{
list
:
[]
}
}
=
useDataQuery
()
const
{
fieldOptions
,
getFieldName
}
=
useDataFieldQuery
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
current
,
setCurrent
]
=
useState
(
0
)
const
[
form
]
=
Form
.
useForm
()
const
[
dataSource
,
setDataSource
]
=
useState
<
{
key
:
number
;
raw_value
:
string
;
mapping_value
:
string
}[]
>
([])
const
[
step
,
setStep
]
=
useState
(
-
1
)
const
[
dataSource
,
setDataSource
]
=
useState
<
{
key
:
number
;
raw_value
:
string
;
new_value
:
string
}[]
>
([])
// 使用 Form.useWatch 监听表单值变化
const
checked
=
Form
.
useWatch
(
'checked'
,
form
)
const
field
=
Form
.
useWatch
(
'field'
,
form
)
// 当 checked 或 data 变化时更新数据源
useEffect
(()
=>
{
if
(
checke
d
&&
data
.
list
?.
length
)
{
const
uniqList
=
uniqBy
(
data
.
list
,
checke
d
)
if
(
fiel
d
&&
data
.
list
?.
length
)
{
const
uniqList
=
uniqBy
(
data
.
list
,
fiel
d
)
setDataSource
(
uniqList
.
map
((
item
:
any
,
index
)
=>
({
key
:
index
+
1
,
raw_value
:
item
[
checke
d
]
||
''
,
mapping
_value
:
''
,
raw_value
:
item
[
fiel
d
]
||
''
,
new
_value
:
''
,
}))
)
}
},
[
checke
d
,
data
.
list
])
},
[
fiel
d
,
data
.
list
])
// 处理映射值变化
const
handle
Mapping
ValueChange
=
(
value
:
string
,
key
:
number
)
=>
{
const
handleValueChange
=
(
value
:
string
,
key
:
number
)
=>
{
setDataSource
((
prevDataSource
)
=>
prevDataSource
.
map
((
item
)
=>
(
item
.
key
===
key
?
{
...
item
,
mapping
_value
:
value
}
:
item
))
prevDataSource
.
map
((
item
)
=>
(
item
.
key
===
key
?
{
...
item
,
new
_value
:
value
}
:
item
))
)
}
// 处理下一步按钮逻辑
const
handleNext
=
async
()
=>
{
if
(
current
===
0
)
{
// 第一步验证表单
await
form
.
validateFields
([
'name'
,
'english_name'
,
'field'
])
}
setCurrent
(
current
+
1
)
}
const
{
mutate
,
isPending
,
progress
,
message
}
=
useProcessData
()
// 开始处理
const
handleStart
=
()
=>
{
setStep
(
0
)
// Simulate processing steps with timeouts
setTimeout
(()
=>
{
setStep
(
1
)
setTimeout
(()
=>
{
setStep
(
4
)
message
.
success
(
'数据处理完成!'
)
},
1000
)
},
1000
)
const
values
=
form
.
getFieldsValue
()
const
rule
=
dataSource
.
reduce
((
result
,
item
)
=>
{
return
{
...
result
,
[
item
.
raw_value
]:
item
.
new_value
}
},
{})
const
params
=
{
...
values
,
rule
:
JSON
.
stringify
(
rule
)
}
mutate
(
params
,
{
onSuccess
:
handleClose
,
})
}
// 关闭并重置
const
handleClose
=
()
=>
{
setOpen
(
false
)
setCurrent
(
0
)
}
// 步骤定义
...
...
@@ -65,12 +80,12 @@ export default function ButtonModal() {
rules=
{
[{
required
:
true
,
message
:
'请输入英文名称'
}]
}
>
<
Input
placeholder=
"请输入"
/>
</
Form
.
Item
>
<
Form
.
Item
label=
"请选择值映射字段"
name=
"
checke
d"
rules=
{
[{
required
:
true
,
message
:
'请选择值映射字段'
}]
}
>
<
Form
.
Item
label=
"请选择值映射字段"
name=
"
fiel
d"
rules=
{
[{
required
:
true
,
message
:
'请选择值映射字段'
}]
}
>
<
Radio
.
Group
>
<
Row
gutter=
{
[
10
,
10
]
}
>
{
fields
.
map
((
item
)
=>
(
<
Col
span=
{
8
}
key=
{
item
.
english_nam
e
}
>
<
Radio
value=
{
item
.
english_name
}
>
{
item
.
name
}
</
Radio
>
{
field
Option
s
.
map
((
item
)
=>
(
<
Col
span=
{
8
}
key=
{
item
.
valu
e
}
>
<
Radio
value=
{
item
.
value
}
>
{
item
.
label
}
</
Radio
>
</
Col
>
))
}
</
Row
>
...
...
@@ -83,7 +98,7 @@ export default function ButtonModal() {
title
:
'配置值映射规则'
,
content
:
(
<>
<
Form
.
Item
label=
"值映射操作字段"
>
{
checked
}
</
Form
.
Item
>
<
Form
.
Item
label=
"值映射操作字段"
>
{
getFieldName
(
field
)
}
</
Form
.
Item
>
<
Form
.
Item
>
<
Table
bordered
...
...
@@ -93,12 +108,12 @@ export default function ButtonModal() {
{
title
:
'原始值'
,
dataIndex
:
'raw_value'
,
align
:
'center'
},
{
title
:
'映射值'
,
dataIndex
:
'
mapping
_value'
,
dataIndex
:
'
new
_value'
,
align
:
'center'
,
render
:
(
_
,
record
)
=>
(
<
Input
value=
{
record
.
mapping
_value
}
onChange=
{
(
e
)
=>
handle
Mapping
ValueChange
(
e
.
target
.
value
,
record
.
key
)
}
value=
{
record
.
new
_value
}
onChange=
{
(
e
)
=>
handleValueChange
(
e
.
target
.
value
,
record
.
key
)
}
placeholder=
"请输入映射值"
/>
),
...
...
@@ -115,12 +130,12 @@ export default function ButtonModal() {
content
:
(
<>
<
Flex
vertical
align=
"center"
style=
{
{
marginTop
:
'20px'
}
}
>
<
Button
type=
"primary"
onClick=
{
handleStart
}
disabled=
{
step
>=
0
}
>
<
Button
type=
"primary"
onClick=
{
handleStart
}
loading=
{
isPending
}
>
开始处理
</
Button
>
<
AppProgressSteps
style=
{
{
margin
:
'80px'
}
}
current=
{
step
}
current=
{
progress
}
items=
{
[
{
title
:
(
...
...
@@ -157,13 +172,7 @@ export default function ButtonModal() {
处理结果
</>
),
description
:
(
<>
累计处理
{
dataSource
.
length
}
个字段
<
br
/>
累计处理
{
data
.
list
?.
length
||
0
}
条记录
</>
),
description
:
<>
{
message
[
3
]
}
</>,
},
]
}
/>
...
...
@@ -173,29 +182,6 @@ export default function ButtonModal() {
},
]
// 处理下一步按钮逻辑
const
handleNext
=
async
()
=>
{
try
{
if
(
current
===
0
)
{
// 第一步验证表单
await
form
.
validateFields
([
'name'
,
'english_name'
,
'checked'
])
}
setCurrent
(
current
+
1
)
}
catch
(
error
)
{
// 表单验证错误处理
console
.
error
(
'表单验证失败'
,
error
)
}
}
// 重置状态
const
handleClose
=
()
=>
{
setOpen
(
false
)
setCurrent
(
0
)
setStep
(
-
1
)
form
.
resetFields
()
setDataSource
([])
}
return
(
<>
<
Button
type=
"primary"
onClick=
{
()
=>
setOpen
(
true
)
}
>
...
...
@@ -214,7 +200,7 @@ export default function ButtonModal() {
</
Button
>
)
}
{
current
===
steps
.
length
-
1
&&
(
<
Button
type=
"primary"
onClick=
{
handleClose
}
>
<
Button
type=
"primary"
onClick=
{
handleClose
}
disabled=
{
isPending
}
>
关闭
</
Button
>
)
}
...
...
src/modules/data/process/mapping/query.ts
0 → 100644
浏览文件 @
b5a25e0b
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
message
}
from
'antd'
import
{
processData
}
from
'./api'
import
type
{
ProcessDataParams
}
from
'./types'
import
{
useProcessProgressQuery
}
from
'@/hooks/useQuery'
// 处理数据
export
function
useProcessData
()
{
const
queryClient
=
useQueryClient
()
const
{
data
,
start
,
stop
}
=
useProcessProgressQuery
({
function_name
:
'mapping'
})
const
query
=
useMutation
({
mutationFn
:
(
data
:
ProcessDataParams
)
=>
{
start
()
return
processData
(
data
)
},
onSuccess
:
()
=>
{
stop
()
message
.
success
(
'处理完成'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'data'
]
})
},
})
return
{
...
query
,
progress
:
data
?.
progress
??
-
1
,
message
:
data
?.
message
??
{}
}
}
src/modules/data/process/mapping/types.ts
0 → 100644
浏览文件 @
b5a25e0b
export
interface
ProcessDataParams
{
name
:
string
english_name
:
string
field
:
string
rule
:
string
}
src/utils/axios.ts
浏览文件 @
b5a25e0b
...
...
@@ -47,13 +47,13 @@ axiosInstance.interceptors.response.use(
},
(
error
)
=>
{
if
(
error
.
response
)
{
const
{
status
,
message
}
=
error
.
response
.
data
const
{
status
,
message
:
errorMessage
}
=
error
.
response
.
data
// 未登录
if
(
status
===
403
)
{
location
.
href
=
`
${
import
.
meta
.
env
.
VITE_LOGIN_URL
}
?rd=
${
encodeURIComponent
(
location
.
href
)}
`
}
else
{
message
.
error
(
m
essage
||
error
.
message
)
console
.
error
(
`
${
status
}
:
${
m
essage
}
`
)
message
.
error
(
errorM
essage
||
error
.
message
)
console
.
error
(
`
${
status
}
:
${
errorM
essage
}
`
)
}
}
else
{
console
.
error
(
error
)
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论