/** * * 报表设置列表 * create by ChenLong on 2022/6/28 * * 功能路径:src\pages\product\ReportsManage\Components\ReportsSetting.js * * 菜单参数列表:*变量名*(变量说明,数据类型,是否必填,取值范围) * @changelog: edit by ChenLong 2022年7月7日 * 增加日期类型的过滤,可以配置日期选择器,只允许存在一个日期类型的过滤;在表单提交时做校验 edit by ChenLong 2022年7月8日 表单的使用方式需要变更,需求为:1. * 动态表单控件需要封装成组件; 2. 动态列表需要使用Form.List替换】 待执行 edit by ChenLong 2022年7月8日 变更单页、全部统计的规则 */ import React, { useEffect, useRef, useState } from 'react'; import { DeleteOutlined, FormOutlined, MinusCircleOutlined, PlusOutlined, MenuOutlined, SettingOutlined, LeftOutlined, ExportOutlined, ImportOutlined, } from '@ant-design/icons'; import { Button, Checkbox, Divider, Form, Input, InputNumber, message, Modal, Row, Select, Space, Switch, Tooltip, Table, Upload, } from 'antd'; import { SketchPicker } from 'react-color'; import { arrayMoveImmutable } from 'array-move'; import BasicTable from '@wisdom-components/basictable'; import { reportService } from '../api'; import style from './ReportsSetting.less'; import classname from 'classnames'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { addReportDetailInfoIndex, API, exportReportConfig, importReportConfig, } from '../api/service/report'; import { isNumber, isString } from './utils/utils'; import moment from 'moment'; import CustomerColorPicker from './Components/customerColorPicker/CustomerColorPicker'; const { Option, OptGroup } = Select; const { TextArea } = Input; const { Search } = Input; const typeArray = { '文本': ['文本', '多行文本', '标签', '链接', '功能', '附件'], '数值': ['数值', '数值标签'], '日期': ['日期', '日期时间'], }; const filterRule = ['文本', '下拉', '多选', '日期', '复选框']; const publicSplit = '&split;'; const USER_ID = window.globalConfig.userInfo.OID; const ReportsSetting = () => { // 报表列表 const layout = { labelCol: { span: 4 }, wrapperCol: { span: 20 }, }; const [form] = Form.useForm(); const [createMainTableForm] = Form.useForm(); const [patchSubTableForm] = Form.useForm(); const [editDetailForm] = Form.useForm(); const watchType = Form.useWatch('type', form); const showFilter = Form.useWatch('isFilter', form); const fieldGroupLevel = Form.useWatch('level', form); const isStatistics = Form.useWatch('isStatistics', form); const [isCreatingMainTable, setIsCreatingMainTable] = useState(false); const colorPicker = useRef(); const reportDetails = useRef(); const [tableData, setTableData] = useState([]); // 常规使用的数据 const [tableLoading, setTableLoading] = useState(false); const [detailTableVisible, setDetailTableVisible] = useState(false); const columns = [ { title: '报表名称', dataIndex: 'reportName', key: 'reportName', width: 260, }, { title: '数据源', dataIndex: 'db_sourcesname', key: 'db_sourcesname', width: 200, render: text => !text ? '本地' : text, }, { title: '主表名称', dataIndex: 'tableName', key: 'tableName', width: 300, }, { title: '报表字段', dataIndex: 'reportFields', key: 'reportFields', // ellipsis:true, render: (text) => <Tooltip title={text}> {/* 自动折叠内容时,如果使用Tooltip,Tooltip会无法正确定位;建议手动设置内容折叠 */} <span className={style.reportFiled}>{text}</span> </Tooltip>, }, { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 200, }, { title: '创建人', dataIndex: 'creator', key: 'creator', width: 100, }, { title: '操作', width: 120, render: (text, record) => { return <div style={{ display: 'flex', justifyContent: 'space-around' }}> <FormOutlined title={'编辑字段'} onClick={() => { setCurrentDataSourceType( dataSourcesList.find(item => item.id === record.sourcesId)?.db_type || '', ); editReport(record); }} style={{ color: '#1685FF' }}/> <SettingOutlined title={'设置'} style={{ color: 'rgba(0,0,0,.55)' }} onClick={() => { setCurrentReport(record); setCurrentDataSourceType( dataSourcesList.find(item => item.id === record.sourcesId)?.db_type || '', ); clickReport(record.id); }}/> <ExportOutlined title={'导出配置'} onClick={() => exportConfigs(record)}/> <DeleteOutlined title={'删除报表'} style={{ color: 'red' }} onClick={() => deleteReport(record)}/> </div>; }, }, ]; // 详情表 const [detailData, setDetailData] = useState([]); // 详情表的数据 const [tempDetailData, setTempDetailData] = useState([]); // 备份数据 const [detailVisible, setDetailVisible] = useState(false); const [backgroundColor, setBackgroundColor] = useState('rgba(0,0,0,.85)'); const [showSketchPicker, setShowSketchPicker] = useState(false); const [createModalVisible, setCreateModalVisible] = useState(false); const [activeID, setActiveID] = useState(null); const [currentField, setCurrentField] = useState(null); const [patchFieldVisible, setPatchFieldVisible] = useState(false); const [subTableList, setSubTableList] = useState([]); const [allTableList, setAllTableList] = useState([]); // 数据库表 const [allFields, setAllFields] = useState([]); // 新增主表时的选择的表字段 const [allSubFields, setAllSubFields] = useState([]);// 新增子表字段 const [createBtnLoading, setCreateBtnLoading] = useState(false); const [currentReport, setCurrentReport] = useState({}); const [colorCardPosition, setColorCardPosition] = useState({}); const [labelColorPickerArray, setLabelColorPickerArray] = useState([]); // 标签色板 const [textColorPickerArray, setTextColorPickerArray] = useState([]); // 文本色板 const [numberColorPickerArray, setNumberColorPickerArray] = useState([]); // 数值色板 const [currentColorPicker, setCurrentColorPicker] = useState({ // 因为使用单例,需要记录是哪一个色板触发了 data: [], callback: () => { }, index: 0, key: 'init', // init 初始化时的key,用来解决初始化报错的问题;wordColor 用来区分是那部分的色板 }); // 记录需要修改的对象 const [submitFieldLoading, setSubmitFieldLoading] = useState(false); const [relationship, setRelationship] = useState([]); const [patchSubTableBtnLoading, setPatchSubTableBtnLoading] = useState(false); const [isEditing, setIsEditing] = useState(true); const [detailTableLoading, setDetailTableLoading] = useState(false); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRows, setSelectedRows] = useState([]); const [dataSourcesList, setDataSourcesList] = useState([]); const [currentDataSource, setCurrentDataSource] = useState(''); const [currentDataSourceType, setCurrentDataSourceType] = useState(''); const SortableItem = SortableElement((props) => <tr {...props} />); const SortableBody = SortableContainer((props) => <tbody {...props} />); // 导入配置 const uploadProps = { action: `${window.location.origin}${API.IMPORT_REPORT_DATA}`, multiple: false, showUploadList: false, headers: { 'Content-Type': 'multipart/form-data', }, withCredentials: true, customRequest({ action, file, headers, withCredentials }) { const formData = new FormData(); formData.append('file', file); const _data = { userId: USER_ID }; importReportConfig( { headers: { 'Content-Type': 'multipart/form-data', }, }, { ..._data }, formData, ).then(res => { if (res.code === 0) { message.success('导入成功!'); getData(); } else { message.info(res.msg); } }); }, }; const onSortEnd = ({ oldIndex, newIndex }) => { if (oldIndex !== newIndex) { const newData = arrayMoveImmutable(detailData.slice(), oldIndex, newIndex).filter( (el) => !!el, ); console.log('Sorted items: ', newData); setDetailData(newData); setTempDetailData(newData); editDetailForm.setFieldsValue(newData); saveOrder(newData); } }; const DraggableContainer = (props) => ( <SortableBody useDragHandle disableAutoscroll helperClass="row-dragging" onSortEnd={onSortEnd} {...props} /> ); const DraggableBodyRow = ({ className, style, ...restProps }) => { const index = detailData.findIndex((x) => x.id === restProps['data-row-key']); return <SortableItem index={index} {...restProps} />; }; const returnEqual = (index, key) => { // return detailData !== tempDetailData || detailData[index] !== tempDetailData[index] || (detailData[index] && tempDetailData[index] && detailData[index][key] !== tempDetailData[index][key]); return (detailData[index] && !tempDetailData[index]) || (detailData[index] && tempDetailData[index] && detailData[index][key] !== tempDetailData[index][key]); }; const detailColumns = [ { title: '', dataIndex: 'sort', width: isEditing ? 0 : 30, className: 'drag-visible', render: () => <DragHandle/>, }, { title: '表名', dataIndex: 'tableName', className: 'drag-visible', key: 'tableName', // colSpan: currentDataSourceType === 'webapi' ? 0 : 1, }, { title: '字段名', dataIndex: 'fieldName', key: 'fieldName', }, { title: '字段组', dataIndex: 'fieldGroup', key: 'fieldGroup', }, { title: '形态', dataIndex: 'type', key: 'type', width: 80, }, { title: '列宽', dataIndex: 'columnWidth', key: 'columnWidth', width: 120, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'columnWidth']} rules={[{ required: true, message: '列宽不能为空', }]}><InputNumber value={record?.columnWidth} className={returnEqual(index, 'columnWidth') ? style.boxShadow : ''} onChange={(e) => modifyDetailData('columnWidth', e, record, index)}/></Form.Item> : `${text}px`; }, }, { title: '对齐方式', dataIndex: 'alignType', key: 'alignType', width: 80, render: (text, record, index) => { const _map = { left: '左', right: '右', center: '中', }; return isEditing ? <Form.Item name={[index, 'alignType']}> <Select onChange={(e) => modifyDetailData('alignType', e, record, index)} className={returnEqual(index, 'alignType') ? style.boxShadowOfSelect : ''}> <Option value={text ? 'left' : ''}>左</Option> <Option value={'center'}>中</Option> <Option value={'right'}>右</Option> </Select> </Form.Item> : (_map[text] || '左'); }, }, { title: '是否固定', dataIndex: 'fixedColumn', key: 'fixedColumn', width: 120, render: (text, record, index) => { const _map = { left: '左', right: '右', }; return isEditing ? <Form.Item name={[index, 'fixedColumn']}> <Select onChange={(e) => modifyDetailData('fixedColumn', e, record, index)} className={returnEqual(index, 'fixedColumn') ? style.boxShadowOfSelect : ''}> <Option value={''}>不固定</Option> <Option value={'left'}>左</Option> <Option value={'right'}>右</Option> </Select> </Form.Item> : (_map[text] || '不固定'); }, }, { title: '是否显示', dataIndex: 'isShow', key: 'isShow', width: 100, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'isShow']} valuePropName="checked"> <Switch onChange={(e) => modifyDetailData('isShow', e, record, index)} checkedChildren="显示" unCheckedChildren="不显示" defaultChecked={false} className={returnEqual(index, 'isShow') ? style.boxShadowOfSwitch : ''}/> </Form.Item> : (text ? '是' : '否'); }, }, { title: '是否过滤', dataIndex: 'isFilter', key: 'isFilter', width: 120, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'isFilter']} valuePropName="checked"> <Switch onChange={(e) => modifyDetailData('isFilter', e, record, index)} checkedChildren="开启" unCheckedChildren="关闭" defaultChecked={false} className={returnEqual(index, 'isFilter') ? style.boxShadowOfSwitch : ''}/> </Form.Item> : (text ? '是' : '否'); }, }, { title: '过滤类型', dataIndex: 'filterRule', key: 'filterRule', width: 120, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'filterRule']}> <Select disabled={!record.isFilter} onChange={(e) => modifyDetailData('filterRule', e, record, index)} className={returnEqual(index, 'filterRule') ? style.boxShadowOfSelect : ''}> <Option value={''}>不过滤</Option> { filterRule.map(item => <Option value={item}>{item}</Option>) } </Select> </Form.Item> : text; }, }, { title: '向下合并', dataIndex: 'isMerge', key: 'isMerge', width: 120, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'isMerge']} valuePropName="checked"> <Switch onChange={(e) => modifyDetailData('isMerge', e, record, index)} checkedChildren="开启" unCheckedChildren="关闭" defaultChecked={false} className={returnEqual(index, 'isMerge') ? style.boxShadowOfSwitch : ''}/> </Form.Item> : (text ? '合并' : '不合并'); }, }, { title: '是否必填', dataIndex: 'isRequired', key: 'isRequired', width: 100, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'isRequired']} valuePropName="checked"> <Switch onChange={(e) => modifyDetailData('isRequired', e, record, index)} checkedChildren="是" unCheckedChildren="否" defaultChecked={false} className={returnEqual(index, 'isRequired') ? style.boxShadowOfSwitch : ''}/> </Form.Item> : (text ? '是' : '否'); }, }, { title: '是否只读', dataIndex: 'isReadOnly', key: 'isReadOnly', width: 100, render: (text, record, index) => { return isEditing ? <Form.Item name={[index, 'isReadOnly']} valuePropName="checked"> <Switch onChange={(e) => modifyDetailData('isReadOnly', e, record, index)} checkedChildren="是" unCheckedChildren="否" defaultChecked={false} className={returnEqual(index, 'isReadOnly') ? style.boxShadowOfSwitch : ''}/> </Form.Item> : (text ? '是' : '否'); }, }, { title: '操作', width: 80, render: (text, record) => { return <div style={{ display: 'flex', justifyContent: 'space-around' }}> <FormOutlined onClick={() => { setActiveID(record.id); if (record.color) setBackgroundColor(record.color); form.setFieldsValue(setDefaultValue(record)); setCurrentField(setDefaultValue(record)); setDetailVisible(true); } }/> <DeleteOutlined onClick={() => deleteReportDetail(record.id)} style={{ color: 'red' }}/> </div>; }, }, ]; const rowSelection = { onChange: (selectedRowKeys, selectedRows) => { setSelectedRowKeys(selectedRowKeys); setSelectedRows(selectedRows); }, }; const wordInputWidth = 300; const numberInputWidth = 120; const rangeWidth = 500; const tagWidth = 400; const getData = () => { setTableLoading(true); reportService.getReportConfigList().then(res => { if (res.code === 0) { // 增加visible属性,后续搜索时需要 let _data = res.data.map(item => { let _item = { ...item }; _item.visible = true; return _item; }); setTableData(_data); } else { message.error(res.msg); } setTableLoading(false); }).catch(err => { setTableLoading(false); }); }; const clickReport = (reportId) => { setTableLoading(true); reportService.getReportDetailsInfo({ reportId }).then(res => { if (res.code === 0) { setTableLoading(false); setDetailTableVisible(true); // 增加visible属性,方便后续检索的属性变更 let _final = res.data.details.map(item => { let _item = { ...item }; _item.visible = true; return _item; }); _final.sort((a, b) => b.isShow - a.isShow); // 将显示项放在前边 edit by zhangzhiwei 2023-07-04 editDetailForm.setFieldsValue(_final); setDetailData(_final); setTempDetailData(_final); // 存储关联关系 setRelationship(res.data.child); } }).catch(err => { setTableLoading(false); }); }; const restCreateReportForm = () => { createMainTableForm.resetFields(); setAllFields([]); }; const createReport = () => { setCreateBtnLoading(true); createMainTableForm.validateFields().then( values => { let _data = { reportName: values.reportName, tableName: values.tableName, reportFields: values.reportFields.join(','), creator: String(globalConfig.userInfo.OID), }; if (currentReport && currentReport.id) { _data.id = currentReport.id; return editReportOrSubTable({ rM_ReportInfo: [_data], sourcesId: currentReport.sourcesId, isAdd: false, }, () => { setCreateBtnLoading(false); setCreateModalVisible(false); getData(); restCreateReportForm(); }); } addReportOrPatchSubTable({ rM_ReportInfo: [_data], sourcesId: values.sourcesId, isAdd: true }, () => { setCreateBtnLoading(false); setCreateModalVisible(false); getData(); restCreateReportForm(); }); }, ).catch(err => { setCreateBtnLoading(false); }); }; const deleteReport = (report) => { Modal.confirm({ title: '请确认', content: `是否删除【${report.reportName}】报表?`, onOk: () => { reportService.deleteReportInfo({ reportId: report.id }).then(res => { if (res.code === 0) { message.success('删除成功!'); getData(); } }); }, }); }; const deleteReportDetail = (reportDetailId) => { Modal.confirm({ title: '请确认', content: '是否删除该参数?', onOk: () => { reportService.deleteReportDetailInfo({ reportDetailId }).then(res => { if (res.code === 0) { clickReport(currentReport.id); message.success('删除成功!'); } else { message.error(res.code); } }); }, }); }; const editReport = (record) => { openCreateModal(); setCurrentReport(record); setIsCreatingMainTable(false); createMainTableForm.setFieldsValue({ tableName: record.tableName, reportName: record.reportName, reportFields: record.reportFields.split(','), }); getFieldsFromTable(record.tableName, 'mainTable', record); }; const addReportOrPatchSubTable = (data, callback) => { reportService.addReportInfo(data).then(res => { if (res.code === 0) { message.success('提交成功!'); } else { message.error(res.msg); } if (callback) callback(); }); }; const editReportOrSubTable = (data, callback) => { reportService.editReportInfo(data).then(res => { if (res.code === 0) { message.success('提交成功!'); } else { message.error(res.msg); } if (callback) callback(); }); }; // 切换字段的同时,如果数据有修改,那需要保存之前的数据 edit by ChenLong 2022年8月29日 const changeField = (record) => { // submitReportDetails('changeField').then(res => { setActiveID(record.id); form.setFieldsValue(setDefaultValue(record)); // 手动设置文字的颜色 setBackgroundColor(record.color); // 手动设置labelConfig和number的设置 setNumberColorPickerArray(record.numericalConfigs); setLabelColorPickerArray(record.labelConfigs); setCurrentField(setDefaultValue(record)); // 为了确保前后数据统一 // }); }; const setDefaultValue = (record) => { if (!record) return {}; let _record = { ...record }; if (!_record.type) _record.type = '文本'; if (isString(_record.fieldGroup)) { _record.fieldGroup = _record.fieldGroup.split('-').reduce((final, curr, index) => { final[`fieldGroup_${record.fieldAlias}_${index}`] = curr; return final; }, {}); } if (!_record.filterRule) _record.filterRule = '下拉'; if (!_record.statisticsRule) _record.statisticsRule = '求和'; // 统计规则变更 if (isString(_record.statisticsData)) _record.statisticsData = { 单页: _record.statisticsData.includes('单页'), 全部: _record.statisticsData.includes('全部'), }; // 对齐方式设置默认值 if (!_record.alignType) _record.alignType = 'left'; return _record; }; // @params: {type:String} 不传入type,默认提交表单、关闭表单;传入type时 const submitReportDetails = (type) => { // 1.表单内的值;2.标签值 return form.validateFields().then(value => { // 需要将表单内带索引的fieldGroup_[number]处理成后端需要的fieldGroups: a-b-c-d; value.fieldGroup = Object.values(value.fieldGroup).join('-'); let _value = Object.assign(currentField, value); // 处理数值颜色和标签颜色 // 后端需求:labelConfig和numberConfig里面都需要设置默认configId并且id设置为0; if (numberColorPickerArray.length) _value.numericalConfigs = numberColorPickerArray.map(item => { let _item = { ...item }; Object.keys(_item).forEach(key => { if (_item[key] === '') _item[key] = null; }); _item.configId = _value.id; _item.id = 0; return _item; }); if (labelColorPickerArray.length) _value.labelConfigs = labelColorPickerArray.map(item => { let _item = { ...item }; _item.configId = _value.id; _item.id = 0; return _item; }); // 文字的颜色 if (backgroundColor) { _value.color = backgroundColor; } // 过滤规则的设置,需要确保日期类型的过滤规则字段是唯一的 let _isDateArray = detailData.filter(item => item.filterRule === '日期'); if (_isDateArray.length > 1 || (_isDateArray.length === 1 && _value.filterRule === '日期' && _isDateArray[0].fieldName !== _value.fieldName)) return message.error('已存在日期类型的过滤,请确保日期类型的过滤规则只存在一个!'); // 统计规则的提交变更 let _statisticsData = _value.statisticsData; _value.statisticsData = Object.keys(_statisticsData).filter(key => _statisticsData[key]).join(','); // 提交请求 setSubmitFieldLoading(true); reportService.addReportDetailInfo({ reportDetails: [_value] }).then(res => { if (res.code === 0) { message.success('提交成功!'); } else { message.error(res.msg); } setSubmitFieldLoading(false); if (!type) { setDetailVisible(false); } clickReport(currentReport.id); }); }); }; const searchReportList = (e) => { let _data = [...tableData]; let final = _data.map(item => { let _item = { ...item }; if (!e) { _item.visible = true; } else { _item.visible = _item.reportName.includes(e); } return _item; }); setTableData(final); }; const openCreateModal = (callback) => { if (callback) callback(); getTableFromDB((data) => { setAllTableList(data); createMainTableForm.setFieldsValue({ sourcesId: 0, }); setCreateModalVisible(true); }); }; const getTableFromDB = (callback, sourcesId) => { reportService.getTables({ sourcesId }).then(res => { if (res.code === 0) { callback(res.data); } else { message.error(res.msg); } }); }; const getFieldsFromTable = (tableName, type, record) => { //webapi的tableName传null let _data = tableName ? tableName.split(',').map(name => ({ name: name })) : null; // webapi类型的,不需要传tableName let _tempData = tableName ? { tableName: _data, sourcesId: (record ? record.sourcesId : currentReport.sourcesId) || 0, } : { tableName: [{ 'name': '', 'type': '' }], sourcesId: (record ? record.sourcesId : currentReport.sourcesId) || 0, }; reportService.getTableFields(_tempData).then(res => { if (res.code === 0) { if (type === 'mainTable') { setAllFields(res.data[0]?.fieldName || []); } if (type === 'subTable') { // setTable setAllSubFields(res.data); } } }); }; const showPatchSubModal = (sourceId) => { getTableFromDB((data) => { setSubTableList(data.filter(item => item.name !== currentReport.tableName)); }, sourceId); setPatchFieldVisible(true); getFieldsFromTable(currentReport.tableName, 'mainTable'); let subTableName = relationship.map(item => item.tableName); if (subTableName && subTableName.length) getFieldsFromTable(subTableName.join(','), 'subTable'); let _relationshipObject = {}; relationship.forEach(item => { let _arr = item.relation.split('='); _relationshipObject[(item.tableName + publicSplit + 'mainTable')] = _arr[0]; _relationshipObject[(item.tableName + publicSplit + 'subTable')] = _arr[1]; _relationshipObject[(item.tableName + publicSplit + 'isMasterDetail')] = item.isMasterDetail; }); patchSubTableForm.setFieldsValue({ subTableName, subTableFields: detailData.map(item => item.tableName + publicSplit + item.fieldName), ..._relationshipObject, }); }; const addVirtualColumn = () => { // 添加虚拟列;1. 增加字段;2.保存 const _detailData = [...detailData]; const _temp = { ..._detailData[0] }; delete _temp.id; _temp.filterRule = '';// 确保filterRule不是日期 _temp.alignType = 'left'; _temp.fixedColumn = ''; _temp.isFilter = false; // delete _temp.tableName; _temp.index = _detailData.length - 1; _temp.isVirtualColumn = true; //fieldAlias: "软件开票" // fieldGroup: "软件开票" // fieldName: "软件开票" _temp.fieldAlias = _temp.fieldGroup = _temp.fieldName = `虚拟字段${moment().format('YYYY-MM-DD-HH-mm-ss').replace(/-/g, '')}`; _detailData.push(_temp); setDetailData(_detailData); // setTempDetailData(_detailData); editDetailForm.setFieldsValue(_detailData); // submitDetailFromTable(); }; const editDetailInTable = () => { // setIsEditing(true); }; const submitDetailFromTable = () => { setDetailTableLoading(true); editDetailForm.validateFields().then(res => { // 去除掉标签、数字区间内的id let _detailData = detailData.map(item => { let _item = { ...item }; _item.numericalConfigs = _item.numericalConfigs.map(obj => { let _obj = { ...obj }; _obj.id = 0; return _obj; }); _item.labelConfigs = _item.labelConfigs.map(obj => { let _obj = { ...obj }; _obj.id = 0; return _obj; }); return _item; }); reportService.addReportDetailInfo({ reportDetails: _detailData }).then(res => { if (res.code === 0) { message.success('提交成功!'); } else { message.error(res.msg); } setDetailTableLoading(false); setSubmitFieldLoading(false); setDetailVisible(false); clickReport(currentReport.id); }).catch(err => { setDetailTableLoading(false); }); }); }; const patchSubTable2MainTable = () => { let _subTable = patchSubTableForm.getFieldValue('subTableName'); if (_subTable && _subTable.length === 0) { return clearRelation(currentReport.id); } patchSubTableForm.validateFields().then(async value => { setPatchSubTableBtnLoading(true); // 由于是动态表单数据,导致表单对象无法正常监听数据,要过滤掉未能监听的数据。 let _tempArray = value.subTableFields.filter(item => value.subTableName.includes(item.split(publicSplit)[0])).map(item => item.split(publicSplit)); if (!_tempArray || _tempArray.length === 0) return message.error('请勾选子表字段'); // 因为数据结构的问题,导致暂时无法正确获取表单数据,只能这样提示 let _tempObject = {}; _tempArray.forEach(item => { if (_tempObject[item[0]]) { _tempObject[item[0]].push(item[1]); } else { _tempObject[item[0]] = [item[1]]; } }); let rM_ReportInfo = Object.keys(_tempObject).map(key => { return { parentId: currentReport.id, tableName: key, reportFields: _tempObject[key].join(','), relation: `${value[key + `${publicSplit}mainTable`]}=${value[key + `${publicSplit}subTable`]}`, isMasterDetail: value[key + `${publicSplit}isMasterDetail`], }; }); // debugger // return false await reportService.addReportInfo({ rM_ReportInfo, sourcesId: currentReport.sourcesId, isAdd: false, }).then(res => { if (res.code === 0) { message.success('保存成功!'); setPatchFieldVisible(false); } else { message.error(res.msg); } }).catch(err => { message.error('保存失败!'); setPatchSubTableBtnLoading(false); }); setPatchSubTableBtnLoading(false); clickReport(currentReport.id); }); }; const clearRelation = (reportId) => { Modal.confirm({ title: '请确认', content: '是否需要清空关联关系?', onOk: () => { reportService.delReportChild({ reportId }).then(res => { if (res.code === 0) { message.success('删除成功!'); patchSubTableForm.resetFields(); setAllSubFields([]); getFieldsFromTable(currentReport.tableName, 'mainTable'); } else { message.error(res.msg); } }); }, }); }; const clickColorCard = (e) => { let _cardPosition = e.target.getBoundingClientRect(); let _wrapperPosition = reportDetails.current.getBoundingClientRect(); let _colorPicker = colorPicker.current.getBoundingClientRect(); // 减去最外层的边距之后,还需要减去色块的高度+外边白边的高度+1px的边框+1px间隙 + 8px的最外层容器的padding let _cardLeft = _cardPosition.left - _wrapperPosition.left - 4 - 8; let _cardTop = _cardPosition.top - _wrapperPosition.top + 14 + 4 + 1 + 1 - 8; // 需要考虑超出边距的问题,如果超出边界,则向上,向左平移 let isOuterOfBottom = (_cardTop + _colorPicker.height) - _wrapperPosition.height; // let isOuterOfRight = (_colorPicker.left + _colorPicker.width) - (_wrapperPosition.top + _wrapperPosition.height); if (isOuterOfBottom > 0) { _cardTop -= (isOuterOfBottom + 10); // 向上平移,10px保证显示效果 _cardLeft -= (_colorPicker.width + 5); // 向左平移,5px保证显示效果 } setColorCardPosition({ left: _cardLeft, top: _cardTop, }); setShowSketchPicker(true); }; const addColorPicker = (data, callback, init) => { let _labels = [...data]; _labels.push(init); callback(_labels); }; const removeColorPicker = (data, callback, index) => { let _labels = [...data]; _labels.splice(index, 1); callback(_labels); }; const changeColorLabel = (e, data, callback, key, index) => { // 接口需要id全部为 0 let _labels = [...data]; _labels[index][key] = e !== null ? isNumber(e) ? e : e.target.value : null; // e为数值时是InputNumber,e为对象时是Input callback(_labels); }; const changeBackgroundColor = (e) => { // 改变当前的 let _rgb = e.rgb; if (currentColorPicker.key === 'wordColor') { setBackgroundColor(`rgba(${_rgb.r},${_rgb.g},${_rgb.b},${_rgb.a})`); return; } let { data, callback, index, key } = currentColorPicker; let _data = [...data]; if (['tagColor', 'textColor'].includes(currentColorPicker.key)) { _data[index].color = e; } else { _data[index][key] = `rgba(${_rgb.r},${_rgb.g},${_rgb.b},${_rgb.a})`; } callback(_data); }; const returnCurrentColor = () => { let { data, index, key } = currentColorPicker; if (key === 'init') return 'rgba(0,0,0,.65)'; return data[index][key]; }; // 拖拽 const DragHandle = SortableHandle(() => ( <MenuOutlined style={{ cursor: 'grab', color: '#999', }} /> )); const saveOrder = (data) => { let _data = data.map((item, index) => { let _item = {}; _item.index = index; _item.id = item.id; return _item; }); addReportDetailInfoIndex(_data).then(res => { if (res.code !== 0) { message.error(res.msg); } else { clickReport(currentReport.id); } }); }; const submitDetail = (data) => { reportService.addReportDetailInfo({ reportDetails: data }).then(res => { if (res.code === 0) { message.success('提交成功!'); } else { message.error(res.msg); } setSubmitFieldLoading(false); clickReport(currentReport.id); }); }; const modifyDetailData = (key, value, record, index, data = detailData) => { let _data = [...data]; let _record = { ...record }; _record[key] = value; _data.splice(index, 1, _record); setDetailData(_data); }; const batchModify = (key, value) => { // 1.取出勾选的字段;2.批量修改值 if (selectedRowKeys.length === 0) return message.info('未勾选任何字段'); let _detailData = detailData.map(item => { let _item = { ...item }; if (selectedRowKeys.includes(_item.id)) { _item[key] = value; } return _item; }); setDetailData(_detailData); editDetailForm.setFieldsValue(_detailData); }; const exportConfigs = (record) => { setTableLoading(true); exportReportConfig({ responseType: 'blob' }, { reportId: record.id, }).then(res => { setTableLoading(false); if (res && res.code === -1) return message.error(res.msg); const url = window.URL.createObjectURL( new Blob([res], { type: 'application/json;charset=UTF-8' }), ); const a = document.createElement('a'); a.href = url; a.target = '_blank'; a.download = `${record.reportName}.json`; a.click(); a.remove(); }); }; const getDataSourcesList = () => { reportService.getDataSources().then(res => { if (res.code === 0) { setDataSourcesList(res.data); } else { setDataSourcesList([]); } }); }; const selectDataSource = (e) => { setCurrentDataSource(e); createMainTableForm.setFieldsValue({ tableName: '', reportFields: [] }); let type = dataSourcesList.find(item => item.id === e)?.db_type || ''; setCurrentDataSourceType(type); setAllFields([]); let _arr = e ? [(data) => { setAllTableList(data); }, e] : [(data) => { setAllTableList(data); }]; if (type === 'webapi') { // webapi不取表,接收接口返回的数据 getFieldsFromTable(null, 'mainTable', { sourcesId: e }); } else { getTableFromDB(..._arr); } }; useEffect(() => { getData(); getDataSourcesList(); }, []); useEffect(() => { let numericalConfigs = currentField ? currentField.numericalConfigs : []; let labelConfigs = currentField ? currentField.labelConfigs : []; setNumberColorPickerArray(numericalConfigs); setLabelColorPickerArray(labelConfigs); }, [watchType]); return <div className={style.reportSettings}> { detailTableVisible ? <div ref={reportDetails} className={style.reportDetails}> {/* 色板容器 */} <div onClick={(e) => { if (e.target.className.includes('colorSketch')) { setShowSketchPicker(false); } }} style={{ visibility: showSketchPicker ? 'visible' : 'hidden', }} className={style.colorSketch}> <div ref={colorPicker} style={{ position: 'absolute', left: colorCardPosition.left, top: colorCardPosition.top, }}> { ['textColor', 'tagColor'].includes(currentColorPicker.key) ? <CustomerColorPicker clickColorPicker={(backgroundColor) => { changeBackgroundColor(backgroundColor); }}/> : <SketchPicker width={240} presetColors={[ 'rgb(129, 134, 143)', 'rgb(41, 114, 244)', 'rgb(0, 163, 245)', 'rgb(69, 176, 118)', 'rgb(222, 60, 54)', 'rgb(248, 136, 37)', 'rgb(216,180,255)', 'rgb(154, 56, 215)', 'rgb(221, 64, 151)', ]} color={currentColorPicker.key === 'wordColor' ? backgroundColor : returnCurrentColor()} onChange={(e) => changeBackgroundColor(e)}/> } </div> </div> <Modal title={'附加子表'} width={600} visible={patchFieldVisible} onCancel={() => { setPatchFieldVisible(false); setAllFields([]); setAllSubFields([]); }} onOk={patchSubTable2MainTable} okButtonProps={{ loading: patchSubTableBtnLoading, }} footer={[ <Button onClick={() => clearRelation(currentReport.id)}>清空挂接关系</Button>, <Button onClick={() => { setPatchFieldVisible(false); setAllFields([]); setAllSubFields([]); patchSubTableForm.resetFields(); }}>取消</Button>, <Button type="primary" htmlType={'submit'} onClick={patchSubTable2MainTable}>确定</Button>, ]} > <Form form={patchSubTableForm} {...layout}> <Form.Item label={'子表'} rules={[{ required: true, message: '请选择需要附加的子表,若清空子表后提交,则会清空该报表关联关系', }]} name={'subTableName'}> <Select placeholder={'请选择子表'} maxTagCount={2} style={{ width: '100%' }} mode={'multiple'} onChange={(value) => { if (value && value.length === 0) { setAllSubFields([]); } else { getFieldsFromTable(value.join(','), 'subTable'); } }}> { subTableList.map(item => <Option value={item.name}>{item.name}</Option>) } </Select> </Form.Item> { allSubFields && allSubFields.length ? <Form.Item label={'子表字段'} rules={[{ required: true, message: '请选择字段', }]} name={'subTableFields'}> <Checkbox.Group style={{ height: 400, overflowY: 'scroll' }}> { allSubFields.map((item, index) => { return <div> <Divider orientation="left">{item.tableName}</Divider> <Row style={{ display: 'flex' }}> <Form.Item label={'主表'} name={`${item.tableName}${publicSplit}mainTable`} rules={[{ required: true, message: '请选择对应字段', }]}> <Select style={{ width: 150 }} placeholder={'主表对应字段'}> { allFields.map(field => <Option value={`${currentReport.tableName}.${field.name}`}>{field.name}</Option>) } </Select> </Form.Item> <Form.Item label={'子表'} name={`${item.tableName}${publicSplit}subTable`} rules={[{ required: true, message: '请选择对应字段', }]}> <Select style={{ width: 150 }} placeholder={'子表关联字段'}> { item.fieldName.map(field => <Option value={`${item.tableName}.${field.name}`}>{field.name}</Option>) } </Select> </Form.Item> </Row> <Row> {/*<Form.Item label={'是否主从表'} name={`${item.tableName}${publicSplit}isMasterDetail`}*/} <Form.Item label={'是否关联关系'} name={`${item.tableName}${publicSplit}isMasterDetail`} valuePropName={'checked'}> <Switch checkedChildren="是" unCheckedChildren="否"/> </Form.Item> </Row> { item.fieldName.map(field => { return <Row><Checkbox value={`${item.tableName}${publicSplit}${field.name}`}>{field.name}</Checkbox></Row>; }) } </div>; }) } </Checkbox.Group> </Form.Item> : '' } </Form> </Modal> <Modal title={'编辑字段属性'} width={920} visible={detailVisible} onCancel={() => setDetailVisible(false)} destroyOnClose footer={null} onClick={() => setShowSketchPicker(false)} > <div style={{ display: 'flex' }}> <div style={{ width: 200 }}> { detailData ? <ul> { detailData.map((item, index) => <li onClick={() => changeField(item)} className={classname(style.fieldList, activeID === item.id ? style.active : '')} key={item.id}>{item.fieldAlias}</li>) } </ul> : '' } </div> <div style={{ flex: 1, }}> {/*<Form {...layout} form={form} initialValues={setDefaultValue(currentField)}*/} <Form {...layout} form={form} onFinish={submitReportDetails}> <div style={{ height: 500, overflowY: 'scroll' }}> <Form.Item disabled label={'字段'} name={'fieldName'} rules={[ { required: true, message: '编码名称必填', }, ]}> <Input disabled style={{ width: wordInputWidth }}/> </Form.Item> <Form.Item label={'别名'} name={'fieldAlias'} rules={[ { required: true, message: '别名必填且不可重复', }, ]}> <Input style={{ width: wordInputWidth }}/> </Form.Item> <Form.Item label={'表头级数'} name={'level'} rules={[ { required: true, message: '别名必填且不可重复', }, ]}> <InputNumber min={1}/> </Form.Item> { fieldGroupLevel ? <Form.Item style={{ marginBottom: 0 }} label={'分组'}> <Input.Group compact> { (new Array((Number(fieldGroupLevel) * 2 - 1)).fill(1)).map((item, index) => { if (index % 2 === 0) { return <Form.Item key={`fieldGroup_${index / 2}`} style={{ width: 160 }} name={['fieldGroup', `fieldGroup_${currentField.fieldAlias}_${index / 2}`]} rules={[{ required: true, message: '分组名称必填', }]}> <Input/> </Form.Item>; } else { return <span style={{ color: 'rgba(0,0,0,.25)' }}> _ </span>; } }) } </Input.Group> </Form.Item> : '' } <Form.Item label={'形态'} name={'type'}> <Select style={{ width: wordInputWidth }}> { Object.keys(typeArray).map(key => { return <OptGroup label={key}> { typeArray[key].map(item => <Option value={item}>{item}</Option>) } </OptGroup>; }) } </Select> </Form.Item> <Form.Item label={'字体颜色'} name={'color'}> <div style={{ padding: 4, display: 'inline-flex', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', }}> <div style={{ width: '36px', height: '14px', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', backgroundColor: backgroundColor, }} onClick={(e) => { clickColorCard(e); setCurrentColorPicker({ key: 'wordColor', }); }}/> </div> </Form.Item> { watchType === '数值' ? <Form.Item label={'区间设置'}> { numberColorPickerArray.map((item, index) => { return <Space key={item.key} style={{ display: 'flex', marginBottom: 8, width: rangeWidth, }} align="baseline" > <Form.Item label={'最小值'} > <InputNumber value={item.minValue} onChange={(e) => changeColorLabel(e, numberColorPickerArray, setNumberColorPickerArray, 'minValue', index)}/> </Form.Item> <Form.Item label={'最大值'} > <InputNumber value={item.maxValue} onChange={(e) => changeColorLabel(e, numberColorPickerArray, setNumberColorPickerArray, 'maxValue', index)}/> </Form.Item> <Form.Item label={'颜色'}> <div style={{ padding: 4, display: 'inline-flex', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', }}> <div style={{ width: '36px', height: '14px', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', backgroundColor: item.color, }} onClick={(e) => { clickColorCard(e); setCurrentColorPicker({ data: numberColorPickerArray, callback: setNumberColorPickerArray, index, key: 'color', }); }}/> </div> </Form.Item> <MinusCircleOutlined onClick={() => removeColorPicker(numberColorPickerArray, setNumberColorPickerArray, index)}/> </Space>; }) } <Form.Item> <Button type="dashed" onClick={() => addColorPicker(numberColorPickerArray, setNumberColorPickerArray, { maxValue: '', minValue: '', color: 'rgba(0,0,0,.65)', })} block icon={<PlusOutlined/>}> 增加区间 </Button> </Form.Item> </Form.Item> : '' } { ['文本'].includes(watchType) ? <Form.Item label={'文本设置'}> { labelColorPickerArray.map((item, index) => { return <Space key={item.key} style={{ display: 'flex', marginBottom: 8, }} align="baseline" > <Form.Item label={'文本'} > <Input value={item.labelValue} onChange={(e) => changeColorLabel(e, labelColorPickerArray, setLabelColorPickerArray, 'labelValue', index)}/> </Form.Item> <Form.Item label={'颜色'} > <div style={{ padding: 4, display: 'inline-flex', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', }}> <div style={{ width: '36px', height: '14px', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', backgroundColor: item.color, }} onClick={(e) => { clickColorCard(e); setCurrentColorPicker({ data: labelColorPickerArray, callback: setLabelColorPickerArray, index, key: 'color', }); }}/> </div> </Form.Item> <MinusCircleOutlined onClick={() => removeColorPicker(labelColorPickerArray, setLabelColorPickerArray, index)}/> </Space>; }) } <Form.Item> <Button type="dashed" onClick={() => addColorPicker(labelColorPickerArray, setLabelColorPickerArray, { color: 'rgba(0,0,0,.65)', labelValue: '', })} block icon={<PlusOutlined/>}> 增加区间 </Button> </Form.Item> </Form.Item> : '' } { ['标签', '数值标签'].includes(watchType) ? <Form.Item label={'标签设置'}> { labelColorPickerArray.map((item, index) => { return <Space key={item.key} style={{ display: 'flex', marginBottom: 8, }} align="baseline" > <Form.Item label={'标签'} > <Input value={item.labelValue} onChange={(e) => changeColorLabel(e, labelColorPickerArray, setLabelColorPickerArray, 'labelValue', index)}/> </Form.Item> <Form.Item label={'颜色'} > <div style={{ padding: 4, display: 'inline-flex', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', }}> <div style={{ width: '36px', height: '14px', borderRadius: '2px', border: '1px solid rgba(0,0,0,.35)', backgroundColor: item.color, }} onClick={(e) => { clickColorCard(e); setCurrentColorPicker({ data: labelColorPickerArray, callback: setLabelColorPickerArray, index, key: 'tagColor', }); }}/> </div> </Form.Item> <MinusCircleOutlined onClick={() => removeColorPicker(labelColorPickerArray, setLabelColorPickerArray, index)}/> </Space>; }) } <Form.Item> <Button type="dashed" onClick={() => addColorPicker(labelColorPickerArray, setLabelColorPickerArray, { color: 'rgba(0,0,0,.65)', labelValue: '', })} block icon={<PlusOutlined/>}> 增加区间 </Button> </Form.Item> </Form.Item> : '' } { ['数值', '数值标签'].includes(watchType) ? <Form.Item label={'统计规则'} style={{ display: 'flex' }}> <Space style={{ display: 'flex', marginBottom: 8, }}> <Form.Item style={{ marginBottom: 0 }} name={'isStatistics'} valuePropName={'checked'}> <Switch checkedChildren="开启" unCheckedChildren="关闭" defaultChecked={false}/> </Form.Item> { isStatistics ? <> <Form.Item label={'统计规则'} rules={[{ required: true, message: '请选择统计规则', }]} style={{ marginBottom: 0 }} name={'statisticsRule'}> <Select style={{ width: 120 }}> <Option value={'求和'}>求和</Option> <Option value={'求平均'}>求平均</Option> <Option value={'求方差'}>求方差</Option> </Select> </Form.Item> <Form.Item name={['statisticsData', '单页']} style={{ marginBottom: 0 }} label={'单页统计'} valuePropName={'checked'}> <Switch checkedChildren="开启" unCheckedChildren="关闭"/> </Form.Item> <Form.Item name={['statisticsData', '全部']} style={{ marginBottom: 0 }} label={'全部统计'} valuePropName={'checked'}> <Switch checkedChildren="开启" unCheckedChildren="关闭"/> </Form.Item> </> : '' } </Space> </Form.Item> : '' } <Form.Item label={'配置'} name={'configItems'}> <TextArea rows={6}/> </Form.Item> </div> <Form.Item label={' '} colon={false} style={{ marginTop: 10 }}> <Button onClick={() => setDetailVisible(false)}>取消</Button> <Button loading={submitFieldLoading} style={{ marginLeft: 8 }} type="primary" htmlType="submit">提交</Button> </Form.Item> </Form> </div> </div> </Modal> <div className={style.tableWrapper}> <Row className={style.controlRow}> <LeftOutlined className={style.leftBtn} onClick={() => { setDetailTableVisible(false); }}/> <Form layout={'inline'} style={{ display: 'flex', flex: 1, justifyContent: 'space-between' }}> <div style={{ display: 'flex' }}> <Form.Item label={'快速索引'}> <Search onSearch={(e) => { let _detailData = detailData.map(item => { let _item = { ...item }; if (e) { _item.visible = item.fieldName.includes(e) || item.fieldAlias.includes(e); } else { _item.visible = true; } return _item; }); setDetailData(_detailData); setTempDetailData(_detailData); }}/> </Form.Item> <Form.Item> <Button style={{ marginRight: 8 }} onClick={() => showPatchSubModal(currentReport.sourcesId)}>附加子表</Button> <Button onClick={addVirtualColumn}>添加虚拟字段</Button> </Form.Item> </div> <Form.Item style={{ marginRight: 0 }}> { isEditing ? <> <Button style={{ marginRight: 8 }} onClick={() => { setDetailData(tempDetailData); editDetailForm.setFieldsValue(tempDetailData); }}>重置</Button> <Button type={'primary'} loading={detailTableLoading} style={{ marginRight: 8 }} onClick={submitDetailFromTable}>保存字段</Button> </> : '' } { isEditing ? <Button type={'primary'} onClick={() => setIsEditing(false)}>拖动排序</Button> : <Button type={'primary'} onClick={() => setIsEditing(true)}>关闭排序</Button> } </Form.Item> </Form> </Row> <div className={style.tableContent}> <Form className={style.tableForm} form={editDetailForm}> <BasicTable loading={detailTableLoading} pagination={false} bordered scroll={{ y: `calc(100% - ${selectedRowKeys.length ? 90 : 40}px)` }} // 需要考虑总结栏的高度 rowKey={'id'} columns={currentDataSourceType === 'webapi' ? detailColumns.filter(item => item.title !== '表名') : detailColumns} rowSelection={isEditing ? { type: 'checkbox', ...rowSelection, } : null} dataSource={detailData.filter(item => item.visible)} summary={(pageData) => { if (detailData && detailData.length > 1 && isEditing && selectedRows.length) { return <Table.Summary fixed> <Table.Summary.Row> <Table.Summary.Cell colSpan={7}>批量操作</Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <InputNumber onChange={(e) => batchModify('columnWidth', e)}/> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Select onChange={(e) => batchModify('alignType', e)}> <Option value={'left'}>左</Option> <Option value={'center'}>中</Option> <Option value={'right'}>右</Option> </Select> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Select onChange={(e) => batchModify('fixedColumn', e)}> <Option value={''}>不固定</Option> <Option value={'left'}>左</Option> <Option value={'right'}>右</Option> </Select> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Switch checkedChildren="显示" unCheckedChildren="不显示" defaultChecked={false} onChange={(e) => batchModify('isShow', e)}/> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Switch checkedChildren="开启" unCheckedChildren="关闭" defaultChecked={false} onChange={(e) => batchModify('isFilter', e)}/> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Select onChange={(e) => batchModify('isFilter', e)}> <Option value={''}>不过滤</Option> <Option value={'文本'}>文本</Option> <Option value={'下拉'}>下拉</Option> <Option value={'多选'}>多选</Option> <Option value={'日期'}>日期</Option> <Option value={'复选框'}>复选框</Option> </Select> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <Switch checkedChildren="开启" unCheckedChildren="关闭" defaultChecked={false} onChange={(e) => batchModify('isMerge', e)}/> </Form.Item> </Table.Summary.Cell> <Table.Summary.Cell> <Form.Item> <DeleteOutlined onClick={() => batchModify('delete')} title={'批量删除'} style={{ color: 'red' }}/> </Form.Item> </Table.Summary.Cell> </Table.Summary.Row> </Table.Summary>; } }} components={isEditing ? '' : { body: { wrapper: DraggableContainer, row: DraggableBodyRow, }, }} onRow={record => { return { onDoubleClick: (e) => { return false; if (e.target.cellIndex === detailColumns.length - 1 || e.target.cellIndex === void 0) return false; setActiveID(record.id); if (record.color) setBackgroundColor(record.color); form.setFieldsValue(setDefaultValue(record)); setCurrentField(setDefaultValue(record)); setDetailVisible(true); }, }; }} /> </Form> </div> </div> </div> : <div className={style.reportDetails}> <Modal onCancel={() => { setCreateModalVisible(false); setIsCreatingMainTable(false); setCurrentDataSource(''); createMainTableForm.resetFields(); }} closable={false} visible={createModalVisible} footer={null} destroyOnClose > <Form form={createMainTableForm} initialValues={{ sourcesId: 0 }} {...layout} onFinish={createReport}> { isCreatingMainTable ? <Form.Item label={'数据源'} name={'sourcesId'}> <Select onChange={selectDataSource}> <Option value={0}>本地</Option> { dataSourcesList.map(item => { return <Option value={item.id}>{item.db_sourcesname} <span style={{ color: 'rgba(0,0,0,.45)' }}>({item.db_type})</span></Option>; }) } </Select> </Form.Item> : '' } { currentDataSourceType !== 'webapi' ? <Form.Item label={'主表'} name={'tableName'} rules={[{ required: true, message: '请选择一张主表', }]}> <Select disabled={!isCreatingMainTable} placeholder={'选择一张表作为主表'} showSearch optionFilterProp="children" filterOption={(input, option) => option.children[0].includes(input)} onChange={(e) => { getFieldsFromTable(e, 'mainTable', { sourcesId: currentDataSource }); createMainTableForm.setFields([{ 'reportFields': [] }]); }} > { allTableList.map(item => <Option value={item.name}>{item.name} <span style={{ color: 'rgba(0,0,0,.45)' }}>({item.type === 'table' ? '表' : '视图'})</span></Option>) } </Select> </Form.Item> : '' } <Form.Item label={'报表名称'} name={'reportName'} rules={[{ required: true, message: '请输入报表名称', }]}> <Input placeholder={'请输入报表名称'}/> </Form.Item> { allFields.length ? <Form.Item label={'报表字段'} name={'reportFields'} rules={[{ required: true, message: '请选择需要绑定的字段!' }]}> <Checkbox.Group style={{ maxHeight: 400, overflowY: 'scroll' }}> { allFields.map(item => <Row><Checkbox value={item.name}>{item.name}</Checkbox></Row>) } </Checkbox.Group> </Form.Item> : '' } <Form.Item label={' '} colon={false}> <Button onClick={() => { setCreateModalVisible(false); setCurrentDataSource(''); createMainTableForm.resetFields(); }}>取消</Button> <Button loading={createBtnLoading} style={{ marginLeft: 8 }} type={'primary'} htmlType={'submit'}>提交</Button> </Form.Item> </Form> </Modal> <div className={style.tableWrapper}> <Row className={style.controlRow}> <Form layout={'inline'}> <Form.Item label={'快速索引'}> <Search onSearch={(e) => searchReportList(e)}/> </Form.Item> <Form.Item> <Button type={'primary'} style={{ marginRight: 8 }} onClick={() => openCreateModal(() => { setCurrentReport({}); setAllFields([]); setIsCreatingMainTable(true); createMainTableForm.setFieldsValue({ tableName: '', reportName: '', reportFields: [], }); })}>新增</Button> <Upload {...uploadProps}> <Button size="middle" icon={<ImportOutlined/>}> 导入 </Button> </Upload> </Form.Item> </Form> </Row> <div className={style.tableContent}> <BasicTable pagination={false} bordered loading={tableLoading} rowKey={'id'} columns={columns} dataSource={tableData.filter(item => item.visible)} /> </div> </div> </div> } </div>; } ; export default ReportsSetting;