From 7ea1c5f53702951fc4df60e969fc67ef5d7af4dd Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期二, 14 一月 2020 10:13:05 +0800 Subject: [PATCH] 2020-01-14 --- src/tabviews/tableshare/mutilform/index.jsx | 29 + src/templates/formtabconfig/editable/index.jsx | 258 +++++++++++++ src/templates/modalconfig/index.scss | 31 + src/templates/tableshare/dragelement/index.jsx | 21 - src/templates/formtabconfig/index.jsx | 201 +++++++-- src/tabviews/tableshare/mutilform/index.scss | 14 src/templates/comtableconfig/index.jsx | 14 src/templates/modalconfig/dragelement/index.scss | 4 src/templates/formtabconfig/modalform/index.jsx | 411 +++++++++++++++++++++ src/templates/formtabconfig/dragelement/index.jsx | 15 src/templates/modalconfig/index.jsx | 10 src/templates/formtabconfig/editable/index.scss | 36 + src/templates/formtabconfig/modalform/index.scss | 16 src/templates/formtabconfig/source.jsx | 36 + src/templates/modalconfig/dragelement/index.jsx | 11 src/locales/zh-CN/comtable.js | 3 src/templates/modalconfig/dragelement/card.jsx | 19 src/locales/en-US/comtable.js | 3 src/templates/formtabconfig/index.scss | 5 src/utils/option.js | 3 20 files changed, 1,018 insertions(+), 122 deletions(-) diff --git a/src/locales/en-US/comtable.js b/src/locales/en-US/comtable.js index 3357cac..ed31042 100644 --- a/src/locales/en-US/comtable.js +++ b/src/locales/en-US/comtable.js @@ -84,6 +84,9 @@ 'header.form.text': 'Text', 'header.form.description': '鎻忚堪', 'header.form.textarea': '澶氳鏂囨湰', + 'header.form.fileupload': '鏂囦欢涓婁紶', + 'header.form.funcvar': '鍑芥暟鍙橀噺', + 'header.form.linkForm': '鍏宠仈琛ㄥ崟', 'header.form.picture': '鍥剧墖', 'header.form.number': '鏁板瓧', 'header.form.colspan': '鍚堝苟鍒�', diff --git a/src/locales/zh-CN/comtable.js b/src/locales/zh-CN/comtable.js index 917d5c1..4d89eb6 100644 --- a/src/locales/zh-CN/comtable.js +++ b/src/locales/zh-CN/comtable.js @@ -84,6 +84,9 @@ 'header.form.text': '鏂囨湰', 'header.form.description': '鎻忚堪', 'header.form.textarea': '澶氳鏂囨湰', + 'header.form.fileupload': '鏂囦欢涓婁紶', + 'header.form.funcvar': '鍑芥暟鍙橀噺', + 'header.form.linkForm': '鍏宠仈琛ㄥ崟', 'header.form.picture': '鍥剧墖', 'header.form.number': '鏁板瓧', 'header.form.colspan': '鍚堝苟鍒�', diff --git a/src/tabviews/tableshare/mutilform/index.jsx b/src/tabviews/tableshare/mutilform/index.jsx index 83fe6a0..064cd74 100644 --- a/src/tabviews/tableshare/mutilform/index.jsx +++ b/src/tabviews/tableshare/mutilform/index.jsx @@ -8,6 +8,7 @@ import './index.scss' const {MonthPicker} = DatePicker +const { TextArea } = Input class MainSearch extends Component { static propTpyes = { @@ -61,7 +62,7 @@ let _inputfields = formlist.filter(item => item.type === 'text' || item.type === 'number') // 鐢ㄤ簬杩囨护涓嬫媺鑿滃崟鍏宠仈琛ㄥ崟 formlist = formlist.map(item => { - if (item.type === 'select' || item.type === 'link') { + if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') { if (item.setAll === 'true') { item.options.unshift({ key: Utils.getuuid(), @@ -461,6 +462,32 @@ </Form.Item> </Col> ) + } else if (item.type === 'textarea') { + let _labelcol = cols !== 3 ? 8 / cols : 3 + let _wrapcol = cols !== 3 ? 16 + (cols - 1) * 4 : 21 + let _style = {} + if (cols === 2) { + _style.paddingLeft = '7px' + } + fields.push( + <Col span={24} key={index} className="textarea-row" style={{..._style}}> + <Form.Item label={item.label} labelCol={{xs: { span: 24 }, sm: { span: _labelcol }}} wrapperCol={ {xs: { span: 24 }, sm: { span: _wrapcol }} }> + {getFieldDecorator(item.field, { + initialValue: item.initval || '', + rules: [ + { + required: item.required === 'true', + message: this.props.dict['form.required.input'] + item.label + '!' + }, + { + max: formRule.textarea.max, + message: formRule.textarea.message + } + ] + })(<TextArea autosize={{ minRows: 2, maxRows: 6 }} disabled={item.readonly === 'true'} />)} + </Form.Item> + </Col> + ) } }) diff --git a/src/tabviews/tableshare/mutilform/index.scss b/src/tabviews/tableshare/mutilform/index.scss index 2a79447..62fcc66 100644 --- a/src/tabviews/tableshare/mutilform/index.scss +++ b/src/tabviews/tableshare/mutilform/index.scss @@ -3,13 +3,23 @@ padding: 0px 24px 20px; .ant-form-item { display: flex; - // margin-bottom: 10px; } .ant-form-item-control-wrapper { flex: 1; } .ant-form-item-label { - min-width: 100px; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + white-space: nowrap; + } + .textarea-row { + .ant-col-sm-3 { + width: 10.5%; + } + .ant-col-sm-21 { + width: 89.5%; + } } .ant-input-number { width: 100%; diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx index 89d3e62..564910d 100644 --- a/src/templates/comtableconfig/index.jsx +++ b/src/templates/comtableconfig/index.jsx @@ -354,7 +354,7 @@ type: 'text', key: 'label', label: this.state.dict['header.form.name'], - initVal: card.label, + initVal: card.label || '', required: true, readonly: false }, @@ -362,7 +362,7 @@ type: 'text', key: 'field', label: this.state.dict['header.form.field'], - initVal: card.field, + initVal: card.field || '', tooltip: '瀛楁鍚嶅彲浠ヤ娇鐢ㄩ�楀彿鍒嗛殧锛岃繘琛屽瀛楁缁煎悎鎼滅储锛屾敞锛氱患鍚堟悳绱粎鍦ㄦ枃鏈被鍨嬫椂鏈夋晥', tooltipClass: 'middle', required: true, @@ -612,7 +612,7 @@ type: 'select', key: 'pageTemplate', label: this.state.dict['header.form.pageTemplate'], - initVal: card.pageTemplate, + initVal: card.pageTemplate || '', required: true, options: [] }, @@ -641,7 +641,7 @@ type: 'text', key: 'innerFunc', label: this.state.dict['header.form.innerFunc'], - initVal: card.innerFunc, + initVal: card.innerFunc || '', tooltip: <div> <p>鍐呴儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屽嚱鏁板悕绉伴渶浠ableField}绛夊瓧绗﹀紑濮嬶紱鏈缃椂浼氳皟鐢ㄧ郴缁熷嚱鏁帮紝浣跨敤绯荤粺鍑芥暟闇�瀹屽杽鏁版嵁婧愬強鎿嶄綔绫诲瀷;</p> <p>澶栭儴鎺ュ彛: 鍙嚜瀹氫箟鏁版嵁澶勭悊鍑芥暟锛屾彁浜ゆ暟鎹粡杩囧唴閮ㄥ嚱鏁板鐞嗗悗锛屼紶鍏ュ閮ㄦ帴鍙o紝鏈缃椂锛屾暟鎹細鐩存帴浼犲叆澶栭儴鎺ュ彛銆�</p> @@ -669,7 +669,7 @@ type: 'text', key: 'outerFunc', label: this.state.dict['header.form.outerFunc'], - initVal: card.outerFunc, + initVal: card.outerFunc || '', required: false, readonly: false }, @@ -677,7 +677,7 @@ type: 'text', key: 'interface', label: this.state.dict['header.form.interface'], - initVal: card.sysInterface === 'true' ? (window.GLOB.mainSystemApi || window.GLOB.subSystemApi) : card.interface, + initVal: card.sysInterface === 'true' ? (window.GLOB.mainSystemApi || window.GLOB.subSystemApi) : (card.interface || ''), required: true, readonly: card.sysInterface === 'true' }, @@ -685,7 +685,7 @@ type: 'text', key: 'callbackFunc', label: this.state.dict['header.form.callbackFunc'], - initVal: card.callbackFunc, + initVal: card.callbackFunc || '', required: false, readonly: false }, diff --git a/src/templates/formtabconfig/dragelement/index.jsx b/src/templates/formtabconfig/dragelement/index.jsx index 530e296..83ca042 100644 --- a/src/templates/formtabconfig/dragelement/index.jsx +++ b/src/templates/formtabconfig/dragelement/index.jsx @@ -63,6 +63,14 @@ const [, drop] = useDrop({ accept: ItemTypes[type], drop(item) { + if (item.hasOwnProperty('originalIndex') && groupId) { + const { card } = findCard(item.id) + + if (!card) { + handleList(type, cards, null, groupId, item.id) + } + } + if (item.hasOwnProperty('originalIndex')) { return } @@ -134,7 +142,7 @@ const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] }) setCards(_cards) - handleList(type, _cards, newcard) + handleList(type, _cards, newcard, groupId) target = null } }) @@ -144,7 +152,7 @@ {type === 'action' && cards.map(card => ( <Card key={card.uuid} - id={`${card.uuid}`} + id={card.uuid} type={type} card={card} moveCard={moveCard} @@ -159,7 +167,8 @@ {type === 'search' && cards.map(card => ( <Col key={card.uuid} span={24 / setting.cols}> <Card - id={`${card.uuid}`} + id={card.uuid} + key={card.uuid} type={type} card={card} moveCard={moveCard} diff --git a/src/templates/formtabconfig/editable/index.jsx b/src/templates/formtabconfig/editable/index.jsx new file mode 100644 index 0000000..4f10603 --- /dev/null +++ b/src/templates/formtabconfig/editable/index.jsx @@ -0,0 +1,258 @@ +import React, {Component} from 'react' +import { Table, Input, Button, Popconfirm, Form, Icon } from 'antd' +import Utils from '@/utils/utils.js' +import './index.scss' + +const EditableContext = React.createContext() + +const EditableRow = ({ form, index, ...props }) => ( + <EditableContext.Provider value={form}> + <tr {...props} /> + </EditableContext.Provider> +) + +const EditableFormRow = Form.create()(EditableRow) + +class EditableCell extends Component { + state = { + editing: false + } + + toggleEdit = () => { + const editing = !this.state.editing + this.setState({ editing }, () => { + if (editing) { + this.input.focus() + } + }) + } + + save = e => { + const { record, handleSave } = this.props + this.form.validateFields((error, values) => { + handleSave({ ...record, ...values }) + if (error && error[e.currentTarget.id]) { + return + } + this.toggleEdit() + // handleSave({ ...record, ...values }) + }) + } + + renderCell = form => { + this.form = form + const { children, dataIndex, record } = this.props + const { editing } = this.state + return editing ? ( + <Form.Item style={{ margin: 0 }}> + {form.getFieldDecorator(dataIndex, { + rules: [ + { + required: true, + message: 'NOT NULL.', + }, + ], + initialValue: record[dataIndex] + })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)} + </Form.Item> + ) : ( + <div + className="editable-cell-value-wrap" + onClick={this.toggleEdit} + > + {children} + </div> + ) + } + + render() { + const { + editable, + dataIndex, + title, + record, + index, + handleSave, + children, + ...restProps + } = this.props + return ( + <td {...restProps}> + {editable ? ( + <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer> + ) : ( + children + )} + </td> + ) + } +} + +class EditTable extends Component { + constructor(props) { + super(props) + let columns = [ + { + title: 'Value', + dataIndex: 'Value', + width: props.type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Text', + dataIndex: 'Text', + width: props.type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: '鎿嶄綔', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + this.state.dataSource.length >= 1 ? ( + <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}> + <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + ) : null, + } + ] + + if (props.type === 'link') { + columns.unshift({ + title: 'ParentID', + dataIndex: 'ParentID', + width: '27%', + editable: true + }) + } + + this.state = { + columns: columns, + dataSource: props.data, + count: props.data.length, + type: props.type + } + } + + handleDelete = key => { + const dataSource = [...this.state.dataSource] + this.setState({ dataSource: dataSource.filter(item => item.key !== key) }) + } + + handleAdd = () => { + const { type, count, dataSource } = this.state + const newData = { + key: Utils.getuuid(), + Value: `${count}`, + Text: `${count}` + } + if (type === 'link') { + newData.ParentID = `${count}` + } + this.setState({ + dataSource: [...dataSource, newData], + count: count + 1 + }) + } + + handleSave = row => { + const newData = [...this.state.dataSource] + const index = newData.findIndex(item => row.key === item.key) + const item = newData[index] + newData.splice(index, 1, { + ...item, + ...row + }) + this.setState({ dataSource: newData }) + } + + resetColumn = (type) => { + let columns = [ + { + title: 'Value', + dataIndex: 'Value', + width: type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: 'Text', + dataIndex: 'Text', + width: type === 'link' ? '27%' : '40%', + editable: true + }, + { + title: '鎿嶄綔', + align: 'center', + dataIndex: 'operation', + render: (text, record) => + this.state.dataSource.length >= 1 ? ( + <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}> + <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> + </Popconfirm> + ) : null, + } + ] + + if (type === 'link') { + columns.unshift({ + title: 'ParentID', + dataIndex: 'ParentID', + width: '27%', + editable: true + }) + } + + this.setState({ + columns: columns, + type: type + }) + } + + UNSAFE_componentWillReceiveProps (nextProps) { + if (this.props.type !== nextProps.type) { + this.resetColumn(nextProps.type) + } + } + + render() { + const { dataSource } = this.state + const components = { + body: { + row: EditableFormRow, + cell: EditableCell + } + } + const columns = this.state.columns.map(col => { + if (!col.editable) { + return col + } + return { + ...col, + onCell: record => ({ + record, + editable: col.editable, + dataIndex: col.dataIndex, + title: col.title, + handleSave: this.handleSave, + }) + } + }) + return ( + <div className="common-modal-edit-table"> + <Button onClick={this.handleAdd} type="primary" className="add-row"> + 娣诲姞 + </Button> + <Table + components={components} + rowClassName={() => 'editable-row'} + bordered + dataSource={dataSource} + columns={columns} + pagination={false} + /> + </div> + ) + } +} + +export default EditTable \ No newline at end of file diff --git a/src/templates/formtabconfig/editable/index.scss b/src/templates/formtabconfig/editable/index.scss new file mode 100644 index 0000000..f8f0942 --- /dev/null +++ b/src/templates/formtabconfig/editable/index.scss @@ -0,0 +1,36 @@ +.common-modal-edit-table { + .add-row { + position: absolute; + z-index: 1; + right: 12px; + top: -40px; + } + .ant-table-thead > tr > th { + padding: 10px 16px; + } + .ant-table-tbody > tr > td { + padding: 0px 16px; + } + .editable-cell-value-wrap { + cursor: pointer; + height: 40px; + width: 100px; + display: table-cell; + vertical-align: middle; + word-wrap: break-word; + word-break: break-word; + .ant-input { + height: 30px; + padding: 0 11px; + } + } + .ant-form-item-control-wrapper { + width: 100%; + } + .ant-table-placeholder { + padding: 5px 16px; + .ant-empty-normal { + margin: 0; + } + } +} diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx index c8e43f2..e8a15df 100644 --- a/src/templates/formtabconfig/index.jsx +++ b/src/templates/formtabconfig/index.jsx @@ -11,7 +11,7 @@ import TabForm from './tabform' import TabDragElement from './tabdragelement' import Api from '@/api' -import SearchForm from '@/templates/tableshare/searchform' +import SearchForm from './modalform' import DragElement from './dragelement' import EditCard from '@/templates/tableshare/editcard' import VerifyCard from '@/templates/tableshare/verifycard' @@ -52,7 +52,6 @@ card: null, // 缂栬緫鍏冪礌 searchloading: false, // 鎼滅储鏉′欢鍔犺浇涓� actionloading: false, // 鎸夐挳鍔犺浇涓� - columnsloading: false, // 鏄剧ず鍒楀姞杞戒腑 tabloading: false, // 鏍囩椤靛姞杞戒腑 menuloading: false, // 鑿滃崟淇濆瓨涓� menucloseloading: false, // 鑿滃崟鍏抽棴鏃讹紝閫夋嫨淇濆瓨 @@ -76,9 +75,6 @@ UNSAFE_componentWillMount () { const { menu, editAction, config } = this.props - console.log(menu) - console.log(editAction) - console.log(config) let _config = '' if (!config) { @@ -240,8 +236,8 @@ } } - handleList = (type, list, card, groupId) => { - const { config } = this.state + handleList = (type, list, card, groupId, elementId) => { + let config = JSON.parse(JSON.stringify(this.state.config)) if (type === 'tabs') { // 鏍囩椤佃皟鏁撮『搴忔垨娣诲姞鍏冪礌 if (list.length > config[card.groupId].length) { @@ -278,14 +274,77 @@ } else { this.setState({config: {...config, action: list}}) } + } else if (type === 'search') { + let _group = config.groups.filter(group => group.uuid === groupId)[0] + let isChange = list.length > _group.length + let isAdd = !elementId && list.length > _group.length + + if (isAdd) { + _group.sublist = list.filter(item => !item.origin) + this.handleSearch(card) + } else if (elementId) { + // 淇敼宸叉湁鍏冪礌鐨勫垎缁� + let element = null + config.groups.forEach(item => { + item.sublist = item.sublist.filter(cell => { + if (cell.uuid !== elementId) { + return true + } else { + element = cell + return false + } + }) + }) + _group.sublist.push(element) + } else { + _group.sublist = list + } + + config.groups = config.groups.map(item => { + if (item.uuid === _group.uuid) { + return _group + } else { + return item + } + }) + + if (isChange) { + this.setState({ + searchloading: true, + config: config + }, () => { + // 鍒锋柊瀵瑰簲鐨勯厤缃俊鎭� + this.setState({ + searchloading: false + }) + }) + } else { + this.setState({ + config: config + }) + } } } handleSearch = (card) => { + const { config } = this.state + let _inputfields = [] + + // 璁剧疆涓嬫媺鑿滃崟鍙叧鑱斿瓧娈� + config.groups.forEach(group => { + let sublist = group.sublist.filter(item => item.type === 'text' || item.type === 'number') + _inputfields = [..._inputfields, ...sublist] + }) + + if (card.linkSubField && card.linkSubField.length > 0) { + let fields = _inputfields.map(item => item.field) + card.linkSubField = card.linkSubField.filter(item => fields.includes(item)) + } + this.setState({ visible: true, formtemp: 'search', - modalTitle: '缂栬緫-鎼滅储鏉′欢', + modalTitle: '缂栬緫-琛ㄥ崟', card: card, formlist: [ { @@ -301,8 +360,6 @@ key: 'field', label: this.state.dict['header.form.field'], initVal: card.field, - tooltip: '瀛楁鍚嶅彲浠ヤ娇鐢ㄩ�楀彿鍒嗛殧锛岃繘琛屽瀛楁缁煎悎鎼滅储锛屾敞锛氱患鍚堟悳绱粎鍦ㄦ枃鏈被鍨嬫椂鏈夋晥', - tooltipClass: 'middle', required: true, readonly: false }, @@ -316,6 +373,9 @@ value: 'text', text: this.state.dict['header.form.text'] }, { + value: 'number', + text: this.state.dict['header.form.number'] + }, { value: 'select', text: this.state.dict['header.form.select'] }, { @@ -325,17 +385,20 @@ value: 'link', text: this.state.dict['header.form.link'] }, { + value: 'fileupload', + text: this.state.dict['header.form.fileupload'] + }, { value: 'date', text: this.state.dict['header.form.dateday'] - }, { - value: 'dateweek', - text: this.state.dict['header.form.dateweek'] }, { value: 'datemonth', text: this.state.dict['header.form.datemonth'] }, { - value: 'daterange', - text: this.state.dict['header.form.daterange'] + value: 'datetime', + text: this.state.dict['header.form.datetime'] + }, { + value: 'textarea', + text: this.state.dict['header.form.textarea'] }] }, { @@ -434,41 +497,58 @@ }] }, { - type: 'select', - key: 'match', - label: this.state.dict['header.form.match'], - initVal: card.match || 'like', - required: true, + type: 'number', + key: 'decimal', + label: this.state.dict['header.form.decimal'], + initVal: card.decimal || 0, + required: false + }, + { + type: 'number', + key: 'min', + label: '鏈�灏忓��', + initVal: card.min || '', + required: false + }, + { + type: 'number', + key: 'max', + label: '鏈�澶у��', + initVal: card.max || '', + required: false + }, + { + type: 'radio', + key: 'readonly', + label: this.state.dict['header.form.readonly'], + initVal: card.readonly || 'false', options: [{ - value: 'like', - text: 'like' + value: 'true', + text: this.state.dict['header.form.true'] }, { - value: 'equal', - text: 'equal' - }, { - value: 'greater', - text: '>' - }, { - value: 'less', - text: '<' - }, { - value: 'greaterequal', - text: '>=' + value: 'false', + text: this.state.dict['header.form.false'] }] }, { - type: 'select', - key: 'display', - label: this.state.dict['header.form.display'], - initVal: card.display || 'dropdown', - required: true, + type: 'radio', + key: 'required', + label: this.state.dict['header.form.field.required'], + initVal: card.required || 'false', options: [{ - value: 'dropdown', - text: this.state.dict['header.form.dropdown'] + value: 'true', + text: this.state.dict['header.form.true'] }, { - value: 'button', - text: this.state.dict['header.form.button'] + value: 'false', + text: this.state.dict['header.form.false'] }] + }, + { + type: 'multiselect', + key: 'linkSubField', + label: this.state.dict['header.form.linkForm'], + initVal: card.linkSubField || [], + options: _inputfields } ] }) @@ -809,8 +889,9 @@ }) } - if (res.type !== 'tabs') { - _config[res.type] = _config[res.type].map(item => { + + if (res.type === 'action') { + _config.action = _config.action.map(item => { if (item.uuid === res.values.uuid) { isupdate = true return res.values @@ -818,11 +899,25 @@ return item } }) - _config[res.type] = _config[res.type].filter(item => !item.origin) + _config.action = _config.action.filter(item => !item.origin) if (!isupdate) { // 鎿嶄綔涓嶆槸淇敼锛屾坊鍔犲厓绱犺嚦鍒楄〃 - _config[res.type].push(res.values) + _config.action.push(res.values) } + } else if (res.type === 'search') { + _config.groups = _config.groups.map(item => { + item.sublist = item.sublist.map(cell => { + if (cell.uuid === res.values.uuid) { + return res.values + } else { + return cell + } + }) + if (item.isDefault) { + item.sublist = item.sublist.filter(cell => !cell.origin) + } + return item + }) } else { // 鏍囩椤电殑娣诲姞涓庝慨鏀� _config[res.values.groupId] = _config[res.values.groupId].map(item => { if (item.uuid === res.values.uuid) { @@ -843,14 +938,12 @@ config: _config, searchloading: true, actionloading: true, - columnsloading: true, tabloading: true, visible: false }, () => { this.setState({ searchloading: false, actionloading: false, - columnsloading: false, tabloading: false }) }) @@ -1564,13 +1657,11 @@ ParentID: res.parentId }, searchloading: true, - actionloading: true, - columnsloading: true + actionloading: true }, () => { this.setState({ searchloading: false, - actionloading: false, - columnsloading: false + actionloading: false }) }) @@ -2004,11 +2095,9 @@ this.setState({ config: {...config, setting: res}, settingVisible: false, - columnsloading: true, tabloading: true }, () => { this.setState({ - columnsloading: false, tabloading: false }) }) @@ -2269,13 +2358,13 @@ />} </Panel> {/* 鎼滅储鏉′欢娣诲姞 */} - <Panel header={this.state.dict['header.menu.search']} key="1"> + <Panel header={this.state.dict['header.menu.form']} key="1"> <div className="search-element"> {Source.searchItems.map((item, index) => { return (<SourceElement key={index} content={item}/>) })} </div> - <Button type="primary" block onClick={() => this.queryField('search')}>{this.state.dict['header.menu.search.add']}</Button> + <Button type="primary" block onClick={() => this.queryField('search')}>{this.state.dict['header.menu.form.add']}</Button> </Panel> {/* 鎸夐挳娣诲姞 */} <Panel header={this.state.dict['header.menu.action']} key="2"> diff --git a/src/templates/formtabconfig/index.scss b/src/templates/formtabconfig/index.scss index f43082a..cafce11 100644 --- a/src/templates/formtabconfig/index.scss +++ b/src/templates/formtabconfig/index.scss @@ -173,13 +173,16 @@ border-radius: 0; background: #1890ff; color: #ffffff; + padding-left: 30px; + padding-right: 20px; .anticon { font-size: 16px; } .ant-collapse-extra { .anticon-edit { position: absolute; - right: 15px; + left: 5px; + top: 2px; } } } diff --git a/src/templates/formtabconfig/modalform/index.jsx b/src/templates/formtabconfig/modalform/index.jsx new file mode 100644 index 0000000..6a8c3b3 --- /dev/null +++ b/src/templates/formtabconfig/modalform/index.jsx @@ -0,0 +1,411 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { Form, Row, Col, Input, Select, Icon, Radio, notification, InputNumber } from 'antd' +import { formRule } from '@/utils/option.js' +import { dateOptions } from '@/utils/option.js' +import EditTable from '../editable' +import './index.scss' + +const { TextArea } = Input + +class MainSearch extends Component { + static propTpyes = { + dict: PropTypes.object, // 瀛楀吀椤� + formlist: PropTypes.any, + card: PropTypes.object + } + + state = { + openType: null, + resourceType: null, + formlist: null + } + + UNSAFE_componentWillMount () { + let formlist = JSON.parse(JSON.stringify(this.props.formlist)) + + let type = formlist.filter(cell => cell.key === 'type')[0].initVal + let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal + let _options = ['label', 'field', 'initval', 'type', 'readonly', 'required'] // 榛樿鏄剧ず椤� + + if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') { // 閫夋嫨绫诲瀷銆佽嚜瀹氫箟璧勬簮 + _options = [..._options, 'resourceType', 'options'] + } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 閫夋嫨绫诲瀷銆佹暟鎹簮 + _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType'] + } else if (type === 'number') { + _options = [..._options, 'decimal', 'min', 'max'] + } else if (type === 'fileupload') { + _options = ['label', 'field', 'type', 'readonly', 'required'] + } + + if (type === 'select') { + _options = [..._options, 'setAll', 'linkSubField'] + } else if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斿瓧娈� + _options = [..._options, 'setAll', 'linkField'] + } else if (type === 'funcvar') { // 璁剧疆涓哄嚱鏁板彉閲忔椂锛屼笉闇�瑕佸叾浠栦俊鎭� + _options = ['label', 'field', 'type'] + } + + this.setState({ + openType: type, + resourceType: resourceType, + formlist: formlist.map(form => { + if (dateOptions.hasOwnProperty(type) && form.key === 'initval') { + form.options = dateOptions[type] + form.type = 'select' + } else if (type === 'number' && form.key === 'initval') { + form.type = 'number' + form.initVal = 0 + } + form.hidden = !_options.includes(form.key) + return form + }) + }) + } + + componentDidMount () { + const { card } = this.props + + if (card.focus) { + try { + let _form = document.getElementById('label') + _form.select() + } catch { + console.warn('琛ㄥ崟focus澶辫触锛�') + } + } + } + + openTypeChange = (key, value) => { + if (key === 'type') { + let _options = ['label', 'field', 'initval', 'type', 'readonly', 'required'] + + if ((value === 'multiselect' || value === 'select' || value === 'link') && this.state.resourceType === '0') { // 閫夋嫨绫诲瀷銆佽嚜瀹氫箟璧勬簮 + _options = [..._options, 'resourceType', 'options'] + } else if ((value === 'multiselect' || value === 'select' || value === 'link') && this.state.resourceType === '1') { // 閫夋嫨绫诲瀷銆佹暟鎹簮 + _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType'] + } else if (value === 'number') { + _options = [..._options, 'decimal', 'min', 'max'] + } else if (value === 'fileupload') { + _options = ['label', 'field', 'type', 'readonly', 'required'] + } + + if (value === 'select') { + _options = [..._options, 'setAll', 'linkSubField'] + } else if (value === 'link') { + _options = [..._options, 'setAll', 'linkField'] + } else if (value === 'funcvar') { + _options = ['label', 'field', 'type'] + } + + this.setState({ + openType: value, + formlist: this.state.formlist.map(form => { + form.hidden = !_options.includes(form.key) + if (form.key === 'initval') { + if (dateOptions.hasOwnProperty(value)) { + form.options = dateOptions[value] + form.type = 'select' + form.initVal = '' + } else if (value === 'number') { + form.type = 'number' + form.initVal = 0 + } else { + form.type = 'text' + form.initVal = '' + } + form.hidden = true + } + return form + }) + }, () => { + this.setState({ + formlist: this.state.formlist.map(form => { + if (form.key === 'initval' && value !== 'fileupload' && value !== 'funcvar') { + form.hidden = false + } + return form + }) + }) + }) + } + } + + onChange = (e, key) => { + const { openType } = this.state + let value = e.target.value + if (key === 'resourceType') { + let _options = ['label', 'field', 'initval', 'type', 'resourceType', 'readonly', 'required'] + if (value === '0') { + _options = [..._options, 'options'] + } else if (value === '1') { + _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType'] + } + + if (openType === 'select') { + _options = [..._options, 'setAll', 'linkSubField'] + } else if (openType === 'link') { + _options = [..._options, 'setAll', 'linkField'] + } + + this.setState({ + resourceType: value, + formlist: this.state.formlist.map(form => { + form.hidden = !_options.includes(form.key) + return form + }) + }) + } + } + + getFields() { + const { getFieldDecorator } = this.props.form + const fields = [] + + this.state.formlist.forEach((item, index) => { + if (item.hidden) return + + if (item.type === 'text') { // 鏂囨湰鎼滅储 + let rules = [] + if (item.key === 'field') { + rules = [{ + pattern: formRule.field.pattern, + message: formRule.field.message + }, { + max: formRule.field.max, + message: formRule.field.maxMessage + }] + } else { + rules = [ + { + max: formRule.input.max, + message: formRule.input.message + } + ] + } + 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.input'] + item.label + '!' + }, + ...rules + ] + })(<Input placeholder="" autoComplete="off" disabled={item.readonly} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'number') { + if (item.key === 'decimal') { + fields.push( + <Col span={12} key={index}> + <Form.Item label={item.label}> + {getFieldDecorator(item.key, { + initialValue: item.initVal || 0, + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<InputNumber min={0} max={18} precision={0} />)} + </Form.Item> + </Col> + ) + } else { + 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.input'] + item.label + '!' + } + ] + })(<InputNumber />)} + </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[2].toLowerCase().indexOf(input.toLowerCase()) >= 0} + onChange={(value) => {this.openTypeChange(item.key, value)}} + getPopupContainer={() => document.getElementById('modal-fields-form-box')} + > + {item.options.map(option => + <Select.Option id={option.value} title={option.text} key={option.value} value={option.value}> + {item.key === 'icon' && <Icon type={option.text} />} {option.text} + </Select.Option> + )} + </Select> + )} + </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 => + <Select.Option id={option.uuid} key={option.uuid} value={option.field}>{option.label}</Select.Option> + )} + </Select> + )} + </Form.Item> + </Col> + ) + } else if (item.type === 'radio') { + 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 + '!' + } + ] + })( + <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}> + { + item.options.map(option => { + return ( + <Radio key={option.value} value={option.value}>{option.text}</Radio> + ) + }) + } + </Radio.Group>, + )} + </Form.Item> + </Col> + ) + } else if (item.type === 'textarea') { + fields.push( + <Col span={20} offset={4} key={index}> + <Form.Item className="text-area"> + {getFieldDecorator(item.key, { + initialValue: item.initVal, + rules: [ + { + required: !!item.required, + message: this.props.dict['form.required.input'] + item.label + '!' + } + ] + })(<TextArea rows={4} />)} + </Form.Item> + </Col> + ) + } else if (item.type === 'options') { + fields.push( + <Col span={20} offset={4} key={index}> + <EditTable data={item.initVal} type={this.state.openType} ref="editTable"/> + </Col> + ) + } + }) + + return fields + } + + handleConfirm = () => { + // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭� + return new Promise((resolve, reject) => { + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + let isvalid = true + values.uuid = this.props.card.uuid + // 涓嬫媺鑿滃崟鎴栧叧鑱旇彍鍗� + if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') { + values.options = this.refs.editTable.state.dataSource + values.dataSource = '' + let emptys = [] + if (values.type === 'multiselect' || values.type === 'select') { + emptys = values.options.filter(op => !(op.Value && op.Text)) + } else { + emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID)) + } + if (emptys.length > 0) { + isvalid = false + notification.warning({ + top: 92, + message: this.props.dict['header.form.selectItem.error'], + duration: 10 + }) + } + } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') { + values.options = [] + } else if (values.type === 'funcvar') { // 鍑芥暟鍙橀噺涓哄彧璇诲厓绱� + values.readonly = 'true' + } else if (values.type === 'number' && (values.min || values.min === 0) && (values.max || values.max === 0)) { // 鏁板�煎瀷楠岃瘉鏈�灏忔渶澶у�� + if (values.min > values.max) { + isvalid = false + notification.warning({ + top: 92, + message: '鏈�灏忓�间笉鍙ぇ浜庢渶澶у�硷紒', + duration: 10 + }) + } + } + + if (isvalid) { + resolve({ + type: 'search', + values + }) + } + } else { + reject(err) + } + }) + }) + } + + render() { + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + sm: { span: 8 } + }, + wrapperCol: { + xs: { span: 24 }, + sm: { span: 16 } + } + } + return ( + <Form {...formItemLayout} className="ant-advanced-search-form modal-fields-form" id="modal-fields-form-box"> + <Row gutter={24}>{this.getFields()}</Row> + </Form> + ) + } +} + +export default Form.create()(MainSearch) \ No newline at end of file diff --git a/src/templates/formtabconfig/modalform/index.scss b/src/templates/formtabconfig/modalform/index.scss new file mode 100644 index 0000000..0cdacad --- /dev/null +++ b/src/templates/formtabconfig/modalform/index.scss @@ -0,0 +1,16 @@ +.ant-advanced-search-form.modal-fields-form { + min-height: 180px; + .ant-col-offset-4 { + padding-left: 6px!important; + padding-bottom: 20px; + } + .ant-form-item.text-area { + margin-bottom: 0px; + .ant-form-item-control-wrapper { + width: 100%; + } + } + .ant-input-number { + width: 100%; + } +} \ No newline at end of file diff --git a/src/templates/formtabconfig/source.jsx b/src/templates/formtabconfig/source.jsx index 267165c..6c209eb 100644 --- a/src/templates/formtabconfig/source.jsx +++ b/src/templates/formtabconfig/source.jsx @@ -214,38 +214,50 @@ searchItems = [ { type: 'search', - label: '鏂囨湰妗�', + label: '鏂囨湰', subType: 'text', url: '' }, { type: 'search', - label: '涓嬫媺妗�', + label: '鏁板瓧', + subType: 'number', + url: '' + }, + { + type: 'search', + label: '涓嬫媺閫夋嫨', subType: 'select', url: '' }, { type: 'search', - label: '鏃堕棿妗嗭紙澶╋級', + label: '鏂囦欢涓婁紶', + subType: 'fileupload', + url: '' + }, + { + type: 'search', + label: '鏃堕棿锛堝ぉ锛�', subType: 'date', url: '' }, { type: 'search', - label: '鏃堕棿妗嗭紙鍛級', - subType: 'dateweek', - url: '' - }, - { - type: 'search', - label: '鏃堕棿妗嗭紙鏈堬級', + label: '鏃堕棿锛堟湀锛�', subType: 'datemonth', url: '' }, { type: 'search', - label: '鏃堕棿妗嗭紙鍖洪棿锛�', - subType: 'daterange', + label: '鏃堕棿锛堢锛�', + subType: 'datetime', + url: '' + }, + { + type: 'search', + label: '澶氳鏂囨湰', + subType: 'textarea', url: '' } ] diff --git a/src/templates/modalconfig/dragelement/card.jsx b/src/templates/modalconfig/dragelement/card.jsx index ea5c8e2..d1fda91 100644 --- a/src/templates/modalconfig/dragelement/card.jsx +++ b/src/templates/modalconfig/dragelement/card.jsx @@ -8,7 +8,7 @@ const { MonthPicker } = DatePicker const { TextArea } = Input -const Card = ({ id, card, moveCard, findCard, editCard, closeCard, hasDrop }) => { +const Card = ({ id, card, cols, moveCard, findCard, editCard, closeCard, hasDrop }) => { const originalIndex = findCard(id).index const [{ isDragging }, drag] = useDrag({ item: { type: ItemTypes.form, id, originalIndex }, @@ -55,15 +55,26 @@ selectval = '鍏ㄩ儴' } } + let labelCol = 'ant-col-sm-8' + let wrapCol = 'ant-col-sm-16' + if (card.type === 'textarea') { + if (cols === '2') { + labelCol = 'ant-col-sm-4' + wrapCol = 'ant-col-sm-20' + } else if (cols === '3') { + labelCol = 'ant-col-cuslabel' + wrapCol = 'ant-col-cuswrap' + } + } return ( <div className="page-card" style={{ opacity: opacity}}> <div ref={node => drag(drop(node))}> {<div className="ant-row ant-form-item"> - <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8"> + <div className={'ant-col ant-form-item-label ant-col-xs-24 ' + labelCol}> <label title={card.label}>{card.label}</label> </div> - <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16"> + <div className={'ant-col ant-form-item-control-wrapper ant-col-xs-24 ' + wrapCol}> {card.type === 'text' && <Input style={{marginTop: '4px'}} defaultValue={card.initval} /> } @@ -83,7 +94,7 @@ <DatePicker showTime defaultValue={card.initval ? moment().subtract(card.initval, 'days') : null} /> } {card.type === 'textarea' && - <TextArea autoSize={{ minRows: 2, maxRows: 6 }} /> + <TextArea autosize={{ minRows: 2, maxRows: 6 }} /> } {card.type === 'fileupload' && <Button> diff --git a/src/templates/modalconfig/dragelement/index.jsx b/src/templates/modalconfig/dragelement/index.jsx index 677b61d..ab122e1 100644 --- a/src/templates/modalconfig/dragelement/index.jsx +++ b/src/templates/modalconfig/dragelement/index.jsx @@ -90,12 +90,8 @@ const { index: overIndex } = findCard(`${targetId}`) let targetIndex = overIndex - // if (!target) { + targetIndex++ - // } - // if (targetIndex < 0) { - // targetIndex = 0 - // } const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] }) setCards(_cards) @@ -115,9 +111,10 @@ return ( <div ref={drop} className="ant-row modal-fields-row"> {cards.map(card => ( - <Col key={card.uuid} span={card.type !== 'textarea' ? _cols : 24}> + <Col key={card.uuid} className={card.type === 'textarea' ? 'textarea' + setting.cols : ''} span={card.type !== 'textarea' ? _cols : 24}> <Card - id={`${card.uuid}`} + id={card.uuid} + cols={setting.cols} card={card} moveCard={moveCard} editCard={editCard} diff --git a/src/templates/modalconfig/dragelement/index.scss b/src/templates/modalconfig/dragelement/index.scss index 248e718..a61965a 100644 --- a/src/templates/modalconfig/dragelement/index.scss +++ b/src/templates/modalconfig/dragelement/index.scss @@ -15,4 +15,8 @@ } .modal-fields-row { padding-bottom: 35px; + .ant-col { + padding-left: 12px; + padding-right: 12px; + } } \ No newline at end of file diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx index 00530a6..b3cdf2a 100644 --- a/src/templates/modalconfig/index.jsx +++ b/src/templates/modalconfig/index.jsx @@ -374,7 +374,7 @@ text: this.state.dict['header.form.link'] }, { value: 'fileupload', - text: '鏂囦欢涓婁紶' + text: this.state.dict['header.form.fileupload'] }, { value: 'date', text: this.state.dict['header.form.dateday'] @@ -386,10 +386,10 @@ text: this.state.dict['header.form.datetime'] }, { value: 'textarea', - text: '澶氳鏂囨湰' + text: this.state.dict['header.form.textarea'] }, { value: 'funcvar', - text: '鍑芥暟鍙橀噺' + text: this.state.dict['header.form.funcvar'] }] }, { @@ -537,7 +537,7 @@ { type: 'multiselect', key: 'linkSubField', - label: '鍏宠仈琛ㄥ崟', + label: this.state.dict['header.form.linkForm'], initVal: card.linkSubField || [], options: _inputfields } @@ -902,7 +902,7 @@ orderBy: '', orderType: 'asc', readonly: 'false', - required: 'false' + required: 'true' } items.push(newcard) diff --git a/src/templates/modalconfig/index.scss b/src/templates/modalconfig/index.scss index 04547e8..21270e3 100644 --- a/src/templates/modalconfig/index.scss +++ b/src/templates/modalconfig/index.scss @@ -211,7 +211,6 @@ display: flex; margin-bottom: 0px; .ant-form-item-label { - // width: 100px; height: 40px; label { width: 100%; @@ -223,7 +222,6 @@ } } .ant-form-item-control-wrapper { - flex: 1 1; .ant-select { width: 100%; margin-top: 4px; @@ -245,20 +243,45 @@ opacity: 0; } } + .ant-col-cuslabel { + width: 10.5%; + } + .ant-col-cuswrap { + width: 89.5%; + } } .edit { position: absolute; - left: calc(33% - 100px); + left: calc(33% - 70px); top: 0px; color: #1890ff; cursor: pointer; display: none; } .edit.close { - left: calc(33% - 75px); + left: calc(33% - 45px); color: #ff4d4f; } } + .ant-col.textarea2 { + padding-left: 7px; + .page-card { + .edit { + left: calc(17% - 70px); + } + .edit.close { + left: calc(17% - 45px); + } + } + } + .ant-col.textarea3 .page-card { + .edit { + left: calc(11% - 70px); + } + .edit.close { + left: calc(11% - 45px); + } + } .page-card:hover { .edit { display: inline-block; diff --git a/src/templates/tableshare/dragelement/index.jsx b/src/templates/tableshare/dragelement/index.jsx index 13d1460..17f483d 100644 --- a/src/templates/tableshare/dragelement/index.jsx +++ b/src/templates/tableshare/dragelement/index.jsx @@ -9,6 +9,7 @@ const Container = ({list, setting, gridBtn, type, placeholder, handleList, handleMenu, deleteMenu, copyElement, profileMenu, handleGridBtn, showfield }) => { let target = null + const [cards, setCards] = useState(list) const moveCard = (id, atIndex) => { const { card, index } = findCard(id) @@ -78,43 +79,29 @@ } newcard.label = 'label' - newcard.field = '' newcard.initval = '' newcard.type = item.subType newcard.resourceType = '0' newcard.options = [] - newcard.dataSource = '' newcard.setAll = 'false' - newcard.linkField = '' - newcard.valueField = '' - newcard.valueText = '' - newcard.orderBy = '' newcard.orderType = 'asc' newcard.match = _match newcard.display = 'dropdown' } else if (item.type === 'action') { newcard.label = 'button' - newcard.innerFunc = '' - newcard.outerFunc = '' - newcard.sql = '' newcard.sqlType = '' newcard.Ot = 'requiredSgl' newcard.OpenType = item.subType newcard.tabType = 'SubTable' - newcard.linkTab = '' newcard.icon = '' newcard.class = 'default' newcard.intertype = 'inner' - newcard.interface = '' newcard.method = 'POST' newcard.position = 'toolbar' newcard.execSuccess = 'grid' newcard.execError = 'never' newcard.popClose = 'never' newcard.errorTime = 15 - newcard.callbackFunc = '' - newcard.pageTemplate = '' - newcard.url = '' newcard.verify = null if (item.subType === 'excelIn' || item.subType === 'excelOut') { @@ -144,12 +131,8 @@ const { index: overIndex } = findCard(`${targetId}`) let targetIndex = overIndex - // if (!target) { + targetIndex++ - // } - // if (targetIndex < 0) { - // targetIndex = 0 - // } const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] }) setCards(_cards) diff --git a/src/utils/option.js b/src/utils/option.js index 8d529e6..5068926 100644 --- a/src/utils/option.js +++ b/src/utils/option.js @@ -25,7 +25,8 @@ innerMessage: '鍐呴儴鍑芥暟鍚嶇О鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶅拰涓嬪垝绾匡紝涓斾互鎸囧畾瀛楃寮�濮嬨��' }, textarea: { - max: 1024 + max: 1024, + message: '闀挎枃鏈渶澶�1024涓瓧绗︺��' } } -- Gitblit v1.8.0