import fetch from 'dva/fetch'; import React from 'react'; import ReactDOM from 'react-dom'; import { Select, Button, Modal, Input, Transfer, Row, Col, Form, message, notification } from 'antd'; import { connect } from 'dva'; import { getToken } from '@/utils/authority'; import config from '@/config/config'; import QueryItem from './QueryItem'; import OrderItem from './OrderItem'; import FormdataWrapper from '@/utils/object-to-formdata-custom'; const Option = Select.Option; let keyX = 1; function swapArray(arr, index1, index2) { arr[index1] = arr.splice(index2, 1, arr[index1])[0]; return arr; } const FormItem = Form.Item; @connect(({ DataObj, loading }) => ({ DataObj, loading: loading.models.DataObj, })) @Form.create() export default class Index extends React.Component { constructor(props) { super(props); this.state = { visiable: false, queryVisiable: false, groupVisiable: false, sortVisiable: false, currentQueryKey: null, currentGroupKey: null, orderVisiable: false, currentOrderKey: null, querys: [], orders: [], groups: [], gs: [], os: [], qs: [], mockData: [], targetKeys: [], sourceSelectedKeys: [], targetSelectedKeys: [], infos: {}, confirmLoading: false, }; } onSelectChange = (sourceSelectedKeys, targetSelectedKeys) => { this.setState({ sourceSelectedKeys, targetSelectedKeys }); }; deleteQuery = (i) => { const querys = this.state.querys; querys.splice(i, 1); this.setState({ querys }); }; deleteOrder = (i) => { const orders = this.state.orders; orders.splice(i, 1); this.setState({ orders }); }; deleteGroup = (i) => { const groups = this.state.groups; groups.splice(i, 1); this.setState({ groups }); }; open = () => { const { dispatch } = this.props; dispatch({ type: 'DataObj/getExportInfo', payload: { objId: this.props.objId, }, callback: (infos) => { const mockData = []; const qs = []; const gs = []; const os = []; for (var key in infos) { const x = infos[key]; mockData.push({ key: x.field, title: x.name, chosen: false, }); if (x.canQuery) { qs.push(x); } if (x.canGroup) { gs.push(x); } if (x.canOrder) { os.push(x); } } this.setState({ mockData, infos, visiable: true, qs, gs, os, }); }, }); }; onCancle = () => { this.setState({ visiable: false }); }; handleChange = (targetKeys, direction, moveKeys) => { this.setState({ targetKeys }); }; up = () => { keyX = keyX + 1; var { targetKeys, targetSelectedKeys } = this.state; for (var i = 0; i < targetKeys.length; i++) { if (targetKeys[i] === targetSelectedKeys[0]) { if (i === 0) return; targetKeys = swapArray(targetKeys, i, i - 1); break; } } this.setState({ targetKeys }); }; down = () => { keyX = keyX + 1; var { targetKeys, targetSelectedKeys } = this.state; for (var i = 0; i < targetKeys.length; i++) { if (targetKeys[i] === targetSelectedKeys[0]) { if (i === targetKeys.length - 1) return; targetKeys = swapArray(targetKeys, i, i + 1); break; } } this.setState({ targetKeys }); }; bottom = () => { keyX = keyX + 1; const { targetKeys, targetSelectedKeys } = this.state; var x = []; for (var i = 0; i < targetKeys.length; i++) { if (!targetSelectedKeys.includes(targetKeys[i])) { x.push(targetKeys[i]); } } x = [...x, ...targetSelectedKeys]; this.setState({ targetKeys: x }); }; top = () => { keyX = keyX + 1; const { targetKeys, targetSelectedKeys } = this.state; const x = [...targetSelectedKeys]; for (var i = 0; i < targetKeys.length; i++) { if (!targetSelectedKeys.includes(targetKeys[i])) { x.push(targetKeys[i]); } } this.setState({ targetKeys: x }); }; renderItem = (item) => { if (this.state.targetKeys.includes(item.key)) { const customLabel = ( <span className="custom-item" key={item.key}> {item.title} </span> ); return { label: customLabel, // for displayed item value: item.title, // for title and filter matching }; } else { const customLabel = ( <span className="custom-item" key={item.key}> {item.title} </span> ); return { label: customLabel, // for displayed item value: item.title, // for title and filter matching }; } }; addOrder = () => { this.setState({ orderVisiable: true }); }; okOrder = () => { const orders = this.state.orders; orders.push(this.state.infos[this.state.currentOrderKey]); this.setState({ orders, orderVisiable: false, currentOrderKey: null }); }; okGroup = () => { const groups = this.state.groups; groups.push(this.state.infos[this.state.currentGroupKey]); this.setState({ groups, groupVisiable: false, currentGroupKey: null }); }; addGroup = () => { this.setState({ groupVisiable: true }); }; addQuery = () => { this.setState({ queryVisiable: true }); }; okQuery = () => { const querys = this.state.querys; querys.push(this.state.infos[this.state.currentQueryKey]); this.setState({ querys, queryVisiable: false, currentQueryKey: null }); }; export = () => { this.props.form.validateFields((err, fieldsValue) => { if (err) return; //form.resetFields(); var qqs; if (this.props.mustQuerys != null) { qqs = [...this.props.mustQuerys]; } else { qqs = []; } const oos = []; const ggs = []; for (let key in fieldsValue) { var x = key.indexOf('__'); let kk = key.substr(x + 2); if (key.indexOf('q__') > -1) { qqs.push({ notes: this.state.infos[kk].notes, hql: this.state.infos[kk].hql, c: this.state.infos[kk].type, x: fieldsValue[key].stringX, v: fieldsValue[key].string, }); } else if (key.indexOf('o__') > -1) { oos.push({ hql: this.state.infos[kk].hql, x: fieldsValue[key].stringX }); } else if (key.indexOf('g__') > -1) { ggs.push({ hql: this.state.infos[kk].hql }); } } if (this.props.voClass && ggs.length === 0) { message.error('请至少选择一个聚合条件'); return; } if (this.state.targetKeys.length === 0) { message.error('请至少选择一个导出字段'); return; } const names = []; for (let i = 0; i < this.state.targetKeys.length; i++) { names.push(this.state.infos[this.state.targetKeys[i]].name); } let divElement = document.getElementById('downloadDiv'); console.log(config.sqlFormsServer); let downloadUrl = config.sqlFormsServer + '/DataObjApi/exportFormData?'; const token = getToken() != null && getToken() != 'null' ? getToken() : '0000'; downloadUrl = `${downloadUrl}token=${token}`; let param = { fields: this.state.targetKeys, names: names, beanName: this.props.beanName, querys: JSON.stringify(qqs), orders: JSON.stringify(oos), groups: JSON.stringify(ggs), voClass: this.props.voClass, objId:this.props.objId, modelClass: this.props.modelClass, preHandleClass: this.props.preHandleClass, hqlHandleClass: this.props.hqlHandleClass, }; param = {...param, ...this.props.params || {}} this.downloadFile(downloadUrl, param); }); }; downloadFile(url, params) { this.setState({ confirmLoading: true }); fetch(url, { method: 'POST', body: FormdataWrapper(params), }).then(res => { if (res.status != '200') { return res.json(); } else { return res.blob(); } }).then(data => { if (data instanceof Blob) { let a = document.createElement('a'); let url = window.URL.createObjectURL(data); let filename = (this.props.fileName ? this.props.fileName : '导出文件') + '.xlsx'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); a = null; } else { notification.error({ message: `文件导出错误`, description: data.errMsg, }); } }).catch(err => { notification.error({ message: `网络请求超时`, }); }).finally(() => { this.setState({ confirmLoading: false }); }); } cancelGroup = () => { this.setState({ currentGroupKey: null, groupVisiable: false }); }; cancelQuery = () => { this.setState({ currentQueryKey: null, queryVisiable: false }); }; cancelOrder = () => { this.setState({ currentOrderKey: null, orderVisiable: false }); }; selectOrder = (e) => { this.setState({ currentOrderKey: e }); }; selectQuery = (e) => { this.setState({ currentQueryKey: e }); }; selectGroup = (e) => { this.setState({ currentGroupKey: e }); }; render() { const { form } = this.props; const { visiable, targetKeys, sourceSelectedKeys, queryVisiable, querys, orders, groups, confirmLoading, targetSelectedKeys, mockData, qs, os, gs, currentQueryKey, currentOrderKey, orderVisiable, currentGroupKey, groupVisiable, } = this.state; return ( <span> <Button shape='round' onClick={this.open}>自定义导出</Button> <div id='downloadDiv' style={{ display: 'none' }}></div> <Modal width={670} maskClosable={false} destroyOnClose title="自定义查询、排序、导出" style={{ textAlign: 'center' }} visible={visiable} onOk={this.export} onCancel={this.onCancle} confirmLoading={confirmLoading} > <div style={{ overflowY: 'auto', maxHeight: '500px', height: '500px' }}> <div style={{ textAlign: 'left' }}> <Button type="primary">新增查询条件</Button> <Select style={{ width: 200, paddingRight: '10px' }} value={currentQueryKey} onChange={this.selectQuery}> {qs.map((r) => { return <Option key={r.field} value={r.field}> {r.name} </Option>; }, )} </Select> {currentQueryKey ? <span style={{ paddingLeft: '0' }}> <Button type="primary" onClick={this.okQuery}>确定</Button> </span> : ''} <div style={{ height: '12px' }}> </div> {querys.map((r, i) => <FormItem key={r.name + i} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} colon={false} label={r.name}> {form.getFieldDecorator(i + 'q__' + r.field, { initialValue: { stringX: '=' }, rules: [{ validator: (rule, value, callback) => { var errors = []; if (value == null) { errors.push(new Error('请输入查询值!', rule.field)); } else { if (value.stringX != 'IS NOT NULL' && value.stringX != 'IS NULL' && value.string == null) { errors.push(new Error('请输入查询值!', rule.field)); } } callback(errors); }, }], })( <QueryItem obj={r} key={r.name + i} deleteQuery={this.deleteQuery.bind(this, i)}/>)} </FormItem>) } </div> <div style={{ textAlign: 'left', paddingTop: '15px' }}> <Button type="primary">新增排序条件</Button> <Select style={{ width: 200, paddingRight: '10px' }} value={currentOrderKey} onChange={this.selectOrder}> {os.map((r) => { for (let j = 0; j < orders.length; j++) { if (orders[j].field === r.field) return; } return <Option key={r.field} value={r.field}>{r.name}</Option>; }, )} </Select> {currentOrderKey ? <span style={{ paddingLeft: '0' }}> <Button type="primary" onClick={this.okOrder}>确定</Button> </span> : ''} <div style={{ height: '12px' }}> </div> {orders.map((r, i) => <FormItem key={r.name + i} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} colon={false} label={'按' + r.name}> {form.getFieldDecorator(i + 'o__' + r.field, { initialValue: { stringX: 'desc' }, })( <OrderItem deleteOrder={this.deleteOrder.bind(this, i)}/>)} </FormItem>)} </div> {this.props.voClass ? <div style={{ textAlign: 'left', paddingTop: '15px' }}> <span style={{ paddingRight: '10px' }}>聚合条件:</span> {!groupVisiable ? <Button type="primary" onClick={this.addGroup}>新增</Button> : <span> <Select style={{ width: 100 }} value={currentGroupKey} onChange={this.selectGroup}> {gs.map((r) => { for (var j = 0; j < groups.length; j++) { if (groups[j].field == r.field) return; } return <Option key={r.field} value={r.field}> {r.name} </Option>; }, )} </Select> {currentGroupKey ? <Button type="primary" onClick={this.okGroup}>确定</Button> : ''} <Button type="primary" onClick={this.cancelGroup}>取消</Button> </span>} {groups.map((r, i) => <FormItem key={i + r.name} labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label={'按' + r.name + '聚合'}> {form.getFieldDecorator(i + 'g__' + r.field)( <Input style={{ display: 'none' }} value=""/>)} <Button type="danger" onClick={this.deleteGroup.bind(this, i)}>删除</Button> </FormItem>)} </div> : ''} <Row> <Col span={24} style={{ textAlign: 'left', paddingTop: '15px' }}> <span style={{ paddingRight: '10px' }}>导出项:</span> </Col> <Col span={18}> <Transfer key={keyX} style={{ textAlign: 'left' }} dataSource={mockData} listStyle={{ width: 200, height: 300, }} onSelectChange={this.onSelectChange} selectedKeys={[...sourceSelectedKeys, ...targetSelectedKeys]} rowKey={record => record.key} targetKeys={targetKeys} onChange={this.handleChange} render={this.renderItem} /> </Col> <Col span={2}> <div style={{ marginTop: 100 }}> <Button size="small" disabled={targetSelectedKeys.length === 0} onClick={this.top}> 批量置顶 </Button> <Button size="small" style={{ marginTop: 10 }} disabled={targetSelectedKeys.length !== 1} onClick={this.up}> 单项上移 </Button> <Button size="small" style={{ marginTop: 10 }} disabled={targetSelectedKeys.length !== 1} onClick={this.down}> 单项下移 </Button> <Button size="small" style={{ marginTop: 10 }} disabled={targetSelectedKeys.length === 0} onClick={this.bottom}> 批量置底 </Button> </div> </Col> </Row> </div> </Modal> </span> ); } }