Commit deac1b87 authored by 陈龙's avatar 陈龙

feat: 升级报表组件

parent 42bf1200
......@@ -40,4 +40,14 @@ export default {
'/PandaCore': '/PandaCore',
},
},
'/PandaWater': {
target: proxyURL,
changeOrigin: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
pathRewrite: {
'/PandaWater': '/PandaWater',
},
},
};
import React from 'react';
import { Row, Form, Select, InputNumber, Switch, Input, Slider } from 'antd';
import styles from './index.less';
const { Option } = Select;
const TableLayoutFormItems = (props) => {
const { defaultTableWidth, defaultTableHeight } = props;
return <>
<Form.Item
label="宽度"
name="width"
initialValue={defaultTableWidth}
>
<Slider/>
</Form.Item>
<Form.Item
label="高度"
name="height"
initialValue={defaultTableHeight}
>
<Slider/>
</Form.Item>
<Form.Item
label="标题"
name="title"
rules={[
{
required: true,
message: '标题必填',
},
]}
>
<Input/>
</Form.Item>
</>;
};
const OthersFormItems = () => {
return <>
<Form.Item label="标题" name="text">
<Input/>
</Form.Item>
<Form.Item label="字体大小" name="fontSize" initialValue={14}>
<InputNumber/>
</Form.Item>
<Form.Item
label="字体颜色"
name="fontColor"
initialValue={'#000000'}
>
<Input type="color" style={{ width: 70 }}/>
</Form.Item>
<Row className={styles.commonTitle}>y轴配置</Row>
<Form.Item label="轴1名称" name="yAxisName">
<Input/>
</Form.Item>
<Form.Item label="轴2名称" name="yAxisName2">
<Input/>
</Form.Item>
<Row className={styles.commonTitle}>其他配置</Row>
<Form.Item
label="图例位置"
name="legendPosition"
initialValue={'right'}
>
<Select>
<Option value="left"></Option>
<Option value="center"></Option>
<Option value="right"></Option>
</Select>
</Form.Item>
<Form.Item label="图表布局">
<Form.Item label="左" name="left" initialValue={20}>
<InputNumber/>
</Form.Item>
<Form.Item label="右" name="right" initialValue={20}>
<InputNumber/>
</Form.Item>
<Form.Item label="上" name="top" initialValue={20}>
<InputNumber/>
</Form.Item>
<Form.Item label="下" name="bottom" initialValue={20}>
<InputNumber/>
</Form.Item>
</Form.Item>
<Form.Item
label="数据缩放"
name="showDataZoom"
valuePropName="checked"
>
<Switch/>
</Form.Item>
</>;
};
export {
OthersFormItems, TableLayoutFormItems,
};
.chartConfig {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
.controlRow {
display: flex;
align-items: center;
margin-bottom: 4px;
height: 44px;
padding: 6px;
background: #ffffff;
.leftBtn {
font-size: 18px;
font-weight: bold;
cursor: pointer;
margin-right: 10px;
&:hover {
color: #1685FF;
opacity: 0.8;
}
}
}
.contentWrapper {
flex: 1;
width: 100%;
display: flex;
column-gap: 8px;
overflow: hidden;
:global {
.@{ant-prefix}-form-item {
margin-bottom: 8px;
}
.@{ant-prefix}-input-number {
width: 100%;
}
}
.leftLayout {
flex: 1;
height: 100%;
padding: 8px;
background: #fff;
overflow: auto;
.layoutWrapper {
width: 100%;
height: 100%;
display: flex;
.chartWrapper {
display: flex;
column-gap: 8px;
flex: 1;
overflow: hidden;
.chartItem {
border: 1px dashed #3d3d3d;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
&.activeChart {
//background: #1685FF;
border-color: #1685FF;
color: #fff;
}
}
}
.tableWrapper {
border: 1px dashed #3d3d3d;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
// 上下布局
&.columnLayout {
flex-direction: column;
row-gap: 8px;
.tableWrapper {
width: 100%;
height: 50%;
}
.chartWrapper {
width: 100%;
flex: 1;
.chartItem {
//flex: 1;
width: 100%;
border: 1px dashed #333;
&.activeChart {
border-color: #1685FF;
color: #fff;
}
}
}
}
// 左右布局
&.rowLayout {
column-gap: 8px;
.chartWrapper {
display: flex;
flex-direction: column;
row-gap: 8px;
.chartItem {
//flex: 1;
width: 100%;
border: 1px dashed #333;
&.activeChart {
border-color: #1685FF;
color: #fff;
}
}
}
}
}
}
.rightPanel {
flex: none;
width: 500px;
height: 100%;
background: #fff;
overflow: hidden;
display: flex;
flex-direction: column;
.configForm {
width: 100%;
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
.titleWrap {
display: flex;
height: 40px;
flex: none;
justify-content: center;
align-items: center;
background: #1685FF;
color: #ffffff;
}
.tableFormWrap {
flex: none;
}
.commonTitle {
position: relative;
padding-left: 20px;
&::before {
position: absolute;
top: 50%;
left: 8px;
transform: translateY(-50%);
content: '';
width: 3px;
height: 14px;
background: #1685FF;
}
}
.saveBtnWrap {
flex-direction: row-reverse;
column-gap: 4px;
padding: 0 12px;
margin-top: 8px;
align-items: center;
}
.chartFormWrap {
flex: 1;
overflow: auto;
.pointerEvents {
pointer-events: none;
}
}
}
.submitWrap {
width: 100%;
height: 40px;
flex: none;
display: flex;
align-items: center;
flex-direction: row-reverse;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
}
}
}
}
const handleMarkLineOrMarkPoint = (options, arr) => {
return options
.filter((item) => arr?.includes(item.value))
?.map((v) => ({
type: v.value,
name: v.label,
}));
};
const handleSeries = (form, seriesData, option) => {
let series = form?.seriesArray?.map((item, index) => {
let _temp = {
type: item.chartType,
// name: item?.chartName ?? '',
colorBy: 'series',
data:
form.xDataType === 'selectedData'
? `$[${form.seriesData}]`
: '${' + seriesData[index] + '}',
custom_config: {
unit: item?.unit ?? '',
},
};
_temp.markPoint = {
data: handleMarkLineOrMarkPoint(option, item.markPoint),
};
_temp.markLine = {
data: handleMarkLineOrMarkPoint(option, item.markLine),
};
return _temp;
});
return {
series,
};
};
const handleOthers = (form) => {
let legend = {
left: form.legendPosition ?? '',
};
let grid = {
left: form.left,
right: form.right,
top: form.top,
bottom: form.bottom,
};
let dataZoom = {
show: form?.showDataZoom ?? false,
};
return { legend, grid, dataZoom };
};
const handleCustomConfig = (form) => {
return {
custom_style: {
width: form.width + '%',
height: form.height + '%',
},
custom_config: {
renderBy: form.xDataType,
},
};
};
const handleTitle = (form) => {
return {
title: {
show: form?.showTitle ?? false,
text: form?.text ?? '',
textStyle: {
color: form?.fontColor ?? '',
fontSize: form.fontSize,
},
},
};
};
const defaultChartOptions = {
'custom_style': {
'width': '',
'height': '',
},
'custom_config': {
'renderBy': 'allData',
},
'title': {
'show': false,
'text': '',
'textStyle': {
'color': '#000000',
'fontSize': 14,
},
},
'series': [],
'legend': {
'left': 'right',
},
'grid': {
'left': 20,
'right': 20,
'top': 20,
'bottom': 20,
},
'dataZoom': {
'show': false,
},
'xAxis': {
'name': '',
'type': 'category',
'data': '',
},
'yAxis': [
{
'name': '',
'gridIndex': 0,
},
],
};
const defaultLayoutOptions = {
'layout': '上表下图',
'chartCount': 1,
'tableConfigs': [
{
'title': '',
'width': '100%',
'height': '70%',
},
],
};
const defaultConfig = {
'layoutOptions': {
'layout': '上表下图',
'chartCount': 1,
'tableConfigs': [
{
'title': '',
'width': '100%',
'height': '60%',
},
],
},
'chartOptions': [
{
'custom_style': {
'width': '100%',
'height': '100%',
},
'custom_config': {
'renderBy': 'allData',
},
'title': {
'text': '',
'textStyle': {
'color': '#000000',
'fontSize': 14,
},
},
'xAxis': {
'name': '',
'type': 'category',
'data': '',
},
'yAxis': [
{
'name': '',
'gridIndex': 0,
},
],
'series': [],
'legend': {
'left': 'right',
},
'grid': {
'left': 20,
'right': 20,
'top': 20,
'bottom': 20,
},
'dataZoom': {
show: false,
},
},
],
};
const calculateWidth = () => {
};
export {
handleSeries, handleOthers, handleCustomConfig, handleTitle, defaultChartOptions, defaultLayoutOptions,defaultConfig
};
import React, { useEffect, useState } from 'react';
import { AutoComplete, InputNumber } from 'antd';
import { useRef } from 'react/index';
/**
* @params {string} type 单元格 统计栏
* */
const NumberConfig = ({ value, onChange, defaultValues, type }) => {
const [values, setValues] = useState({
prefix: '',
suffix: '',
precision: '',
ratio: 1,
});
const wrapper = {
display: 'flex',
gap: 6,
};
const width = { width: 80 };
const optRef = useRef({
prefix: [
{ value: '$' }, { value: '¥' },
],
suffix: [
{ value: '千' }, { value: '万' }, { value: '元' }, { value: '万元' },
],
precision: [
{ value: '0.0' }, { value: '0.00' }, { value: '0.000' }, { value: '0.0000' },
],
});
const valueChange = (key, value) => {
let _values = { ...values };
_values[key] = value;
setValues(_values);
onChange(_values);
};
useEffect(() => {
let _values = { ...values };
_values.prefix = value;
}, [value]);
return <div style={wrapper}>
{/* 精度 倍率 前缀 后缀 类型*/}
<AutoComplete onChange={(e) => valueChange('prefix', e)}
value={values.prefix} placeholder={'前缀'}
options={optRef.current.prefix} style={{ ...width }}/>
<AutoComplete onChange={(e) => valueChange('suffix', e)}
value={values.suffix} placeholder={'单位/后缀'}
options={optRef.current.suffix}
style={{ ...width, width: 100 }}/>
<AutoComplete onChange={(e) => valueChange('precision', e)}
value={values.precision} placeholder={'精度'}
options={optRef.current.precision} style={{ ...width }}/>
<span>倍率:<InputNumber onChange={(e) => valueChange('ratio', e)}
value={values.ratio} step={1} style={{ ...width }}
min={1}/></span>
</div>;
};
export default NumberConfig;
import React from 'react';
import ReactDOM from 'react-dom';
import Simple_table from './modal/simple_table';
const Print = (data, printTemp) => {
//创建iframe标签
const iframe = document.createElement('iframe');
iframe.setAttribute(
'style',
'position:absolute;width:0px;height:0px;left:500px;top:500px;size:auto;margin:0mm;',
);
//将iframe添加到body
document.body.appendChild(iframe);
//创建打印内容document对象
let doc = iframe.contentWindow.document;
let tem = '';
switch (printTemp) {
case 'simple_table':
tem = <Simple_table data={data}/>;
break;
default:
tem = <Simple_table data={data}/>;
}
ReactDOM.render(tem, doc);
setTimeout(() => {
doc.close();
//打印
iframe.contentWindow.focus();
iframe.contentWindow.print();
//清理iframe
if (navigator.userAgent.indexOf('MSIE') > 0) {
document.body.removeChild(iframe);
}
}, 1000);
};
export default Print;
import moment from 'moment';
import React, { useMemo } from 'react';
const Template_record = (props) => {
const { data } = props;
const { tableData, reportName, columns } = data;
const handleHead = (columns) => {
let _rows = [];
let countLevel = (arr) => {
let _childrenArr = [];
let _currentRowArr = [];
arr.forEach((item, index) => {
let _item = { ...item };
if (_item?.children?.length) {
_item.hasChild = true;
_childrenArr = _childrenArr.concat(_item.children);
}
_currentRowArr.push(_item);
});
_rows.push(_currentRowArr);
if (_childrenArr.length) countLevel(_childrenArr);
};
countLevel(columns);
return _rows;
};
const handleCols = (columns) => {
let _cols = [];
let handleColumns = (arr) => {
let _childrenArr = [];
arr.forEach((item, index) => {
let _item = { ...item };
if (_item?.children?.length) {
_childrenArr = _childrenArr.concat(_item.children);
} else {
_cols.push(_item)
}
});
if (_childrenArr.length) handleColumns(_childrenArr);
};
handleColumns(columns);
return _cols;
}
const headArr = useMemo(() => {
return handleHead(columns);
}, [columns]);
const columnsArr = useMemo(()=>{
return handleCols(columns)
},[columns])
return (
<div style={{ padding: '0px 0px' }}>
<style>
{`@page{margin: 20px 80px 20px 80px;}table{border-collapse:collapse;font-size:10px;}
table,th,td{border:1px solid #333333;text-align:center;padding:3px 1px;}`}
</style>
<div
style={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{reportName}
</div>
<div style={{ marginTop: '10px' }}>
<table width="100%" border="0">
<thead>
{
headArr.map((row, index) => {
return <tr>
{
row.map(col => {
return <th rowSpan={col?.children?.length ? 1 : headArr.length - index} width={`${col.width??200}px`}
colSpan={col?.children?.length ?? 1}>{col.title}</th>;
})
}
</tr>;
})
}
</thead>
{tableData.map((item, index) => {
return (
<tr key={`${item.r}_ ${index}`}>
{
/**
* 1. 序号没有onCell,单独输出
* 2. 其他的有onCell的,按照rowSpan输出来分配位置
* 3. 没有onCell的,或者rowSpan等于0的,打印的时候需要被移除
* */
columnsArr.map(col => {
if (col.title === '序号') return <td>{item[col.dataIndex]}</td>;
if (col.onCell && col.onCell(item, index).rowSpan !== 0) return <td
rowSpan={col.onCell(item, index).rowSpan}>{item[col.dataIndex]}</td>;
return null;
}).filter(item => item)
}
</tr>
);
})}
</table>
</div>
</div>
);
};
export default Template_record;
......@@ -34,6 +34,7 @@ import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
import './fileUpload.less';
import { downloadFunc, filenameVerification } from '../../utils/utils';
import { uploadFileUrl, downloadFileUrl } from '../../../api/service/workflow';
import {isArray} from "lodash";
const videoTypeArray = ['.mp4'];
const audioTypeArray = ['.mp4'];
const fileTypeArray = [];
......@@ -47,22 +48,21 @@ const FileUpload = ({ value, onChange, schema }) => {
const [previewTitle, setPreviewTitle] = useState('');
const [previewVisible, setPreviewVisible] = useState(false);
const [previewUrl, setPreviewUrl] = useState('');
const [showList, setShowList] = useState('');
const file = value || schema.default;
const [showList, setShowList] = useState([]);
const option = {
name: 'file',
action: `${window.location.origin}${uploadFileUrl}`,
listType: _isRecordingOrVideo ? 'picture-card' : 'picture',
withCredentials: true,
beforeUpload(file, fileList) {
/** @tips: 解决提交文件中存在特殊字符的问题 */
/** @Tips: 解决提交文件中存在特殊字符的问题 */
let _continueUpload = true;
let _msg = {
type: 'success',
content: '上传成功!',
};
fileList.forEach((item) => {
let _msgObject = filenameVerification(item);
fileList.forEach(item => {
let _msgObject = filenameVerification(item.name);
if (_msgObject.type === 'error') {
_continueUpload = false;
_msg = {
......@@ -74,9 +74,10 @@ const FileUpload = ({ value, onChange, schema }) => {
_msg.type === 'error' ? message[_msg.type](_msg.content) : '';
return _continueUpload;
},
onRemove:()=>{return true},
onChange: ({ file, fileList, event }) => {
// 检验名字,名字不通过不允许显示
if (filenameVerification(file).type === 'error') return false;
if (filenameVerification(file.name).type === 'error') return false;
// 返回的链接在file.response内;不设置url,预览图表不可点击
if (file.status === 'done' && file.response.code === 0) {
file.url = `${downloadFileUrl}?filePath=${file.response.data}`;
......@@ -86,8 +87,8 @@ const FileUpload = ({ value, onChange, schema }) => {
file.status = 'error';
message.error('上传失败!');
}
onChange((fileList && fileList.length && JSON.stringify(fileList)) || '');
setShowList(JSON.stringify(fileList));
onChange(fileList ?? []);
// setShowList(fileList ?? []);
},
onPreview(file) {
if (_isRecordingOrVideo) {
......@@ -95,7 +96,6 @@ const FileUpload = ({ value, onChange, schema }) => {
setPreviewUrl(file.url);
}
},
previewFile(file) {},
onDownload(file) {
downloadFunc(file.url, file.name, '_self');
},
......@@ -105,11 +105,11 @@ const FileUpload = ({ value, onChange, schema }) => {
setPreviewTitle('');
};
/**
* @description: 返回文件类型限定值
* @params: {Array} typeArray: Video | Recording | File
* @date: 2021/12/2
* @author: ChenLong
*/
* @Description: 返回文件类型限定值
* @Params: {Array} typeArray: Video | Recording | File
* @Date: 2021/12/2
* @Author: ChenLong
* */
const returnFileTypeString = (type) => {
let _obj = {
Video: videoTypeArray,
......@@ -120,101 +120,53 @@ const FileUpload = ({ value, onChange, schema }) => {
return _obj[type].join(',');
};
useEffect(() => {
let fileList = [];
(file || '').split(',').forEach((item, index) => {
if (item && filenameVerification({ name: item }, true).type !== 'error') {
// @Tips: 直接过滤掉名字中有异常字符的文件
let _obj = {
uid: index + '_' + Math.random(),
value: item,
name: item.split('\\').reverse()[0],
type: schema.renderTo === 'Image' ? 'image' : 'file',
status: 'done',
url: `${downloadFileUrl}?filePath=${item}`,
sourcePath: item,
};
if (schema.renderTo === 'Image') _obj.thumbUrl = `${downloadFileUrl}?filePath=${item}`;
fileList.push(_obj);
}
});
// onChange(fileList.length && JSON.stringify(fileList) || '');
setShowList(JSON.stringify(fileList));
}, []);
useEffect(() => {
if (value) {
let fileList = [];
(file || '').split(',').forEach((item, index) => {
if (item && filenameVerification({ name: item }, true).type !== 'error') {
// @Tips: 直接过滤掉名字中有异常字符的文件
let _obj = {
uid: index + '_' + Math.random(),
value: item,
name: item.split('\\').reverse()[0],
type: schema.renderTo === 'Image' ? 'image' : 'file',
status: 'done',
url: `${downloadFileUrl}?filePath=${item}`,
sourcePath: item,
};
if (schema.renderTo === 'Image') _obj.thumbUrl = `${downloadFileUrl}?filePath=${item}`;
fileList.push(_obj);
}
});
// onChange(fileList.length && JSON.stringify(fileList) || '');
setShowList(JSON.stringify(fileList));
if (isArray(value)) {
setShowList(value);
}
}, [value]);
return (
<>
{/** @tips: 裁剪功能无法正常工作,暂不提供 */}
{/* <ImgCrop beforeCrop={(file) => {
let _returnObj = filenameVerification(file);
if (_returnObj.type === 'error') {
message.error(_returnObj.content);
return false;
}
return schema.renderTo === 'Image';
}} rotate locale={'zh-cn'} modalTitle={'编辑图片'} modalOk={'确定'}
modalCancel={'取消'}>*/}
<Upload
disabled={schema.disabled}
{...option}
fileList={showList ? JSON.parse(showList) : []}
multiple
style={{ width: '100%' }}
className={_isRecordingOrVideo ? 'formUploadVideoOrRecording' : 'formUpload'}
showUploadList={{
showPreviewIcon: _isRecordingOrVideo,
showDownloadIcon: true,
downloadIcon: <DownloadOutlined />,
}}
accept={returnFileTypeString(schema.renderTo)}
>
{!_isRecordingOrVideo ? (
<Button disabled={schema.disabled} icon={<UploadOutlined />}>
Upload
</Button>
) : (
'+ Upload'
)}
</Upload>
{/* </ImgCrop>*/}
<Modal
style={{ width: '30%' }}
bodyStyle={{ textAlign: 'center' }}
visible={previewVisible}
title={previewTitle}
footer={null}
onCancel={handleCancel}
>
{_isVideo ? (
<video width={'100%'} height={'100%'} controls autoPlay src={previewUrl} />
) : (
''
)}
{_isAudio ? <audio controls autoPlay src={previewUrl} /> : ''}
{_isImage ? <img width={'100%'} height={'100%'} src={previewUrl} alt="缩略图" /> : ''}
</Modal>
</>
<>
<Upload
disabled={schema.disabled}
{...option}
fileList={showList ?? []}
multiple
style={{ width: '100%' }}
className={_isRecordingOrVideo ? 'formUploadVideoOrRecording' : 'formUpload'}
showUploadList={{
showPreviewIcon: _isRecordingOrVideo,
showDownloadIcon: true,
downloadIcon: <DownloadOutlined/>,
}}
accept={returnFileTypeString(schema.renderTo)}
>
{
!_isRecordingOrVideo ?
<Button disabled={schema.disabled} icon={<UploadOutlined/>}>Upload</Button> : '+ Upload'
}
</Upload>
{/* </ImgCrop>*/}
<Modal
style={{ width: '30%' }}
bodyStyle={{ textAlign: 'center' }}
visible={previewVisible}
title={previewTitle}
footer={null}
onCancel={handleCancel}
>
{
_isVideo ?
<video width={'100%'} height={'100%'} controls autoPlay src={previewUrl}/> : ''
}
{
_isAudio ? <audio controls autoPlay src={previewUrl}/> : ''
}
{
_isImage ? <img width={'100%'} height={'100%'} src={previewUrl} alt="缩略图"/> : ''
}
</Modal>
</>
);
};
......
import React, { useEffect, useMemo, useState,useRef } from 'react';
import { BasicChart } from '@wisdom-components/basicchart';
import { reportService } from '../../../api';
import styles from './index.less';
import { returnFields, returnOptionsArr } from '../../utils/handleOption';
const ChartComponent = (props) => {
const [columnsData, setColumnsData] = useState([]);
const [options, setOptions] = useState([]);
const { reportName, chartOptions, reportData } = props;
const chartRef = useRef();
const getData = () => {
let columns = returnFields(JSON.stringify(chartOptions));
if (!columns.length) return ''; //
reportService.getChartConfigDataByColumn({
reportName,
columns,
}).then(res => {
let _data = [];
if (res.code === 0) _data = res.data.data;
setColumnsData(_data);
});
};
useEffect(() => {
getData();
}, []);
useEffect(() => {
let _options = returnOptionsArr(chartOptions, columnsData, reportData.selectedRows);
setOptions(_options);
}, [columnsData, reportData.selectedRows.length]);
const resizeChart = () => {
chartRef.current.resize();
};
useEffect(() => {
window.addEventListener('resize', resizeChart);
return () => window.removeEventListener('resize', resizeChart);
}, []);
return <div className={styles.chartWrapper}>
{
options.map((option, index) => <div className={styles.chart} style={{ ...option.custom_style }}>
<BasicChart ref={chartRef} style={{ width: '100%', height: '100%' }} key={`${index}_${option.series.length}`}
option={option}/>
</div>)
}
</div>;
};
export default ChartComponent;
.chartWrapper {
width: 100%;
height: 100%;
display: flex;
padding: 0 8px 8px;
gap: 8px;
overflow: hidden;
.chart {
background: #ffffff;
}
}
import React, { useRef } from 'react';
import styles from './index.less';
const LayOutComponent = ({ layoutOptions, children }) => {
const {
layout,
chartCount,
tableConfigs,
chartConfigs,
} = layoutOptions;
const { width, height } = tableConfigs[0];
const layoutRef = useRef({
layoutMap: {
'上表下图': {
flexDirection: 'column',
},
'上图下表': {
flexDirection: 'column-reverse',
},
'左表右图': {
flexDirection: 'row',
},
'左图右表': {
flexDirection: 'row-reverse',
},
},
chartLayoutMap: {
'上表下图': {
flexDirection: 'row',
},
'上图下表': {
flexDirection: 'row',
},
'左表右图': {
flexDirection: 'column',
},
'左图右表': {
flexDirection: 'column',
},
},
});
return <div className={styles.wrapper} style={{ ...layoutRef.current.layoutMap[layout] }}>
<div className={styles.tableWrapper} style={{ width, height }}>
{children.find(item => item.key === 'table')}
</div>
<div className={styles.chartWrapper}
style={{ ...layoutRef.current.chartLayoutMap[layout] }}>
{children.find(item => item.key === 'chart')}
</div>
</div>;
};
export default LayOutComponent;
.wrapper {
display: flex;
width: 100%;
height: 100%;
gap: 6px;
.chartWrapper {
flex:1;
overflow: hidden;
}
.tableWrapper {
}
}
/**
* 原版报表功能,支持报表展示;
* 当前功能,配置了图表,则暂时报表+图表;否则只展示报表
* @Steps
* 1. 获取图表配置
* */
import React, { useEffect, useRef, useState } from 'react';
import ChartComponent from '../ReportWithChart/ChartComponent';
import LayOutComponent from '../ReportWithChart/ChartComponent';
import ReportsManage from '../../ReportsManage/ReportsManage';
import { reportService } from '../../api';
import { isString } from 'lodash';
const ReportWithChart = (props) => {
const { reportName, config } = props.params;
const [layoutOptions, setLayoutOptions] = useState(null);
const [chartOptions, setChartOptions] = useState(null);
const [reportData, setReportData] = useState(null);
const reportRef = useRef(null);
const getChartConfig = () => {
return reportService.getChartConfig({
reportName,
});
};
const trigger = (str) => {
let _data = reportRef?.current?.getData();
setReportData(_data);
};
useEffect(() => {
async function _getData() {
let _layoutOptions = null;
let _chartOptions = null;
if (config && isString(config)) {
let _str = JSON.parse(config);
_layoutOptions = _str.layoutOptions;
_chartOptions = _str.chartOptions;
} else {
let _config = await getChartConfig();
let _str = JSON.parse(_config.data.configInfo);
_layoutOptions = _str.layoutOptions;
_chartOptions = _str.chartOptions;
}
setLayoutOptions(_layoutOptions);
setChartOptions(_chartOptions);
}
_getData();
}, [config]);
return <>{layoutOptions && chartOptions ? <LayOutComponent layoutOptions={layoutOptions}>
<ReportsManage key={'table'} {...props} ref={reportRef} trigger={trigger}/>
<ChartComponent key={'chart'} reportName={reportName} chartOptions={chartOptions} reportData={reportData}/>
</LayOutComponent> : <ReportsManage {...props} ref={reportRef} trigger={trigger}/>
}</>;
};
export default ReportWithChart;
......@@ -102,7 +102,6 @@ const ReportsDataSourceSetting = () => {
setSubmitLoading(false);
})
.catch((err) => {
console.log(err);
setSubmitLoading(false);
});
},
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment