提交 25767edf authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 b5a25e0b
import type { StepsProps } from 'antd' import type { StepsProps } from 'antd'
import { Spin, Steps } from 'antd' import { Spin, Steps } from 'antd'
export default function AppSteps({ ...props }: StepsProps) { function stepToChinese(step: number): string {
const stepMap = ['第一步', '第二步', '第三步', '第四步', '第五步', '第六步']
return stepMap[step] || ''
}
export default function AppSteps({ items, ...props }: StepsProps) {
const customDot = (dot, { status }) => { const customDot = (dot, { status }) => {
const statusMap: any = { const statusMap: any = {
wait: '待处理', wait: '待处理',
...@@ -16,5 +21,22 @@ export default function AppSteps({ ...props }: StepsProps) { ...@@ -16,5 +21,22 @@ export default function AppSteps({ ...props }: StepsProps) {
</> </>
) )
} }
return <Steps className="app-process-steps" progressDot={customDot} labelPlacement="vertical" {...props}></Steps> return (
<Steps className="app-process-steps" progressDot={customDot} labelPlacement="vertical" {...props}>
{items?.map(({ title, ...item }, index) => {
return (
<Steps.Step
key={index}
title={
<>
{stepToChinese(index)}
<br />
{title}
</>
}
{...item}></Steps.Step>
)
})}
</Steps>
)
} }
...@@ -4,14 +4,14 @@ export default function DataRender({ pagination = {}, ...props }: TableProps) { ...@@ -4,14 +4,14 @@ export default function DataRender({ pagination = {}, ...props }: TableProps) {
return ( return (
<Table <Table
bordered bordered
scroll={{ x: 'max-content', y: 800 }} scroll={{ x: 'max-content' }}
tableLayout="auto" tableLayout="auto"
size="middle" size="middle"
pagination={{ pagination={{
hideOnSinglePage: true, hideOnSinglePage: true,
showSizeChanger: true, showSizeChanger: true,
defaultPageSize: 100, defaultPageSize: 100,
pageSizeOptions: [100, 200, 500], pageSizeOptions: [10, 20, 50, 100, 200, 500],
showTotal: (total: number) => `共${total}条数据`, showTotal: (total: number) => `共${total}条数据`,
...pagination, ...pagination,
}} }}
......
import { Flex, Input } from 'antd'
import SelectFieldButtonModal from '@/components/data/SelectFieldButtonModal'
export default function FunctionInput({ fieldType, ...props }: any) {
const handleFieldSelect = (fieldName: string) => {
const value = (props.value || '') as string
let updatedValue = ''
if (value.endsWith('()')) {
updatedValue = value.replace('()', `(${fieldName})`)
} else {
updatedValue = value.includes('(') ? value.replace(')', `, ${fieldName})`) : `${value}, ${fieldName}`
}
// 调用 props.onChange 通知父组件更新 value
props.onChange?.(updatedValue)
}
return (
<Flex gap={10} align="center">
<Input.TextArea rows={6} {...props} />
<SelectFieldButtonModal onChange={handleFieldSelect} fieldType={fieldType}></SelectFieldButtonModal>
</Flex>
)
}
import { useState } from 'react'
import { Button, Flex, Modal, Select } from 'antd'
import { useDataFieldQuery } from '@/hooks/useQuery'
export default function SelectFieldButtonModal({
fieldType,
onChange,
}: {
fieldType: string
onChange?: (value: string) => void
}) {
const [open, setOpen] = useState(false)
const { fieldOptions } = useDataFieldQuery()
const [value, setValue] = useState<string>('')
const currentFieldOptions = fieldOptions.filter((option) => {
if (fieldType === 'string') return option.type.includes('VARCHAR')
if (fieldType === 'number') return option.type.includes('DECIMAL') || option.type.includes('SMALLINT')
return true
})
const handleOk = () => {
setOpen(false)
if (value && onChange) onChange(value)
setValue('')
}
const Footer = () => {
return (
<Flex justify="center">
<Button type="primary" onClick={handleOk}>
确定
</Button>
</Flex>
)
}
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
添加字段
</Button>
<Modal title="添加字段" width={400} open={open} footer={<Footer />} onCancel={() => setOpen(false)}>
<div style={{ padding: '20px 0' }}>
<Select
placeholder="请选择字段"
options={currentFieldOptions}
value={value}
onChange={setValue}
style={{ width: '100%' }}></Select>
</div>
</Modal>
</>
)
}
...@@ -80,7 +80,7 @@ const menus: MyMenuItem[] = [ ...@@ -80,7 +80,7 @@ const menus: MyMenuItem[] = [
{ name: '文本计算', path: '/data/process/string' }, { name: '文本计算', path: '/data/process/string' },
{ name: '数值计算', path: '/data/process/number' }, { name: '数值计算', path: '/data/process/number' },
{ name: '逻辑计算', path: '/data/process/logic' }, { name: '逻辑计算', path: '/data/process/logic' },
{ name: '数据透视', path: '/data/process/perspective' }, { name: '数据透视', path: '/data/process/perspective', disabled: true },
], ],
}, },
{ {
...@@ -112,7 +112,7 @@ const menus: MyMenuItem[] = [ ...@@ -112,7 +112,7 @@ const menus: MyMenuItem[] = [
{ name: '散点图', path: '/data/chart/point' }, { name: '散点图', path: '/data/chart/point' },
{ name: '气泡图', path: '/data/chart/bubble' }, { name: '气泡图', path: '/data/chart/bubble' },
{ name: '词云', path: '/data/chart/wordCloud' }, { name: '词云', path: '/data/chart/wordCloud' },
{ name: '地图', path: '/data/chart/map' }, { name: '地图', path: '/data/chart/map', disabled: true },
{ name: '指标卡', path: '/data/chart/indicator' }, { name: '指标卡', path: '/data/chart/indicator' },
{ name: '漏斗图', path: '/data/chart/funnel' }, { name: '漏斗图', path: '/data/chart/funnel' },
{ name: '直方图', path: '/data/chart/histogram' }, { name: '直方图', path: '/data/chart/histogram' },
......
...@@ -119,7 +119,7 @@ export function useProcessProgressQuery(params: { function_name: string }) { ...@@ -119,7 +119,7 @@ export function useProcessProgressQuery(params: { function_name: string }) {
}, },
select: (res) => res.data, select: (res) => res.data,
enabled, enabled,
refetchInterval: enabled ? 1000 : false, refetchInterval: enabled ? 10000 : false,
}) })
// 开始轮询的方法 // 开始轮询的方法
......
.dashboard { .dashboard {
width: 1240px; max-width: 1240px;
margin: 0 auto; margin: 0 auto;
} }
.carousel-banner { .carousel-banner {
......
...@@ -138,31 +138,13 @@ export default function ButtonModal() { ...@@ -138,31 +138,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>启动</>,
<>
第一步
<br />
启动
</>
),
}, },
{ {
title: ( title: <>计算</>,
<>
第二步
<br />
计算
</>
),
}, },
{ {
title: ( title: <>计算结束</>,
<>
第三步
<br />
计算结束
</>
),
}, },
]} ]}
/> />
......
...@@ -66,40 +66,16 @@ export default function ButtonModal() { ...@@ -66,40 +66,16 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>新建字段</>,
<>
第一步
<br />
新建字段
</>
),
}, },
{ {
title: ( title: <>复制数据</>,
<>
第二步
<br />
复制数据
</>
),
}, },
{ {
title: ( title: <>值映射处理</>,
<>
第三步
<br />
值映射处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第四步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -94,31 +94,13 @@ export default function ButtonModal() { ...@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>逻辑错误值处理</>,
<>
第二步
<br />
逻辑错误值处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -94,31 +94,13 @@ export default function ButtonModal() { ...@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>过大值处理</>,
<>
第二步
<br />
过大值处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -94,31 +94,13 @@ export default function ButtonModal() { ...@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>过小值处理</>,
<>
第二步
<br />
过小值处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -156,31 +156,13 @@ export default function ButtonModal() { ...@@ -156,31 +156,13 @@ export default function ButtonModal() {
current={progress} current={progress}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>缺失值处理</>,
<>
第二步
<br />
缺失值处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: <>{message[3]}</>, description: <>{message[3]}</>,
}, },
]} ]}
......
...@@ -100,31 +100,13 @@ export default function ButtonModal() { ...@@ -100,31 +100,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>重复值处理</>,
<>
第二步
<br />
重复值处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -88,31 +88,13 @@ export default function ButtonModal() { ...@@ -88,31 +88,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>检查字段处理规则</>,
<>
第一步
<br />
检查字段处理规则
</>
),
}, },
{ {
title: ( title: <>数据去空格处理</>,
<>
第二步
<br />
数据去空格处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理XX个字段 累计处理XX个字段
......
...@@ -178,31 +178,13 @@ export default function ButtonModal() { ...@@ -178,31 +178,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>新增字段</>,
<>
第一步
<br />
新增字段
</>
),
}, },
{ {
title: ( title: <>数据拼接</>,
<>
第二步
<br />
数据拼接
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
description: ( description: (
<> <>
累计处理{concatenatedFields.length}个字段 累计处理{concatenatedFields.length}个字段
......
...@@ -69,40 +69,16 @@ export default function ButtonModal() { ...@@ -69,40 +69,16 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>计算拆分字段</>,
<>
第一步
<br />
计算拆分字段
</>
),
}, },
{ {
title: ( title: <>数据库表增加拆分字段</>,
<>
第二步
<br />
数据库表增加拆分字段
</>
),
}, },
{ {
title: ( title: <>更新拆分字段</>,
<>
第三步
<br />
更新拆分字段
</>
),
}, },
{ {
title: ( title: <>更新原始字段</>,
<>
第四步
<br />
更新原始字段
</>
),
}, },
{ {
title: ( title: (
......
...@@ -61,31 +61,13 @@ export default function ButtonModal() { ...@@ -61,31 +61,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>开始</>,
<>
第一步
<br />
开始
</>
),
}, },
{ {
title: ( title: <>数据去标点处理</>,
<>
第二步
<br />
数据去标点处理
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
}, },
]} ]}
/> />
......
...@@ -84,31 +84,13 @@ export default function ButtonModal() { ...@@ -84,31 +84,13 @@ export default function ButtonModal() {
current={step} current={step}
items={[ items={[
{ {
title: ( title: <>开始</>,
<>
第一步
<br />
开始
</>
),
}, },
{ {
title: ( title: <>数据类型转换</>,
<>
第二步
<br />
数据类型转换
</>
),
}, },
{ {
title: ( title: <>处理结果</>,
<>
第三步
<br />
处理结果
</>
),
}, },
]} ]}
/> />
......
...@@ -181,43 +181,10 @@ export default function ButtonModal() { ...@@ -181,43 +181,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }} style={{ margin: '80px' }}
current={progress} current={progress}
items={[ items={[
{ { title: '新建字段' },
title: ( { title: '复制数据' },
<> { title: '数据分箱处理' },
第一步 { title: '处理结果', description: <>{message[3]}</> },
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
数据分箱处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
]} ]}
/> />
</Flex> </Flex>
......
...@@ -3,5 +3,5 @@ import type { ProcessDataParams } from './types' ...@@ -3,5 +3,5 @@ import type { ProcessDataParams } from './types'
// 数据分箱 // 数据分箱
export function processData(data: ProcessDataParams) { export function processData(data: ProcessDataParams) {
return httpRequest.post('/api/resource/bi/v1/processing/processing/anonymization', data) return httpRequest.post('/api/resource/bi/v1/processing/processing/date', data)
} }
import { useState } from 'react' import { useState } from 'react'
import { Button, Flex, Modal, Radio, Input, Form, Row, Col, Space, Select } from 'antd' import { Button, Flex, Modal, Radio, Input, Form, Row, Col, Select } from 'antd'
import { useDataFieldQuery } from '@/hooks/useQuery' import { useDataFieldQuery } from '@/hooks/useQuery'
import AppProgressSteps from '@/components/AppProgressSteps' import AppProgressSteps from '@/components/AppProgressSteps'
import FunctionInput from '@/components/data/FunctionInput'
import { useProcessData } from '../query' import { useProcessData } from '../query'
const functionShortcutOptions = [ const functionShortcutOptions = [
...@@ -84,7 +85,7 @@ const functionOptions = [ ...@@ -84,7 +85,7 @@ const functionOptions = [
] ]
export default function ButtonModal() { export default function ButtonModal() {
const { fieldOptions, getFieldName } = useDataFieldQuery() const { fieldOptions } = useDataFieldQuery()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0) const [current, setCurrent] = useState(0)
...@@ -107,7 +108,15 @@ export default function ButtonModal() { ...@@ -107,7 +108,15 @@ export default function ButtonModal() {
// 开始处理 // 开始处理
const handleStart = () => { const handleStart = () => {
const values = form.getFieldsValue() const values = form.getFieldsValue()
const params = { ...values, rules: JSON.stringify(values.rules), action: '固定步长分箱' } const content = values.content || ''
// 提取 content 中的参数
const fieldsMatch = content.match(/\((.*?)\)/) // 匹配括号内的内容
const fields = fieldsMatch ? fieldsMatch[1].split(',').map((field: string) => field.trim()) : []
if (action === '快速日期计算') {
fields.push(values.field)
}
const params = { ...values, fields: JSON.stringify(fields) } // 将提取的参数赋值给 fields
mutate(params, { mutate(params, {
onSuccess: handleClose, onSuccess: handleClose,
}) })
...@@ -119,6 +128,10 @@ export default function ButtonModal() { ...@@ -119,6 +128,10 @@ export default function ButtonModal() {
setCurrent(0) setCurrent(0)
} }
const handleFunctionChange = (value: string) => {
form.setFieldsValue({ content: `${value}()` })
}
// 步骤定义 // 步骤定义
const steps = [ const steps = [
{ {
...@@ -141,41 +154,48 @@ export default function ButtonModal() { ...@@ -141,41 +154,48 @@ export default function ButtonModal() {
title: '配置日期计算规则', title: '配置日期计算规则',
content: ( content: (
<> <>
<Form.Item label="请选择日期计算方法" name="action"> <Form.Item label="请选择日期计算方法" name="action" rules={[{ required: true, message: '请选择方法' }]}>
<Radio.Group options={['快速日期计算', '日期函数计算']} /> <Radio.Group options={['快速日期计算', '日期函数计算']} />
</Form.Item> </Form.Item>
{action === '快速日期计算' && ( {action === '快速日期计算' && (
<> <>
<Form.Item label="请选择快速日期计算方法" name="function"> <Form.Item
label="请选择快速日期计算方法"
name="function"
rules={[{ required: true, message: '请选择方法' }]}>
<Radio.Group style={{ width: '100%' }}> <Radio.Group style={{ width: '100%' }}>
{functionShortcutOptions.map((item) => ( {functionShortcutOptions.map((item) => (
<Flex> <Row gutter={[10, 10]} key={item.value} style={{ marginBottom: 10 }}>
<Radio value={item.value}> <Col span={12}>
<Space key={item.value}> <Radio value={item.value}>{item.label}</Radio>
<p style={{ minWidth: 200 }}>{item.label}</p> </Col>
<p style={{ color: '#999' }}>{item.demo}</p> <Col span={12}>
</Space> <p style={{ color: '#999' }}>{item.demo}</p>
</Radio> </Col>
</Flex> </Row>
))} ))}
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
<Form.Item label="请选择字段" name="field" rules={[{ required: true, message: '请选择字段' }]}>
<Radio.Group>
<Row gutter={[10, 10]}>
{fieldOptions.map((item) => (
<Col span={8} key={item.value}>
<Radio value={item.value}>{item.label}</Radio>
</Col>
))}
</Row>
</Radio.Group>
</Form.Item>
</> </>
)} )}
{action === '日期函数计算' && ( {action === '日期函数计算' && (
<> <>
<Form.Item label="请选择函数" name="function"> <Form.Item label="请选择函数" name="function" rules={[{ required: true, message: '请选择函数' }]}>
<Select options={functionOptions} /> <Select options={functionOptions} onChange={handleFunctionChange} />
</Form.Item> </Form.Item>
<Form.Item label="请输入函数公式"> <Form.Item label="请输入函数公式" name="content" rules={[{ required: true, message: '请输入函数公式' }]}>
<Flex gap={10}> <FunctionInput />
<Form.Item name="content" noStyle>
<Input.TextArea rows={4} />
</Form.Item>
<Button type="primary" style={{ height: 100 }}>
添加字段
</Button>
</Flex>
</Form.Item> </Form.Item>
</> </>
)} )}
...@@ -194,43 +214,10 @@ export default function ButtonModal() { ...@@ -194,43 +214,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }} style={{ margin: '80px' }}
current={progress} current={progress}
items={[ items={[
{ { title: '新建字段' },
title: ( { title: '复制数据' },
<> { title: '日期计算处理' },
第一步 { title: '处理结果', description: <>{message[3]}</> },
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
日期计算处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
]} ]}
/> />
</Flex> </Flex>
...@@ -239,6 +226,25 @@ export default function ButtonModal() { ...@@ -239,6 +226,25 @@ export default function ButtonModal() {
}, },
] ]
const Footer = () => {
return (
<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>
)
}
return ( return (
<> <>
<Button type="primary" onClick={() => setOpen(true)}> <Button type="primary" onClick={() => setOpen(true)}>
...@@ -247,27 +253,12 @@ export default function ButtonModal() { ...@@ -247,27 +253,12 @@ export default function ButtonModal() {
<Modal <Modal
title={steps[current]?.title} title={steps[current]?.title}
open={open} open={open}
footer={ footer={<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 destroyOnClose
width={800} width={800}
onCancel={handleClose}> onCancel={handleClose}>
<div style={{ minHeight: 300, padding: '20px 0' }}> <div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} labelCol={{ span: 5 }} preserve={false} initialValues={{ action: '快速日期计算' }}> <Form form={form} labelCol={{ span: 6 }} preserve={false} initialValues={{ action: '快速日期计算' }}>
{steps.map((item, index) => ( {steps.map((item, index) => (
<div key={index} hidden={current !== index} style={{ marginTop: '20px' }}> <div key={index} hidden={current !== index} style={{ marginTop: '20px' }}>
{item.content} {item.content}
......
...@@ -7,7 +7,7 @@ import { useProcessProgressQuery } from '@/hooks/useQuery' ...@@ -7,7 +7,7 @@ import { useProcessProgressQuery } from '@/hooks/useQuery'
// 处理数据 // 处理数据
export function useProcessData() { export function useProcessData() {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { data, start, stop } = useProcessProgressQuery({ function_name: 'anonymization' }) const { data, start, stop } = useProcessProgressQuery({ function_name: 'date' })
const query = useMutation({ const query = useMutation({
mutationFn: (data: ProcessDataParams) => { mutationFn: (data: ProcessDataParams) => {
......
export interface ProcessDataParams { export interface ProcessDataParams {
name: string name: string
english_name: string english_name: string
field: string
action: string
function: string function: string
char?: string fields: string
sm_fun?: string
start?: string
end?: string
} }
...@@ -201,43 +201,10 @@ export default function ButtonModal() { ...@@ -201,43 +201,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }} style={{ margin: '80px' }}
current={progress} current={progress}
items={[ items={[
{ { title: '新建字段' },
title: ( { title: '复制数据' },
<> { title: '数据脱敏处理' },
第一步 { title: '处理结果', description: <>{message[3]}</> },
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
数据脱敏处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
]} ]}
/> />
</Flex> </Flex>
......
...@@ -161,40 +161,16 @@ export default function ButtonModal() { ...@@ -161,40 +161,16 @@ export default function ButtonModal() {
current={progress} current={progress}
items={[ items={[
{ {
title: ( title: '新建字段',
<>
第一步
<br />
新建字段
</>
),
}, },
{ {
title: ( title: '复制数据',
<>
第二步
<br />
复制数据
</>
),
}, },
{ {
title: ( title: '数据分组处理',
<>
第三步
<br />
数据分组处理
</>
),
}, },
{ {
title: ( title: '处理结果',
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>, description: <>{message[3]}</>,
}, },
]} ]}
......
import httpRequest from '@/utils/axios'
import type { ProcessDataParams } from './types'
// 数据分箱
export function processData(data: ProcessDataParams) {
return httpRequest.post('/api/resource/bi/v1/processing/processing/logic', data)
}
import { useState } from 'react'
import { Button, Flex, Modal, Input, Form, Select } from 'antd'
import AppProgressSteps from '@/components/AppProgressSteps'
import FunctionInput from '@/components/data/FunctionInput'
import { useProcessData } from '../query'
const functionOptions = [
{ label: 'ABS:返回数字的绝对值', value: 'ABS' },
{ label: 'AVERAGE:计算数值的平均值', value: 'AVERAGE' },
{ label: 'CEILING:将数值向上舍入到指定基数的倍数', value: 'CEILING' },
{ label: 'COUNT:统计包含数字的单元格数量', value: 'COUNT' },
{ label: 'COUNTIF:统计满足条件的单元格数量', value: 'COUNTIF' },
{ label: 'FLOOR:将数值向下舍入到指定基数的倍数', value: 'FLOOR' },
{ label: 'INT:将数值向下舍入到最接近的整数', value: 'INT' },
{ label: 'MAX:返回一组数值中的最大值', value: 'MAX' },
{ label: 'MIN:返回一组数值中的最小值', value: 'MIN' },
{ label: 'MOD:返回两数相除的余数', value: 'MOD' },
{ label: 'POWER:计算数值的指定次幂', value: 'POWER' },
{ label: 'PRODUCT:计算所有参数的乘积', value: 'PRODUCT' },
{ label: 'ROUND:将数值四舍五入到指定小数位数', value: 'ROUND' },
{ label: 'ROUNDUP:将数值向上舍入到指定小数位数', value: 'ROUNDUP' },
{ label: 'ROUNDDOWN:将数值向下舍入到指定小数位数', value: 'ROUNDDOWN' },
{ label: 'SQRT:返回数值的平方根', value: 'SQRT' },
{ label: 'SUM:计算所有数值的总和', value: 'SUM' },
{ label: 'SUMIF:对满足条件的单元格求和', value: 'SUMIF' },
{ label: 'SUMPRODUCT:计算多个数组的对应元素乘积之和', value: 'SUMPRODUCT' },
{ label: 'TRUNC:截断数值的小数部分(不四舍五入)', value: 'TRUNC' },
]
export default function ButtonModal() {
const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0)
const [form] = Form.useForm()
// 处理下一步按钮逻辑
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 content = values.content || ''
// 提取 content 中的参数
const fieldsMatch = content.match(/\((.*?)\)/) // 匹配括号内的内容
const fields = fieldsMatch ? fieldsMatch[1].split(',').map((field: string) => field.trim()) : []
const params = { ...values, fields: JSON.stringify(fields) } // 将提取的参数赋值给 fields
mutate(params, {
onSuccess: handleClose,
})
}
// 关闭并重置
const handleClose = () => {
setOpen(false)
setCurrent(0)
}
const handleFunctionChange = (value: string) => {
form.setFieldsValue({ content: `${value}()` })
}
// 步骤定义
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="function" rules={[{ required: true, message: '请选择函数' }]}>
<Select options={functionOptions} onChange={handleFunctionChange} />
</Form.Item>
<Form.Item label="请输入函数公式" name="content" rules={[{ required: true, message: '请输入函数公式' }]}>
<FunctionInput fieldType="string" />
</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: '新建字段' },
{ title: '复制数据' },
{ title: '逻辑计算处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
</>
),
},
]
const Footer = () => {
return (
<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>
)
}
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
逻辑计算
</Button>
<Modal
title={steps[current]?.title}
open={open}
footer={<Footer />}
destroyOnClose
width={800}
onCancel={handleClose}>
<div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} labelCol={{ span: 6 }} preserve={false}>
{steps.map((item, index) => (
<div key={index} hidden={current !== index} style={{ marginTop: '20px' }}>
{item.content}
</div>
))}
</Form>
</div>
</Modal>
</>
)
}
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: 'logic' })
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 ?? {} }
}
export interface ProcessDataParams {
name: string
english_name: string
function: string
fields: string
}
import { lazy } from 'react'
import DataWrap from '@/components/data/DataWrap' import DataWrap from '@/components/data/DataWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('../components/ButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <DataWrap title="数据加工:逻辑计算" buttons={<Button type="primary">逻辑计算</Button>}></DataWrap> return <DataWrap title="数据加工:逻辑计算" buttons={<ButtonModal />}></DataWrap>
} }
...@@ -137,43 +137,10 @@ export default function ButtonModal() { ...@@ -137,43 +137,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }} style={{ margin: '80px' }}
current={progress} current={progress}
items={[ items={[
{ { title: '新建字段' },
title: ( { title: '复制数据' },
<> { title: '值映射处理' },
第一步 { title: '处理结果', description: <>{message[3]}</> },
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
值映射处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
]} ]}
/> />
</Flex> </Flex>
......
import httpRequest from '@/utils/axios'
import type { ProcessDataParams } from './types'
// 数据分箱
export function processData(data: ProcessDataParams) {
return httpRequest.post('/api/resource/bi/v1/processing/processing/numeric', data)
}
import { useState } from 'react'
import { Button, Flex, Modal, Input, Form, Select } from 'antd'
import AppProgressSteps from '@/components/AppProgressSteps'
import FunctionInput from '@/components/data/FunctionInput'
import { useProcessData } from '../query'
const functionOptions = [
{ label: 'ABS:返回数字的绝对值', value: 'ABS' },
{ label: 'AVERAGE:计算数值的平均值', value: 'AVERAGE' },
{ label: 'CEILING:将数值向上舍入到指定基数的倍数', value: 'CEILING' },
{ label: 'COUNT:统计包含数字的单元格数量', value: 'COUNT' },
{ label: 'COUNTIF:统计满足条件的单元格数量', value: 'COUNTIF' },
{ label: 'FLOOR:将数值向下舍入到指定基数的倍数', value: 'FLOOR' },
{ label: 'INT:将数值向下舍入到最接近的整数', value: 'INT' },
{ label: 'MAX:返回一组数值中的最大值', value: 'MAX' },
{ label: 'MIN:返回一组数值中的最小值', value: 'MIN' },
{ label: 'MOD:返回两数相除的余数', value: 'MOD' },
{ label: 'POWER:计算数值的指定次幂', value: 'POWER' },
{ label: 'PRODUCT:计算所有参数的乘积', value: 'PRODUCT' },
{ label: 'ROUND:将数值四舍五入到指定小数位数', value: 'ROUND' },
{ label: 'ROUNDUP:将数值向上舍入到指定小数位数', value: 'ROUNDUP' },
{ label: 'ROUNDDOWN:将数值向下舍入到指定小数位数', value: 'ROUNDDOWN' },
{ label: 'SQRT:返回数值的平方根', value: 'SQRT' },
{ label: 'SUM:计算所有数值的总和', value: 'SUM' },
{ label: 'SUMIF:对满足条件的单元格求和', value: 'SUMIF' },
{ label: 'SUMPRODUCT:计算多个数组的对应元素乘积之和', value: 'SUMPRODUCT' },
{ label: 'TRUNC:截断数值的小数部分(不四舍五入)', value: 'TRUNC' },
]
export default function ButtonModal() {
const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0)
const [form] = Form.useForm()
// 处理下一步按钮逻辑
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 content = values.content || ''
// 提取 content 中的参数
const fieldsMatch = content.match(/\((.*?)\)/) // 匹配括号内的内容
const fields = fieldsMatch ? fieldsMatch[1].split(',').map((field: string) => field.trim()) : []
const params = { ...values, fields: JSON.stringify(fields) } // 将提取的参数赋值给 fields
mutate(params, {
onSuccess: handleClose,
})
}
// 关闭并重置
const handleClose = () => {
setOpen(false)
setCurrent(0)
}
const handleFunctionChange = (value: string) => {
form.setFieldsValue({ content: `${value}()` })
}
// 步骤定义
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="function" rules={[{ required: true, message: '请选择函数' }]}>
<Select options={functionOptions} onChange={handleFunctionChange} />
</Form.Item>
<Form.Item label="请输入函数公式" name="content" rules={[{ required: true, message: '请输入函数公式' }]}>
<FunctionInput fieldType="string" />
</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: '新建字段' },
{ title: '复制数据' },
{ title: '数值计算处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
</>
),
},
]
const Footer = () => {
return (
<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>
)
}
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
数值计算
</Button>
<Modal
title={steps[current]?.title}
open={open}
footer={<Footer />}
destroyOnClose
width={800}
onCancel={handleClose}>
<div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} labelCol={{ span: 6 }} preserve={false}>
{steps.map((item, index) => (
<div key={index} hidden={current !== index} style={{ marginTop: '20px' }}>
{item.content}
</div>
))}
</Form>
</div>
</Modal>
</>
)
}
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: 'numeric' })
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 ?? {} }
}
export interface ProcessDataParams {
name: string
english_name: string
function: string
fields: string
}
import { lazy } from 'react'
import DataWrap from '@/components/data/DataWrap' import DataWrap from '@/components/data/DataWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('../components/ButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <DataWrap title="数据加工:数值计算" buttons={<Button type="primary">数值计算</Button>}></DataWrap> return <DataWrap title="数据加工:数值计算" buttons={<ButtonModal />}></DataWrap>
} }
import httpRequest from '@/utils/axios'
import type { ProcessDataParams } from './types'
// 数据分箱
export function processData(data: ProcessDataParams) {
return httpRequest.post('/api/resource/bi/v1/processing/processing/text', data)
}
import { useState } from 'react'
import { Button, Flex, Modal, Input, Form, Select } from 'antd'
import AppProgressSteps from '@/components/AppProgressSteps'
import FunctionInput from '@/components/data/FunctionInput'
import { useProcessData } from '../query'
const functionOptions = [
{ label: 'CHAR:返回 ASCII 码对应的字符', value: 'CHAR' },
{ label: 'CLEAN:删除文本中所有不可打印字符(如换行符、制表符)', value: 'CLEAN' },
{ label: 'CODE:返回文本中首个字符的 ASCII 码', value: 'CODE' },
{ label: 'CONCAT:合并多个文本', value: 'CONCAT' },
{ label: 'EXACT:严格比较两个文本是否完全相同(区分大小写)', value: 'EXACT' },
{ label: 'FIND:查找子文本在字符串中的位置(区分大小写)', value: 'FIND' },
{ label: 'LEFT:从文本左侧提取指定数量的字符', value: 'LEFT' },
{ label: 'LEN:返回文本的字符数(包括空格)', value: 'LEN' },
{ label: 'LOWER:将文本转换为全小写', value: 'LOWER' },
{ label: 'MID:从指定位置提取文本中的子字符串', value: 'MID' },
{ label: 'PROPER:将文本中每个单词的首字母大写', value: 'PROPER' },
{ label: 'REPLACE:替换文本中指定位置的字符', value: 'REPLACE' },
{ label: 'REPT:重复文本指定次数', value: 'REPT' },
{ label: 'RIGHT:从文本右侧提取指定数量的字符', value: 'RIGHT' },
{ label: 'SEARCH:查找子文本在字符串中的位置(不区分大小写)', value: 'SEARCH' },
{ label: 'SUBSTITUTE:替换文本中的特定子字符串', value: 'SUBSTITUTE' },
{ label: 'TEXT:将数值/日期按指定格式转换为文本', value: 'TEXT' },
{ label: 'TEXTJOIN:用分隔符合并多个文本,可忽略空值', value: 'TEXTJOIN' },
{ label: 'TRIM:删除文本中多余的空格(保留单词间单个空格)', value: 'TRIM' },
{ label: 'UPPER:将文本转换为全大写', value: 'UPPER' },
{ label: 'VALUE:将文本格式的数字转换为数值', value: 'VALUE' },
]
export default function ButtonModal() {
const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0)
const [form] = Form.useForm()
// 处理下一步按钮逻辑
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 content = values.content || ''
// 提取 content 中的参数
const fieldsMatch = content.match(/\((.*?)\)/) // 匹配括号内的内容
const fields = fieldsMatch ? fieldsMatch[1].split(',').map((field: string) => field.trim()) : []
const params = { ...values, fields: JSON.stringify(fields) } // 将提取的参数赋值给 fields
mutate(params, {
onSuccess: handleClose,
})
}
// 关闭并重置
const handleClose = () => {
setOpen(false)
setCurrent(0)
}
const handleFunctionChange = (value: string) => {
form.setFieldsValue({ content: `${value}()` })
}
// 步骤定义
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="function" rules={[{ required: true, message: '请选择函数' }]}>
<Select options={functionOptions} onChange={handleFunctionChange} />
</Form.Item>
<Form.Item label="请输入函数公式" name="content" rules={[{ required: true, message: '请输入函数公式' }]}>
<FunctionInput fieldType="string" />
</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: '新建字段' },
{ title: '复制数据' },
{ title: '文本计算处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
</>
),
},
]
const Footer = () => {
return (
<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>
)
}
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
文本计算
</Button>
<Modal
title={steps[current]?.title}
open={open}
footer={<Footer />}
destroyOnClose
width={800}
onCancel={handleClose}>
<div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} labelCol={{ span: 6 }} preserve={false}>
{steps.map((item, index) => (
<div key={index} hidden={current !== index} style={{ marginTop: '20px' }}>
{item.content}
</div>
))}
</Form>
</div>
</Modal>
</>
)
}
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: 'text' })
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 ?? {} }
}
export interface ProcessDataParams {
name: string
english_name: string
function: string
fields: string
}
import { lazy } from 'react'
import DataWrap from '@/components/data/DataWrap' import DataWrap from '@/components/data/DataWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('../components/ButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <DataWrap title="数据加工:文本计算" buttons={<Button type="primary">文本计算</Button>}></DataWrap> return <DataWrap title="数据加工:文本计算" buttons={<ButtonModal />}></DataWrap>
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论