lanjianrong 3 年之前
父節點
當前提交
669dff8e2d

+ 49 - 82
src/pages/Project/Management/components/ProjectModal.tsx

@@ -4,12 +4,24 @@ import { Button, message } from 'antd'
 import { addProject, getProject, updateProject } from '@/services/api/project'
 import { delay } from '@/utils/util'
 import FormRender, { useForm } from 'form-render'
-import { BaseMenuEnum } from '@/pages/Schema/Base'
+import { BaseMenuEnum, SchemaEnum } from '@/pages/Schema/Base'
 import type { SchemaBaseModelState } from '@/pages/Schema/Base/model'
 import type { ConnectProps } from 'umi'
 import type { ProjectModelState } from '../../model'
 import consts from '@/utils/consts'
-import { createForm, onFieldMount } from '@formily/core'
+import { createForm, onFieldMount, onFormInit } from '@formily/core'
+import {
+  Form,
+  FormButtonGroup,
+  Submit,
+  FormLayout,
+  FormItem,
+  Input,
+  Select,
+  Reset
+} from '@formily/antd'
+import { createSchemaField } from '@formily/react'
+import { connectSchema } from '@/utils/schema'
 
 export enum ModalType {
   ADD = 0,
@@ -22,21 +34,36 @@ type ProjectModalProps = ConnectProps & {
   setVisible: (visible: boolean) => void
   readOnly: boolean
   type: ModalType
-  defaultFormData?: {
-    dataID: string
-  }
+  defaultFormData: Record<string, any> | null
   pTypeList: API.ProjectTypeList
   reload: () => void
-  schema?: Record<string, any> | null
+  projectSchema?: Record<string, any> | null
 }
 const ProjectModal: React.FC<ProjectModalProps> = ({
   setVisible,
-  schema,
+  projectSchema,
   type,
   defaultFormData,
   pTypeList,
   reload
 }) => {
+  const formInstance = createForm({
+    validateFirst: true,
+    initialValues: type === ModalType.ADD ? null : defaultFormData,
+    effects() {
+      onFieldMount('projectTypeID', field => (field.dataSource = pTypeList))
+    }
+  })
+
+  const SchemaField = createSchemaField({
+    components: {
+      FormLayout,
+      FormItem,
+      Input,
+      Select
+    }
+  })
+
   const { run: tryUpdateProject } = useRequest(updateProject, {
     manual: true,
     onSuccess: () => {
@@ -50,40 +77,13 @@ const ProjectModal: React.FC<ProjectModalProps> = ({
     }
   })
 
-  // const onMount = async () => {
-  //   if (defaultFormData?.dataID) {
-  //     const { code = -1, data = {} } = await getProject({ ID: defaultFormData.dataID })
-  //     if (code === consts.RET_CODE.SUCCESS) {
-  //       const currentFormData = { ...data }
-  //       const keys = Object.keys(currentFormData)
-  //       keys.forEach(key => {
-  //         if (currentFormData[key] instanceof Object) {
-  //           const targetMap = currentFormData[key]
-  //           delete currentFormData[key]
-  //           currentFormData[`${key}ID`] = targetMap.ID
-  //         }
-  //       })
-  //       form.setValues(type === ModalType.ADD ? {} : { ...currentFormData })
-  //       delay(80).then(() => {
-  //         // console.log(pTypeList)
-
-  //         form.setSchemaByPath('projectTypeID', {
-  //           enum: pTypeList.map(item => item.value),
-  //           enumNames: pTypeList.map(item => item.label)
-  //         })
-  //       })
-  //     }
-  //   }
-  // }
-
-  const onFinish = async (formData, errors) => {
-    if (errors?.length) return
+  const onFinish = async formData => {
     try {
       // 执行表单提交
       if (type === ModalType.ADD) {
         await tryAddProject(formData)
       } else {
-        await tryUpdateProject(formData)
+        await tryUpdateProject({ ...formData, ID: defaultFormData.ID })
       }
       setVisible(false)
       reload()
@@ -92,53 +92,20 @@ const ProjectModal: React.FC<ProjectModalProps> = ({
     }
   }
 
-  const renderForm = () => {
-    const form = createForm({
-      validateFirst: true,
-      effects() {
-        onFieldMount('projectTypeID', field => (field.dataSource = pTypeList))
-      }
-    })
-
-    const SchemaField = createSchemaField({
-      components: {
-        FormLayout,
-        FormItem,
-        Input,
-        Select
-      }
-    })
-    return (
-      <FormProvider form={form}>
+  return (
+    <div className="max-w-800px mt-20px">
+      <Form form={formInstance} labelCol={6} wrapperCol={8}>
         <SchemaField
-          schema={connectSchema(SchemaEnum?.[BaseMenuEnum.PROJECT], schema)}
-          scope={{ useAsyncDataSource, loadProjectTypeData }}
+          schema={connectSchema(SchemaEnum?.[BaseMenuEnum.PROJECT], projectSchema)}
+          // scope={{ useAsyncDataSource }}
         />
-      </FormProvider>
-    )
-  }
-
-  return (
-    <div>
-      {schema && <FormRender form={form} schema={schema} onFinish={onFinish} onMount={onMount} />}
-      <div className="ml-120px">
-        {/* * 重置会导致下拉框的options丢失
-          <Button onClick={() => form.setValues({})}>重置</Button> */}
-        <Button type="primary" onClick={form.submit}>
-          提交
-        </Button>
-      </div>
-      <div className="max-w-800px">{renderForm()}</div>
-      {/* <Form>
-        {schema && <FormRender form={form} schema={schema} onFinish={onFinish} onMount={onMount} />}
-        <div className="ml-120px">
-          * 重置会导致下拉框的options丢失
-          <Button onClick={() => form.setValues({})}>重置</Button>
-          <Button type="primary" onClick={form.submit}>
-            提交
-          </Button>
-        </div>
-      </Form> */}
+        <FormButtonGroup.Sticky>
+          <FormButtonGroup.FormItem>
+            <Submit onSubmit={onFinish}>提交</Submit>
+            <Reset>重置</Reset>
+          </FormButtonGroup.FormItem>
+        </FormButtonGroup.Sticky>
+      </Form>
     </div>
   )
 }
@@ -146,6 +113,6 @@ const ProjectModal: React.FC<ProjectModalProps> = ({
 export default connect(
   ({ project, schemaBase }: { project: ProjectModelState; schemaBase: SchemaBaseModelState }) => ({
     pTypeList: project.projectTypeList.map(item => ({ label: item.name, value: item.ID })),
-    schema: schemaBase.base[BaseMenuEnum.PROJECT]?.schema
+    projectSchema: schemaBase.base[BaseMenuEnum.PROJECT]
   })
 )(ProjectModal)

+ 16 - 16
src/pages/Project/Management/index.tsx

@@ -1,21 +1,21 @@
 import { delProject, getProjectList } from '@/services/api/project'
 import ProTable from '@ant-design/pro-table'
-import type { ProColumnType, ActionType } from '@ant-design/pro-table'
 import { Button, Popconfirm, Tag } from 'antd'
 import consts from '@/utils/consts'
 import { useRef, useState, useEffect } from 'react'
 import { connect, useRequest } from 'umi'
-import type { ConnectProps } from 'umi'
-import type { ProjectModelState } from '../model'
 import { DeleteOutlined } from '@ant-design/icons'
 import ProjectModal, { ModalType } from './components/ProjectModal'
 import dayjs from 'dayjs'
 import { PageContainer } from '@ant-design/pro-layout'
-import type { SchemaBaseModelState } from '@/pages/Schema/Base/model'
 import { BaseMenuEnum } from '@/pages/Schema/Base'
-import { generateColumns } from '@/utils/util'
 import Detail from './components/Detail'
 import AnimateContent from '@/components/AnimateContent'
+import { transformToSchemaData } from '@/utils/schema'
+import type { ProColumnType, ActionType } from '@ant-design/pro-table'
+import type { ConnectProps } from 'umi'
+import type { ProjectModelState } from '../model'
+import type { SchemaBaseModelState } from '@/pages/Schema/Base/model'
 
 type ListProps = ConnectProps & {
   pTypeList: { label: string; value: string }[]
@@ -30,12 +30,14 @@ const List: React.FC<ListProps> = ({ schema, dispatch, pTypeList }) => {
         type: 'project/queryProjectTypeList'
       })
     }
-    dispatch({
-      type: 'schemaBase/querySchema',
-      payload: {
-        columnType: BaseMenuEnum.PROJECT
-      }
-    })
+    if (!schema) {
+      dispatch({
+        type: 'schemaBase/querySchema',
+        payload: {
+          columnType: BaseMenuEnum.PROJECT
+        }
+      })
+    }
   }, [])
 
   const [state, setState] = useState({
@@ -87,7 +89,6 @@ const List: React.FC<ListProps> = ({ schema, dispatch, pTypeList }) => {
       title: '项目类型',
       filters: true,
       filterMultiple: false,
-      render: (_, record) => <div>{record.projectType.name}</div>,
       valueEnum: pTypeList.reduce((prev, curr) => {
         const items = { ...prev }
         items[curr.value] = {
@@ -133,9 +134,7 @@ const List: React.FC<ListProps> = ({ schema, dispatch, pTypeList }) => {
                 visible: true,
                 currentModalType: ModalType.UPDATE,
                 title: record.name,
-                defaultFormData: {
-                  dataID: record.ID
-                }
+                defaultFormData: transformToSchemaData(record, BaseMenuEnum.PROJECT, schema)
               })
             }}>
             编辑
@@ -162,7 +161,8 @@ const List: React.FC<ListProps> = ({ schema, dispatch, pTypeList }) => {
         params={state.params}
         actionRef={tRef}
         scroll={{ y: document.body.clientHeight - 313 }}
-        columns={generateColumns(columns, schema)}
+        // columns={generateColumns(columns, schema)}
+        columns={columns}
         request={async (params, filter, sorter) => {
           const { code = -1, data: { items = [], total = 0 } = {} } = await getProjectList({
             ...params,

+ 31 - 1
src/pages/Schema/Base/index.tsx

@@ -12,7 +12,6 @@ import {
   institutionSchema,
   staffSchema,
   connectSchema,
-  generateFieldIsCreated,
   useAsyncDataSource,
   loadAccountTypeData,
   loadProjectTypeData
@@ -40,6 +39,37 @@ type BaseProps = ConnectProps & {
   pTypeList: { label: string; value: string }[]
 }
 
+export const generateFieldIsCreated = (field: GeneralField) => {
+  if (field.query('ID')?.get('value')) {
+    if (!field.value) {
+      field.setDecoratorProps({
+        addonAfter: (
+          <span>
+            开启后,该账号添加成功后将成为 "
+            <Link to="/project/created" className="text-primary">
+              项目创建人
+            </Link>
+            "
+          </span>
+        )
+      })
+    } else {
+      field.setPattern('readPretty')
+      field.setDecoratorProps({
+        addonAfter: (
+          <div>
+            <span className="text-red-500">需要移除请进入</span>"
+            <Link to="/project/created" className="text-primary">
+              项目创建人
+            </Link>
+            "
+          </div>
+        )
+      })
+    }
+  }
+}
+
 const Index: React.FC<BaseProps> = ({ base, pTypeList, dispatch }) => {
   const [state, setState] = useState({
     activeKey: BaseMenuEnum.PROJECT

+ 57 - 0
src/utils/is.ts

@@ -0,0 +1,57 @@
+const { toString } = Object.prototype
+
+export function is(val: unknown, type: string) {
+  return toString.call(val) === `[object ${type}]`
+}
+
+export function isDef<T = unknown>(val?: T): val is T {
+  return typeof val !== 'undefined'
+}
+
+export function isUnDef<T = unknown>(val?: T): val is T {
+  return !isDef(val)
+}
+
+export function isNull(val: unknown): val is null {
+  return val === null
+}
+
+export function isObject(val: any): val is Record<any, any> {
+  return val !== null && is(val, 'Object')
+}
+
+export function isBoolean(val: unknown): val is boolean {
+  return is(val, 'Boolean')
+}
+
+export function isString(val: unknown): val is string {
+  return is(val, 'String')
+}
+
+export function isArray(val: any): val is any[] {
+  return val && Array.isArray(val)
+}
+
+export function isNullOrUnDef(val: unknown): val is null | undefined {
+  return isUnDef(val) || isNull(val)
+}
+
+export function isEmpty<T = unknown>(val: T): val is T {
+  if (isArray(val) || isString(val)) {
+    return val.length === 0
+  }
+
+  if (val instanceof Map || val instanceof Set) {
+    return val.size === 0
+  }
+
+  if (isObject(val)) {
+    return Object.keys(val).length === 0
+  }
+
+  return false
+}
+
+export function isMobile() {
+  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
+}

+ 37 - 28
src/utils/schema.tsx

@@ -1,9 +1,14 @@
 import { getAccountTypeList } from '@/services/api/institution'
 import { getProjectTypeList } from '@/services/api/project'
-import { Link } from 'umi'
+import { Link, useDispatch } from 'umi'
 import { action } from '@formily/reactive'
 import type { GeneralField } from '@formily/core'
 import consts from './consts'
+import { useEffect, useState } from 'react'
+import type { BaseMenuEnum } from '@/pages/Schema/Base'
+import { SchemaEnum } from '@/pages/Schema/Base'
+import type { ISchema } from '@formily/react'
+import { isDef, isUnDef } from './is'
 
 // 项目schema
 export const projectSchema = {
@@ -318,35 +323,39 @@ export const connectSchema = (initialSchemas, schemas) => {
   return b
 }
 
-export const generateFieldIsCreated = (field: GeneralField) => {
-  if (field.query('ID')?.get('value')) {
-    if (!field.value) {
-      field.setDecoratorProps({
-        addonAfter: (
-          <span>
-            开启后,该账号添加成功后将成为 "
-            <Link to="/project/created" className="text-primary">
-              项目创建人
-            </Link>
-            "
-          </span>
-        )
-      })
-    } else {
-      field.setPattern('readPretty')
-      field.setDecoratorProps({
-        addonAfter: (
-          <div>
-            <span className="text-red-500">需要移除请进入</span>"
-            <Link to="/project/created" className="text-primary">
-              项目创建人
-            </Link>
-            "
-          </div>
-        )
-      })
+/**
+ * 根据传入的数据格式化成表单所需的数据
+ * */
+export const transformToSchemaData = (
+  data: Record<string, any>,
+  columnType: BaseMenuEnum,
+  syncSchema: ISchema
+): Record<string, any> => {
+  const keys = []
+  // schema原始对象
+  function generateKey(obj) {
+    if ('properties' in obj) {
+      return generateKey(obj.properties)
+    }
+    for (const key in obj) {
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
+        const s = obj[key]
+        if ('properties' in s) {
+          generateKey(s.properties)
+        } else if (s['x-decorator'] && s['x-decorator'] === 'FormItem') {
+          keys.push(key)
+        }
+      }
     }
   }
+  generateKey(connectSchema(SchemaEnum[columnType], syncSchema))
+  const formData = {}
+  keys.forEach(key => {
+    if (key in data) {
+      formData[key] = data?.[key]
+    }
+  })
+  return formData
 }
 
 export const useAsyncDataSource = service => field => {