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

chore: update

上级 730790f2
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@ant-design/charts": "^2.2.7",
"@ant-design/icons": "^5.6.1", "@ant-design/icons": "^5.6.1",
"@antv/g2": "^5.2.12",
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0", "@dnd-kit/sortable": "^10.0.0",
......
...@@ -16,21 +16,26 @@ export function getProcessProgress(params: { function_name: string }) { ...@@ -16,21 +16,26 @@ export function getProcessProgress(params: { function_name: string }) {
} }
// 数据可视化组件列表 // 数据可视化组件列表
export function getComponentList(params?: Partial<{ page: number; 'per-page': number; type: string }>) { export function getChartComponentList(params?: Partial<{ page: number; 'per-page': number; type: string }>) {
return httpRequest.get('/api/resource/bi/v1/reporting/component/list', { params }) return httpRequest.get('/api/resource/bi/v1/reporting/component/list', { params })
} }
// 更新数据可视化组件 // 更新数据可视化组件
export function updateComponent(data: { id: string; name: string; type: string; content: string }) { export function createChartComponent(data: { name: string; type: string; content: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/component/list', data) return httpRequest.post('/api/resource/bi/v1/reporting/component/create', data)
}
// 更新数据可视化组件
export function updateChartComponent(data: { id: string; name: string; type: string; content: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/component/update', data)
} }
// 删除数据可视化组件 // 删除数据可视化组件
export function deleteComponent(data: { id: string }) { export function deleteChartComponent(data: { id: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/component/list', data) return httpRequest.post('/api/resource/bi/v1/reporting/component/delete', data)
} }
// 数据可视化组件详情 // 数据可视化组件详情
export function getComponent(params: { id: string }) { export function getChartComponent(params: { id: string }) {
return httpRequest.get('/api/resource/bi/v1/reporting/component/list', { params }) return httpRequest.get('/api/resource/bi/v1/reporting/component/view', { params })
} }
import { useState } from 'react' import { useState } from 'react'
import { Button, Flex, Modal, Form, Divider, Select, Radio, Row, Col, Input } from 'antd' import { Button, Flex, Modal, Form, Divider, Select, Radio, Row, Col, Input } from 'antd'
import { useDataFieldQuery } from '@/hooks/useQuery' import { useDataQuery, useDataFieldQuery } from '@/hooks/useQuery'
import { useCreateChart } from '@/hooks/useChartQuery'
import { useAI } from '@/hooks/useAI'
import { Column } from '@ant-design/plots'
export default function ButtonModal() { export default function ButtonModal({ title = '新建柱状图', type = '1' }) {
const { data } = useDataFieldQuery() const { data } = useDataQuery()
const { fieldOptions } = useDataFieldQuery()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [form] = Form.useForm() const [form] = Form.useForm()
const fieldOptions = data?.map((item) => ({ label: item.name, value: item.name })) const [results, setResults] = useState({})
const config = { data: data.list, xField: '', yField: '', ...results }
const hiddenOptions = [ const { post } = useAI({
{ onComplete: (message) => {
label: '隐藏', console.log(message)
value: true, try {
const { results } = JSON.parse(message.content)
setResults(results)
console.log(results)
} catch (e) {
console.log(e)
}
}, },
{ })
label: '不隐藏',
value: false, const hiddenOptions = ['隐藏', '不隐藏']
},
] const handlePreview = () => {
const values = form.getFieldsValue()
post({
response_format: { type: 'json_object' },
messages: [
{
role: 'user',
content: `
用户配置:X轴字段为${values.x},Y轴字段为${values.y},标签字段为${values.label},是否隐藏行轴为${values.hidden_axis_x},是否隐藏列轴为${values.hidden_axis_y},颜色规则为${values.fill_color},是否有标题为${values.has_title},标题为${values.title},填充图案为${values.fill_image},是否隐藏图例为${values.legend},是否四个角圆滑为${values.radius}
根据以上用户配置,生成Ant Design Charts柱状图配置,不需要返回data, 以 JSON 的形式输出,输出的 JSON 需遵守以下的格式:
{
"results": {
"xField": "x",
"yField": "y",
}
}
`,
},
],
})
}
const { mutate } = useCreateChart()
// 保存
const handleSubmit = () => {
form.validateFields().then((values) => {
const params = { ...values, type, content: JSON.stringify({ config }) }
mutate(params, {
onSuccess: () => setOpen(false),
})
})
}
return ( return (
<> <>
<Button type="primary" onClick={() => setOpen(true)}> <Button type="primary" onClick={() => setOpen(true)}>
新建柱状图 {title}
</Button> </Button>
<Modal <Modal
title="新建柱状图" title={title}
open={open} open={open}
footer={ footer={
<Flex justify="center" gap={20}> <Flex justify="center" gap={20}>
<Button type="primary">预览组件效果</Button> <Button type="primary" onClick={handlePreview}>
预览组件效果
</Button>
<Button type="primary">AI对话调整</Button> <Button type="primary">AI对话调整</Button>
<Button type="primary" autoInsertSpace> <Button type="primary" autoInsertSpace onClick={handleSubmit}>
保存 保存
</Button> </Button>
</Flex> </Flex>
...@@ -42,52 +87,56 @@ export default function ButtonModal() { ...@@ -42,52 +87,56 @@ export default function ButtonModal() {
width={1000} width={1000}
onCancel={() => setOpen(false)}> onCancel={() => setOpen(false)}>
<div style={{ minHeight: 300, padding: '20px 0' }}> <div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} preserve={false}> <Form
form={form}
preserve={false}
initialValues={{
hidden_axis_x: '隐藏',
hidden_axis_y: '隐藏',
fill_color: '自动颜色',
radius: '不做圆滑处理',
legend: '隐藏',
has_title: '无',
fill_image: '纯色',
}}>
<Form.Item label="组件名称" name="name">
<Input placeholder="请输入" />
</Form.Item>
<Divider orientation="left" orientationMargin="0"> <Divider orientation="left" orientationMargin="0">
步骤1:数字字段设置 步骤1:数字字段设置
</Divider> </Divider>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}> <Col span={8}>
<Form.Item label="请选择“行”字段" name="x"> <Form.Item label="请选择“度量”字段" name="y">
<Select options={fieldOptions} placeholder="请选择" mode="multiple"></Select> <Select options={fieldOptions} placeholder="请选择"></Select>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={8}> <Col span={8}>
<Form.Item label="计算规则" name="x_rule"> <Form.Item label="计算规则" name="y_rule">
<Select options={fieldOptions} placeholder="请选择"></Select> <Select options={[{ label: '无计算', value: '无计算' }]} placeholder="请选择"></Select>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={8}> <Col span={8}>
<Form.Item label="排序规则" name="x_sort"> <Form.Item label="排序规则" name="y_sort">
<Select options={fieldOptions} placeholder="请选择"></Select> <Select options={[{ label: '无排序', value: '无排序' }]} placeholder="请选择"></Select>
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}> <Col span={8}>
<Form.Item label="请选择“列”字段" name="y"> <Form.Item label="请选择“维度”字段" name="x">
<Select options={fieldOptions} placeholder="请选择"></Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="计算规则" name="y_rule">
<Select options={fieldOptions} placeholder="请选择"></Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="排序规则" name="y_sort">
<Select options={fieldOptions} placeholder="请选择"></Select> <Select options={fieldOptions} placeholder="请选择"></Select>
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}> <Col span={8}>
<Form.Item label="是否隐藏行轴" name="hidden_x"> <Form.Item label="是否隐藏行轴" name="hidden_axis_x">
<Radio.Group options={hiddenOptions}></Radio.Group> <Radio.Group options={hiddenOptions}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={8}> <Col span={8}>
<Form.Item label="是否隐藏列轴" name="hidden_y"> <Form.Item label="是否隐藏列轴" name="hidden_axis_y">
<Radio.Group options={hiddenOptions}></Radio.Group> <Radio.Group options={hiddenOptions}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
...@@ -97,29 +146,21 @@ export default function ButtonModal() { ...@@ -97,29 +146,21 @@ export default function ButtonModal() {
</Divider> </Divider>
<Row gutter={20}> <Row gutter={20}>
<Col span={12}> <Col span={12}>
<Form.Item label="请选择“标签”字段"> <Form.Item label="请选择“标签”字段" name="label">
<Select options={fieldOptions} placeholder="请选择"></Select> <Select options={fieldOptions} placeholder="请选择"></Select>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="请选择颜色规则"> <Form.Item label="请选择颜色规则" name="fill_color">
<Radio.Group <Radio.Group options={['自动颜色', '不同柱子颜色不同']}></Radio.Group>
options={[
{ label: '自动颜色', value: '自动颜色' },
{ label: '不同柱子颜色不同', value: '不同柱子颜色不同' },
]}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={12}> <Col span={12}>
<Flex> <Flex>
<Form.Item label="是否有标题" name="hidden_y"> <Form.Item label="是否有标题" name="has_title">
<Radio.Group <Radio.Group options={['无', '有']}></Radio.Group>
options={[
{ label: '无', value: '无' },
{ label: '有', value: '有' },
]}></Radio.Group>
</Form.Item> </Form.Item>
<Form.Item name="title"> <Form.Item name="title">
<Input placeholder="请输入" /> <Input placeholder="请输入" />
...@@ -127,37 +168,27 @@ export default function ButtonModal() { ...@@ -127,37 +168,27 @@ export default function ButtonModal() {
</Flex> </Flex>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="请选择填充图案" name="padding"> <Form.Item label="请选择填充图案" name="fill_image">
<Radio.Group <Radio.Group options={['纯色', '斜线', '横线', '竖线']}></Radio.Group>
options={[
{ label: '纯色', value: '纯色' },
{ label: '斜线', value: '斜线' },
{ label: '横线', value: '横线' },
{ label: '竖线', value: '竖线' },
]}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={12}> <Col span={12}>
<Form.Item label="是否隐藏图例" name="hidden_len"> <Form.Item label="是否隐藏图例" name="legend">
<Radio.Group options={hiddenOptions}></Radio.Group> <Radio.Group options={hiddenOptions}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item label="是否四个角圆滑" name="radio"> <Form.Item label="是否四个角圆滑" name="radius">
<Radio.Group <Radio.Group options={['不做圆滑处理', '四个角圆滑处理', '两个角圆滑处理']}></Radio.Group>
options={[
{ label: '不做圆滑处理', value: '不做圆滑处理' },
{ label: '四个角圆滑处理', value: '四个角圆滑处理' },
{ label: '两个角圆滑处理', value: '两个角圆滑处理' },
]}></Radio.Group>
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Divider orientation="left" orientationMargin="0"> <Divider orientation="left" orientationMargin="0">
步骤3:预览组件效果 步骤3:预览组件效果
</Divider> </Divider>
{!!Object.keys(results).length && <Column {...config} />}
</Form> </Form>
</div> </div>
</Modal> </Modal>
......
...@@ -2,12 +2,45 @@ import { Button, Card, Flex } from 'antd' ...@@ -2,12 +2,45 @@ import { Button, Card, Flex } from 'antd'
import { ReactNode } from 'react' import { ReactNode } from 'react'
import AppList, { AppListProps } from '@/components/AppList' import AppList, { AppListProps } from '@/components/AppList'
import ViewDataButtonModal from '../data/ViewMyDataButtonModal' import ViewDataButtonModal from '../data/ViewMyDataButtonModal'
import { getComponentList } from '@/api/data' import { getChartComponentList } from '@/api/data'
import { useDeleteChart } from '@/hooks/useChartQuery'
const chartType: any = {
1: '柱状图',
2: '折线图',
3: '饼状图',
4: '雷达图',
5: '散点图',
6: '气泡图',
7: '词云',
8: '地图',
9: '指标卡',
10: '漏斗图',
11: '直方图',
12: '表格',
13: '帕累托图',
14: '矩形树图',
}
export default function DataWrap({
title,
buttons,
type,
}: {
type: string
title: string
buttons: ReactNode
children?: ReactNode
}) {
const { mutate } = useDeleteChart()
const handleRemove = (record: any) => {
mutate({ id: record.id })
}
export default function DataWrap({ title, buttons }: { title: string; buttons: ReactNode; children?: ReactNode }) {
const listOptions: AppListProps = { const listOptions: AppListProps = {
queryKey: ['chartComponentList', { type }],
fetchApi: async (params) => { fetchApi: async (params) => {
const { data } = await getComponentList(params) const { data } = await getChartComponentList({ ...params, type })
return { ...data } return { ...data }
}, },
columns: [ columns: [
...@@ -20,11 +53,18 @@ export default function DataWrap({ title, buttons }: { title: string; buttons: R ...@@ -20,11 +53,18 @@ export default function DataWrap({ title, buttons }: { title: string; buttons: R
width: 62, width: 62,
align: 'center', align: 'center',
}, },
{ title: '组件类型', dataIndex: 'type', align: 'center' }, {
title: '组件类型',
dataIndex: 'type',
align: 'center',
render(value) {
return chartType[value] || value
},
},
{ title: '组件名称', dataIndex: 'name', align: 'center' }, { title: '组件名称', dataIndex: 'name', align: 'center' },
{ title: '创建人', dataIndex: 'create_user', align: 'center' }, { title: '创建人', dataIndex: 'created_operator_name', align: 'center' },
{ title: '创建时间', dataIndex: 'create_time', align: 'center' }, { title: '创建时间', dataIndex: 'created_time', align: 'center' },
{ title: '更新时间', dataIndex: 'update_time', align: 'center' }, { title: '更新时间', dataIndex: 'updated_time', align: 'center' },
{ {
title: '操作', title: '操作',
key: 'x', key: 'x',
...@@ -39,7 +79,7 @@ export default function DataWrap({ title, buttons }: { title: string; buttons: R ...@@ -39,7 +79,7 @@ export default function DataWrap({ title, buttons }: { title: string; buttons: R
<Button color="primary" variant="text"> <Button color="primary" variant="text">
编辑 编辑
</Button> </Button>
<Button color="danger" variant="text"> <Button color="danger" variant="text" onClick={() => handleRemove(record)}>
删除 删除
</Button> </Button>
</> </>
......
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { createChartComponent, deleteChartComponent } from '@/api/data'
import { message } from 'antd'
// 创建
export function useCreateChart() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: { name: string; type: string; content: string }) => createChartComponent(data),
onSuccess: () => {
message.success('创建成功')
queryClient.invalidateQueries({ queryKey: ['chartComponentList'] })
},
})
}
// 删除
export function useDeleteChart() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: { id: string }) => deleteChartComponent(data),
onSuccess: () => {
message.success('删除成功')
queryClient.invalidateQueries({ queryKey: ['chartComponentList'] })
},
})
}
import { lazy } from 'react' import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap' import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('../components/ButtonModal')) const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <ChartWrap title="可视化:柱状图" buttons={<ButtonModal />}></ChartWrap> return <ChartWrap title="可视化:柱状图" type="1" buttons={<ButtonModal title="新建柱状图" type="1" />}></ChartWrap>
} }
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:气泡图" type="6" buttons={<ButtonModal title="新建气泡图" type="6" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:漏斗图" type="10" buttons={<ButtonModal title="新建漏斗图" type="10" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:直方图" type="11" buttons={<ButtonModal title="新建直方图" type="11" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:指标卡" type="9" buttons={<ButtonModal title="新建指标卡" type="9" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap' import ChartWrap from '@/components/chart/ChartWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <ChartWrap title="可视化:柱状图" buttons={<Button type="primary">新建柱状图</Button>}></ChartWrap> return <ChartWrap title="可视化:折线图" type="2" buttons={<ButtonModal title="新建折线图" type="2" />}></ChartWrap>
} }
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:地图" type="8" buttons={<ButtonModal title="新建地图" type="8" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return (
<ChartWrap title="可视化:帕累托图" type="13" buttons={<ButtonModal title="新建帕累托图" type="13" />}></ChartWrap>
)
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap' import ChartWrap from '@/components/chart/ChartWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <ChartWrap title="可视化:柱状图" buttons={<Button type="primary">新建柱状图</Button>}></ChartWrap> return <ChartWrap title="可视化:饼状图" type="3" buttons={<ButtonModal title="新建饼状图" type="3" />}></ChartWrap>
} }
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:散点图" type="5" buttons={<ButtonModal title="新建散点图" type="5" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap' import ChartWrap from '@/components/chart/ChartWrap'
import { Button } from 'antd'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() { export default function DataProcess() {
return <ChartWrap title="可视化:柱状图" buttons={<Button type="primary">新建柱状图</Button>}></ChartWrap> return <ChartWrap title="可视化:雷达图" type="4" buttons={<ButtonModal title="新建雷达图" type="4" />}></ChartWrap>
} }
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:表格" type="12" buttons={<ButtonModal title="新建表格" type="12" />}></ChartWrap>
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return (
<ChartWrap title="可视化:矩形树图" type="14" buttons={<ButtonModal title="新建矩形树图" type="14" />}></ChartWrap>
)
}
import { lazy } from 'react'
import ChartWrap from '@/components/chart/ChartWrap'
const ButtonModal = lazy(() => import('@/components/chart/ChartButtonModal'))
export default function DataProcess() {
return <ChartWrap title="可视化:词云" type="7" buttons={<ButtonModal title="新建词云" type="7" />}></ChartWrap>
}
...@@ -62,19 +62,19 @@ export const routes: RouteObject[] = [ ...@@ -62,19 +62,19 @@ export const routes: RouteObject[] = [
// 数据可视化组件 // 数据可视化组件
{ path: 'chart', element: <Navigate to="bar" /> }, { path: 'chart', element: <Navigate to="bar" /> },
{ path: 'chart/bar', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/bar', Component: lazy(() => import('./chart/bar/views/Index')) },
{ path: 'chart/line', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/line', Component: lazy(() => import('./chart/line/views/Index')) },
{ path: 'chart/pie', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/pie', Component: lazy(() => import('./chart/pie/views/Index')) },
{ path: 'chart/radar', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/radar', Component: lazy(() => import('./chart/radar/views/Index')) },
{ path: 'chart/point', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/point', Component: lazy(() => import('./chart/point/views/Index')) },
{ path: 'chart/bubble', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/bubble', Component: lazy(() => import('./chart/bubble/views/Index')) },
{ path: 'chart/wordCloud', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/wordCloud', Component: lazy(() => import('./chart/wordCloud/views/Index')) },
{ path: 'chart/map', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/map', Component: lazy(() => import('./chart/bar/views/Index')) },
{ path: 'chart/indicator', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/indicator', Component: lazy(() => import('./chart/indicator/views/Index')) },
{ path: 'chart/funnel', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/funnel', Component: lazy(() => import('./chart/funnel/views/Index')) },
{ path: 'chart/histogram', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/histogram', Component: lazy(() => import('./chart/histogram/views/Index')) },
{ path: 'chart/table', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/table', Component: lazy(() => import('./chart/table/views/Index')) },
{ path: 'chart/pareto', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/pareto', Component: lazy(() => import('./chart/pareto/views/Index')) },
{ path: 'chart/treeMap', Component: lazy(() => import('./chart/bar/views/Index')) }, { path: 'chart/treeMap', Component: lazy(() => import('./chart/treeMap/views/Index')) },
{ path: 'screen', Component: lazy(() => import('./screen/views/Index')) }, { path: 'screen', Component: lazy(() => import('./screen/views/Index')) },
], ],
}, },
......
import httpRequest from '@/utils/axios'
// 大屏列表
export function getLargeScreenList(params?: Partial<{ page: number; 'per-page': number; type: string }>) {
return httpRequest.get('/api/resource/bi/v1/reporting/large-screen/list', { params })
}
// 更新大屏
export function createLargeScreen(data: { name: string; type: string; content: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/large-screen/create', data)
}
// 更新大屏
export function updateLargeScreen(data: { id: string; name: string; type: string; content: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/large-screen/update', data)
}
// 删除大屏
export function deleteLargeScreen(data: { id: string }) {
return httpRequest.post('/api/resource/bi/v1/reporting/large-screen/delete', data)
}
// 大屏详情
export function getLargeScreen(params: { id: string }) {
return httpRequest.get('/api/resource/bi/v1/reporting/large-screen/view', { params })
}
import { useState } from 'react'
import { Button, Flex, Modal, Form, Divider, Select, Radio, Input } from 'antd'
import { useCreateLargeScreen } from '../query'
export default function ButtonModal({ title = '新建大屏' }) {
const [open, setOpen] = useState(false)
const [form] = Form.useForm()
const { mutate } = useCreateLargeScreen()
// 保存
const handleSubmit = () => {
form.validateFields().then((values) => {
const params = { ...values, content: JSON.stringify(values) }
mutate(params, {
onSuccess: () => setOpen(false),
})
})
}
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
{title}
</Button>
<Modal
title={title}
open={open}
footer={
<Flex justify="center" gap={20}>
<Button autoInsertSpace onClick={() => setOpen(false)}>
取消
</Button>
<Button type="primary">预览</Button>
<Button type="primary" autoInsertSpace onClick={handleSubmit}>
保存
</Button>
</Flex>
}
destroyOnClose
width={1000}
onCancel={() => setOpen(false)}>
<div style={{ minHeight: 300, padding: '20px 0' }}>
<Form form={form} preserve={false} initialValues={{ size: '1920*1080', bg: 'default', layout: 'auto' }}>
<Form.Item label="名称" name="name" rules={[{ required: true, message: '请输入' }]}>
<Input placeholder="请输入" />
</Form.Item>
<Form.Item label="标题" name="title" rules={[{ required: true, message: '请输入' }]}>
<Input placeholder="请输入" />
</Form.Item>
<Form.Item label="大小" name="size" rules={[{ required: true, message: '请选择' }]}>
<Select
options={[
{ label: '1920*1080', value: '1920*1080' },
{ label: '1024*768', value: '1024*768' },
]}
placeholder="请选择"></Select>
</Form.Item>
<Form.Item label="背景" name="bg" rules={[{ required: true, message: '请选择' }]}>
<Radio.Group
options={[
{ label: '默认', value: 'default' },
{ label: '纯色', value: 'color' },
{ label: '图片', value: 'image' },
]}></Radio.Group>
</Form.Item>
<Divider />
<Button type="primary">添加可视化组件</Button>
<Form.Item label="组件布局方式" name="layout" rules={[{ required: true, message: '请选择' }]}>
<Radio.Group options={[{ label: '自动布局', value: 'auto' }]}></Radio.Group>
</Form.Item>
</Form>
</div>
</Modal>
</>
)
}
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { createLargeScreen, deleteLargeScreen } from './api'
import { message } from 'antd'
// 创建
export function useCreateLargeScreen() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: { name: string; type: string; content: string }) => createLargeScreen(data),
onSuccess: () => {
message.success('创建成功')
queryClient.invalidateQueries({ queryKey: ['largeScreenList'] })
},
})
}
// 删除
export function useDeleteLargeScreen() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: { id: string }) => deleteLargeScreen(data),
onSuccess: () => {
message.success('删除成功')
queryClient.invalidateQueries({ queryKey: ['largeScreenList'] })
},
})
}
import DataWrap from '@/components/data/DataWrap' import { Button, Card, Flex } from 'antd'
import { Button } from 'antd' import AppList, { AppListProps } from '@/components/AppList'
import ViewDataButtonModal from '@/components/data/ViewMyDataButtonModal'
import ButtonModal from '../components/ButtonModal'
import { getLargeScreenList } from '../api'
import { useDeleteLargeScreen } from '../query'
export default function DataProcess() { export default function DataWrap() {
return <DataWrap title="数据可视化大屏" buttons={<Button type="primary">数据透视</Button>}></DataWrap> const { mutate } = useDeleteLargeScreen()
const handleRemove = (record: any) => {
mutate({ id: record.id })
}
const listOptions: AppListProps = {
queryKey: ['largeScreenList'],
fetchApi: async (params) => {
const { data } = await getLargeScreenList(params)
return { ...data }
},
columns: [
{
title: '序号',
key: 'index',
render(_value, _record, index) {
return index + 1
},
width: 62,
align: 'center',
},
{ title: '名称', dataIndex: 'name', align: 'center' },
{ title: '创建人', dataIndex: 'created_operator_name', align: 'center' },
{ title: '创建时间', dataIndex: 'created_time', align: 'center' },
{ title: '更新时间', dataIndex: 'updated_time', align: 'center' },
{
title: '操作',
key: 'x',
width: 220,
align: 'center',
render(_value, record) {
return (
<>
<Button color="primary" variant="text">
查看
</Button>
<Button color="primary" variant="text">
编辑
</Button>
<Button color="danger" variant="text" onClick={() => handleRemove(record)}>
删除
</Button>
</>
)
},
},
],
}
return (
<Flex gap={20} style={{ height: '100%' }}>
<Card className="app-card" style={{ flex: 1, overflowX: 'hidden' }}>
<Flex justify="space-between" style={{ marginBottom: '20px' }}>
<Flex wrap gap={10}>
<ButtonModal></ButtonModal>
</Flex>
<ViewDataButtonModal></ViewDataButtonModal>
</Flex>
<AppList {...listOptions} />
</Card>
</Flex>
)
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论