index.js 10.4 KB
Newer Older
田翔's avatar
田翔 committed
1
import React, { useRef, useState, useContext, forwardRef, useImperativeHandle, useMemo, useLayoutEffect } from 'react'
田翔's avatar
田翔 committed
2
import { ConfigProvider, message, Modal, Button } from 'antd'
3
import { ExclamationCircleOutlined } from '@ant-design/icons'
田翔's avatar
田翔 committed
4
import Generator, { defaultSettings, defaultCommonSettings, defaultGlobalSettings } from 'fr-generator'
田翔's avatar
田翔 committed
5 6
import { settings, baseSettings, globalSettings } from './config'
import widgets from '../widgets'
7
import { saveTableConfig, GetTableConfigJson, ReloadTableFields } from '../../apis/process'
田翔's avatar
田翔 committed
8
import FormRender from '../FormRender'
9
import { isObject, getVerify, setFieldJson, getNanoid } from '../../utils'
10
import Drag from '../components/Drag'
田翔's avatar
田翔 committed
11
import styles from '../../main.less'
田翔's avatar
田翔 committed
12

13
const FormDesigner = (props, ref) => {
田翔's avatar
田翔 committed
14

田翔's avatar
田翔 committed
15 16 17 18 19
  useImperativeHandle(ref, () => (
    {
      clear,
      preview,
      submit,
田翔's avatar
田翔 committed
20
      initLayout,
田翔's avatar
田翔 committed
21 22 23
    }
  ))

田翔's avatar
田翔 committed
24
  const { tableName, extra } = props
田翔's avatar
田翔 committed
25 26
  const [visible, setVisible] = useState(false)
  const [schema, setSchema] = useState({})
27
  const [fieldName, setFieldName] = useState([])
28
  const [textShow, setTextShow] = useState(false)
29
  const designerRef = useRef(null)
田翔's avatar
田翔 committed
30
  const formRenderRef = useRef(null)
31

32 33 34 35
  const settingsParent = useMemo(() => {
    let settingsParent = []
    settings.forEach(v => {
      v.widgets.forEach(s => {
田翔's avatar
田翔 committed
36
        s.schema.tableNameParent = tableName
37 38 39 40 41 42
      })
      settingsParent.push(v)
    })
    return settingsParent
  }, [settings, tableName])

43
  const getJSON = (json, fieldName) => {
44
    let nanoid = getNanoid()
田翔's avatar
田翔 committed
45 46
    let properties = json?.properties
    let parent = {}
田翔's avatar
田翔 committed
47
    let paths = []
48
    let title = '(未分组)'
田翔's avatar
田翔 committed
49 50 51 52 53
    let ungroupedChild = {}
    if (isObject(properties)) {
      for (let v in properties) {
        if (properties[v].type === 'object') {
          parent[v] = properties[v]
54
          if (v !== '(未分组)') {
田翔's avatar
田翔 committed
55
            paths.push(v)
56 57
          } else {
            title = properties[v].title
田翔's avatar
田翔 committed
58 59 60 61
          }
          let child = properties[v]?.properties
          if (isObject(child)) {
            for (let s in child) {
62 63 64 65 66 67
              let IsSystemField = false
              fieldName.forEach(j => {
                if (j.name === s) {
                  IsSystemField = j.IsSystemField
                }
              })
田翔's avatar
田翔 committed
68
              child[s].tableNameParent = tableName
69 70
              child[s].tableTypeParent = json.tableType
              child[s].IsSystemField = IsSystemField
田翔's avatar
田翔 committed
71 72 73 74 75
            }
          }
        } else {
          ungroupedChild[v] = {
            ...properties[v],
76
            tableTypeParent: json.tableType,
田翔's avatar
田翔 committed
77
            tableNameParent: tableName
78 79 80 81
          }
        }
      }
    }
田翔's avatar
田翔 committed
82
    if (JSON.stringify(ungroupedChild) !== '{}') {
83
      parent[nanoid] = {
84
        title: title,
85
        type: 'object',
田翔's avatar
田翔 committed
86 87 88 89 90
        collapsed: false,
        properties: {
          ...ungroupedChild
        }
      }
91
      paths.push(nanoid)
田翔's avatar
田翔 committed
92 93 94 95 96 97
    }
    return {
      ...json,
      paths,
      properties: parent,
    }
98
  }
田翔's avatar
田翔 committed
99

田翔's avatar
田翔 committed
100
  const getTableConfig = async (tableName) => {
田翔's avatar
田翔 committed
101
    const { code, data, msg } = await GetTableConfigJson({ tableName })
102 103 104 105 106 107
    const res = await ReloadTableFields({ tableName })
    if (code === 0 && res.data && res.data.root) {
      if (data && typeof data === 'string' && Array.isArray(res.data.root)) {
        setFieldName(res.data.root)
        let json = getJSON(JSON.parse(data), res.data.root)
        designerRef?.current?.setValue(json)
108
        setSchema(json)
田翔's avatar
田翔 committed
109 110
      }
    } else {
田翔's avatar
田翔 committed
111
      message.error(msg)
田翔's avatar
田翔 committed
112
    }
田翔's avatar
田翔 committed
113 114
  }

田翔's avatar
田翔 committed
115 116 117 118 119
  useLayoutEffect(() => {
    if (tableName) {
      getTableConfig(tableName)
    }
  }, [tableName])
田翔's avatar
田翔 committed
120

田翔's avatar
田翔 committed
121 122 123 124 125 126 127 128 129
  const clear = () => {
    Modal.confirm({
      title: '确定要清空该表单配置吗?',
      icon: <ExclamationCircleOutlined />,
      centered: true,
      cancelText: '取消',
      okText: '确定',
      onCancel: () => {
        console.log('取消清空')
130
      },
田翔's avatar
田翔 committed
131 132
      onOk: () => {
        const schema = designerRef.current.getValue()
田翔's avatar
田翔 committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
        const { tableName, properties: parent } = schema
        let parentObj = {}
        if (tableName?.includes('设备_台账')) {
          for (let v in parent) {
            if (isObject(parent)) {
              let child = parent[v].properties
              if (isObject(child)) {
                for (let s in child) {
                  if (s === '编码') {
                    parentObj = {
                      [v]: {
                        ...parent[v],
                        properties: {
                          [s]: child[s]
                        }
                      },
                    }
                  }
                }
              }
            }
田翔's avatar
田翔 committed
154
          }
田翔's avatar
田翔 committed
155
        }
田翔's avatar
田翔 committed
156 157 158 159
        let newschema = {
          ...schema,
          properties: parentObj
        }
田翔's avatar
田翔 committed
160
        designerRef.current.setValue(newschema)
田翔's avatar
田翔 committed
161
      }
田翔's avatar
田翔 committed
162 163 164 165
    })
  }

  const preview = () => {
166
    let json = designerRef.current.getValue()
167 168
    let verify = getVerify(json)
    if (verify === true) {
169
      setTextShow(false)
170 171 172
      setVisible(true)
      setSchema(json)
    }
田翔's avatar
田翔 committed
173 174 175
  }

  const submit = async () => {
176
    let json = designerRef.current.getValue()
177 178 179 180 181 182 183 184 185 186 187 188
    let verify = getVerify(json)
    if (verify === true) {
      const { code, data, msg } = await saveTableConfig(json)
      if (code === 0) {
        message.info('保存成功')
      } else {
        message.error(msg)
      }
    }
  }

  const initLayout = () => {
189
    let json = designerRef.current.getValue()
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    let verify = getVerify(json)
    if (verify === true) {
      Modal.confirm({
        title: '是否确定使用剩余附加字段一键生成表单?',
        icon: <ExclamationCircleOutlined />,
        centered: true,
        cancelText: '取消',
        okText: '确定',
        onCancel: () => {
          console.log('取消一键生成')
        },
        onOk: () => {
          designerRef.current.setValue(setFieldJson(json, fieldName))
        }
      })
田翔's avatar
田翔 committed
205
    }
田翔's avatar
田翔 committed
206 207
  }

田翔's avatar
田翔 committed
208 209 210 211 212 213 214 215 216 217 218
  const extraButtons = useMemo(() => {
    if (extra) {
      return [
        false,
        false,
        true,
        true,
        {
          text: '清空',
          onClick: clear
        },
219 220 221 222
        {
          text: '一键布局',
          onClick: initLayout,
        },
田翔's avatar
田翔 committed
223 224 225 226 227 228 229
        {
          text: '预览',
          onClick: preview
        },
        {
          text: '提交',
          type: 'primary',
230 231
          onClick: submit,
        },
田翔's avatar
田翔 committed
232 233 234
      ]
    }
    return [false, false, false, false]
235
  }, [extra, fieldName])
田翔's avatar
田翔 committed
236

田翔's avatar
田翔 committed
237
  const getFields = (schema) => {
238
    let array = []
239 240 241
    let paths = []
    let inError = false
    let outError = false
田翔's avatar
田翔 committed
242
    let parent = schema?.properties
243
    let parentObj = {}
田翔's avatar
田翔 committed
244 245
    if (isObject(parent)) {
      for (let v in parent) {
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
        if (parent[v].type === 'object') {
          paths.push(v)
          parentObj[v] = parent[v]
          let child = parent[v]?.properties
          if (isObject(child)) {
            let childObj = {}
            for (let s in child) {
              if (child[s].type !== 'object') {
                array.push({ ...child[s], fieldName: s })
                childObj[s] = child[s]
              } else {
                inError = true
                let sun = child[s]?.properties
                if (isObject(sun)) {
                  for (let k in sun) {
                    array.push({ ...sun[k], fieldName: k })
                    childObj[k] = sun[k]
                  }
                }
              }
            }
            parentObj[v].properties = childObj
          }
        } else {
          outError = true
          let nanoid = getNanoid()
          paths.push(nanoid)
          parentObj[nanoid] = {
            title: '(未分组)',
            type: 'object',
            collapsed: false,
            properties: {
              [v]: parent[v]
            }
田翔's avatar
田翔 committed
280 281 282 283
          }
        }
      }
    }
284 285 286 287 288 289 290 291 292 293
    return {
      inError,
      outError,
      fields: array,
      newSchema: {
        ...schema,
        paths,
        properties: parentObj
      }
    }
田翔's avatar
田翔 committed
294 295 296
  }

  const onSchemaChange = (schema) => {
297
    let { inError, outError, fields, newSchema } = getFields(schema)
298
    window.designer = fields
299 300 301
    if (inError || outError) {
      designerRef.current.setValue(newSchema)
    }
302 303
  }

田翔's avatar
田翔 committed
304
  const testSubmit = async () => {
田翔's avatar
田翔 committed
305
    const { formValue, relationForm, errors } = await formRenderRef?.current?.getValues()
田翔's avatar
田翔 committed
306
    if (errors.length) {
307
      setTextShow(false)
田翔's avatar
田翔 committed
308
      return message.error('表单校验未通过!')
309 310
    } else {
      setTextShow(true)
田翔's avatar
田翔 committed
311
    }
田翔's avatar
田翔 committed
312 313
  }

314
  const canDelete = (values) => {
田翔's avatar
田翔 committed
315
    const { $id, tableTypeParent, IsSystemField, title, type } = values
316 317
    if (tableTypeParent === '物联设备表' && IsSystemField) {
      if (fieldName.some(v => v.name === $id)) {
田翔's avatar
田翔 committed
318
        message.info(`表类型为:【物联设备表】内部字段【${$id}】不允许删除!`)
319 320 321
        return false
      }
    }
田翔's avatar
田翔 committed
322 323 324 325
    if (type === 'object' && ($id === '#/物联数据' || $id === '物联数据')) {
      message.info(`表类型为:【物联设备表】包含内部字段不允许删除`)
      return false
    }
326 327 328
    return true
  }

田翔's avatar
田翔 committed
329 330 331 332
  if (!tableName) {
    return null
  }

田翔's avatar
田翔 committed
333
  return (
田翔's avatar
田翔 committed
334
    <div className={styles.pandaXform} style={{ height: '100%' }}>
田翔's avatar
田翔 committed
335
      <div style={{ width: '100%', height: '100%' }}>
336
        <Generator
田翔's avatar
田翔 committed
337
          // configProvider={{ prefixCls: prefixClsPandaXform }}
338
          canDelete={canDelete}
339 340 341
          mapping={{
            object: 'Header',
          }}
342
          validation={false}
343
          ref={designerRef}
344 345
          extraButtons={extraButtons}
          widgets={widgets}
346
          settings={settingsParent}
347 348
          commonSettings={baseSettings}
          globalSettings={globalSettings}
田翔's avatar
田翔 committed
349
          onSchemaChange={onSchemaChange}
350
        />
351
        <Drag
352 353 354 355 356 357
          title={tableName}
          width='80%'
          bodyStyle={{ height: '700px', overflow: 'auto' }}
          onOk={() => setVisible(false)}
          onCancel={() => setVisible(false)}
          visible={visible}
田翔's avatar
田翔 committed
358
          getContainer={false}
359
          destroyOnClose
田翔's avatar
田翔 committed
360 361
          footer={
            <div>
362
              <span style={{ color: '#18b918', fontSize: '14px', paddingRight: '10px', display: textShow ? 'inline-block' : 'none' }}>该表单内容校验通过,可正常使用!</span>
田翔's avatar
田翔 committed
363
              <Button onClick={() => setVisible(false)}>取消</Button>
364
              <Button type='primary' onClick={testSubmit}>测试提交</Button>
田翔's avatar
田翔 committed
365 366
            </div>
          }
367
        >
368 369 370 371
          <FormRender
            ref={formRenderRef}
            schemaValues={{ formJson: schema }}
          />
372
        </Drag>
373
      </div>
田翔's avatar
田翔 committed
374
    </div>
田翔's avatar
田翔 committed
375 376 377 378
  )

}

379
export default forwardRef(FormDesigner)