update 完成表单中上传控件的使用

This commit is contained in:
2021-06-22 11:00:21 +08:00
parent f31f79d59d
commit f05f476789
17 changed files with 883 additions and 106 deletions

View File

@@ -16,6 +16,7 @@ export default class index extends Component {
actived: '0',
loading: true,
record: null,
saveDisabled: true,
saving: false,
}
@@ -42,6 +43,16 @@ export default class index extends Component {
*/
componentDidMount() {}
/**
* 接收到所有子组件已加载完成,并启用提交按钮
*/
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === tabs.filter(p => p.show).length) {
this.setState({ saveDisabled: false })
}
}
async onSubmit() {
for (const child of this.children) {
try {
@@ -62,7 +73,7 @@ export default class index extends Component {
}
render() {
const { actived, loading, record, saving } = this.state
const { actived, loading, record, saveDisabled, saving } = this.state
return (
<div className="yo-form-page">
@@ -77,6 +88,7 @@ export default class index extends Component {
取消
</Button>
<Button
disabled={saveDisabled}
loading={saving}
type="primary"
onClick={() => this.onSubmit()}
@@ -125,7 +137,7 @@ export default class index extends Component {
is={tab.component}
record={record}
loading={loading}
onRef={c => this.children.push(c)}
onRef={child => this.call(child, i)}
/>
</div>
)

View File

@@ -34,11 +34,13 @@ export default class index extends Component {
}
/**
* DDOM加载完成钩子,在此将自身传递给父级
* 加载完成,通知父级组件并传递自身
*/
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === parts.length) {
const { onRef } = this.props
if (onRef) onRef(this)
}
}
@@ -85,17 +87,17 @@ export default class index extends Component {
<Card className="yo-form-page--body">
{parts.map((item, i) => (
<section key={i} id={`form-${i}-${id}`}>
{item.title && <h5>{parts.title}</h5>}
{item.title && <h5>{item.title}</h5>}
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName="h-400-min"
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic
is={item.component}
record={record}
onRef={r => this.children.push(r)}
onRef={child => this.call(child, i)}
/>
)}
</Spin>

View File

@@ -36,17 +36,22 @@ export default class part extends Component {
}
/**
* DOM加载完成钩子,在此将自身传递给父级,并且绑定数据
* DOM加载完成钩子,绑定数据
*/
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
}
this.fillData({
record: this.props.record,
})
}
/**
* 加载完成,通知父级组件并传递自身
*/
call() {
const { onRef } = this.props
if (onRef) onRef(this)
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
@@ -59,9 +64,8 @@ export default class part extends Component {
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({
loading: false,
})
this.setState({ loading: false })
this.call()
}
/**

View File

@@ -15,6 +15,7 @@ export default class index extends Component {
state = {
loading: true,
record: null,
saveDisabled: true,
saving: false,
}
@@ -44,6 +45,13 @@ export default class index extends Component {
*/
componentDidMount() {}
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === tabs.filter(p => p.show).length) {
this.setState({ saveDisabled: false })
}
}
/**
* 提交
* [异步,必要]
@@ -86,7 +94,7 @@ export default class index extends Component {
render() {
const { id } = this.props
const { loading, record, saving } = this.state
const { loading, record, saveDisabled, saving } = this.state
return (
<div className="yo-form-page">
@@ -98,17 +106,17 @@ export default class index extends Component {
<Card className="yo-form-page--body">
{parts.map((item, i) => (
<section key={i} id={`form-${i}-${id}`}>
{item.title && <h5>{parts.title}</h5>}
{item.title && <h5>{item.title}</h5>}
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName="h-400-min"
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic
is={item.component}
record={record}
onRef={r => this.children.push(r)}
onRef={child => this.call(child, i)}
/>
)}
</Spin>
@@ -143,6 +151,7 @@ export default class index extends Component {
<span>
<Button onClick={() => window.closeContentWindow()}>取消</Button>
<Button
disabled={saveDisabled}
loading={saving}
type="primary"
onClick={() => this.onSubmit()}

View File

@@ -36,17 +36,22 @@ export default class part extends Component {
}
/**
* DOM加载完成钩子,在此将自身传递给父级,并且绑定数据
* DOM加载完成钩子,绑定数据
*/
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
}
this.fillData({
record: this.props.record,
})
}
/**
* 加载完成,通知父级组件并传递自身
*/
call() {
const { onRef } = this.props
if (onRef) onRef(this)
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
@@ -59,9 +64,8 @@ export default class part extends Component {
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({
loading: false,
})
this.setState({ loading: false })
this.call()
}
/**

View File

@@ -6,7 +6,7 @@ export { default as Container } from './container'
export { default as IconSelector } from './icon-selector'
export { default as Image } from './image'
export { default as ModalForm } from './modal-form'
export { default as PhotoSwipe } from './photo-swipe'
export { default as PhotoPreview } from './photo-preview'
export { default as QueryList } from './query-list'
export { default as QueryTable } from './query-table'
export { default as QueryTableActions } from './query-table-actions'

View File

@@ -0,0 +1,74 @@
import React, { Component } from 'react'
import 'photoswipe/dist/photoswipe.css'
import 'photoswipe/dist/default-skin/default-skin.css'
import PhotoSwipe from 'photoswipe'
import PhotoSwipeUI_Default from 'photoswipe/dist/photoswipe-ui-default'
const defaultOptions = {
index: 0,
bgOpacity: 0.75,
}
export default class PhotoPreview extends Component {
initPhotoSwipe = (items = [], options = {}) => {
const pswpElement = this.refs.pswp
const gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
...defaultOptions,
...options,
})
gallery.init()
}
render() {
return (
<div className="pswp" tabIndex="-1" ref="pswp">
<div className="pswp__bg"></div>
<div className="pswp__scroll-wrap">
<div className="pswp__container">
<div className="pswp__item"></div>
<div className="pswp__item"></div>
<div className="pswp__item"></div>
</div>
<div className="pswp__ui pswp__ui--hidden">
<div className="pswp__top-bar">
<div className="pswp__counter"></div>
<button
className="pswp__button pswp__button--close"
title="Close (Esc)"
></button>
<button
className="pswp__button pswp__button--fs"
title="Toggle fullscreen"
></button>
<button
className="pswp__button pswp__button--zoom"
title="Zoom in/out"
></button>
<div className="pswp__preloader">
<div className="pswp__preloader__icn">
<div className="pswp__preloader__cut">
<div className="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div className="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div className="pswp__share-tooltip"></div>
</div>
<button
className="pswp__button pswp__button--arrow--left"
title="Previous (arrow left)"
></button>
<button
className="pswp__button pswp__button--arrow--right"
title="Next (arrow right)"
></button>
<div className="pswp__caption">
<div className="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
)
}
}

View File

@@ -1,11 +0,0 @@
import React, { Component } from 'react'
export default class PhotoSwipe extends Component {
render() {
return (
<div>
</div>
)
}
}

View File

@@ -107,7 +107,7 @@ export default class index extends Component {
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName="h-400-min"
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic

View File

@@ -0,0 +1,230 @@
import React, { Component } from 'react'
import { Form, Spin, Upload } from 'antd'
import { AntIcon, PhotoPreview } from 'components'
import { cloneDeep, isEqual } from 'lodash'
import { BlobToBase64, GetFileName, PreviewFile } from 'util/file'
import { api } from 'common/api'
const initialValues = {}
const layout = {
labelCol: { flex: '150px' },
wrapperCol: { flex: '1' },
}
export default class aspect extends Component {
state = {
loading: true,
codes: {},
options: {},
}
// 表单实例
form = React.createRef()
photoPreview = React.createRef()
// 初始化数据
record = {}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* 绑定数据
*/
componentDidMount() {
this.fillData({
record: this.props.record,
})
}
/**
* DOM加载完成钩子,在此将自身传递给父级
*/
call() {
if (this.props.onRef) {
this.props.onRef(this)
}
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
*/
async fillData(params) {
this.record = cloneDeep(params.record)
//#region 从后端转换成前段所需格式
if (this.record) {
const { houseInfo } = this.record
const fileValue = []
const fileList =
!houseInfo.facadePhoto || !houseInfo.facadePhoto.length
? []
: houseInfo.facadePhoto.split(',')
for (const fileId of fileList) {
try {
const file = await PreviewFile(fileId)
const base64 = await BlobToBase64(file)
fileValue.push({
uid: fileId,
response: fileId,
name: file.name,
url: base64,
status: 'done',
})
} catch {
const { data: file } = await api.sysFileInfoDetail({ id: fileId })
fileValue.push({
uid: fileId,
response: '文件已丢失',
name: file.fileOriginName,
status: 'error',
})
}
}
houseInfo.facadePhoto = fileValue
}
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({ loading: false })
this.call()
}
/**
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
*/
async getData() {
const form = this.form.current
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
//#region 从前段转换后端所需格式
postData.houseInfo.facadePhoto = postData.houseInfo.facadePhoto
.map(item => (item.uid.startsWith('rc-upload') ? item.response : item.uid))
.join(',')
//#endregion
return postData
}
}
//#region 自定义方法
/**
* 表单change事件处理,包括了所有字段的change
* [异步,非必要]
* @param {*} changedValues
* @param {*} allValues
*/
async onValuesChange(changedValues, allValues) {}
async onFileUpload({ file, onProgress, onSuccess, onError }) {
onProgress({
percent: 0,
})
const fd = new FormData()
fd.append('file', file)
try {
const { data: fileId } = await api.sysFileInfoUpload(fd)
onSuccess(fileId)
} catch {
onError()
}
}
async onFilePreview(file, key) {
const fileList = this.form.current
.getFieldValue(['houseInfo', key])
.filter(p => p.status === 'done')
const items = []
for (const _file of fileList) {
const img = new Image()
const src = _file.url || _file.thumbUrl
img.src = src
items.push({
src,
w: img.naturalWidth,
h: img.naturalHeight,
})
}
this.photoPreview.current.initPhotoSwipe(items, {
index: fileList.indexOf(file),
})
}
async onFileDownload(file) {
const { data, headers } = await api.sysFileInfoDownload({ id: file.response })
const url = window.URL.createObjectURL(data)
const fileName = GetFileName(headers['content-disposition'])
const a = document.createElement('a')
a.href = url
a.download = fileName
a.click()
window.URL.revokeObjectURL(url)
a.remove()
}
//#endregion
render() {
const { loading } = this.state
return (
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<Form
initialValues={initialValues}
ref={this.form}
{...layout}
onValuesChange={(changedValues, allValues) =>
this.onValuesChange(changedValues, allValues)
}
>
<Form.Item
label="外立面照片"
name={['houseInfo', 'facadePhoto']}
valuePropName="fileList"
getValueFromEvent={e => {
if (Array.isArray(e)) {
return e
}
return e && e.fileList
}}
>
<Upload
listType="picture-card"
customRequest={e => this.onFileUpload(e)}
showUploadList={{
showRemoveIcon: true,
showDownloadIcon: true,
}}
onPreview={file => this.onFilePreview(file, 'facadePhoto')}
onDownload={file => this.onFileDownload(file)}
>
<div>
<AntIcon type="plus" />
<div className="ant-upload-text">外立面照片</div>
</div>
</Upload>
</Form.Item>
</Form>
<PhotoPreview ref={this.photoPreview} />
</Spin>
)
}
}

View File

@@ -0,0 +1,238 @@
import React, { Component } from 'react'
import { Button, Form, Spin, Upload } from 'antd'
import { AntIcon } from 'components'
import { cloneDeep, isEqual } from 'lodash'
import { BlobToBase64, GetFileName, PreviewFile } from 'util/file'
import { api } from 'common/api'
const initialValues = {}
const layout = {
labelCol: { flex: '150px' },
wrapperCol: { flex: '1' },
}
const uploads = [
{
key: 'anEntryDocument',
label: '立项文件',
},
{
key: 'planningPermission',
label: '规划许可',
},
{
key: 'completionRecord',
label: '竣工验收备案',
},
{
key: 'monitorDocument',
label: '监理文件',
},
{
key: 'identificationReport',
label: '鉴定报告',
},
{
key: 'otherDocument',
label: '其他附件',
},
]
export default class attachments extends Component {
state = {
loading: true,
codes: {},
options: {},
}
// 表单实例
form = React.createRef()
// 初始化数据
record = {}
/**
* 阻止外部组件引发的渲染,提升性能
* 可自行添加渲染条件
* [必要]
* @param {*} props
* @param {*} state
* @returns
*/
shouldComponentUpdate(props, state) {
return !isEqual(this.state, state)
}
/**
* 绑定数据
*/
componentDidMount() {
this.fillData({
record: this.props.record,
})
}
/**
* DOM加载完成钩子,在此将自身传递给父级
*/
call() {
if (this.props.onRef) {
this.props.onRef(this)
}
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
*/
async fillData(params) {
this.record = cloneDeep(params.record)
//#region 从后端转换成前段所需格式
if (this.record) {
const { houseInfo } = this.record
const keys = uploads.map(p => p.key)
for (const key of keys) {
const fileValue = []
const fileList =
!houseInfo[key] || !houseInfo[key].length ? [] : houseInfo[key].split(',')
for (const fileId of fileList) {
try {
const file = await PreviewFile(fileId)
const base64 = await BlobToBase64(file)
fileValue.push({
uid: fileId,
response: fileId,
name: file.name,
url: base64,
status: 'done',
})
} catch {
const { data: file } = await api.sysFileInfoDetail({ id: fileId })
fileValue.push({
uid: fileId,
response: '文件已丢失',
name: file.fileOriginName,
status: 'error',
})
}
}
houseInfo[key] = fileValue
}
}
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({ loading: false })
this.call()
}
/**
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
*/
async getData() {
const form = this.form.current
const valid = await form.validateFields()
if (valid) {
const postData = form.getFieldsValue()
//#region 从前段转换后端所需格式
const { houseInfo } = postData
for (const key in houseInfo) {
houseInfo[key] = houseInfo[key]
.map(item => (item.uid.startsWith('rc-upload') ? item.response : item.uid))
.join(',')
}
//#endregion
return postData
}
}
//#region 自定义方法
/**
* 表单change事件处理,包括了所有字段的change
* [异步,非必要]
* @param {*} changedValues
* @param {*} allValues
*/
async onValuesChange(changedValues, allValues) {}
async onFileUpload({ file, onProgress, onSuccess, onError }) {
onProgress({
percent: 0,
})
const fd = new FormData()
fd.append('file', file)
try {
const { data: fileId } = await api.sysFileInfoUpload(fd)
onSuccess(fileId)
} catch {
onError()
}
}
async onFileDownload(file) {
const { data, headers } = await api.sysFileInfoDownload({ id: file.response })
const url = window.URL.createObjectURL(data)
const fileName = GetFileName(headers['content-disposition'])
const a = document.createElement('a')
a.href = url
a.download = fileName
a.click()
window.URL.revokeObjectURL(url)
a.remove()
}
//#endregion
render() {
const { loading } = this.state
return (
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<Form
initialValues={initialValues}
ref={this.form}
{...layout}
onValuesChange={(changedValues, allValues) =>
this.onValuesChange(changedValues, allValues)
}
>
{uploads.map((item, i) => (
<Form.Item
key={i}
label={item.label}
name={['houseInfo', item.key]}
valuePropName="fileList"
getValueFromEvent={e => {
if (Array.isArray(e)) {
return e
}
return e && e.fileList
}}
>
<Upload
customRequest={e => this.onFileUpload(e)}
showUploadList={{
showRemoveIcon: true,
showDownloadIcon: true,
}}
onPreview={() => false}
onDownload={file => this.onFileDownload(file)}
>
<Button type="dashed" icon={<AntIcon type="upload" />}>
上传{item.label}
</Button>
</Upload>
</Form.Item>
))}
</Form>
</Spin>
)
}
}

View File

@@ -1,10 +1,22 @@
import React, { Component } from 'react'
import { Row, Col, Form, Input, InputNumber, Radio, Checkbox, Switch, DatePicker, Spin } from 'antd'
import {
Button,
Row,
Col,
Form,
Input,
InputNumber,
Radio,
Checkbox,
Switch,
DatePicker,
Spin,
} from 'antd'
import { cloneDeep, isEqual } from 'lodash'
import { api } from 'common/api'
import { AntIcon } from 'components'
import getDictData from 'util/dic'
import moment from 'moment'
import { CITY } from 'util/global'
const layout = {
labelCol: { flex: '150px' },
@@ -25,6 +37,8 @@ export default class building extends Component {
dicHouseBuildingCurtainWall: [],
dicHouseElevator: [],
},
showMap: false,
}
form = React.createRef()
@@ -34,14 +48,17 @@ export default class building extends Component {
}
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
}
this.fillData({
record: this.props.record,
})
}
call() {
if (this.props.onRef) {
this.props.onRef(this)
}
}
/**
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
@@ -73,9 +90,9 @@ export default class building extends Component {
})
//#endregion
this.form.current.setFieldsValue(this.record)
this.setState({
loading: false,
})
this.setState({ loading: false })
this.call()
}
/**
@@ -101,11 +118,149 @@ export default class building extends Component {
}
//#region 自定义方法
onShowMap() {
this.setState({ showMap: true }, async () => {
await this.initMap()
const { lng, lat } = this.record.houseCode
const position = [lng, lat]
this.setMarker(position)
this.map.setCenter(position)
})
}
initMap() {
// eslint-disable-next-line no-undef
const amap = AMap
return new Promise(resolve => {
const city = CITY
const district = new amap.DistrictSearch({
subdistrict: 0,
extensions: 'all',
level: 'city',
})
district.search(city, (status, result) => {
const bounds = result.districtList[0].boundaries,
mask = []
for (let i = 0; i < bounds.length; i += 1) {
mask.push([bounds[i]])
}
const geocoder = new amap.Geocoder({ city })
geocoder.getLocation(city, (status, result) => {
if (status !== 'complete' || !(result.geocodes && result.geocodes.length))
return
this.citycode = result.geocodes[0].addressComponent.citycode
this.map = new amap.Map(this.refs.map, {
mask,
zoom: 12,
center: result.geocodes[0].location,
})
this.map.on('click', e => {
this.setMarker(e.lnglat, geocoder)
})
this.map.on('complete', () => {
this.map.setFitView()
this.map.setZoom(12)
for (const path of bounds) {
new amap.Polyline({
path,
strokeColor: '#ccc',
strokeWeight: 4,
map: this.map,
})
}
resolve()
})
const auto = new amap.AutoComplete({
input: this.refs['map-search'].input,
city,
citylimit: true,
})
const placeSearch = new amap.PlaceSearch({
city,
citylimit: true,
pageSize: 1,
})
auto.on('select', ({ poi: { name: keywords, adcode } }) => {
placeSearch.search(keywords, async (status, result) => {
const {
poiList: { pois },
} = result
for (const poi of pois) {
await this.setMarker(poi.location, geocoder)
this.map.setCenter(poi.location)
}
})
})
})
})
})
}
setMarker(position, geocoder) {
const set = position => {
if (this.marker) {
this.marker.setPosition(position)
} else {
this.marker = new amap.Marker({
map: this.map,
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
position,
offset: new amap.Pixel(-13, -30),
})
}
}
// eslint-disable-next-line no-undef
const amap = AMap
return new Promise((resolve, reject) => {
if (geocoder) {
geocoder.getAddress(position, (status, result) => {
if (status === 'complete' && result.regeocode) {
if (result.regeocode.addressComponent.citycode !== this.citycode) {
// 如果选到了别的城市,则中断
return
}
this.setPosition(result.regeocode.formattedAddress, position)
set(position)
resolve(position)
} else {
console.error('根据经纬度查询地址失败')
reject()
}
})
} else {
set(position)
resolve(position)
}
})
}
setPosition(address, { lng, lat }) {
this.form.current.setFieldsValue({ houseCode: { address, lng, lat } })
}
//#endregion
render() {
const { loading, codes, showMap } = this.state
return (
<Spin spinning={this.state.loading} indicator={<AntIcon type="loading" />}>
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<Form {...layout} ref={this.form}>
<Row gutter={16}>
<Col span={12}>
@@ -133,7 +288,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择土地性质' }]}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicLandAttribute.map(item => {
{codes.dicLandAttribute.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
@@ -181,17 +336,28 @@ export default class building extends Component {
</Row>
</Form.Item>
<Form.Item colon={false} label={true}>
<div className="yo-map-container">
<div className="yo-map--search">
<Input.Search
autoComplete="off"
allowClear
placeholder="请输入关键字"
ref="map-search"
/>
{showMap ? (
<div className="yo-map-container">
<div className="yo-map--search">
<Input.Search
autoComplete="off"
allowClear
placeholder="请输入关键字"
ref="map-search"
/>
</div>
<div className="h-500" ref="map"></div>
</div>
<div className="h-500" ref="map"></div>
</div>
) : (
<Button
shape="round"
size="large"
icon={<AntIcon type="picture" />}
onClick={() => this.onShowMap()}
>
查看地图
</Button>
)}
</Form.Item>
</Col>
<Col span={24}>
@@ -201,7 +367,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择结构类型' }]}
>
<Radio.Group buttonStyle="solid" placeholder="请选择结构类型">
{this.state.codes.dicHouseStructureType.map(item => {
{codes.dicHouseStructureType.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
@@ -218,7 +384,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择抗震等级' }]}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicHouseAseismicGrade.map(item => {
{codes.dicHouseAseismicGrade.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
@@ -235,7 +401,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择基础情况' }]}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicHouseBaseInfo.map(item => {
{codes.dicHouseBaseInfo.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
@@ -251,7 +417,7 @@ export default class building extends Component {
name={['houseInfo', 'insulationMaterial']}
>
<Checkbox.Group>
{this.state.codes.dicHouseInsulationMaterial.map(item => {
{codes.dicHouseInsulationMaterial.map(item => {
return (
<Checkbox
key={item.code}
@@ -273,7 +439,7 @@ export default class building extends Component {
<Col span={24}>
<Form.Item label="外墙墙体材料" name={['houseInfo', 'wallMaterial']}>
<Checkbox.Group>
{this.state.codes.dicHouseWallMaterial.map(item => {
{codes.dicHouseWallMaterial.map(item => {
return (
<Checkbox
key={item.code}
@@ -299,7 +465,7 @@ export default class building extends Component {
name={['houseInfo', 'fireproofGrade']}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicHouseFireproofGrade.map(item => {
{codes.dicHouseFireproofGrade.map(item => {
return (
<Radio.Button key={item.code} value={item.code}>
{item.value}
@@ -316,7 +482,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择建筑幕墙' }]}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicHouseBuildingCurtainWall.map(item => {
{codes.dicHouseBuildingCurtainWall.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
@@ -327,17 +493,29 @@ export default class building extends Component {
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="有无外墙面砖" name={['houseInfo', 'faceBrick']}>
<Form.Item
label="有无外墙面砖"
name={['houseInfo', 'faceBrick']}
valuePropName="checked"
>
<Switch />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="有无外墙粉刷" name={['houseInfo', 'whiteWash']}>
<Form.Item
label="有无外墙粉刷"
name={['houseInfo', 'whiteWash']}
valuePropName="checked"
>
<Switch />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="有无外墙涂料" name={['houseInfo', 'coating']}>
<Form.Item
label="有无外墙涂料"
name={['houseInfo', 'coating']}
valuePropName="checked"
>
<Switch />
</Form.Item>
</Col>
@@ -348,7 +526,7 @@ export default class building extends Component {
rules={[{ required: true, message: '请选择电梯' }]}
>
<Radio.Group buttonStyle="solid">
{this.state.codes.dicHouseElevator.map(item => {
{codes.dicHouseElevator.map(item => {
return (
<Radio.Button key={item.code} value={item.code}>
{item.value}

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { Row, Col, Card, Anchor, Spin } from 'antd'
import { defaultsDeep } from 'lodash'
import { defaultsDeep, merge } from 'lodash'
import { AntIcon, ComponentDynamic, Container } from 'components'
const parts = [
@@ -9,6 +9,14 @@ const parts = [
title: '建筑物基本信息',
component: () => import('./building'),
},
{
title: '相关附件资料',
component: () => import('./attachments'),
},
{
title: '建筑概貌',
component: () => import('./aspect'),
},
]
export default class index extends Component {
@@ -22,9 +30,13 @@ export default class index extends Component {
return this.props.loading !== props.loading
}
componentDidMount() {
if (this.props.onRef) {
this.props.onRef(this)
// 通知上层组件已加载完毕
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === parts.length) {
if (this.props.onRef) {
this.props.onRef(this)
}
}
}
@@ -39,10 +51,7 @@ export default class index extends Component {
async getData() {
for (const child of this.children) {
const data = await child.getData()
this.formData = {
...this.formData,
...data,
}
merge(this.formData, data)
}
return this.formData
@@ -64,13 +73,13 @@ export default class index extends Component {
<Spin
spinning={loading}
indicator={<AntIcon type="loading" />}
wrapperClassName="h-400-min"
wrapperClassName={loading && 'h-400-min'}
>
{!loading && (
<ComponentDynamic
is={part.component}
{...this.props}
onRef={c => this.children.push(c)}
onRef={child => this.call(child, i)}
/>
)}
</Spin>

View File

@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import { Button, Descriptions, message as Message, Spin, Tabs } from 'antd'
import { isEqual, truncate } from 'lodash'
import { merge, isEqual } from 'lodash'
import { AntIcon, ComponentDynamic, Container } from 'components'
import { api } from 'common/api'
@@ -55,6 +55,7 @@ export default class index extends Component {
loading: true,
record: null,
saveDisabled: true,
saving: false,
}
@@ -79,20 +80,25 @@ export default class index extends Component {
}
}
call(child, index) {
this.children[index] = child
if (this.children.filter(p => p).length === tabs.filter(p => p.show).length) {
this.setState({ saveDisabled: false })
}
}
async onSubmit() {
for (const child of this.children) {
try {
const data = await child.getData()
this.formData = {
...this.formData,
...data,
}
merge(this.formData, data)
} catch (e) {
return e
}
}
//#region 提交数据
console.log(this.formData)
this.setState({ saving: true })
setTimeout(() => {
@@ -103,7 +109,7 @@ export default class index extends Component {
}
render() {
const { loading, record, saving } = this.state
const { loading, record, saveDisabled, saving } = this.state
return (
<div className="yo-form-page">
@@ -118,6 +124,7 @@ export default class index extends Component {
取消
</Button>
<Button
disabled={saveDisabled}
loading={saving}
type="primary"
onClick={() => this.onSubmit()}
@@ -197,7 +204,7 @@ export default class index extends Component {
is={tab.component}
record={record}
loading={loading}
onRef={c => this.children.push(c)}
onRef={child => this.call(child, i)}
/>
</div>
)