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

chore: update

上级 b5a25e0b
import type { StepsProps } 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 statusMap: any = {
wait: '待处理',
......@@ -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) {
return (
<Table
bordered
scroll={{ x: 'max-content', y: 800 }}
scroll={{ x: 'max-content' }}
tableLayout="auto"
size="middle"
pagination={{
hideOnSinglePage: true,
showSizeChanger: true,
defaultPageSize: 100,
pageSizeOptions: [100, 200, 500],
pageSizeOptions: [10, 20, 50, 100, 200, 500],
showTotal: (total: number) => `共${total}条数据`,
...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[] = [
{ name: '文本计算', path: '/data/process/string' },
{ name: '数值计算', path: '/data/process/number' },
{ name: '逻辑计算', path: '/data/process/logic' },
{ name: '数据透视', path: '/data/process/perspective' },
{ name: '数据透视', path: '/data/process/perspective', disabled: true },
],
},
{
......@@ -112,7 +112,7 @@ const menus: MyMenuItem[] = [
{ name: '散点图', path: '/data/chart/point' },
{ name: '气泡图', path: '/data/chart/bubble' },
{ 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/funnel' },
{ name: '直方图', path: '/data/chart/histogram' },
......
......@@ -119,7 +119,7 @@ export function useProcessProgressQuery(params: { function_name: string }) {
},
select: (res) => res.data,
enabled,
refetchInterval: enabled ? 1000 : false,
refetchInterval: enabled ? 10000 : false,
})
// 开始轮询的方法
......
.dashboard {
width: 1240px;
max-width: 1240px;
margin: 0 auto;
}
.carousel-banner {
......
......@@ -138,31 +138,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
启动
</>
),
title: <>启动</>,
},
{
title: (
<>
第二步
<br />
计算
</>
),
title: <>计算</>,
},
{
title: (
<>
第三步
<br />
计算结束
</>
),
title: <>计算结束</>,
},
]}
/>
......
......@@ -66,40 +66,16 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
title: <>新建字段</>,
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
title: <>复制数据</>,
},
{
title: (
<>
第三步
<br />
值映射处理
</>
),
title: <>值映射处理</>,
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
逻辑错误值处理
</>
),
title: <>逻辑错误值处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
过大值处理
</>
),
title: <>过大值处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -94,31 +94,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
过小值处理
</>
),
title: <>过小值处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -156,31 +156,13 @@ export default function ButtonModal() {
current={progress}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
缺失值处理
</>
),
title: <>缺失值处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: <>{message[3]}</>,
},
]}
......
......@@ -100,31 +100,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
重复值处理
</>
),
title: <>重复值处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -88,31 +88,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
检查字段处理规则
</>
),
title: <>检查字段处理规则</>,
},
{
title: (
<>
第二步
<br />
数据去空格处理
</>
),
title: <>数据去空格处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理XX个字段
......
......@@ -178,31 +178,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
新增字段
</>
),
title: <>新增字段</>,
},
{
title: (
<>
第二步
<br />
数据拼接
</>
),
title: <>数据拼接</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
description: (
<>
累计处理{concatenatedFields.length}个字段
......
......@@ -69,40 +69,16 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
计算拆分字段
</>
),
title: <>计算拆分字段</>,
},
{
title: (
<>
第二步
<br />
数据库表增加拆分字段
</>
),
title: <>数据库表增加拆分字段</>,
},
{
title: (
<>
第三步
<br />
更新拆分字段
</>
),
title: <>更新拆分字段</>,
},
{
title: (
<>
第四步
<br />
更新原始字段
</>
),
title: <>更新原始字段</>,
},
{
title: (
......
......@@ -61,31 +61,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
开始
</>
),
title: <>开始</>,
},
{
title: (
<>
第二步
<br />
数据去标点处理
</>
),
title: <>数据去标点处理</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
},
]}
/>
......
......@@ -84,31 +84,13 @@ export default function ButtonModal() {
current={step}
items={[
{
title: (
<>
第一步
<br />
开始
</>
),
title: <>开始</>,
},
{
title: (
<>
第二步
<br />
数据类型转换
</>
),
title: <>数据类型转换</>,
},
{
title: (
<>
第三步
<br />
处理结果
</>
),
title: <>处理结果</>,
},
]}
/>
......
......@@ -181,43 +181,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }}
current={progress}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
数据分箱处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
{ title: '新建字段' },
{ title: '复制数据' },
{ title: '数据分箱处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
......
......@@ -3,5 +3,5 @@ import type { ProcessDataParams } from './types'
// 数据分箱
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 { 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 AppProgressSteps from '@/components/AppProgressSteps'
import FunctionInput from '@/components/data/FunctionInput'
import { useProcessData } from '../query'
const functionShortcutOptions = [
......@@ -84,7 +85,7 @@ const functionOptions = [
]
export default function ButtonModal() {
const { fieldOptions, getFieldName } = useDataFieldQuery()
const { fieldOptions } = useDataFieldQuery()
const [open, setOpen] = useState(false)
const [current, setCurrent] = useState(0)
......@@ -107,7 +108,15 @@ export default function ButtonModal() {
// 开始处理
const handleStart = () => {
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, {
onSuccess: handleClose,
})
......@@ -119,6 +128,10 @@ export default function ButtonModal() {
setCurrent(0)
}
const handleFunctionChange = (value: string) => {
form.setFieldsValue({ content: `${value}()` })
}
// 步骤定义
const steps = [
{
......@@ -141,41 +154,48 @@ export default function ButtonModal() {
title: '配置日期计算规则',
content: (
<>
<Form.Item label="请选择日期计算方法" name="action">
<Form.Item label="请选择日期计算方法" name="action" rules={[{ required: true, message: '请选择方法' }]}>
<Radio.Group options={['快速日期计算', '日期函数计算']} />
</Form.Item>
{action === '快速日期计算' && (
<>
<Form.Item label="请选择快速日期计算方法" name="function">
<Form.Item
label="请选择快速日期计算方法"
name="function"
rules={[{ required: true, message: '请选择方法' }]}>
<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>
<Row gutter={[10, 10]} key={item.value} style={{ marginBottom: 10 }}>
<Col span={12}>
<Radio value={item.value}>{item.label}</Radio>
</Col>
<Col span={12}>
<p style={{ color: '#999' }}>{item.demo}</p>
</Col>
</Row>
))}
</Radio.Group>
</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 === '日期函数计算' && (
<>
<Form.Item label="请选择函数" name="function">
<Select options={functionOptions} />
<Form.Item label="请选择函数" name="function" rules={[{ required: true, message: '请选择函数' }]}>
<Select options={functionOptions} onChange={handleFunctionChange} />
</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 label="请输入函数公式" name="content" rules={[{ required: true, message: '请输入函数公式' }]}>
<FunctionInput />
</Form.Item>
</>
)}
......@@ -194,43 +214,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }}
current={progress}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
日期计算处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
{ title: '新建字段' },
{ title: '复制数据' },
{ title: '日期计算处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
......@@ -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 (
<>
<Button type="primary" onClick={() => setOpen(true)}>
......@@ -247,27 +253,12 @@ export default function ButtonModal() {
<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>
}
footer={<Footer />}
destroyOnClose
width={800}
onCancel={handleClose}>
<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) => (
<div key={index} hidden={current !== index} style={{ marginTop: '20px' }}>
{item.content}
......
......@@ -7,7 +7,7 @@ import { useProcessProgressQuery } from '@/hooks/useQuery'
// 处理数据
export function useProcessData() {
const queryClient = useQueryClient()
const { data, start, stop } = useProcessProgressQuery({ function_name: 'anonymization' })
const { data, start, stop } = useProcessProgressQuery({ function_name: 'date' })
const query = useMutation({
mutationFn: (data: ProcessDataParams) => {
......
export interface ProcessDataParams {
name: string
english_name: string
field: string
action: string
function: string
char?: string
sm_fun?: string
start?: string
end?: string
fields: string
}
......@@ -201,43 +201,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }}
current={progress}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
数据脱敏处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
{ title: '新建字段' },
{ title: '复制数据' },
{ title: '数据脱敏处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</Flex>
......
......@@ -161,40 +161,16 @@ export default function ButtonModal() {
current={progress}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
title: '新建字段',
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
title: '复制数据',
},
{
title: (
<>
第三步
<br />
数据分组处理
</>
),
title: '数据分组处理',
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
title: '处理结果',
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 { 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={<ButtonModal />}></DataWrap>
}
......@@ -137,43 +137,10 @@ export default function ButtonModal() {
style={{ margin: '80px' }}
current={progress}
items={[
{
title: (
<>
第一步
<br />
新建字段
</>
),
},
{
title: (
<>
第二步
<br />
复制数据
</>
),
},
{
title: (
<>
第三步
<br />
值映射处理
</>
),
},
{
title: (
<>
第四步
<br />
处理结果
</>
),
description: <>{message[3]}</>,
},
{ title: '新建字段' },
{ title: '复制数据' },
{ title: '值映射处理' },
{ title: '处理结果', description: <>{message[3]}</> },
]}
/>
</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 { 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={<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 { 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={<ButtonModal />}></DataWrap>
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论