| | |
| | | "filter": "false", |
| | | "defaultApp": "mk", |
| | | "defaultLang": "zh-CN", |
| | | "WXAppID": "", |
| | | "WXAppID": "wx4d8a34c8d4494872", |
| | | "WXminiAppID": "", |
| | | "debugger": false, |
| | | "licenseKey": "", |
New file |
| | |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | |
| | | const Formdict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS |
| | | |
| | | /** |
| | | * @description 获取显示列表单配置信息 |
| | | * @param {object} card // 搜索条件对象 |
| | | */ |
| | | export function getColumnForm (card, fields = []) { |
| | | let appType = sessionStorage.getItem('appType') |
| | | let roleList = sessionStorage.getItem('sysRoles') |
| | | if (roleList) { |
| | | try { |
| | | roleList = JSON.parse(roleList) |
| | | } catch (e) { |
| | | roleList = [] |
| | | } |
| | | } else { |
| | | roleList = [] |
| | | } |
| | | |
| | | let menulist = [] |
| | | |
| | | if (appType === 'pc') { |
| | | menulist = sessionStorage.getItem('appMenus') |
| | | } else if (!appType) { |
| | | menulist = sessionStorage.getItem('fstMenuList') |
| | | } |
| | | |
| | | if (menulist) { |
| | | try { |
| | | menulist = JSON.parse(menulist) |
| | | } catch (e) { |
| | | menulist = [] |
| | | } |
| | | } else { |
| | | menulist = [] |
| | | } |
| | | |
| | | let options = [{ |
| | | value: 'text', |
| | | text: Formdict['model.form.text'] |
| | | }, { |
| | | value: 'number', |
| | | text: Formdict['model.form.number'] |
| | | }, { |
| | | value: 'picture', |
| | | text: Formdict['model.form.picture'] |
| | | }, { |
| | | value: 'link', |
| | | text: Formdict['model.form.href'] |
| | | }, { |
| | | value: 'textarea', |
| | | text: Formdict['model.form.textarea'] |
| | | }, { |
| | | value: 'custom', |
| | | text: '自定义列' |
| | | }, { |
| | | value: 'colspan', |
| | | text: '合并列' |
| | | }, { |
| | | value: 'formula', |
| | | text: '公式' |
| | | }, { |
| | | value: 'index', |
| | | text: '序号' |
| | | }] |
| | | |
| | | if (!card.isSub) { |
| | | options.push({ |
| | | value: 'action', |
| | | text: '操作' |
| | | }) |
| | | } |
| | | |
| | | if (!card.linkurl && (!card.linkmenu || card.linkmenu.length === 0)) { |
| | | card.perspective = '' |
| | | } |
| | | |
| | | return [ |
| | | { |
| | | type: 'text', |
| | | key: 'label', |
| | | label: '列头文字', |
| | | initVal: card.label, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'type', |
| | | label: Formdict['model.form.type'], |
| | | initVal: card.type, |
| | | required: true, |
| | | options: options |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'field', |
| | | label: Formdict['model.form.field'], |
| | | initVal: card.field, |
| | | required: true, |
| | | options: fields |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'nameField', |
| | | label: Formdict['model.name'] + Formdict['model.form.field'], |
| | | initVal: card.nameField || '', |
| | | required: false, |
| | | options: [{uuid: 'empty', field: '', label: '空'}, ...fields] |
| | | }, |
| | | { |
| | | type: 'number', |
| | | key: 'Width', |
| | | min: 20, |
| | | max: 1000, |
| | | decimal: 0, |
| | | label: Formdict['model.form.columnWidth'], |
| | | initVal: card.Width || 120, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'joint', |
| | | label: Formdict['model.form.paramJoint'], |
| | | initVal: card.joint || 'true', |
| | | required: true, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'Hide', |
| | | label: Formdict['model.hidden'], |
| | | initVal: card.Hide || 'false', |
| | | required: true, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'IsSort', |
| | | label: Formdict['model.sort'], |
| | | initVal: card.IsSort || (card.isSub ? 'false' : 'true'), |
| | | required: true, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'Align', |
| | | label: Formdict['model.form.align'], |
| | | initVal: card.Align || 'left', |
| | | required: true, |
| | | options: [{ |
| | | value: 'left', |
| | | text: Formdict['model.form.alignLeft'] |
| | | }, { |
| | | value: 'center', |
| | | text: Formdict['model.form.alignCenter'] |
| | | }, { |
| | | value: 'right', |
| | | text: Formdict['model.form.alignRight'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'rowspan', |
| | | label: '行合并', |
| | | initVal: card.rowspan || 'false', |
| | | tooltip: '相邻行信息相同时,单元格合并。', |
| | | required: false, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'sum', |
| | | label: '显示合计', |
| | | initVal: card.sum || 'false', |
| | | tooltip: '合计信息只在使用系统数据源时有效。', |
| | | required: false, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'number', |
| | | key: 'decimal', |
| | | min: 0, |
| | | max: 18, |
| | | decimal: 0, |
| | | label: Formdict['header.form.decimal'], |
| | | initVal: card.decimal || 0, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'format', |
| | | label: Formdict['header.form.format'], |
| | | initVal: card.format || 'none', |
| | | options: [{ |
| | | value: 'none', |
| | | text: '无' |
| | | }, { |
| | | value: 'thdSeparator', |
| | | text: '千分位' |
| | | }, { |
| | | value: 'percent', |
| | | text: '百分比' |
| | | }, { |
| | | value: 'abs', |
| | | text: '绝对值' |
| | | }], |
| | | required: false |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'textFormat', |
| | | label: Formdict['header.form.format'], |
| | | initVal: card.textFormat || 'none', |
| | | options: [{ |
| | | value: 'none', |
| | | text: '无' |
| | | }, { |
| | | value: 'encryption', |
| | | text: '加密' |
| | | }, { |
| | | value: 'YYYY-MM-DD', |
| | | text: 'YYYY-MM-DD' |
| | | }, { |
| | | value: 'YYYY-MM-DD HH:mm:ss', |
| | | text: 'YYYY-MM-DD HH:mm:ss' |
| | | }], |
| | | required: false |
| | | }, |
| | | { |
| | | type: 'text', |
| | | key: 'prefix', |
| | | label: Formdict['header.form.prefix'], |
| | | initVal: card.prefix || '', |
| | | required: false, |
| | | readonly: false |
| | | }, |
| | | { |
| | | type: 'text', |
| | | key: 'postfix', |
| | | label: Formdict['header.form.postfix'], |
| | | initVal: card.postfix || '', |
| | | required: false, |
| | | readonly: false |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'lenWidRadio', |
| | | label: '长宽比', |
| | | initVal: card.lenWidRadio || '1:1', |
| | | required: true, |
| | | options: [ |
| | | { value: '1:1', text: '1:1' }, |
| | | { value: '4:3', text: '4:3' }, |
| | | { value: '3:2', text: '3:2' }, |
| | | { value: '16:9', text: '16:9' }, |
| | | { value: '2:1', text: '2:1' }, |
| | | { value: '3:1', text: '3:1' }, |
| | | { value: '4:1', text: '4:1' }, |
| | | { value: '5:1', text: '5:1' }, |
| | | { value: '6:1', text: '6:1' }, |
| | | { value: '7:1', text: '7:1' }, |
| | | { value: '8:1', text: '8:1' }, |
| | | { value: '9:1', text: '9:1' }, |
| | | { value: '10:1', text: '10:1' }, |
| | | { value: '3:4', text: '3:4' }, |
| | | { value: '2:3', text: '2:3' }, |
| | | { value: '9:16', text: '9:16' }, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'picSort', |
| | | label: '图片排列', |
| | | initVal: card.picSort || '1', |
| | | tooltip: '同一单元格内,含有多张图片时的列数。', |
| | | required: false, |
| | | options: [{ |
| | | value: '1', |
| | | text: '1' |
| | | }, { |
| | | value: '2', |
| | | text: '2' |
| | | }, { |
| | | value: '3', |
| | | text: '3' |
| | | }, { |
| | | value: '4', |
| | | text: '4' |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'scale', |
| | | label: '点击缩放', |
| | | initVal: card.scale || 'true', |
| | | required: false, |
| | | options: [{ |
| | | value: 'true', |
| | | text: Formdict['model.true'] |
| | | }, { |
| | | value: 'false', |
| | | text: Formdict['model.false'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'perspective', |
| | | label: '字段透视', |
| | | initVal: card.perspective || '', |
| | | options: [{ |
| | | value: '', |
| | | text: '无' |
| | | }, { |
| | | value: 'linkmenu', |
| | | text: '菜单' |
| | | }, { |
| | | value: 'linkurl', |
| | | text: '链接' |
| | | }], |
| | | forbidden: appType === 'mob' |
| | | }, |
| | | { |
| | | type: appType === 'pc' ? 'select' : 'cascader', |
| | | key: 'linkmenu', |
| | | label: Formdict['model.menu'], |
| | | initVal: card.linkmenu || (appType === 'pc' ? '' : []), |
| | | required: true, |
| | | options: menulist, |
| | | forbidden: appType === 'mob' |
| | | }, |
| | | { |
| | | type: 'textarea', |
| | | key: 'linkurl', |
| | | label: '链接地址', |
| | | initVal: card.linkurl || '', |
| | | required: true, |
| | | forbidden: appType === 'mob' |
| | | }, |
| | | { |
| | | type: 'multiselect', |
| | | key: 'linkfields', |
| | | label: '关联字段', |
| | | initVal: card.linkfields || [], |
| | | required: false, |
| | | options: fields, |
| | | forbidden: appType === 'mob' |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'open', |
| | | label: '打开方式', |
| | | initVal: card.open || 'blank', |
| | | required: false, |
| | | forbid: appType !== 'pc', |
| | | options: [ |
| | | { value: 'blank', text: '新窗口' }, |
| | | { value: 'self', text: '当前窗口' } |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'eval', |
| | | label: '解析', |
| | | initVal: card.eval || 'true', |
| | | tooltip: '当公式内容涉及计算时请选择“是”,当公式内容为字段拼接时请选择“否”。', |
| | | required: false, |
| | | options: [ |
| | | { value: 'true', text: '是' }, |
| | | { value: 'false', text: '否' } |
| | | ] |
| | | }, |
| | | { |
| | | type: 'textarea', |
| | | key: 'formula', |
| | | label: '公式', |
| | | initVal: card.formula || '', |
| | | tooltip: '执行时会使用查询到的数据替换相应的字段,展示获得的结果,在不使用解析时换行符或空格会替换为页面元素。可使用JS的一些语法,如:三元表达式 @field1@ > @field2@ ? 0 : 1;Math对象,取绝对值 Math.abs(@field@)、四舍五入 Math.round(@field@)等', |
| | | placeholder: '例如:@price@ * @number@', |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'multiselect', |
| | | key: 'blacklist', |
| | | label: Formdict['header.form.blacklist'], |
| | | initVal: card.blacklist || [], |
| | | required: false, |
| | | options: roleList, |
| | | forbidden: appType === 'mob' |
| | | } |
| | | ] |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Cascader, Modal } from 'antd' |
| | | import { QuestionCircleOutlined } from '@ant-design/icons' |
| | | |
| | | import { getColumnForm } from './formconfig' |
| | | import { formRule } from '@/utils/option.js' |
| | | import './index.scss' |
| | | |
| | | const { TextArea } = Input |
| | | const columnTypeOptions = { |
| | | text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'blacklist', 'perspective', 'rowspan'], |
| | | number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'blacklist', 'perspective', 'sum', 'rowspan'], |
| | | link: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'blacklist', 'nameField'], |
| | | textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'blacklist'], |
| | | picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio', 'picSort'], |
| | | colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'], |
| | | custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'], |
| | | action: ['label', 'type', 'Align', 'Width'], |
| | | formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'], |
| | | index: ['label', 'type', 'Align', 'Width'] |
| | | } |
| | | |
| | | class NormalTableColumn extends Component { |
| | | static propTpyes = { |
| | | dict: PropTypes.object, // 字典项 |
| | | visible: PropTypes.bool, |
| | | column: PropTypes.object, |
| | | fields: PropTypes.array, |
| | | submitCol: PropTypes.func, // 提交事件 |
| | | cancelCol: PropTypes.func // 取消时删除事件 |
| | | } |
| | | |
| | | state = { |
| | | visible: false, |
| | | formlist: null |
| | | } |
| | | |
| | | UNSAFE_componentWillReceiveProps (nextProps) { |
| | | if (nextProps.column && !is(fromJS(this.props.column), fromJS(nextProps.column))) { |
| | | this.editColumn(nextProps.column) |
| | | } |
| | | } |
| | | |
| | | editColumn = (column) => { |
| | | let fields = fromJS(this.props.fields).toJS().map(item => { |
| | | if (item.label.toLowerCase() !== item.field.toLowerCase()) { |
| | | item.text = item.label + '(' + item.field + ')' |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | let formlist = getColumnForm(column, fields) |
| | | let _options = fromJS(columnTypeOptions[column.type]).toJS() |
| | | if (column.type === 'text' || column.type === 'number') { |
| | | if (column.perspective === 'linkmenu') { |
| | | _options.push('linkmenu', 'linkfields', 'open') |
| | | } else if (column.perspective === 'linkurl') { |
| | | _options.push('linkurl', 'linkfields', 'open') |
| | | } |
| | | } |
| | | |
| | | this.setState({ |
| | | visible: true, |
| | | type: column.type, |
| | | formlist: formlist.map(item => { |
| | | item.hidden = !_options.includes(item.key) |
| | | |
| | | return item |
| | | }) |
| | | }) |
| | | if (column.focus) { |
| | | setTimeout(() => { |
| | | try { |
| | | let _form = document.getElementById('label') |
| | | _form && _form.select() |
| | | } catch (e) { |
| | | console.warn('表单focus失败!') |
| | | } |
| | | }, 200) |
| | | } |
| | | } |
| | | |
| | | typeChange = (key, value, option) => { |
| | | if (key === 'type') { |
| | | let _options = fromJS(columnTypeOptions[value]).toJS() |
| | | |
| | | this.setState({ |
| | | type: value, |
| | | formlist: this.state.formlist.map(item => { |
| | | item.hidden = !_options.includes(item.key) |
| | | |
| | | return item |
| | | }) |
| | | }, () => { |
| | | if (value === 'link' || value === 'textarea' || value === 'picture') { |
| | | this.props.form.setFieldsValue({IsSort: 'false'}) |
| | | } else if (value === 'text' || value === 'number') { |
| | | this.props.form.setFieldsValue({perspective: ''}) |
| | | } else if (value === 'action' || value === 'colspan') { |
| | | this.props.form.setFieldsValue({Align: 'center'}) |
| | | } |
| | | }) |
| | | } else if (key === 'field') { |
| | | let values = {label: option.props.label || option.props.children} |
| | | if (/Decimal|int/ig.test(option.props.datatype)) { |
| | | let decimal = 0 |
| | | if (/Decimal/ig.test(option.props.datatype)) { |
| | | decimal = +option.props.datatype.replace(/Decimal\(18,/ig, '').replace(')', '') |
| | | } |
| | | values.type = 'number' |
| | | values.decimal = decimal |
| | | } else { |
| | | values.type = 'text' |
| | | } |
| | | |
| | | if (values.type !== this.state.type) { |
| | | values.perspective = '' |
| | | let _options = fromJS(columnTypeOptions[values.type]).toJS() |
| | | |
| | | this.setState({ |
| | | type: values.type, |
| | | formlist: this.state.formlist.map(item => { |
| | | item.hidden = !_options.includes(item.key) |
| | | |
| | | return item |
| | | }) |
| | | }, () => { |
| | | this.props.form.setFieldsValue(values) |
| | | }) |
| | | } else { |
| | | this.props.form.setFieldsValue(values) |
| | | } |
| | | } else if (key === 'format' && value === 'percent') { |
| | | this.props.form.setFieldsValue({postfix: '%'}) |
| | | } |
| | | } |
| | | |
| | | changeRadio = (key, value) => { |
| | | if (key === 'perspective') { |
| | | let _options = fromJS(columnTypeOptions[this.state.type]).toJS() |
| | | |
| | | if (value === 'linkmenu') { |
| | | _options.push('linkmenu', 'linkfields', 'open') |
| | | } else if (value === 'linkurl') { |
| | | _options.push('linkurl', 'linkfields', 'open') |
| | | } |
| | | |
| | | this.setState({ |
| | | formlist: this.state.formlist.map(item => { |
| | | item.hidden = !_options.includes(item.key) |
| | | |
| | | return item |
| | | }) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | getFields() { |
| | | const { getFieldDecorator } = this.props.form |
| | | const { formlist } = this.state |
| | | const fields = [] |
| | | |
| | | if (!formlist) return null |
| | | |
| | | formlist.forEach((item, index) => { |
| | | if (item.hidden || item.forbidden) return |
| | | |
| | | if (item.type === 'text') { |
| | | let rules = [] |
| | | if (item.key !== 'linkurl') { |
| | | rules = [{ |
| | | max: formRule.input.max, |
| | | message: formRule.input.message |
| | | }] |
| | | } |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.tooltip ? |
| | | <Tooltip placement="topLeft" title={item.tooltip}> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {item.label} |
| | | </Tooltip> : item.label |
| | | }> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal || '', |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.input'] + item.label + '!' |
| | | }, |
| | | ...rules |
| | | ] |
| | | })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'number') { |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.tooltip ? |
| | | <Tooltip placement="topLeft" title={item.tooltip}> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {item.label} |
| | | </Tooltip> : item.label |
| | | }> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal, |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.input'] + item.label + '!' |
| | | } |
| | | ] |
| | | })(item.unlimit ? <InputNumber onPressEnter={this.handleSubmit}/> : |
| | | <InputNumber min={item.min} max={item.max} precision={item.decimal} onPressEnter={this.handleSubmit}/>)} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'select') { |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.label}> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal || '', |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.select'] + item.label + '!' |
| | | } |
| | | ] |
| | | })( |
| | | <Select |
| | | showSearch |
| | | filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} |
| | | onChange={(value, option) => {this.typeChange(item.key, value, option)}} |
| | | getPopupContainer={() => document.getElementById('columnwinter')} |
| | | > |
| | | {item.options.map((option, index) => |
| | | <Select.Option key={index} datatype={option.datatype || ''} label={option.label || ''} value={(option.value || option.field || option.MenuID)}> |
| | | {(option.text || option.label || option.MenuName)} |
| | | </Select.Option> |
| | | )} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'radio') { |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.tooltip ? |
| | | <Tooltip placement="topLeft" title={item.tooltip}> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {item.label} |
| | | </Tooltip> : item.label |
| | | }> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal, |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.select'] + item.label + '!' |
| | | } |
| | | ] |
| | | })( |
| | | <Radio.Group onChange={(e) => {this.changeRadio(item.key, e.target.value)}}> |
| | | { |
| | | item.options.map(option => { |
| | | return ( |
| | | <Radio key={option.value} value={option.value}>{option.text}</Radio> |
| | | ) |
| | | }) |
| | | } |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'multiselect') { // 多选 |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.label}> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal || [] |
| | | })( |
| | | <Select |
| | | showSearch |
| | | mode="multiple" |
| | | filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} |
| | | > |
| | | {item.options.map((option, i) => |
| | | <Select.Option id={i} key={i} value={option.value || option.field}>{option.text || option.label}</Select.Option> |
| | | )} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'cascader') { // 多选 |
| | | fields.push( |
| | | <Col span={12} key={index}> |
| | | <Form.Item label={item.label}> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal || [], |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.select'] + item.label + '!' |
| | | } |
| | | ] |
| | | })( |
| | | <Cascader |
| | | options={item.options} |
| | | placeholder="" |
| | | getPopupContainer={() => document.getElementById('columnwinter')} |
| | | /> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'textarea') { |
| | | fields.push( |
| | | <Col span={24} key={index} className="textarea"> |
| | | <Form.Item label={item.tooltip ? |
| | | <Tooltip placement="topLeft" title={item.tooltip}> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {item.label} |
| | | </Tooltip> : item.label |
| | | }> |
| | | {getFieldDecorator(item.key, { |
| | | initialValue: item.initVal || '', |
| | | rules: [ |
| | | { |
| | | required: !!item.required, |
| | | message: this.props.dict['form.required.input'] + item.label + '!' |
| | | } |
| | | ] |
| | | })(<TextArea rows={2} disabled={item.readonly} placeholder={item.placeholder || ''}/>)} |
| | | </Form.Item> |
| | | </Col> |
| | | ) |
| | | } |
| | | }) |
| | | return fields |
| | | } |
| | | |
| | | handleSubmit = () => { |
| | | // 表单提交时检查输入值是否正确 |
| | | this.props.form.validateFieldsAndScroll((err, values) => { |
| | | if (!err) { |
| | | this.setState({visible: false, formlist: null}) |
| | | this.props.submitCol(values) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | editModalCancel = () => { |
| | | this.setState({visible: false, formlist: null}) |
| | | |
| | | this.props.cancelCol() |
| | | } |
| | | |
| | | render() { |
| | | const { visible } = this.state |
| | | const formItemLayout = { |
| | | labelCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 6 } |
| | | }, |
| | | wrapperCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 18 } |
| | | } |
| | | } |
| | | |
| | | return ( |
| | | <div style={{display: 'inline-block'}}> |
| | | <Modal |
| | | title="显示列编辑" |
| | | visible={visible} |
| | | width={800} |
| | | maskClosable={false} |
| | | onOk={this.handleSubmit} |
| | | onCancel={this.editModalCancel} |
| | | destroyOnClose |
| | | > |
| | | <Form {...formItemLayout} className="commontable-column-form" id="columnwinter"> |
| | | <Row gutter={24}>{this.getFields()}</Row> |
| | | </Form> |
| | | </Modal> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Form.create()(NormalTableColumn) |
New file |
| | |
| | | .commontable-column-form { |
| | | min-height: 190px; |
| | | .ant-cascader-menus { |
| | | padding: 5px 0px; |
| | | .ant-cascader-menu:last-child { |
| | | padding-right: 3px; |
| | | } |
| | | } |
| | | .textarea { |
| | | .ant-form-item-label { |
| | | width: 12%; |
| | | } |
| | | .ant-form-item-control-wrapper { |
| | | width: 88%; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | import React, { Component } from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { DndProvider, DragSource, DropTarget } from 'react-dnd' |
| | | import { Table, Popover, Modal, message } from 'antd' |
| | | import { PlusOutlined, FileSyncOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined } from '@ant-design/icons' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | import Utils from '@/utils/utils.js' |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | const { confirm } = Modal |
| | | const EditColumn = asyncIconComponent(() => import('./editColumn')) |
| | | const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent')) |
| | | const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent')) |
| | | const MobPagination = asyncIconComponent(() => import('@/menu/components/share/mobPagination')) |
| | | const PasteComponent = asyncIconComponent(() => import('@/components/paste')) |
| | | |
| | | class HeaderCol extends Component { |
| | | deleteCol = () => { |
| | | const _this = this |
| | | |
| | | confirm({ |
| | | content: '确定删除显示列吗?', |
| | | onOk() { |
| | | _this.props.deleteCol(_this.props.column) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | updateMarks = (vals) => { |
| | | const { column } = this.props |
| | | this.props.updateCol({...column, marks: vals}) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | |
| | | if (this.props.rowSpan !== nextProps.rowSpan || this.props.colSpan !== nextProps.colSpan) { |
| | | return true |
| | | } |
| | | |
| | | if (!nextProps.column) return false |
| | | |
| | | return !is(fromJS(this.props.column), fromJS(nextProps.column)) || |
| | | !is(fromJS(this.props.fields), fromJS(nextProps.fields)) || |
| | | this.props.index !== nextProps.index |
| | | } |
| | | |
| | | render() { |
| | | const { connectDragSource, connectDropTarget, moveCol, addElement, updateCol, editColumn, pasteCell, changeStyle, deleteCol, index, column, align, fields, children, ...restProps } = this.props |
| | | |
| | | if (index !== undefined) { |
| | | return connectDragSource( |
| | | connectDropTarget(<th {...restProps} index={index} style={{ cursor: 'move', textAlign: align }} onDoubleClick={() => column && this.props.editColumn(column)}> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}> |
| | | {column && ['custom', 'colspan', 'action'].includes(column.type) ? |
| | | <PlusOutlined className="plus" title="添加" onClick={() => this.props.addElement(column)} /> : null |
| | | } |
| | | <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} /> |
| | | {column && column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null} |
| | | {column && column.type === 'custom' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null} |
| | | <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} /> |
| | | {column && ['text', 'number', 'formula'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null } |
| | | </div> |
| | | } trigger="hover"> |
| | | {children} |
| | | </Popover> |
| | | </th>), |
| | | ) |
| | | } else if (column) { |
| | | return ( |
| | | <th {...restProps} key={column.uuid} onDoubleClick={() => this.props.editColumn(column)}> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}> |
| | | {column && ['custom', 'colspan'].includes(column.type) ? |
| | | <PlusOutlined className="plus" title="添加" onClick={() => this.props.addElement(column)} /> : null |
| | | } |
| | | <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} /> |
| | | {column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null} |
| | | <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} /> |
| | | {column && ['text', 'number', 'formula'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null } |
| | | </div> |
| | | } trigger="hover"> |
| | | {children} |
| | | </Popover> |
| | | </th> |
| | | ) |
| | | } else { |
| | | return (<th {...restProps}>{children}</th>) |
| | | } |
| | | } |
| | | } |
| | | |
| | | const rowSource = { |
| | | beginDrag(props) { |
| | | return { |
| | | index: props.index, |
| | | } |
| | | } |
| | | } |
| | | |
| | | const ColTarget = { |
| | | drop(props, monitor) { |
| | | const dragIndex = monitor.getItem().index |
| | | const hoverIndex = props.index |
| | | |
| | | if (dragIndex === undefined || hoverIndex === undefined || dragIndex === hoverIndex) { |
| | | return |
| | | } |
| | | |
| | | props.moveCol(dragIndex, hoverIndex) |
| | | monitor.getItem().index = hoverIndex |
| | | }, |
| | | } |
| | | |
| | | const DragableHeaderCol = DropTarget('col', ColTarget, connect => ({ |
| | | connectDropTarget: connect.dropTarget() |
| | | }))( |
| | | DragSource('col', rowSource, connect => ({ |
| | | connectDragSource: connect.dragSource(), |
| | | }))(HeaderCol), |
| | | ) |
| | | |
| | | class EditableColumnCell extends Component { |
| | | updateCard = (vals, btn) => { |
| | | const { column } = this.props |
| | | this.props.upComponent({...column, elements: vals}, btn) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | const { config, column } = this.props |
| | | |
| | | if (!nextProps.column) return true |
| | | |
| | | return !is(fromJS(column), fromJS(nextProps.column)) || |
| | | !is(fromJS(config.columns), fromJS(nextProps.config.columns)) || |
| | | !is(fromJS(config.action), fromJS(nextProps.config.action)) || |
| | | !is(fromJS(config.search), fromJS(nextProps.config.search)) |
| | | } |
| | | |
| | | render() { |
| | | const { column, config, children, className, style } = this.props |
| | | |
| | | if (column && column.type === 'custom') { |
| | | return ( |
| | | <td style={{padding: 0, minWidth: column.Width || 100, ...(column.style || {})}} className={className}> |
| | | <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/> |
| | | </td> |
| | | ) |
| | | } else if (column && column.type === 'action') { |
| | | return ( |
| | | <td style={{padding: '0 5px', textAlign: column.Align, minWidth: column.Width || 100}} className={'action-column ' + className}> |
| | | <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/> |
| | | </td> |
| | | ) |
| | | } else if (column) { |
| | | let val = column.field || '' |
| | | if (column.type === 'index') { |
| | | val = '$Index' |
| | | } else if (column.type === 'formula') { |
| | | val = column.formula |
| | | if (column.eval === 'false') { |
| | | val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, ' ') |
| | | val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span> |
| | | } |
| | | } |
| | | return ( |
| | | <td style={{...style, minWidth: column.Width || 100}} className={className}> |
| | | {val} |
| | | {column.Hide === 'true' ? <CloseCircleOutlined style={{marginLeft: '5px', color: 'orange', fontSize: '12px'}}/> : null} |
| | | {column.marks && column.marks.length ? <AntDesignOutlined className="profile"/> : null} |
| | | </td> |
| | | ) |
| | | } else { |
| | | return ( |
| | | <td style={style} className={className}> |
| | | {children} |
| | | </td> |
| | | ) |
| | | } |
| | | } |
| | | } |
| | | |
| | | class NormalTableColumns extends Component { |
| | | static propTpyes = { |
| | | config: PropTypes.object, // 配置信息 |
| | | updatecolumn: PropTypes.func // 数据变化 |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | appType: sessionStorage.getItem('appType'), |
| | | tableId: '', |
| | | data: [{uuid: Utils.getuuid()}], |
| | | refresh: false, // 强制刷新 |
| | | columns: [], |
| | | fields: [], |
| | | editStyleCard: null, |
| | | lineMarks: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { config } = this.props |
| | | |
| | | let tableId = (() => { |
| | | let uuid = [] |
| | | let _options = 'abcdefghigklmnopqrstuv' |
| | | for (let i = 0; i < 19; i++) { |
| | | uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1)) |
| | | } |
| | | return uuid.join('') |
| | | }) () |
| | | |
| | | this.setState({ |
| | | tableId, |
| | | columns: fromJS(config.cols).toJS(), |
| | | fields: fromJS(config.columns).toJS(), |
| | | lineMarks: config.lineMarks ? fromJS(config.lineMarks).toJS() : [] |
| | | }, () => { |
| | | const element = document.getElementById(tableId) |
| | | element && element.style.setProperty('--mk-table-border-color', config.wrap.borderColor || '#e8e8e8') |
| | | element && element.style.setProperty('--mk-table-color', config.wrap.color || 'rgba(0, 0, 0, 0.65)') |
| | | element && element.style.setProperty('--mk-table-font-size', config.wrap.fontSize || '14px') |
| | | element && element.style.setProperty('--mk-table-font-weight', config.wrap.fontWeight || 'normal') |
| | | }) |
| | | } |
| | | |
| | | UNSAFE_componentWillReceiveProps (nextProps) { |
| | | if (!is(fromJS(this.state.columns), fromJS(nextProps.config.cols))) { |
| | | let _columns = fromJS(nextProps.config.cols).toJS() |
| | | this.setState({columns: _columns}) |
| | | let lastcol = _columns.slice(-1)[0] |
| | | if (lastcol && lastcol.focus) { |
| | | this.editColumn(lastcol) |
| | | } |
| | | } else if (!is(fromJS(this.state.fields), fromJS(nextProps.config.columns))) { |
| | | this.setState({fields: fromJS(nextProps.config.columns).toJS()}) |
| | | } else if (!is(fromJS(this.props.config.wrap), fromJS(nextProps.config.wrap))) { |
| | | const element = document.getElementById(this.state.tableId) |
| | | element && element.style.setProperty('--mk-table-border-color', nextProps.config.wrap.borderColor || '#e8e8e8') |
| | | element && element.style.setProperty('--mk-table-color', nextProps.config.wrap.color || 'rgba(0, 0, 0, 0.65)') |
| | | element && element.style.setProperty('--mk-table-font-size', nextProps.config.wrap.fontSize || '14px') |
| | | element && element.style.setProperty('--mk-table-font-weight', nextProps.config.wrap.fontWeight || 'normal') |
| | | } |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | const { config } = this.props |
| | | |
| | | return !is(fromJS(this.state), fromJS(nextState)) || |
| | | !is(fromJS(config.wrap), fromJS(nextProps.config.wrap)) || |
| | | !is(fromJS(config.search), fromJS(nextProps.config.search)) || |
| | | !is(fromJS(config.action), fromJS(nextProps.config.action)) || |
| | | config.setting.laypage !== nextProps.config.setting.laypage |
| | | } |
| | | |
| | | moveCol = (dragIndex, hoverIndex) => { |
| | | let _columns = fromJS(this.state.columns).toJS() |
| | | |
| | | _columns.splice(hoverIndex, 0, ..._columns.splice(dragIndex, 1)) |
| | | |
| | | this.setState({ |
| | | columns: _columns |
| | | }, () => { |
| | | this.props.updatecolumn({...this.props.config, cols: _columns}) |
| | | }) |
| | | } |
| | | |
| | | loopCol = (columns, col) => { |
| | | return columns.map(column => { |
| | | if (column.type === 'colspan') { |
| | | column.subcols = this.loopCol(column.subcols, col) |
| | | } |
| | | if (column.uuid === col.uuid) { |
| | | return col |
| | | } |
| | | return column |
| | | }) |
| | | } |
| | | |
| | | updateCol = (col, btn) => { |
| | | let _columns = fromJS(this.state.columns).toJS() |
| | | _columns = this.loopCol(_columns, col) |
| | | |
| | | this.setState({ |
| | | columns: _columns, |
| | | }, () => { |
| | | let config = {...this.props.config, cols: _columns} |
| | | if (btn) { |
| | | config.action = config.action.filter(item => item.uuid !== btn.uuid) |
| | | } |
| | | |
| | | this.props.updatecolumn(config) |
| | | }) |
| | | } |
| | | |
| | | editColumn = (col) => { |
| | | this.setState({ |
| | | card: fromJS(col).toJS() |
| | | }) |
| | | } |
| | | |
| | | pasteCell = (col, cell, resolve) => { |
| | | resolve({status: true}) |
| | | |
| | | delete cell.copyType |
| | | cell.uuid = Utils.getuuid() |
| | | cell.focus = true |
| | | |
| | | MKEmitter.emit('cardAddElement', [this.props.config.uuid, col.uuid], cell) |
| | | } |
| | | |
| | | addElement = (col) => { |
| | | const { config } = this.props |
| | | let column = fromJS(col).toJS() |
| | | |
| | | if (column.type === 'colspan') { |
| | | column.subcols = column.subcols || [] |
| | | let subcol = { isSub: true, focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' } |
| | | column.subcols.push(subcol) |
| | | |
| | | this.setState({ |
| | | card: subcol |
| | | }) |
| | | this.updateCol(column) |
| | | } else if (column.type === 'custom') { |
| | | let newcard = {uuid: Utils.getuuid(), focus: true, width: 24, eleType: 'text', datatype: 'dynamic', style: {paddingLeft: '4px'}} |
| | | |
| | | // 注册事件-添加元素 |
| | | MKEmitter.emit('cardAddElement', [config.uuid, column.uuid], newcard) |
| | | } else if (column.type === 'action') { |
| | | let newcard = { |
| | | uuid: Utils.getuuid(), |
| | | focus: true, |
| | | eleType: 'button', |
| | | label: 'button', |
| | | OpenType: 'prompt', |
| | | class: 'primary', |
| | | intertype: 'system', |
| | | execSuccess: 'grid', |
| | | execError: 'never', |
| | | show: 'link' |
| | | } |
| | | |
| | | // 注册事件-添加元素 |
| | | MKEmitter.emit('cardAddElement', [config.uuid, column.uuid], newcard) |
| | | } |
| | | } |
| | | |
| | | submitCol = (col) => { |
| | | const { card } = this.state |
| | | |
| | | col.uuid = card.uuid |
| | | col.isSub = card.isSub === true |
| | | col.marks = card.marks || [] |
| | | |
| | | if (col.type === 'colspan') { |
| | | col.subcols = card.subcols || [] |
| | | } else if (col.type === 'custom') { |
| | | col.elements = card.type === 'custom' ? (card.elements || []) : [] |
| | | } else if (col.type === 'action') { |
| | | col.elements = card.type === 'action' ? (card.elements || []) : [] |
| | | } |
| | | |
| | | this.setState({card: null}) |
| | | this.updateCol(col) |
| | | } |
| | | |
| | | changeStyle = (col) => { |
| | | this.setState({ |
| | | editStyleCard: fromJS(col).toJS() |
| | | }) |
| | | |
| | | MKEmitter.emit('changeStyle', ['font', 'padding'], col.style || {}, this.getStyle) |
| | | } |
| | | |
| | | getStyle = (style) => { |
| | | const { editStyleCard } = this.state |
| | | |
| | | let _card = {...editStyleCard, style} |
| | | |
| | | this.updateCol(_card) |
| | | } |
| | | |
| | | cancelCol = () => { |
| | | const { card } = this.state |
| | | |
| | | if (card.focus) { |
| | | this.deleteCol(card) |
| | | } |
| | | |
| | | this.setState({card: null}) |
| | | } |
| | | |
| | | loopDelCol = (columns, col) => { |
| | | return columns.filter(column => { |
| | | if (column.type === 'colspan') { |
| | | column.subcols = this.loopDelCol(column.subcols, col) |
| | | } |
| | | return column.uuid !== col.uuid |
| | | }) |
| | | } |
| | | |
| | | deleteCol = (col) => { |
| | | const { appType } = this.state |
| | | let _columns = fromJS(this.state.columns).toJS() |
| | | |
| | | _columns = this.loopDelCol(_columns, col) |
| | | |
| | | this.setState({ |
| | | columns: _columns |
| | | }, () => { |
| | | this.props.updatecolumn({...this.props.config, cols: _columns}) |
| | | }) |
| | | |
| | | if (col.type !== 'action' || appType === 'mob') return |
| | | |
| | | let uuids = [] |
| | | col.elements && col.elements.forEach(c => { |
| | | if (appType === 'pc' && c.OpenType !== 'popview') return |
| | | |
| | | uuids.push(c.uuid) |
| | | }) |
| | | |
| | | if (uuids.length === 0) return |
| | | |
| | | MKEmitter.emit('delButtons', uuids) |
| | | } |
| | | |
| | | updateLineMarks = (vals) => { |
| | | this.setState({ |
| | | lineMarks: vals |
| | | }, () => { |
| | | this.props.updatecolumn({...this.props.config, lineMarks: vals}) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 显示列复制 |
| | | */ |
| | | copycolumn = () => { |
| | | const { columns } = this.state |
| | | |
| | | let oInput = document.createElement('input') |
| | | let val = { |
| | | copyType: 'cols', |
| | | cols: columns.filter(col => !col.origin) |
| | | } |
| | | |
| | | let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId') |
| | | if (srcid) { |
| | | val.$srcId = srcid |
| | | } |
| | | |
| | | oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val))) |
| | | document.body.appendChild(oInput) |
| | | oInput.select() |
| | | document.execCommand('Copy') |
| | | oInput.className = 'oInput' |
| | | oInput.style.display = 'none' |
| | | |
| | | message.success('复制成功。') |
| | | |
| | | document.body.removeChild(oInput) |
| | | } |
| | | |
| | | handlecolumns = (columns, fields, config, isSub) => { |
| | | return columns.map((col, index) => { |
| | | return { |
| | | title: col.label, |
| | | dataIndex: col.uuid, |
| | | align: col.Align, |
| | | // sorter: !isSub && col.IsSort === 'true', |
| | | sorter: col.IsSort === 'true', |
| | | onCell: () => ({ |
| | | column: col, |
| | | width: col.Width, |
| | | config: config, |
| | | upComponent: this.updateCol |
| | | }), |
| | | onHeaderCell: () => ({ |
| | | index: isSub ? undefined : index, |
| | | column: col, |
| | | fields: fields, |
| | | align: col.Align, |
| | | moveCol: this.moveCol, |
| | | updateCol: this.updateCol, |
| | | addElement: this.addElement, |
| | | editColumn: this.editColumn, |
| | | pasteCell: this.pasteCell, |
| | | changeStyle: this.changeStyle, |
| | | deleteCol: this.deleteCol, |
| | | }), |
| | | children: col.subcols && col.subcols.length ? this.handlecolumns(col.subcols, fields, config, true) : null, |
| | | } |
| | | }) |
| | | } |
| | | |
| | | syncfield = () => { |
| | | const { fields } = this.state |
| | | let columns = fromJS(this.state.columns).toJS() |
| | | |
| | | columns = columns.filter(c => !c.origin) |
| | | |
| | | let keys = columns.map(col => col.field) |
| | | |
| | | fields.forEach(item => { |
| | | if (keys.includes(item.field)) return |
| | | |
| | | let cell = { uuid: Utils.getuuid(), label: item.label, field: item.field, Align: 'left', Hide: 'false', IsSort: 'true', Width: 120, blacklist: [], postfix: '', prefix: '', linkmenu: [], marks: [], perspective: 'linkmenu' } |
| | | |
| | | if (/Nvarchar|date/ig.test(item.datatype)) { |
| | | cell.type = 'text' |
| | | cell.rowspan = 'false' |
| | | cell.textFormat = 'none' |
| | | } else { |
| | | cell.type = 'number' |
| | | cell.format = 'none' |
| | | cell.sum = 'false' |
| | | cell.decimal = item.decimal || 0 |
| | | cell.Width = 80 |
| | | } |
| | | |
| | | columns.push(cell) |
| | | }) |
| | | |
| | | const _this = this |
| | | |
| | | confirm({ |
| | | content: '确定同步字段集吗?', |
| | | onOk() { |
| | | _this.setState({columns}, () => { |
| | | _this.props.updatecolumn({..._this.props.config, cols: columns}) |
| | | }) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | clear = () => { |
| | | const _this = this |
| | | |
| | | confirm({ |
| | | content: '确定清空显示列吗?', |
| | | onOk() { |
| | | _this.setState({columns: []}, () => { |
| | | _this.props.updatecolumn({..._this.props.config, cols: []}) |
| | | }) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { config } = this.props |
| | | const { fields, card, lineMarks, dict, tableId, appType } = this.state |
| | | const components = { |
| | | header: { |
| | | cell: DragableHeaderCol |
| | | }, |
| | | body: { |
| | | cell: EditableColumnCell |
| | | } |
| | | } |
| | | |
| | | const columns = this.handlecolumns(this.state.columns, fields, config) |
| | | |
| | | return ( |
| | | <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''}`} id={tableId}> |
| | | <div className="col-control"> |
| | | <CopyOutlined title="复制显示列" onClick={this.copycolumn} /> |
| | | <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} /> |
| | | <FileSyncOutlined title="同步字段集" onClick={this.syncfield} /> |
| | | <DeleteOutlined title="清空显示列" onClick={this.clear}/> |
| | | </div> |
| | | <DndProvider> |
| | | <Table |
| | | rowKey="uuid" |
| | | size={config.wrap.size || 'middle'} |
| | | rowClassName="editable-row" |
| | | bordered={config.wrap.bordered !== 'false'} |
| | | components={components} |
| | | dataSource={this.state.data} |
| | | rowSelection={config.wrap.tableType ? { type: 'radio' } : null} |
| | | columns={columns} |
| | | pagination={appType !== 'mob' ? { |
| | | current: 1, |
| | | pageSize: 10, |
| | | pageSizeOptions: ['10', '25', '50', '100', '500', '1000'], |
| | | showSizeChanger: true, |
| | | total: 58, |
| | | showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条` |
| | | } : false} |
| | | /> |
| | | {appType === 'mob' && config.setting.laypage !== 'fasle' ? <MobPagination /> : null} |
| | | </DndProvider> |
| | | <EditColumn column={card} dict={dict} fields={fields} submitCol={this.submitCol} cancelCol={this.cancelCol}/> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default NormalTableColumns |
New file |
| | |
| | | .normal-table-columns { |
| | | position: relative; |
| | | --mk-table-border-color: #e8e8e8; |
| | | --mk-table-color: rgba(0, 0, 0, 0.65); |
| | | --mk-table-font-size: 14px; |
| | | --mk-table-font-weight: normal; |
| | | |
| | | .ant-table { |
| | | color: inherit; |
| | | font-size: inherit; |
| | | font-weight: inherit; |
| | | } |
| | | .ant-table-body { |
| | | overflow-x: auto; |
| | | tr { |
| | | td { |
| | | background: #ffffff; |
| | | } |
| | | td:not(.ant-table-selection-column) { |
| | | position: relative; |
| | | padding: 12px 8px; |
| | | >.profile { |
| | | position: absolute; |
| | | top: 2px; |
| | | right: 2px; |
| | | color: purple; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | } |
| | | .action-column { |
| | | .card-detail-row:empty { |
| | | min-height: 40px; |
| | | } |
| | | } |
| | | tr:hover td { |
| | | background: #ffffff!important; |
| | | } |
| | | } |
| | | |
| | | .ant-table-thead { |
| | | th { |
| | | position: relative; |
| | | .ant-table-column-sorter::before { |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | content: ''; |
| | | } |
| | | } |
| | | > tr > th { |
| | | padding: 12px 8px; |
| | | .ant-table-column-sorter .ant-table-column-sorter-inner { |
| | | .ant-table-column-sorter-up.on, .ant-table-column-sorter-down.on { |
| | | color: unset; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .col-control { |
| | | position: absolute; |
| | | z-index: 2; |
| | | right: 0; |
| | | top: -25px; |
| | | >.anticon, >div > .anticon { |
| | | font-size: 16px; |
| | | margin-right: 10px; |
| | | cursor: pointer; |
| | | } |
| | | >.anticon-copy { |
| | | color: #26C281; |
| | | } |
| | | >.anticon-delete { |
| | | color: #ff4d4f; |
| | | } |
| | | >.anticon-file-sync { |
| | | color: #1890ff; |
| | | } |
| | | >div >.profile { |
| | | color: purple; |
| | | } |
| | | } |
| | | .ant-table-small > .ant-table-content > .ant-table-body { |
| | | margin: 0; |
| | | } |
| | | |
| | | table, tr, th, td { |
| | | border-color: var(--mk-table-border-color)!important; |
| | | } |
| | | table tr { |
| | | th .ant-table-column-title { |
| | | // color: var(--mk-table-color)!important; |
| | | font-size: var(--mk-table-font-size)!important; |
| | | font-weight: var(--mk-table-font-weight)!important; |
| | | } |
| | | td { |
| | | color: var(--mk-table-color)!important; |
| | | font-size: var(--mk-table-font-size)!important; |
| | | font-weight: var(--mk-table-font-weight)!important; |
| | | } |
| | | } |
| | | } |
| | | .normal-table-columns.false { |
| | | .ant-pagination { |
| | | display: none; |
| | | } |
| | | } |
| | | .normal-table-columns.checkbox { |
| | | .ant-radio-inner { |
| | | border-radius: 0; |
| | | } |
| | | .ant-radio-inner::after { |
| | | border-radius: 0; |
| | | } |
| | | .ant-radio-checked::after { |
| | | border-radius: 0; |
| | | } |
| | | } |
| | | |
| | | .normal-table-columns.ghost { |
| | | .ant-table-thead > tr { |
| | | > th { |
| | | color: inherit; |
| | | background: transparent; |
| | | .ant-table-column-sorter .ant-table-column-sorter-inner { |
| | | color: inherit; |
| | | } |
| | | } |
| | | > th:hover { |
| | | background: transparent; |
| | | } |
| | | } |
| | | .ant-table-body { |
| | | overflow-x: auto; |
| | | tr { |
| | | td { |
| | | background: transparent; |
| | | } |
| | | } |
| | | tr:hover td { |
| | | background: transparent!important; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Popover } from 'antd' |
| | | import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | import { resetStyle } from '@/utils/utils-custom.js' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import getWrapForm from './options' |
| | | import Utils from '@/utils/utils.js' |
| | | |
| | | import './index.scss' |
| | | |
| | | const SettingComponent = asyncIconComponent(() => import('@/menu/datasource')) |
| | | const NormalForm = asyncIconComponent(() => import('@/components/normalform')) |
| | | const SearchComponent = asyncComponent(() => import('@/templates/sharecomponent/searchcomponent')) |
| | | const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent')) |
| | | const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader')) |
| | | const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) |
| | | const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent')) |
| | | const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent')) |
| | | // const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent')) |
| | | const ColumnComponent = asyncComponent(() => import('./columns')) |
| | | |
| | | class TableCardEditComponent extends Component { |
| | | static propTpyes = { |
| | | card: PropTypes.object, |
| | | deletecomponent: PropTypes.func, |
| | | updateConfig: PropTypes.func, |
| | | } |
| | | |
| | | state = { |
| | | appType: sessionStorage.getItem('appType'), |
| | | card: null, |
| | | back: false |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { card } = this.props |
| | | const { appType } = this.state |
| | | |
| | | if (card.isNew) { |
| | | let _card = { |
| | | uuid: card.uuid, |
| | | type: card.type, |
| | | tabId: card.tabId || '', |
| | | parentId: card.parentId || '', |
| | | format: 'array', // 组件属性 - 数据格式 |
| | | pageable: true, // 组件属性 - 是否可分页 |
| | | switchable: true, // 组件属性 - 数据是否可切换 |
| | | dataName: card.dataName || '', |
| | | width: card.width || 24, |
| | | search: [ |
| | | { origin: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text', match: 'like' }, |
| | | { origin: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'select', match: 'equal' } |
| | | ], |
| | | action: [ |
| | | { origin: true, uuid: Utils.getuuid(), label: '添加', intertype: 'system', OpenType: 'pop', execSuccess: 'grid', icon: 'plus', class: 'green', style: {color: 'rgb(255, 255, 255)', background: 'rgb(38, 194, 129)', marginRight: '15px'} }, |
| | | { origin: true, uuid: Utils.getuuid(), label: '修改', intertype: 'system', OpenType: 'pop', execSuccess: 'grid', icon: 'form', class: 'purple', style: {color: 'rgb(255, 255, 255)', background: 'rgb(142, 68, 173)', marginRight: '15px'} }, |
| | | { origin: true, uuid: Utils.getuuid(), label: '删除', intertype: 'system', OpenType: 'prompt', execSuccess: 'grid', Ot: 'required', icon: 'delete', class: 'danger', style: {color: 'rgb(255, 255, 255)', background: 'rgb(255, 77, 79)', marginRight: '15px'} } |
| | | ], |
| | | name: card.name, |
| | | subtype: card.subtype, |
| | | setting: { interType: 'system' }, |
| | | wrap: { name: card.name, width: card.width || 24, bordered: 'true', tableType: 'checkbox', show: 'true' }, |
| | | style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' }, |
| | | headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' }, |
| | | columns: [], |
| | | cols: [ |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label1', field: '', Hide: 'false', type: 'text', Width: 120 }, |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label2', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 }, |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label3', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 }, |
| | | ], |
| | | scripts: [], |
| | | btnlog: [], |
| | | isNew: true |
| | | } |
| | | |
| | | if (card.config) { |
| | | let config = fromJS(card.config).toJS() |
| | | |
| | | _card.wrap = config.wrap |
| | | _card.wrap.name = card.name |
| | | _card.style = config.style |
| | | _card.headerStyle = config.headerStyle |
| | | |
| | | _card.setting = config.setting |
| | | _card.columns = config.columns |
| | | _card.scripts = config.scripts |
| | | |
| | | let oriUids = {} |
| | | _card.action = config.action.map(item => { |
| | | let _uuid = Utils.getuuid() |
| | | oriUids[item.uuid] = _uuid |
| | | item.uuid = _uuid |
| | | return item |
| | | }) |
| | | _card.search = config.search.map(item => { |
| | | item.uuid = Utils.getuuid() |
| | | return item |
| | | }) |
| | | _card.cols = config.cols.map(col => { |
| | | col.uuid = Utils.getuuid() |
| | | if (col.type === 'colspan' && col.subcols) { |
| | | col = this.loopCol(col) |
| | | } else if (col.type === 'custom' && col.elements) { |
| | | col.elements = col.elements.map(cell => { |
| | | cell.uuid = Utils.getuuid() |
| | | return cell |
| | | }) |
| | | } else if (col.type === 'action' && col.elements) { |
| | | col.elements = col.elements.map(cell => { |
| | | cell.uuid = Utils.getuuid() |
| | | return cell |
| | | }) |
| | | } |
| | | return col |
| | | }) |
| | | |
| | | if (_card.wrap.doubleClick) { |
| | | _card.wrap.doubleClick = oriUids[_card.wrap.doubleClick] || '' |
| | | } |
| | | } |
| | | |
| | | if (appType === 'mob') { |
| | | _card.search = [] |
| | | _card.action = _card.action.filter(a => !a.origin) |
| | | } |
| | | |
| | | this.updateComponent(_card) |
| | | } else { |
| | | let _card = fromJS(card).toJS() |
| | | if (appType === 'mob') { |
| | | _card.search = [] |
| | | } |
| | | |
| | | this.setState({ |
| | | card: _card |
| | | }) |
| | | } |
| | | } |
| | | |
| | | componentDidMount () { |
| | | MKEmitter.addListener('submitModal', this.handleSave) |
| | | // MKEmitter.addListener('logButton', this.logButton) |
| | | MKEmitter.addListener('completeSave', this.completeSave) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('submitModal', this.handleSave) |
| | | // MKEmitter.removeListener('logButton', this.logButton) |
| | | MKEmitter.removeListener('completeSave', this.completeSave) |
| | | } |
| | | |
| | | completeSave = () => { |
| | | const { card } = this.state |
| | | |
| | | if (card.isNew) { |
| | | let item = fromJS(card).toJS() |
| | | item.search = item.search.filter(a => !a.origin) |
| | | item.action = item.action.filter(a => !a.origin) |
| | | item.cols = item.cols.filter(a => !a.origin) |
| | | |
| | | delete item.isNew |
| | | |
| | | this.setState({card: item}, () => { MKEmitter.emit('revert') }) |
| | | } |
| | | } |
| | | |
| | | loopCol = (col) => { |
| | | col.subcols = col.subcols.map(c => { |
| | | c.uuid = Utils.getuuid() |
| | | if (c.type === 'colspan' && c.subcols) { |
| | | c = this.loopCol(c) |
| | | } else if (c.type === 'custom' && c.elements) { |
| | | c.elements = c.elements.map(cell => { |
| | | cell.uuid = Utils.getuuid() |
| | | return cell |
| | | }) |
| | | } |
| | | return c |
| | | }) |
| | | |
| | | return col |
| | | } |
| | | |
| | | /** |
| | | * @description 卡片行外层信息更新(数据源,样式等) |
| | | */ |
| | | updateComponent = (card) => { |
| | | card.width = card.wrap.width |
| | | card.name = card.wrap.name |
| | | |
| | | if (!window.GLOB.styling || !card.errors) { // 样式修改时不做筛查 |
| | | card.errors = [] |
| | | |
| | | // let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : '' |
| | | // if (supModule === 'empty') { |
| | | // supModule = '' |
| | | // } |
| | | let doubleClick = card.wrap.doubleClick || '' |
| | | |
| | | let columns = card.columns.map(c => c.field) |
| | | // let lowcols = card.columns.map(c => c.field.toLowerCase()) |
| | | |
| | | if (card.setting.interType === 'system' && card.setting.execute !== 'false' && !card.setting.dataresource) { |
| | | card.errors.push({ level: 0, detail: '未设置数据源!'}) |
| | | } else if (card.setting.interType === 'system' && card.setting.execute === 'false' && card.scripts.filter(script => script.status !== 'false').length === 0) { |
| | | card.errors.push({ level: 0, detail: '数据源中无可用脚本!'}) |
| | | } else if (!card.setting.primaryKey) { |
| | | card.errors.push({ level: 0, detail: '未设置主键!'}) |
| | | } else if (!columns.includes(card.setting.primaryKey)) { |
| | | card.errors.push({ level: 0, detail: '主键已失效!'}) |
| | | } else if (!card.setting.supModule) { |
| | | card.errors.push({ level: 0, detail: '未设置上级组件!'}) |
| | | } |
| | | |
| | | card.action.forEach(cell => { |
| | | if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) { |
| | | if (!cell.modal || cell.modal.fields.length === 0) { |
| | | card.errors.push({ level: 1, detail: `按钮“${cell.label}”中表单尚未添加`}) |
| | | // } else { |
| | | // cell.modal.fields.forEach(m => { |
| | | // if (m.type === 'linkMain' && !supModule) { |
| | | // card.errors.push({ level: 1, detail: `按钮“${cell.label}”中关联主表表单“${m.label}”无效`}) |
| | | // } else if (m.field && !columns.includes(m.field) && lowcols.includes(m.field.toLowerCase())) { |
| | | // card.errors.push({ level: 1, detail: `按钮“${cell.label}”中表单“${m.label}”大小写与字段集不一致`}) |
| | | // } |
| | | // }) |
| | | } |
| | | } |
| | | if (doubleClick === cell.uuid) { |
| | | doubleClick = '' |
| | | } |
| | | }) |
| | | |
| | | card.cols.forEach(col => { |
| | | if (col.type === 'action') { |
| | | col.elements.forEach(cell => { |
| | | if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) { |
| | | if (!cell.modal || cell.modal.fields.length === 0) { |
| | | card.errors.push({ level: 1, detail: `按钮“${cell.label}”中表单尚未添加`}) |
| | | // } else { |
| | | // cell.modal.fields.forEach(m => { |
| | | // if (m.type === 'linkMain' && !supModule) { |
| | | // card.errors.push({ level: 1, detail: `按钮“${cell.label}”中关联主表表单“${m.label}”无效`}) |
| | | // } else if (m.field && !columns.includes(m.field) && lowcols.includes(m.field.toLowerCase())) { |
| | | // card.errors.push({ level: 1, detail: `按钮“${cell.label}”中表单“${m.label}”大小写与字段集不一致`}) |
| | | // } |
| | | // }) |
| | | } |
| | | } |
| | | if (doubleClick === cell.uuid) { |
| | | doubleClick = '' |
| | | } |
| | | }) |
| | | } else if (col.type === 'custom') { |
| | | col.elements.forEach(cell => { |
| | | if (cell.datatype === 'dynamic' && cell.field && !columns.includes(cell.field)) { |
| | | card.errors.push({ level: 1, detail: `显示列“${col.label}”中动态字段“${cell.field}”无效`}) |
| | | } |
| | | }) |
| | | } else if (col.field && !columns.includes(col.field)) { |
| | | card.errors.push({ level: 1, detail: `显示列“${col.label}”中字段“${col.field}”无效`}) |
| | | } |
| | | }) |
| | | |
| | | if (doubleClick) { |
| | | card.errors.push({ level: 1, detail: `绑定的双击按钮已删除`}) |
| | | } |
| | | } |
| | | |
| | | this.setState({ |
| | | card: card |
| | | }) |
| | | |
| | | let _card = card.isNew ? fromJS(card).toJS() : card |
| | | if (_card.isNew) { |
| | | _card.cols = _card.cols.filter(a => !a.origin) |
| | | _card.search = _card.search.filter(a => !a.origin) |
| | | _card.action = _card.action.filter(a => !a.origin) |
| | | |
| | | delete _card.isNew |
| | | } |
| | | |
| | | this.props.updateConfig(_card) |
| | | } |
| | | |
| | | // logButton = (id, item) => { |
| | | // const { card } = this.state |
| | | |
| | | // if (id !== card.uuid) return |
| | | |
| | | // let btnlog = card.btnlog || [] |
| | | // btnlog.push(item) |
| | | |
| | | // this.updateComponent({...card, btnlog}) |
| | | // } |
| | | |
| | | changeStyle = () => { |
| | | const { card } = this.state |
| | | |
| | | let style = {...card.style} |
| | | style.color = card.wrap.color || 'rgba(0, 0, 0, 0.65)' |
| | | style.fontSize = card.wrap.fontSize || 14 |
| | | style.fontWeight = card.wrap.fontWeight || 'normal' |
| | | |
| | | MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow'], style, this.getStyle) |
| | | } |
| | | |
| | | getStyle = (style) => { |
| | | const { card } = this.state |
| | | |
| | | let _card = fromJS(card).toJS() |
| | | let _style = fromJS(style).toJS() |
| | | |
| | | let color = style.color |
| | | let fontSize = style.fontSize |
| | | let fontWeight = style.fontWeight |
| | | |
| | | delete _style.color |
| | | delete _style.fontSize |
| | | delete _style.fontWeight |
| | | |
| | | _card.style = _style |
| | | _card.wrap.color = color |
| | | _card.wrap.fontSize = fontSize |
| | | _card.wrap.fontWeight = fontWeight |
| | | |
| | | this.updateComponent(_card) |
| | | } |
| | | |
| | | addColumns = () => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | |
| | | card.cols.push({ focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' }) |
| | | |
| | | this.setState({card}) |
| | | } |
| | | |
| | | addSearch = () => { |
| | | const { card } = this.state |
| | | |
| | | MKEmitter.emit('plusSearch', card.uuid, {uuid: Utils.getuuid(), focus: true, label: 'label', type: 'text', match: '='}, 'simple') |
| | | } |
| | | |
| | | addButton = () => { |
| | | const { card } = this.state |
| | | |
| | | let newcard = {} |
| | | newcard.uuid = Utils.getuuid() |
| | | newcard.focus = true |
| | | |
| | | newcard.label = 'label' |
| | | newcard.sqlType = '' |
| | | newcard.Ot = 'requiredSgl' |
| | | newcard.OpenType = 'pop' |
| | | newcard.icon = '' |
| | | newcard.class = 'green' |
| | | newcard.intertype = card.setting.interType || 'system' |
| | | newcard.innerFunc = card.setting.innerFunc || '' |
| | | newcard.sysInterface = card.setting.sysInterface || '' |
| | | newcard.outerFunc = card.setting.outerFunc || '' |
| | | newcard.interface = card.setting.interface || '' |
| | | newcard.execSuccess = 'grid' |
| | | newcard.execError = 'never' |
| | | newcard.verify = null |
| | | newcard.show = 'button' |
| | | newcard.style = {marginRight: '15px'} |
| | | |
| | | // 注册事件-添加按钮 |
| | | MKEmitter.emit('addButton', card.uuid, newcard) |
| | | } |
| | | |
| | | setSubConfig = (item) => { |
| | | const { card, appType } = this.state |
| | | let btn = fromJS(item).toJS() |
| | | |
| | | if (btn.OpenType === 'pop' || btn.execMode === 'pop') { |
| | | if (!btn.modal) { |
| | | btn.modal = { |
| | | setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' }, |
| | | tables: [], |
| | | groups: [], |
| | | fields: [] |
| | | } |
| | | } |
| | | MKEmitter.emit('changeModal', card, btn) |
| | | } else if (btn.OpenType === 'popview') { |
| | | MKEmitter.emit('changePopview', card, btn) |
| | | } |
| | | } |
| | | |
| | | handleSave = (_cards, btn, modal) => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | |
| | | if (card.uuid !== _cards.uuid) return |
| | | |
| | | let _index = card.action.findIndex(cell => cell.uuid === btn.uuid) |
| | | |
| | | if (_index === -1) return |
| | | |
| | | card.action = card.action.map(cell => { |
| | | if (cell.uuid === btn.uuid) { |
| | | cell.modal = modal |
| | | } |
| | | |
| | | return cell |
| | | }) |
| | | |
| | | this.updateComponent(card) |
| | | } |
| | | |
| | | // handleLog = (type, logs, item) => { |
| | | // let card = fromJS(this.state.card).toJS() |
| | | |
| | | // if (type === 'revert') { |
| | | // let done = false |
| | | // if (item.$parentId) { |
| | | // card.cols.forEach(col => { |
| | | // if (col.type !== 'action') return |
| | | // if (item.$parentId === col.uuid) { |
| | | // col.elements = col.elements ? [...col.elements, item] : [item] |
| | | // done = true |
| | | // } |
| | | // }) |
| | | // } |
| | | |
| | | // if (!done) { |
| | | // card.action = card.action ? [...card.action, item] : [item] |
| | | // } |
| | | |
| | | // card.btnlog = logs |
| | | |
| | | // this.updateComponent(card) |
| | | // notification.success({ |
| | | // top: 92, |
| | | // message: '恢复成功!', |
| | | // duration: 2 |
| | | // }) |
| | | // } else { |
| | | // card.btnlog = logs |
| | | // this.updateComponent(card) |
| | | // notification.success({ |
| | | // top: 92, |
| | | // message: '清除成功!', |
| | | // duration: 2 |
| | | // }) |
| | | // } |
| | | // } |
| | | |
| | | getWrapForms = () => { |
| | | const { wrap, action, columns, cols } = this.state.card |
| | | |
| | | let _actions = [...action] |
| | | |
| | | cols.forEach(col => { |
| | | if (col.type !== 'action') return |
| | | _actions.push(...col.elements) |
| | | }) |
| | | |
| | | return getWrapForm(wrap, _actions, columns) |
| | | } |
| | | |
| | | updateWrap = (res) => { |
| | | const { card } = this.state |
| | | |
| | | res.color = card.wrap.color |
| | | res.fontSize = card.wrap.fontSize |
| | | res.fontWeight = card.wrap.fontWeight |
| | | |
| | | res.show = card.wrap.show || 'true' |
| | | res.advanceType = card.wrap.advanceType || 'modal' |
| | | res.advanceWidth = card.wrap.advanceWidth || 1000 |
| | | res.drawerPlacement = card.wrap.drawerPlacement || 'right' |
| | | res.searchRatio = card.wrap.searchRatio || 6 |
| | | res.searchLwidth = card.wrap.searchLwidth !== undefined ? card.wrap.searchLwidth : 33.3 |
| | | |
| | | this.updateComponent({...card, wrap: res}) |
| | | } |
| | | |
| | | clickComponent = (e) => { |
| | | if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') { |
| | | e.stopPropagation() |
| | | MKEmitter.emit('clickComponent', this.state.card) |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { card, appType } = this.state |
| | | let options = ['action', 'search', 'form', 'cols'] |
| | | let _style = resetStyle(card.style) |
| | | |
| | | if (appType === 'mob') { |
| | | options = ['action', 'cols'] |
| | | } |
| | | |
| | | return ( |
| | | <div className="menu-normal-table-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}> |
| | | <NormalHeader hideSearch="true" config={card} updateComponent={this.updateComponent}/> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <PlusOutlined className="plus" title="添加列" onClick={this.addColumns}/> |
| | | {appType !== 'mob' ? <PlusCircleOutlined className="plus" title="添加搜索" onClick={this.addSearch}/> : null} |
| | | <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton}/> |
| | | <NormalForm title="表格设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}> |
| | | <EditOutlined style={{color: '#1890ff'}} title="编辑"/> |
| | | </NormalForm> |
| | | <CopyComponent type="normaltable" card={card}/> |
| | | <PasteComponent config={card} options={options} updateConfig={this.updateComponent} /> |
| | | <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/> |
| | | {/* <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} /> */} |
| | | <UserComponent config={card}/> |
| | | <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} /> |
| | | <SettingComponent config={card} updateConfig={this.updateComponent} /> |
| | | </div> |
| | | } trigger="hover"> |
| | | <ToolOutlined /> |
| | | </Popover> |
| | | <SearchComponent config={card} updatesearch={this.updateComponent}/> |
| | | <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/> |
| | | <ColumnComponent config={card} updatecolumn={this.updateComponent}/> |
| | | <div className="component-name"> |
| | | <div className="center"> |
| | | <div className="title">{card.name}</div> |
| | | <div className="content"> |
| | | {card.errors && card.errors.map((err, index) => { |
| | | if (err.level === 0) { |
| | | return <span key={index} className="error">{err.detail}</span> |
| | | } else { |
| | | return <span key={index} className="waring">{err.detail};</span> |
| | | } |
| | | })} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default TableCardEditComponent |
New file |
| | |
| | | .menu-normal-table-edit-box { |
| | | position: relative; |
| | | box-sizing: border-box; |
| | | background: #ffffff; |
| | | background-position: center center; |
| | | background-repeat: no-repeat; |
| | | background-size: cover; |
| | | min-height: 100px; |
| | | |
| | | .model-table-search-list { |
| | | padding: 10px 0px 15px; |
| | | min-height: 65px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | .page-card { |
| | | background: transparent; |
| | | } |
| | | .quickly-add { |
| | | display: inline-block; |
| | | position: absolute; |
| | | z-index: 3; |
| | | right: 70px; |
| | | bottom: 5px; |
| | | .ant-btn-block { |
| | | background-color: transparent; |
| | | color: #1890ff; |
| | | border: none; |
| | | box-shadow: none !important; |
| | | height: 18px; |
| | | padding: 0 10px; |
| | | } |
| | | } |
| | | } |
| | | .model-table-search-list.length0 { |
| | | min-height: 10px; |
| | | border-bottom: 0; |
| | | >.quickly-add { |
| | | right: unset; |
| | | left: -8px; |
| | | bottom: 0; |
| | | } |
| | | >.ant-row { |
| | | display: none; |
| | | } |
| | | >.ant-switch { |
| | | display: none; |
| | | } |
| | | } |
| | | .model-table-search-list.length0 + .length0 { |
| | | margin-top: -25px; |
| | | } |
| | | .anticon-tool { |
| | | position: absolute; |
| | | z-index: 2; |
| | | font-size: 16px; |
| | | right: 1px; |
| | | top: 1px; |
| | | cursor: pointer; |
| | | padding: 5px; |
| | | background: rgba(255, 255, 255, 0.55); |
| | | } |
| | | .model-menu-action-list { |
| | | line-height: 55px; |
| | | padding: 0px; |
| | | min-height: 55px; |
| | | >.ant-row { |
| | | min-height: 30px; |
| | | } |
| | | } |
| | | .card-add-button { |
| | | text-align: right; |
| | | clear: left; |
| | | .anticon-plus { |
| | | font-size: 20px; |
| | | color: #26C281; |
| | | padding: 5px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .ant-btn.mk-link { |
| | | padding: 0; |
| | | } |
| | | } |
| | | .menu-normal-table-edit-box::after { |
| | | display: block; |
| | | content: ' '; |
| | | clear: both; |
| | | } |
| | | .menu-normal-table-edit-box:hover { |
| | | z-index: 1; |
| | | box-shadow: 0px 0px 4px #1890ff; |
| | | } |
New file |
| | |
| | | /** |
| | | * @description Wrap表单配置信息 |
| | | */ |
| | | export default function (wrap, action = [], columns = []) { |
| | | let roleList = sessionStorage.getItem('sysRoles') |
| | | let appType = sessionStorage.getItem('appType') |
| | | |
| | | if (roleList) { |
| | | try { |
| | | roleList = JSON.parse(roleList) |
| | | } catch (e) { |
| | | roleList = [] |
| | | } |
| | | } else { |
| | | roleList = [] |
| | | } |
| | | |
| | | const wrapForm = [ |
| | | { |
| | | type: 'text', |
| | | field: 'title', |
| | | label: '标题', |
| | | initval: wrap.title || '', |
| | | required: false |
| | | }, |
| | | { |
| | | type: 'text', |
| | | field: 'name', |
| | | label: '组件名称', |
| | | initval: wrap.name || '', |
| | | tooltip: '用于组件间的区分。', |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'number', |
| | | field: 'width', |
| | | label: '宽度', |
| | | initval: wrap.width || 24, |
| | | tooltip: '栅格布局,每行等分为24列。', |
| | | min: 1, |
| | | max: 24, |
| | | precision: 0, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'number', |
| | | field: 'height', |
| | | label: '高度', |
| | | initval: wrap.height || '', |
| | | tooltip: '表格高度,空值时高度自适应。', |
| | | min: 10, |
| | | max: 3000, |
| | | precision: 0, |
| | | required: false, |
| | | forbid: appType === 'mob' |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'tableType', |
| | | label: '表格属性', |
| | | initval: wrap.tableType || '', |
| | | required: false, |
| | | options: [ |
| | | {value: '', label: '不可选'}, |
| | | {value: 'radio', label: '单选'}, |
| | | {value: 'checkbox', label: '多选'}, |
| | | ], |
| | | controlFields: [ |
| | | {field: 'selected', values: ['radio', 'checkbox']}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'bordered', |
| | | label: '边框', |
| | | initval: wrap.bordered || 'true', |
| | | required: false, |
| | | options: [ |
| | | {value: 'true', label: '有'}, |
| | | {value: 'false', label: '无'}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'tableHeader', |
| | | label: '表头', |
| | | initval: wrap.tableHeader || 'show', |
| | | required: false, |
| | | options: [ |
| | | {value: 'show', label: '显示'}, |
| | | {value: 'hidden', label: '隐藏'}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'collapse', |
| | | label: '可收起', |
| | | initval: wrap.collapse || 'false', |
| | | required: false, |
| | | options: [ |
| | | {value: 'true', label: '是'}, |
| | | {value: 'false', label: '否'}, |
| | | ], |
| | | forbid: appType === 'mob' || appType === 'pc' |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'size', |
| | | label: '表格大小', |
| | | initval: wrap.size || 'middle', |
| | | tooltip: '表格的内边距,从大到小依次递减。', |
| | | required: false, |
| | | options: [ |
| | | {value: 'default', label: '大'}, |
| | | {value: 'middle', label: '中'}, |
| | | {value: 'small', label: '小'}, |
| | | {value: 'mini', label: '迷你'}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'mode', |
| | | label: '模式', |
| | | initval: wrap.mode || 'default', |
| | | required: false, |
| | | options: [ |
| | | {value: 'default', label: '常规'}, |
| | | {value: 'ghost', label: '透明'}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'selected', |
| | | label: '首行选中', |
| | | initval: wrap.selected || 'false', |
| | | tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。', |
| | | required: false, |
| | | options: [ |
| | | {value: 'false', label: '无'}, |
| | | {value: 'init', label: '初始化'}, |
| | | {value: 'always', label: '数据加载'}, |
| | | ] |
| | | }, |
| | | // { |
| | | // type: 'radio', |
| | | // field: 'show', |
| | | // label: '搜索按钮', |
| | | // initval: wrap.show || 'true', |
| | | // tooltip: '搜索条件存在时,可选择是否显示搜索按钮。', |
| | | // required: false, |
| | | // options: [ |
| | | // {value: 'true', label: '显示'}, |
| | | // {value: 'false', label: '隐藏'}, |
| | | // ] |
| | | // }, |
| | | { |
| | | type: 'color', |
| | | field: 'borderColor', |
| | | label: '边框颜色', |
| | | initval: wrap.borderColor || '#e8e8e8', |
| | | tooltip: '默认值 #e8e8e8。', |
| | | required: false |
| | | }, |
| | | // { |
| | | // type: 'color', |
| | | // field: 'color', |
| | | // label: '字体颜色', |
| | | // initval: wrap.color || 'rgba(0, 0, 0, 0.65)', |
| | | // tooltip: '默认值 rgba(0, 0, 0, 0.65)。', |
| | | // required: false |
| | | // }, |
| | | // { |
| | | // type: 'number', |
| | | // field: 'fontSize', |
| | | // label: '字体大小', |
| | | // initval: wrap.fontSize || 14, |
| | | // min: 12, |
| | | // max: 30, |
| | | // precision: 0, |
| | | // required: false |
| | | // }, |
| | | // { |
| | | // type: 'number', |
| | | // field: 'advanceWidth', |
| | | // label: '高级搜索', |
| | | // initval: wrap.advanceWidth || 1000, |
| | | // tooltip: '高级搜索弹窗的宽度,注:当宽度值小于100时表示占窗口的百分比,大于100时表示宽度的绝对值。', |
| | | // min: 10, |
| | | // max: 3000, |
| | | // precision: 0, |
| | | // required: false, |
| | | // forbid: appType === 'mob' |
| | | // }, |
| | | { |
| | | type: 'select', |
| | | field: 'doubleClick', |
| | | label: '双击事件', |
| | | initval: wrap.doubleClick || '', |
| | | tooltip: '双击表格中行,触发的按钮。', |
| | | required: false, |
| | | allowClear: true, |
| | | options: action.map(item => ({value: item.uuid, label: item.label})), |
| | | forbid: appType === 'mob' |
| | | }, |
| | | { |
| | | type: 'select', |
| | | field: 'controlField', |
| | | label: '禁用字段', |
| | | initval: wrap.controlField || '', |
| | | tooltip: '用于控制行数据是否可选择。', |
| | | required: false, |
| | | allowClear: true, |
| | | options: columns, |
| | | controlFields: [ |
| | | {field: 'controlVal', notNull: true}, |
| | | ] |
| | | }, |
| | | { |
| | | type: 'text', |
| | | field: 'controlVal', |
| | | label: '禁用值', |
| | | initval: wrap.controlVal || '', |
| | | tooltip: '当字段值与禁用值相等时,行数据会禁用,多个值用逗号分隔。', |
| | | required: false |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'empty', |
| | | label: '空值隐藏', |
| | | initval: wrap.empty || 'show', |
| | | tooltip: '当查询数据为空时,隐藏该组件。', |
| | | required: false, |
| | | options: [ |
| | | {value: 'show', label: '否'}, |
| | | {value: 'hidden', label: '是'}, |
| | | ], |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'supKey', |
| | | label: '上级主键', |
| | | initval: wrap.supKey || 'true', |
| | | tooltip: '当设置上级组件时,上级主键值为空是否进行数据查询。', |
| | | required: false, |
| | | options: [ |
| | | {value: 'true', label: '验证'}, |
| | | {value: 'false', label: '忽略'}, |
| | | ], |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | field: 'permission', |
| | | label: '权限验证', |
| | | initval: wrap.permission || 'false', |
| | | required: false, |
| | | options: [ |
| | | {value: 'true', label: '启用'}, |
| | | {value: 'false', label: '禁用'}, |
| | | ], |
| | | forbid: !appType |
| | | }, |
| | | { |
| | | type: 'multiselect', |
| | | field: 'blacklist', |
| | | label: '黑名单', |
| | | initval: wrap.blacklist || [], |
| | | required: false, |
| | | options: roleList, |
| | | forbid: !!appType |
| | | }, |
| | | ] |
| | | |
| | | return wrapForm |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .tables { |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .tools::-webkit-scrollbar { |
| | | width: 4px; |
New file |
| | |
| | | import React from 'react' |
| | | import { useDrag, useDrop } from 'react-dnd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import './index.scss' |
| | | |
| | | const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs')) |
| | | const BaseTable = asyncComponent(() => import('@/menu/components/table/base-table')) |
| | | |
| | | const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => { |
| | | const originalIndex = findCard(id).index |
| | | const [{ isDragging }, drag] = useDrag({ |
| | | item: { type: 'menu', id, originalIndex }, |
| | | collect: monitor => ({ |
| | | isDragging: monitor.isDragging(), |
| | | }), |
| | | }) |
| | | const [, drop] = useDrop({ |
| | | accept: 'menu', |
| | | canDrop: () => true, |
| | | drop: (item) => { |
| | | const { id: draggedId, originalIndex } = item |
| | | if (originalIndex === undefined) { |
| | | item.dropTargetId = id |
| | | } else if (draggedId) { |
| | | if (draggedId === id) return |
| | | const { index: originIndex } = findCard(draggedId) |
| | | |
| | | if (originIndex === -1) return |
| | | |
| | | const { index: overIndex } = findCard(id) |
| | | |
| | | moveCard(draggedId, overIndex) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | let style = { opacity: 1} |
| | | if (isDragging) { |
| | | style = { opacity: 0.3} |
| | | } |
| | | |
| | | const getCardComponent = () => { |
| | | if (card.type === 'table') { |
| | | return (<BaseTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'tabs') { |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } |
| | | } |
| | | return ( |
| | | <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}> |
| | | {getCardComponent()} |
| | | </div> |
| | | ) |
| | | } |
| | | export default Card |
New file |
| | |
| | | import React, { useState } from 'react' |
| | | import { useDrop } from 'react-dnd' |
| | | import update from 'immutability-helper' |
| | | import { Modal } from 'antd' |
| | | |
| | | import Utils from '@/utils/utils.js' |
| | | import Card from './card' |
| | | import './index.scss' |
| | | |
| | | const { confirm } = Modal |
| | | |
| | | const Container = ({menu, handleList }) => { |
| | | const [cards, setCards] = useState(menu.components) |
| | | const moveCard = (id, atIndex) => { |
| | | const { card, index } = findCard(id) |
| | | const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) |
| | | handleList({...menu, components: _cards}) |
| | | setCards(_cards) |
| | | } |
| | | |
| | | if (menu.components.length > cards.length) { |
| | | setCards(menu.components) |
| | | } |
| | | |
| | | const findCard = id => { |
| | | const card = cards.filter(c => `${c.uuid}` === id)[0] |
| | | return { |
| | | card, |
| | | index: cards.indexOf(card), |
| | | } |
| | | } |
| | | |
| | | const updateConfig = (element) => { |
| | | const _cards = cards.map(item => item.uuid === element.uuid ? element : item) |
| | | handleList({...menu, components: _cards}) |
| | | setCards(_cards) |
| | | } |
| | | |
| | | const deleteCard = (id) => { |
| | | const { card } = findCard(id) |
| | | |
| | | let hasComponent = false |
| | | if (card.type === 'tabs') { |
| | | card.subtabs.forEach(tab => { |
| | | if (tab.components.length > 0) { |
| | | hasComponent = true |
| | | } |
| | | }) |
| | | } |
| | | |
| | | confirm({ |
| | | title: `确定删除《${card.name}》吗?`, |
| | | content: hasComponent ? '当前组件中含有子组件!' : '', |
| | | onOk() { |
| | | const _cards = cards.filter(item => item.uuid !== card.uuid) |
| | | handleList({...menu, components: _cards}) |
| | | setCards(_cards) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | const [, drop] = useDrop({ |
| | | accept: 'menu', |
| | | drop(item) { |
| | | if (item.hasOwnProperty('originalIndex') || item.added) { |
| | | delete item.added // 删除组件添加标记 |
| | | return |
| | | } |
| | | |
| | | let name = '' |
| | | let names = { |
| | | tabs: '标签组' |
| | | } |
| | | let i = 1 |
| | | |
| | | while (!name && names[item.component]) { |
| | | let _name = names[item.component] + i |
| | | if (menu.components.filter(com => com.name === _name).length === 0) { |
| | | name = _name |
| | | } |
| | | i++ |
| | | } |
| | | |
| | | let newcard = { |
| | | uuid: Utils.getuuid(), |
| | | type: item.component, |
| | | subtype: item.subtype, |
| | | config: item.config, |
| | | width: item.width || 24, |
| | | dataName: Utils.getdataName(), |
| | | name: name, |
| | | floor: 1, // 组件的层级 |
| | | isNew: true // 新添加标志,用于初始化 |
| | | } |
| | | |
| | | let targetId = '' |
| | | |
| | | if (item.dropTargetId) { |
| | | targetId = item.dropTargetId |
| | | delete item.dropTargetId |
| | | } else if (cards.length > 0) { |
| | | targetId = cards.slice(-1)[0].uuid |
| | | } |
| | | |
| | | const { index: overIndex } = findCard(`${targetId}`) |
| | | const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] }) |
| | | |
| | | handleList({...menu, components: _cards}) |
| | | setCards(_cards) |
| | | } |
| | | }) |
| | | |
| | | return ( |
| | | <div ref={drop} className="table-shell-inner" style={menu.style}> |
| | | <div className="ant-row"> |
| | | {cards.map(card => ( |
| | | <Card |
| | | id={card.uuid} |
| | | key={card.uuid} |
| | | card={card} |
| | | moveCard={moveCard} |
| | | delCard={deleteCard} |
| | | findCard={findCard} |
| | | updateConfig={updateConfig} |
| | | /> |
| | | ))} |
| | | </div> |
| | | </div> |
| | | ) |
| | | } |
| | | export default Container |
New file |
| | |
| | | .table-shell-inner { |
| | | min-height: calc(100vh - 100px); |
| | | width: auto!important; |
| | | overflow-x: hidden; |
| | | background-size: 100%; |
| | | |
| | | .anticon { |
| | | cursor: unset; |
| | | } |
| | | |
| | | .mk-component-card { |
| | | position: relative; |
| | | } |
| | | |
| | | .anticon-tool { |
| | | color: rgba(0, 0, 0, 0.55); |
| | | } |
| | | .anticon-tool:hover { |
| | | color: #1890ff; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .tables { |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .tools::-webkit-scrollbar { |
| | | width: 4px; |
| | |
| | | .ant-collapse-borderless { |
| | | background-color: #ffffff; |
| | | } |
| | | .ant-collapse-item { |
| | | border: 0; |
| | | } |
| | | .ant-input-search { |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .ant-collapse-item.ant-collapse-item-active { |
| | | border-bottom: 1px solid #d9d9d9; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .tables { |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .tools::-webkit-scrollbar { |
| | | width: 4px; |
| | | } |
| | | .tools::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08); |
| | | background: rgba(0, 0, 0, 0.08); |
| | | } |
| | | .tools::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | |
| | | .modal-control { |
| | | position: absolute; |
| | | right: 0; |
| | |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | } |
| | | |
| | | |
| | | .modal-fields { |
| | | .ant-modal { |
| | |
| | | } |
| | | } |
| | | |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | .config-button { |
| | | min-width: 65px; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | .config-button { |
| | | min-width: 65px; |
| | | } |
| | |
| | | import { DndProvider } from 'react-dnd' |
| | | import HTML5Backend from 'react-dnd-html5-backend' |
| | | import moment from 'moment' |
| | | import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Empty, Switch, Tooltip } from 'antd' |
| | | import { QuestionCircleOutlined, CloseOutlined, RedoOutlined, SettingOutlined, PlusOutlined, DeleteOutlined, EditOutlined, SnippetsOutlined } from '@ant-design/icons' |
| | | import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip } from 'antd' |
| | | import { QuestionCircleOutlined, RedoOutlined, SettingOutlined, PlusOutlined, DeleteOutlined, EditOutlined, SnippetsOutlined } from '@ant-design/icons' |
| | | |
| | | import Api from '@/api' |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | |
| | | import SettingForm from './settingform' |
| | | import DragElement from './dragelement' |
| | | import GroupForm from './groupform' |
| | | import EditCard from '@/templates/zshare/editcard' |
| | | |
| | | import MenuForm from '@/templates/zshare/menuform' |
| | | import SourceElement from '@/templates/zshare/dragsource' |
| | |
| | | import './index.scss' |
| | | |
| | | const { Panel } = Collapse |
| | | const { Option } = Select |
| | | const { confirm } = Modal |
| | | const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform')) |
| | | const CreateFunc = asyncComponent(() => import('@/templates/zshare/createfunc')) |
| | |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 字典 |
| | | config: null, // 页面配置 |
| | | modaltype: '', // 模态框类型,控制模态框显示 |
| | | tableVisible: false, // 数据表字段模态框 |
| | | tableColumns: [], // 表格显示列 |
| | | fields: null, // 搜索条件及显示列,可选字段 |
| | | menuformlist: null, // 基本信息表单字段 |
| | |
| | | settingVisible: false, // 全局配置模态框 |
| | | closeVisible: false, // 关闭模态框 |
| | | tables: [], // 可用表名 |
| | | selectedTables: [], // 已选表名 |
| | | originMenu: null, // 原始菜单 |
| | | delActions: [], // 删除按钮列表 |
| | | tabviews: [], // 所有标签页 |
| | |
| | | openEdition: btnTab.open_edition || '', |
| | | columns: columns, |
| | | originMenu: JSON.parse(JSON.stringify(_config)), |
| | | selectedTables: _config.tables, |
| | | menuformlist: [ |
| | | { |
| | | type: 'text', |
| | |
| | | duration: 5 |
| | | }) |
| | | } |
| | | }) |
| | | |
| | | let deffers = this.state.selectedTables.map(item => { |
| | | return new Promise(resolve => { |
| | | Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => { |
| | | res.TBName = item.TbName |
| | | resolve(res) |
| | | }) |
| | | }) |
| | | }) |
| | | Promise.all(deffers).then(response => { |
| | | let _columns = [] |
| | | response.forEach(res => { |
| | | if (res.status) { |
| | | let tabmsg = { |
| | | tableName: res.TBName, |
| | | columns: res.FDName.map(item => { |
| | | let _type = item.FieldType.toLowerCase() |
| | | let _decimal = 0 |
| | | if (/^nvarchar/.test(_type)) { |
| | | _type = 'text' |
| | | } else if (/^int/.test(_type)) { |
| | | _type = 'number' |
| | | } else if (/^decimal/.test(_type)) { |
| | | _decimal = _type.split(',')[1] |
| | | _decimal = parseInt(_decimal) |
| | | if (_decimal > 4) { |
| | | _decimal = 4 |
| | | } |
| | | _type = 'number' |
| | | } else if (/^decimal/.test(_type)) { |
| | | _decimal = _type.split(',')[1] |
| | | _decimal = parseInt(_decimal) |
| | | if (_decimal > 4) { |
| | | _decimal = 4 |
| | | } |
| | | _type = 'number' |
| | | } else if (/^datetime/.test(_type)) { |
| | | _type = 'datetime' |
| | | } else if (/^date/.test(_type)) { |
| | | _type = 'date' |
| | | } else { |
| | | _type = 'text' |
| | | } |
| | | |
| | | return { |
| | | field: item.FieldName, |
| | | label: item.FieldDec, |
| | | type: _type, |
| | | datatype: _type, |
| | | decimal: _decimal |
| | | } |
| | | }) |
| | | } |
| | | _columns.push(tabmsg) |
| | | } else { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: res.message, |
| | | duration: 5 |
| | | }) |
| | | } |
| | | }) |
| | | |
| | | this.setState({ |
| | | tableColumns: _columns |
| | | }) |
| | | }) |
| | | |
| | | Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'tab'}).then(res => { |
| | |
| | | } |
| | | |
| | | let _LongParam = '' |
| | | let _config = {...config, tables: this.state.selectedTables} |
| | | let _config = {...config} |
| | | |
| | | // 数据来源为查询且未设置主键时,启用为false |
| | | if (_config.setting.datatype === 'query' && !_config.setting.primaryKey) { |
| | |
| | | onCancel() {} |
| | | }) |
| | | } else { |
| | | let _config = {...config, tables: this.state.selectedTables} |
| | | let _config = {...config} |
| | | |
| | | if (!is(fromJS(_config), fromJS(originMenu))) { |
| | | this.setState({ |
| | |
| | | this.handleViewBack() |
| | | } |
| | | } |
| | | } |
| | | |
| | | queryField = (type) => { |
| | | const {selectedTables, tableColumns, config} = this.state |
| | | // 判断是否已选择表名 |
| | | if (selectedTables.length === 0) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '请选择表名!', |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 表字段集转为map数据 |
| | | let columns = new Map() |
| | | tableColumns.forEach(table => { |
| | | table.columns.forEach(column => { |
| | | columns.set(column.field, column) |
| | | }) |
| | | }) |
| | | |
| | | if (type === 'search') { |
| | | // 添加搜索条件,字段集中存在搜索条件字段,使用搜索条件对象替换字段集,设置数据类型 |
| | | config.groups.forEach(group => { |
| | | group.sublist.forEach(item => { |
| | | if (columns.has(item.field)) { |
| | | let _datatype = columns.get(item.field).datatype |
| | | columns.set(item.field, {...item, selected: true, datatype: _datatype}) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 显示字段集弹窗 |
| | | this.setState({ |
| | | tableVisible: true, |
| | | fields: [...columns.values()] |
| | | }) |
| | | } |
| | | |
| | | addFieldSubmit = () => { |
| | | const {config} = this.state |
| | | // 字段集为空,关闭弹窗 |
| | | if (!this.state.fields || this.state.fields.length === 0) { |
| | | this.setState({ |
| | | tableVisible: false, |
| | | }) |
| | | } |
| | | |
| | | // 获取已选字段集合 |
| | | let cards = this.refs.searchcard.state.selectCards |
| | | let columnsMap = new Map() |
| | | cards.forEach(card => { |
| | | columnsMap.set(card.field, card) |
| | | }) |
| | | |
| | | let groups = config.groups.map(group => { |
| | | group.sublist = group.sublist.map(item => { |
| | | if (columnsMap.has(item.field)) { |
| | | let cell = columnsMap.get(item.field) |
| | | |
| | | if (cell.selected && cell.type !== item.type) { // 数据类型修改 |
| | | item.type = cell.type |
| | | item.initval = '' |
| | | } |
| | | columnsMap.delete(item.field) |
| | | } |
| | | return item |
| | | }) |
| | | return group |
| | | }) |
| | | |
| | | let items = [...columnsMap.values()].map(item => { |
| | | let newcard = { |
| | | uuid: Utils.getuuid(), |
| | | label: item.label, |
| | | field: item.field, |
| | | initval: '', |
| | | type: item.type, |
| | | resourceType: '0', |
| | | options: [], |
| | | orderType: 'asc' |
| | | } |
| | | |
| | | return newcard |
| | | }) |
| | | |
| | | groups = groups.map(group => { |
| | | if (group.isDefault) { |
| | | group.sublist = [...group.sublist, ...items] |
| | | group.sublist = group.sublist.filter(item => !item.origin) |
| | | } |
| | | return group |
| | | }) |
| | | |
| | | this.setState({ |
| | | config: {...config, groups: groups} |
| | | }) |
| | | notification.success({ |
| | | top: 92, |
| | | message: '操作成功', |
| | | duration: 2 |
| | | }) |
| | | } |
| | | |
| | | onTableChange = (value) => { |
| | | const {tables, selectedTables, tableColumns} = this.state |
| | | |
| | | let _table = tables.filter(item => item.TbName === value)[0] |
| | | let isSelected = !!selectedTables.filter(cell => cell.TbName === value)[0] |
| | | if (!isSelected) { |
| | | this.setState({ |
| | | selectedTables: [...selectedTables, _table] |
| | | }) |
| | | Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => { |
| | | if (res.status) { |
| | | let tabmsg = { |
| | | tableName: _table.name, |
| | | columns: res.FDName.map(item => { |
| | | let _type = item.FieldType.toLowerCase() |
| | | let _decimal = 0 |
| | | if (/^nvarchar/.test(_type)) { |
| | | _type = 'text' |
| | | } else if (/^int/.test(_type)) { |
| | | _type = 'number' |
| | | } else if (/^decimal/.test(_type)) { |
| | | _decimal = _type.split(',')[1] |
| | | _decimal = parseInt(_decimal) |
| | | _type = 'number' |
| | | } else if (/^datetime/.test(_type)) { |
| | | _type = 'datetime' |
| | | } else if (/^date/.test(_type)) { |
| | | _type = 'date' |
| | | } else { |
| | | _type = 'text' |
| | | } |
| | | |
| | | return { |
| | | field: item.FieldName, |
| | | label: item.FieldDec, |
| | | type: _type, |
| | | datatype: _type, |
| | | decimal: _decimal |
| | | } |
| | | }) |
| | | } |
| | | this.setState({ |
| | | tableColumns: [...tableColumns, tabmsg] |
| | | }) |
| | | } else { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: res.message, |
| | | duration: 5 |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | |
| | | deleteTable = (table) => { |
| | | const {selectedTables, tableColumns} = this.state |
| | | |
| | | this.setState({ |
| | | selectedTables: selectedTables.filter(item => item.TbName !== table.TbName), |
| | | tableColumns: tableColumns.filter(item => item.tableName !== table.TbName) |
| | | }) |
| | | } |
| | | |
| | | changeSetting = () => { |
| | |
| | | }) |
| | | } else { |
| | | this.menuformRef.handleConfirm().then(res => { |
| | | let _config = {...config, tables: this.state.selectedTables} |
| | | let _config = {...config} |
| | | |
| | | if (!is(fromJS(originMenu), fromJS(_config))) { |
| | | notification.warning({ |
| | |
| | | formlist={this.state.menuformlist} |
| | | wrappedComponentRef={(inst) => this.menuformRef = inst} |
| | | /> |
| | | {/* 表名添加 */} |
| | | <div className="ant-col ant-form-item-label"> |
| | | <label> |
| | | <Tooltip placement="topLeft" title="此处可以添加配置相关的常用表,在添加搜索条件和显示列时,可通过工具栏中的添加按钮,批量添加表格相关字段。"> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {this.state.dict['header.menu.table.add']} |
| | | </Tooltip> |
| | | </label> |
| | | </div> |
| | | <Select |
| | | showSearch |
| | | className="tables" |
| | | style={{ width: '100%' }} |
| | | optionFilterProp="children" |
| | | value="请选择表名" |
| | | onChange={this.onTableChange} |
| | | showArrow={false} |
| | | getPopupContainer={() => document.getElementById('common-basedata')} |
| | | filterOption={(input, option) => { |
| | | return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 || |
| | | option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0 |
| | | }} |
| | | > |
| | | {this.state.tables.map((table, index) => ( |
| | | <Option key={index} title={table.TbName} value={table.TbName}>{table.Remark}</Option> |
| | | ))} |
| | | </Select> |
| | | {this.state.selectedTables.length > 0 && <List |
| | | size="small" |
| | | bordered |
| | | dataSource={this.state.selectedTables} |
| | | renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}> |
| | | {item.Remark + ' (' + item.TbName + ')'} |
| | | <CloseOutlined onClick={() => this.deleteTable(item)}/> |
| | | <div className="bottom-mask"></div> |
| | | </List.Item>} |
| | | />} |
| | | </Panel> |
| | | {/* 搜索条件添加 */} |
| | | <Panel header={this.state.dict['header.menu.form']} key="1"> |
| | |
| | | return (<SourceElement key={index} content={item}/>) |
| | | })} |
| | | </div> |
| | | <Button type="primary" block onClick={() => this.queryField('search')}>批量添加</Button> |
| | | </Panel> |
| | | {/* 按钮添加 */} |
| | | <Panel header={this.state.dict['header.menu.action']} key="2"> |
| | |
| | | inputSubmit={this.handleSubmit} |
| | | wrappedComponentRef={(inst) => this.actionFormRef = inst} |
| | | /> |
| | | </Modal> |
| | | {/* 根据字段名添加显示列及搜索条件 */} |
| | | <Modal |
| | | wrapClassName="common-table-fields-modal" |
| | | title={this.state.dict['model.edit']} |
| | | visible={this.state.tableVisible} |
| | | width={'65vw'} |
| | | maskClosable={false} |
| | | cancelText={this.state.dict['model.close']} |
| | | onOk={this.addFieldSubmit} |
| | | onCancel={() => { // 取消添加 |
| | | this.setState({ |
| | | tableVisible: false |
| | | }) |
| | | }} |
| | | destroyOnClose |
| | | > |
| | | {this.state.fields && this.state.fields.length > 0 ? |
| | | <EditCard data={this.state.fields} ref="searchcard" type={'form'} dict={this.state.dict} /> : null |
| | | } |
| | | {(!this.state.fields || this.state.fields.length === 0) && |
| | | <Empty /> |
| | | } |
| | | </Modal> |
| | | {/* 按钮使用系统存储过程时,验证信息模态框 */} |
| | | <Modal |
| | |
| | | color: #1890ff; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | } |
| | | .tables { |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | .ant-list { |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | .config-button { |
| | | min-width: 65px; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .tables { |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .tools::-webkit-scrollbar { |
| | | width: 4px; |
| | |
| | | import Api from '@/api' |
| | | import options from '@/store/options.js' |
| | | import Utils from '@/utils/utils.js' |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import { queryTableSql } from '@/utils/option.js' |
| | | |
| | | import './index.scss' |
| | |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | tables: [], // 系统表 |
| | | tableFields: [], // 已选表字段集 |
| | | selectedTables: [], // 已选表 |
| | |
| | | |
| | | render() { |
| | | const { containerId } = this.props |
| | | const { dict, tables, selectedTables } = this.state |
| | | const { tables, selectedTables } = this.state |
| | | |
| | | return ( |
| | | <div className="model-table-tablemanage-view"> |
| | | <div className="model-tablename-manage-view"> |
| | | {/* 表名添加 */} |
| | | <div className="ant-col ant-form-item-label"> |
| | | <label> |
| | | <Tooltip placement="topLeft" title="此处可以添加页面配置相关的常用表,可通过工具栏中的添加按钮,可批量添加表格相关字段。"> |
| | | <QuestionCircleOutlined className="mk-form-tip" /> |
| | | {dict['header.menu.table.add']} |
| | | 表名 |
| | | </Tooltip> |
| | | </label> |
| | | </div> |
| | |
| | | renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}> |
| | | {item.Remark + ' (' + item.TbName + ')'} |
| | | <CloseOutlined onClick={() => this.deleteTable(item)}/> |
| | | <div className="bottom-mask"></div> |
| | | </List.Item>} |
| | | />} |
| | | </div> |
| | |
| | | .model-table-tablemanage-view { |
| | | .model-tablename-manage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | .tables { |
| | | width: 66.66666667%!important; |
| | | .ant-select-selection-selected-value { |
| | | opacity: 0.4!important; |
| | | } |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | |
| | | border-bottom: 1px solid #e8e8e8; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | .config-button { |
| | | min-width: 65px; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | .bottom-mask { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 8px; |
| | | bottom: 0; |
| | | left: 0; |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | } |
| | | .config-button { |
| | | min-width: 65px; |
| | | } |
| | |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | display: block; |
| | | } |
| | | } |
| | | .url-field-component, .model-table-tablemanage-view, .ant-typography { |
| | | .url-field-component, .model-tablename-manage-view, .ant-typography { |
| | | display: none; |
| | | } |
| | | } |
| | |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | const MenuForm = asyncComponent(() => import('./menuform')) |
| | | const Header = asyncComponent(() => import('@/menu/header')) |
| | | const MenuShell = asyncComponent(() => import('@/menu/menushell')) |
| | | const MenuShell = asyncComponent(() => import('@/menu/tableshell')) |
| | | const BgController = asyncComponent(() => import('@/pc/bgcontroller')) |
| | | const StyleController = asyncComponent(() => import('@/menu/stylecontroller')) |
| | | const ReplaceField = asyncComponent(() => import('@/menu/replaceField')) |
| | |
| | | ParentId: '', |
| | | MenuName: '', |
| | | MenuNo: '', |
| | | delButtons: [], |
| | | activeKey: 'basedata', |
| | | menuloading: false, |
| | | oriConfig: null, |
| | |
| | | } |
| | | |
| | | componentDidMount () { |
| | | MKEmitter.addListener('delButtons', this.delButtons) |
| | | MKEmitter.addListener('modalStatus', this.modalStatus) |
| | | MKEmitter.addListener('changePopview', this.initPopview) |
| | | MKEmitter.addListener('triggerMenuSave', this.triggerMenuSave) |
| | |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('delButtons', this.delButtons) |
| | | MKEmitter.removeListener('modalStatus', this.modalStatus) |
| | | MKEmitter.removeListener('changePopview', this.initPopview) |
| | | MKEmitter.removeListener('triggerMenuSave', this.triggerMenuSave) |
| | |
| | | }) |
| | | } |
| | | |
| | | delButtons = (items) => { |
| | | this.setState({ delButtons: [...this.state.delButtons, ...items] }) |
| | | } |
| | | |
| | | initPopview = (card, btn) => { |
| | | const { oriConfig, config } = this.state |
| | | |
| | |
| | | MenuName: MenuName, |
| | | MenuNo: MenuNo, |
| | | tables: [], |
| | | components: [], |
| | | components: [ |
| | | { |
| | | uuid: Utils.getuuid(), |
| | | type: 'table', |
| | | tabId: '', |
| | | parentId: '', |
| | | format: 'array', // 组件属性 - 数据格式 |
| | | pageable: true, // 组件属性 - 是否可分页 |
| | | switchable: true, // 组件属性 - 数据是否可切换 |
| | | dataName: '', |
| | | width: 24, |
| | | search: [ |
| | | { origin: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text', match: 'like' }, |
| | | { origin: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'select', match: 'equal' } |
| | | ], |
| | | action: [ |
| | | { origin: true, uuid: Utils.getuuid(), label: '添加', intertype: 'system', OpenType: 'pop', execSuccess: 'grid', icon: 'plus', class: 'green', style: {color: 'rgb(255, 255, 255)', background: 'rgb(38, 194, 129)', marginRight: '15px'} }, |
| | | { origin: true, uuid: Utils.getuuid(), label: '修改', intertype: 'system', OpenType: 'pop', execSuccess: 'grid', icon: 'form', class: 'purple', style: {color: 'rgb(255, 255, 255)', background: 'rgb(142, 68, 173)', marginRight: '15px'} }, |
| | | { origin: true, uuid: Utils.getuuid(), label: '删除', intertype: 'system', OpenType: 'prompt', execSuccess: 'grid', Ot: 'required', icon: 'delete', class: 'danger', style: {color: 'rgb(255, 255, 255)', background: 'rgb(255, 77, 79)', marginRight: '15px'} } |
| | | ], |
| | | name: '主表', |
| | | subtype: 'basetable', |
| | | setting: { interType: 'system' }, |
| | | wrap: {}, |
| | | style: {}, |
| | | headerStyle: {}, |
| | | columns: [], |
| | | cols: [ |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label1', field: '', Hide: 'false', type: 'text', Width: 120 }, |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label2', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 }, |
| | | { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label3', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 }, |
| | | ], |
| | | scripts: [], |
| | | isNew: true |
| | | } |
| | | ], |
| | | viewType: 'menu', |
| | | style: { |
| | | backgroundColor: '#ffffff', backgroundImage: '', |
| | |
| | | LText: [] |
| | | } |
| | | |
| | | let delButtons = fromJS(this.state.delButtons).toJS() |
| | | let delButtons = [] |
| | | |
| | | btnParam.LText = this.getMenuMessage(delButtons) |
| | | btnParam.LText = btnParam.LText.join(' union all ') |
| | |
| | | }).then(res => { |
| | | if (res && res.status) { |
| | | this.setState({ |
| | | delButtons: [], |
| | | menuloading: false |
| | | }) |
| | | notification.success({ |
| | |
| | | top: 48px; |
| | | z-index: 10; |
| | | height: calc(100vh - 48px); |
| | | width: 300px; |
| | | width: 280px; |
| | | background: #ffffff; |
| | | box-shadow: 0px 2px 5px #bcbcbc; |
| | | transition: left 0.3s; |
| | |
| | | color: #ffffff; |
| | | } |
| | | .ant-collapse-content-box { |
| | | padding: 10px; |
| | | .ant-form-item { |
| | | margin-bottom: 10px; |
| | | } |
| | | .model-table-tablemanage-view { |
| | | >.ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | | display: -webkit-box; |
| | | padding-right: 20px; |
| | | position: relative; |
| | | padding-left: 5px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | min-height: 55px; |
| | | width: 100%; |
| | | .anticon { |
| | | position: absolute; |
| | | top: 0px; |
| | | right: 0px; |
| | | padding: 3px 3px 10px 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | >.tables { |
| | | width: 66.66666667%!important; |
| | | } |
| | | >.ant-form-item-label { |
| | | width: 33.33333333%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | .menu-view { |
| | | position: relative; |
| | | width: calc(100vw - 300px); |
| | | margin-left: 300px; |
| | | width: calc(100vw - 280px); |
| | | margin-left: 280px; |
| | | height: calc(100vh - 50px); |
| | | overflow-y: auto; |
| | | transition: all 0.3s; |
| | |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={24}> |
| | | <Form.Item label="助记码"> |
| | | {getFieldDecorator('easyCode', { |
| | | initialValue: config.easyCode |
| | | })(<Input placeholder="" autoComplete="off" onChange={this.changeEasyCode}/>)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={24}> |
| | | <Form.Item label={'隐藏菜单'}> |
| | | <Switch checkedChildren={'是'} checked={config.hidden === 'true'} unCheckedChildren={'否'} onChange={(value) => { |
| | | this.selectChange('hidden', value + '') |
| | |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={24}> |
| | | <Form.Item label="助记码"> |
| | | {getFieldDecorator('easyCode', { |
| | | initialValue: config.easyCode |
| | | })(<Input placeholder="" autoComplete="off" onChange={this.changeEasyCode}/>)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={24}> |
| | | <Form.Item label="备注"> |
| | | {getFieldDecorator('Remark', { |
| | | initialValue: config.Remark || '', |