update 完成表单中上传控件的使用
This commit is contained in:
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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()}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'
|
||||
|
||||
74
web-react/src/components/photo-preview/index.jsx
Normal file
74
web-react/src/components/photo-preview/index.jsx
Normal 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>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
|
||||
export default class PhotoSwipe extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
230
web-react/src/pages/business/house/info/form/base/aspect.jsx
Normal file
230
web-react/src/pages/business/house/info/form/base/aspect.jsx
Normal 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>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user