lanjianrong 3 år sedan
förälder
incheckning
7a1af612af

+ 1 - 20
config/proxy.ts

@@ -1,30 +1,11 @@
 /**
  * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置
- * -------------------------------
- * The agent cannot take effect in the production environment
- * so there is no configuration of the production environment
- * For details, please see
- * https://pro.ant.design/docs/deploy
  */
 export default {
   dev: {
     '/api/': {
       target: 'http://fabdev.com',
-      // target: 'http://fab.com:8052',
-      changeOrigin: true,
-      pathRewrite: { '^': '' }
-    }
-  },
-  test: {
-    '/api/': {
-      target: 'https://preview.pro.ant.design',
-      changeOrigin: true,
-      pathRewrite: { '^': '' }
-    }
-  },
-  pre: {
-    '/api/': {
-      target: 'your pre url',
+      // target: 'http://fabqa.com',
       changeOrigin: true,
       pathRewrite: { '^': '' }
     }

+ 5 - 5
config/routes.ts

@@ -42,11 +42,11 @@
         name: 'management',
         component: './Project/Management'
       },
-      // {
-      //   path: '/project/verification',
-      //   name: 'verification',
-      //   component: './Project/Verification'
-      // },
+      {
+        path: '/project/verification',
+        name: 'verification',
+        component: './Project/Verification'
+      },
       {
         path: '/project/created',
         name: 'created',

+ 52 - 5
src/pages/Institutions/Company/Detail/components/Role.tsx

@@ -1,10 +1,57 @@
-import React from 'react'
+import type { FC } from 'react'
+import { Card, Form, InputNumber, message } from 'antd'
 
-const Role = () => {
+import ProForm, { ProFormSelect } from '@ant-design/pro-form'
+import consts from '@/utils/consts'
+import { queryAcountList, saveInstitutionSetting } from '@/services/api/institution'
+import { useRequest } from 'umi'
+
+interface RoleProps {
+  dataID: string
+  memberTotal: number
+  managerID: string
+}
+
+const Role: FC<RoleProps> = ({ dataID, memberTotal, managerID }) => {
+  const { run: trySave } = useRequest(saveInstitutionSetting, {
+    manual: true,
+    onSuccess: () => {
+      return message.success('设置成功')
+    }
+  })
   return (
-    <div>
-      <span>角色管理</span>
-    </div>
+    <Card>
+      <ProForm
+        initialValues={{ accountID: managerID, memberTotal }}
+        wrapperCol={{ span: 6 }}
+        onFinish={async values => {
+          await trySave({ ...values, ID: dataID })
+        }}>
+        <ProFormSelect
+          label="单位管理员:管理员可在前台维护单位信息和维护单位下成员"
+          name="accountID"
+          rules={[{ required: true, message: '请选择单位管理员' }]}
+          request={async () => {
+            const { code, data } = await queryAcountList({
+              current: 1,
+              pageSize: 214000,
+              accountType: '1',
+              dataID
+            })
+            if (code === consts.RET_CODE.SUCCESS) {
+              return data.items?.map(item => ({ label: item.name, value: item.ID }))
+            }
+            return []
+          }}
+        />
+        <Form.Item
+          label={`最大成员数量:已有成员${memberTotal}`}
+          name="memberTotal"
+          rules={[{ required: true, message: '请输入成员总数' }]}>
+          <InputNumber style={{ width: '100%' }} />
+        </Form.Item>
+      </ProForm>
+    </Card>
   )
 }
 

+ 45 - 23
src/pages/Institutions/Company/Detail/components/Staff.tsx

@@ -1,6 +1,6 @@
 import ProTable from '@ant-design/pro-table'
 import React, { useState, useEffect, useRef } from 'react'
-import { Button } from 'antd'
+import { Button, Tooltip } from 'antd'
 import consts from '@/utils/consts'
 // import { history } from 'umi'
 import { connect } from 'umi'
@@ -14,11 +14,22 @@ import { generateColumns } from '@/utils/util'
 import { genderEum } from '@/pages/Institutions/Staff'
 import AnimateContent from '@/components/AnimateContent'
 import { ModalType } from '@/utils/enum'
+import { TeamOutlined } from '@ant-design/icons'
 
 type ListProps = ConnectProps & {
   accountType: API.AccountType[]
+  memberTotal: number
+  dataID: string
+  managerID: string
 }
-const Staff: React.FC<ListProps> = ({ schema, dataID, dispatch, accountTypeList }) => {
+const Staff: React.FC<ListProps> = ({
+  schema,
+  dataID,
+  dispatch,
+  accountTypeList,
+  memberTotal = 1,
+  managerID
+}) => {
   const tRef = useRef<ActionType>(null)
   // console.log(accountTypeList)
 
@@ -44,7 +55,8 @@ const Staff: React.FC<ListProps> = ({ schema, dataID, dispatch, accountTypeList
     title: '',
     visible: false,
     currentModalType: ModalType.ADD,
-    defaultFormData: {}
+    defaultFormData: {},
+    total: null
   })
   const columns = [
     {
@@ -53,7 +65,8 @@ const Staff: React.FC<ListProps> = ({ schema, dataID, dispatch, accountTypeList
     },
     {
       dataIndex: 'name',
-      title: '姓名'
+      title: '姓名',
+      renderText: (text, record) => `${text}${record.ID === managerID ? ' (管理员) ' : null}`
     },
     // {
     //   dataIndex: 'password',
@@ -146,15 +159,16 @@ const Staff: React.FC<ListProps> = ({ schema, dataID, dispatch, accountTypeList
         columns={generateColumns(columns, schema)}
         search={false}
         request={async (params, filter, sorter) => {
-          const { code = -1, data: { items = [], totle = 0 } = {} } = await queryAcountList({
+          const { code = -1, data: { items = [], total = 0 } = {} } = await queryAcountList({
             ...params,
             ...filter,
             ...sorter
           })
+          setState({ ...state, total })
           return {
             data: items,
             success: code === consts.RET_CODE.SUCCESS,
-            totle
+            total
           }
         }}
         toolbar={{
@@ -162,23 +176,31 @@ const Staff: React.FC<ListProps> = ({ schema, dataID, dispatch, accountTypeList
             onSearch: val => setState({ ...state, params: { ...state.params, search: val } })
           },
           actions: [
-            <Button
-              type="primary"
-              onClick={() => {
-                setState({
-                  ...state,
-                  visible: true,
-                  currentModalType: ModalType.ADD,
-                  institutionDisable: true,
-                  title: '',
-                  defaultFormData: {
-                    institutionID: dataID,
-                    institutionDisable: true
-                  }
-                })
-              }}>
-              添加人员
-            </Button>
+            state.total && state.total > memberTotal ? (
+              <Tooltip placement="top" title="成员已满,无法新增">
+                <Button type="primary" disabled>
+                  添加人员
+                </Button>
+              </Tooltip>
+            ) : (
+              <Button
+                type="primary"
+                onClick={() => {
+                  setState({
+                    ...state,
+                    visible: true,
+                    currentModalType: ModalType.ADD,
+                    institutionDisable: true,
+                    title: '',
+                    defaultFormData: {
+                      institutionID: dataID,
+                      institutionDisable: true
+                    }
+                  })
+                }}>
+                添加人员
+              </Button>
+            )
           ]
         }}
       />

+ 15 - 88
src/pages/Institutions/Company/Detail/index.tsx

@@ -1,19 +1,11 @@
-// import { GridContent } from '@ant-design/pro-layout'
-import React, { useState, useRef, useLayoutEffect } from 'react'
-import { Menu } from 'antd'
+import React, { useState } from 'react'
 import Staff from './components/Staff'
 import Organization from './components/Organization'
-// import Role from './components/Role'
-// import styles from './style.less'
-import type { RouteComponentProps } from 'react-router'
+import Role from './components/Role'
 import { PageContainer } from '@ant-design/pro-layout'
+import type { RouteComponentProps } from 'react-router'
+import type { InstitutionDetailProps } from '../List'
 
-const { Item } = Menu
-
-type CompanyNameState = {
-  mode: 'inline' | 'horizontal'
-  selectKey: CompanyNameStateKeys
-}
 export enum TabEnum {
   STAFF = '0',
   ORGANIZATION = '1',
@@ -23,57 +15,24 @@ export enum TabEnum {
 type CompanyDetailProps = RouteComponentProps
 
 const CompanyDetail: React.FC<CompanyDetailProps> = ({ location }) => {
-  const { dataID, structureType, name } = location.state
+  const { dataID, structureType, name, memberTotal, managerID } =
+    location.state as InstitutionDetailProps
 
   const menuMap: Record<string, string> = {
     [TabEnum.STAFF]: '人员管理',
-    [TabEnum.ORGANIZATION]: '组织架构'
-    // [TabEnum.ROLE]: '角色权限'
-  }
-  const [initConfig, setInitConfig] = useState<CompanyNameState>({
-    mode: 'inline',
-    selectKey: TabEnum.STAFF
-  })
-  const dom = useRef<HTMLDivElement>()
-  const resize = () => {
-    requestAnimationFrame(() => {
-      if (!dom.current) {
-        return
-      }
-      let mode: 'inline' | 'horizontal' = 'inline'
-      const { offsetWidth } = dom.current
-      if (dom.current.offsetWidth < 641 && offsetWidth > 400) {
-        mode = 'horizontal'
-      }
-      if (window.innerWidth < 768 && offsetWidth > 400) {
-        mode = 'horizontal'
-      }
-      setInitConfig({ ...initConfig, mode: mode as SettingsState['mode'] })
-    })
-  }
-
-  useLayoutEffect(() => {
-    if (dom.current) {
-      window.addEventListener('resize', resize)
-      resize()
-    }
-    return () => {
-      window.removeEventListener('resize', resize)
-    }
-  }, [dom.current])
-  const getMenu = () => {
-    return Object.keys(menuMap).map(item => <Item key={item}>{menuMap[item]}</Item>)
+    [TabEnum.ORGANIZATION]: '组织架构',
+    [TabEnum.ROLE]: '单位设置'
   }
+  const [selectKey, setSelectKey] = useState<TabEnum>(TabEnum.STAFF)
 
   const renderChildren = () => {
-    const { selectKey } = initConfig
     switch (selectKey) {
       case TabEnum.STAFF:
-        return <Staff dataID={dataID} />
+        return <Staff dataID={dataID} memberTotal={memberTotal} managerID={managerID} />
       case TabEnum.ORGANIZATION:
         return <Organization dataID={dataID} structureType={structureType} />
-      // case TabEnum.ROLE:
-      //   return <Role />
+      case TabEnum.ROLE:
+        return <Role dataID={dataID} memberTotal={memberTotal} managerID={managerID} />
       default:
         return null
     }
@@ -85,43 +44,11 @@ const CompanyDetail: React.FC<CompanyDetailProps> = ({ location }) => {
       fixedHeader
       tabList={[
         { tab: menuMap[TabEnum.STAFF], key: TabEnum.STAFF },
-        { tab: menuMap[TabEnum.ORGANIZATION], key: TabEnum.ORGANIZATION }
+        { tab: menuMap[TabEnum.ORGANIZATION], key: TabEnum.ORGANIZATION },
+        { tab: menuMap[TabEnum.ROLE], key: TabEnum.ROLE }
       ]}
-      onTabChange={key =>
-        setInitConfig({
-          ...initConfig,
-          selectKey: key
-        })
-      }>
+      onTabChange={key => setSelectKey(key)}>
       {renderChildren()}
-      {/* <GridContent>
-        <div
-          className={styles.main}
-          ref={ref => {
-            if (ref) {
-              dom.current = ref
-            }
-          }}>
-           */}
-
-      {/* <div className={styles.leftMenu}>
-            <Menu
-              mode={initConfig.mode}
-              selectedKeys={[initConfig.selectKey]}
-              onClick={({ key }) => {
-                setInitConfig({
-                  ...initConfig,
-                  selectKey: key as CompanyNameStateKeys
-                })
-              }}>
-              {getMenu()}
-            </Menu>
-          </div>
-          <div className={styles.right}>
-            <div className={styles.title}>{menuMap[initConfig.selectKey]}</div>
-          </div> */}
-      {/* </div>
-      </GridContent> */}
     </PageContainer>
   )
 }

+ 18 - 3
src/pages/Institutions/Company/List/index.tsx

@@ -21,6 +21,14 @@ type ListProps = ConnectProps & {
   base: Record<string, any>
 }
 
+export type InstitutionDetailProps = {
+  dataID: string
+  structureType: string
+  name: string
+  memberTotal: number
+  managerID: string
+}
+
 const CompanyList: React.FC<ListProps> = ({ base, dispatch, pTypeList }) => {
   const tRef = useRef<ActionType>(null)
   const schema = base?.[BaseMenuEnum.COMPANY]?.schema
@@ -53,7 +61,7 @@ const CompanyList: React.FC<ListProps> = ({ base, dispatch, pTypeList }) => {
   //   onSuccess: () => tRef.current?.reload()
   // })
 
-  const goToDetail = params => {
+  const goToDetail = (params: InstitutionDetailProps) => {
     // return history.push(`/institutions/company/companyname`)
     return history.push({
       pathname: '/institutions/company/detail',
@@ -68,7 +76,13 @@ const CompanyList: React.FC<ListProps> = ({ base, dispatch, pTypeList }) => {
       render: (name, record) => (
         <span
           onClick={() =>
-            goToDetail({ dataID: record.ID, structureType: state.structureType, name: record.name })
+            goToDetail({
+              dataID: record.ID,
+              structureType: state.structureType,
+              name: record.name,
+              memberTotal: record.memberTotal,
+              managerID: record.manager.ID
+            })
           }
           className="text-primary cursor-pointer">
           {name}
@@ -81,7 +95,8 @@ const CompanyList: React.FC<ListProps> = ({ base, dispatch, pTypeList }) => {
     },
     {
       dataIndex: 'institutionAcountTotal',
-      title: '人员账号'
+      title: '人员账号',
+      renderText: (text, record) => `${text}/${record.memberTotal}`
     },
     {
       dataIndex: 'createdTime',

+ 22 - 22
src/pages/Institutions/Staff/index.tsx

@@ -199,28 +199,28 @@ const CompanyList: React.FC<ListProps> = ({ schema, dispatch, accountTypeList })
         toolbar={{
           search: {
             onSearch: val => setState({ ...state, params: { ...state.params, search: val } })
-          },
-          actions: [
-            <Button
-              type="primary"
-              onClick={() =>
-                setState({
-                  ...state,
-                  visible: true,
-                  currentModalType: ModalType.ADD,
-                  title: '',
-                  defaultFormData: {
-                    ...state.defaultFormData,
-                    dataID: null,
-                    institutionID: null,
-                    institutionDisable: false,
-                    hiddenOrganization: true
-                  }
-                })
-              }>
-              新建账号
-            </Button>
-          ]
+          }
+          // actions: [
+          //   <Button
+          //     type="primary"
+          //     onClick={() =>
+          //       setState({
+          //         ...state,
+          //         visible: true,
+          //         currentModalType: ModalType.ADD,
+          //         title: '',
+          //         defaultFormData: {
+          //           ...state.defaultFormData,
+          //           dataID: null,
+          //           institutionID: null,
+          //           institutionDisable: false,
+          //           hiddenOrganization: true
+          //         }
+          //       })
+          //     }>
+          //     新建账号
+          //   </Button>
+          // ]
         }}
         search={false}
       />

+ 53 - 38
src/pages/Project/Management/components/ProjectModal.tsx

@@ -9,6 +9,7 @@ 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'
 
 export enum ModalType {
   ADD = 0,
@@ -29,27 +30,13 @@ type ProjectModalProps = ConnectProps & {
   schema?: Record<string, any> | null
 }
 const ProjectModal: React.FC<ProjectModalProps> = ({
-  visible,
   setVisible,
-  dispatch,
   schema,
   type,
   defaultFormData,
   pTypeList,
   reload
 }) => {
-  const form = useForm()
-  useEffect(() => {
-    if (visible && !schema) {
-      dispatch({
-        type: 'schemaBase/querySchema',
-        payload: {
-          columnType: BaseMenuEnum.PROJECT
-        }
-      })
-    }
-  }, [visible])
-
   const { run: tryUpdateProject } = useRequest(updateProject, {
     manual: true,
     onSuccess: () => {
@@ -63,31 +50,31 @@ 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)
+  // 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)
-          })
-        })
-      }
-    }
-  }
+  //         form.setSchemaByPath('projectTypeID', {
+  //           enum: pTypeList.map(item => item.value),
+  //           enumNames: pTypeList.map(item => item.label)
+  //         })
+  //       })
+  //     }
+  //   }
+  // }
 
   const onFinish = async (formData, errors) => {
     if (errors?.length) return
@@ -104,6 +91,33 @@ const ProjectModal: React.FC<ProjectModalProps> = ({
       message.error(error)
     }
   }
+
+  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}>
+        <SchemaField
+          schema={connectSchema(SchemaEnum?.[BaseMenuEnum.PROJECT], schema)}
+          scope={{ useAsyncDataSource, loadProjectTypeData }}
+        />
+      </FormProvider>
+    )
+  }
+
   return (
     <div>
       {schema && <FormRender form={form} schema={schema} onFinish={onFinish} onMount={onMount} />}
@@ -114,6 +128,7 @@ const ProjectModal: React.FC<ProjectModalProps> = ({
           提交
         </Button>
       </div>
+      <div className="max-w-800px">{renderForm()}</div>
       {/* <Form>
         {schema && <FormRender form={form} schema={schema} onFinish={onFinish} onMount={onMount} />}
         <div className="ml-120px">

+ 31 - 31
src/pages/Schema/Base/components/Designable/antd/components/Field/shared.ts

@@ -1,4 +1,4 @@
-import { ISchema } from '@formily/json-schema'
+import type { ISchema } from '@formily/json-schema'
 import { ReactionsSetter, DataSourceSetter, ValidatorSetter } from '@designable/formily-setters'
 import { FormItemSwitcher } from '../../common/FormItemSwitcher'
 import { AllSchemas } from '../../schemas'
@@ -33,37 +33,37 @@ export const createComponentSchema = (component: ISchema, decorator: ISchema) =>
       properties: {
         'x-decorator-props': decorator
       }
+    },
+    'component-style-group': {
+      type: 'void',
+      'x-component': 'CollapseItem',
+      'x-component-props': { defaultExpand: false },
+      'x-reactions': {
+        fulfill: {
+          state: {
+            visible: '{{!!$form.values["x-component"]}}'
+          }
+        }
+      },
+      properties: {
+        'x-component-props.style': AllSchemas.CSSStyle
+      }
+    },
+    'decorator-style-group': {
+      type: 'void',
+      'x-component': 'CollapseItem',
+      'x-component-props': { defaultExpand: false },
+      'x-reactions': {
+        fulfill: {
+          state: {
+            visible: '{{!!$form.values["x-decorator"]}}'
+          }
+        }
+      },
+      properties: {
+        'x-decorator-props.style': AllSchemas.CSSStyle
+      }
     }
-    // 'component-style-group': {
-    //   type: 'void',
-    //   'x-component': 'CollapseItem',
-    //   'x-component-props': { defaultExpand: false },
-    //   'x-reactions': {
-    //     fulfill: {
-    //       state: {
-    //         visible: '{{!!$form.values["x-component"]}}'
-    //       }
-    //     }
-    //   },
-    //   properties: {
-    //     'x-component-props.style': AllSchemas.CSSStyle
-    //   }
-    // },
-    // 'decorator-style-group': {
-    //   type: 'void',
-    //   'x-component': 'CollapseItem',
-    //   'x-component-props': { defaultExpand: false },
-    //   'x-reactions': {
-    //     fulfill: {
-    //       state: {
-    //         visible: '{{!!$form.values["x-decorator"]}}'
-    //       }
-    //     }
-    //   },
-    //   properties: {
-    //     'x-decorator-props.style': AllSchemas.CSSStyle
-    //   }
-    // }
   }
 }
 

+ 13 - 3
src/pages/Schema/Base/components/Designable/index.tsx

@@ -48,7 +48,7 @@ interface DesignableProps {
 }
 const Designable: FC<DesignableProps> = ({ base, title }) => {
   const {
-    state: { columnType, ID }
+    state: { columnType }
   } = useLocation()
 
   const { run: tryUpdateSchema } = useRequest(updateSchema, {
@@ -59,7 +59,6 @@ const Designable: FC<DesignableProps> = ({ base, title }) => {
       dispatch({
         type: 'schemaBase/changeSchemaByColumnType',
         payload: {
-          ID,
           columnType,
           schema: result.schema
         }
@@ -91,7 +90,18 @@ const Designable: FC<DesignableProps> = ({ base, title }) => {
       <StudioPanel
         logo={<span className="text-base font-medium">{title}</span>}
         actions={
-          <ActionsWidget updateAction={tryUpdateSchema} schema={base[columnType]?.schema} />
+          <ActionsWidget
+            updateAction={tryUpdateSchema}
+            schema={{
+              form: {
+                labelCol: 6,
+                wrapperCol: 12,
+                fullness: true,
+                inset: false
+              },
+              schema: { type: 'object', properties: base[columnType] }
+            }}
+          />
         }>
         <ResourceWidget
           title="sources.Inputs"

+ 1 - 2
src/pages/Schema/Base/components/Designable/widgets/ActionsWidget.tsx

@@ -20,9 +20,8 @@ export const ActionsWidget = observer(({ updateAction, schema }) => {
 
   const saveSchema = () => {
     updateAction({
-      ID,
       columnType,
-      schema: transformToSchema(designer.getCurrentTree())
+      schema: transformToSchema(designer.getCurrentTree()).schema
     })
   }
   return (

+ 68 - 13
src/pages/Schema/Base/index.tsx

@@ -1,10 +1,23 @@
 import { PageContainer } from '@ant-design/pro-layout'
 import LeftMenu from './components/LeftMenu'
 import { useState, useEffect } from 'react'
-import FormRender, { useForm } from 'form-render'
 import { history, connect } from 'umi'
+import type { ProjectModelState, SchemaBaseModelState } from 'umi'
+import { createForm, onFieldMount, onFieldReact } from '@formily/core'
+import { FormProvider, createSchemaField } from '@formily/react'
+import { FormItem, Input, Switch, Select, FormGrid, FormLayout } from '@formily/antd'
+
+import {
+  projectSchema,
+  institutionSchema,
+  staffSchema,
+  connectSchema,
+  generateFieldIsCreated,
+  useAsyncDataSource,
+  loadAccountTypeData,
+  loadProjectTypeData
+} from '@/utils/schema'
 import type { ConnectProps } from 'umi'
-import type { SchemaBaseModelState } from './model'
 
 export enum BaseMenuEnum {
   PROJECT = '1',
@@ -12,6 +25,11 @@ export enum BaseMenuEnum {
   STAFF = '3'
 }
 
+export enum SchemaEnum {
+  '1' = projectSchema,
+  '2' = institutionSchema,
+  '3' = staffSchema
+}
 export const menuOptions = [
   { label: '项目信息', value: BaseMenuEnum.PROJECT },
   { label: '企事业单位信息', value: BaseMenuEnum.COMPANY },
@@ -19,14 +37,14 @@ export const menuOptions = [
 ]
 type BaseProps = ConnectProps & {
   base: SchemaBaseModelState
+  pTypeList: { label: string; value: string }[]
 }
 
-const Index: React.FC<BaseProps> = ({ base, dispatch }) => {
-  const form = useForm()
+const Index: React.FC<BaseProps> = ({ base, pTypeList, dispatch }) => {
   const [state, setState] = useState({
-    activeKey: BaseMenuEnum.PROJECT,
-    schema: base?.[BaseMenuEnum.PROJECT]?.schema
+    activeKey: BaseMenuEnum.PROJECT
   })
+
   const currentSchema = base?.[state.activeKey]
 
   useEffect(() => {
@@ -38,15 +56,49 @@ const Index: React.FC<BaseProps> = ({ base, dispatch }) => {
         }
       })
     }
+    if (!pTypeList.length) {
+      dispatch({
+        type: 'project/queryProjectTypeList'
+      })
+    }
   }, [state.activeKey])
 
-  const gotoDetail = (columnType, ID) => {
+  const gotoDetail = columnType => {
     history.push({
       pathname: '/work-setting/schema/detail',
-      state: { columnType, ID }
+      state: { columnType }
     })
   }
 
+  const renderForm = () => {
+    const normalForm = createForm({
+      validateFirst: true,
+      effects() {
+        onFieldReact('isCreated', field => generateFieldIsCreated(field))
+        onFieldMount('projectTypeID', field => (field.dataSource = pTypeList))
+      }
+    })
+
+    const SchemaField = createSchemaField({
+      components: {
+        FormLayout,
+        FormItem,
+        FormGrid,
+        Input,
+        Switch,
+        Select
+      }
+    })
+    return (
+      <FormProvider form={normalForm}>
+        <SchemaField
+          schema={connectSchema(SchemaEnum?.[state.activeKey], currentSchema)}
+          scope={{ useAsyncDataSource, loadAccountTypeData, loadProjectTypeData }}
+        />
+      </FormProvider>
+    )
+  }
+
   return (
     <PageContainer title={false}>
       <div className="h-full w-full flex flex-row">
@@ -59,16 +111,19 @@ const Index: React.FC<BaseProps> = ({ base, dispatch }) => {
         <div className="w-6/7 ml-8 bg-white p-4 rounded-20px">
           <div className="flex flex-row-reverse mb-4 w-full">
             <div
-              onClick={() => gotoDetail(state.activeKey, currentSchema?.ID)}
+              onClick={() => gotoDetail(state.activeKey)}
               className="w-14px h-14px rounded-1/2 hover:bg-dark-50 hover:cursor-pointer"></div>
           </div>
-          <div>{currentSchema && <FormRender form={form} schema={currentSchema?.schema} />}</div>
+          <div className="max-w-800px">{renderForm()}</div>
         </div>
       </div>
     </PageContainer>
   )
 }
 
-export default connect(({ schemaBase }: { schemaBase: SchemaBaseModelState }) => ({
-  base: schemaBase.base
-}))(Index)
+export default connect(
+  ({ project, schemaBase }: { project: ProjectModelState; schemaBase: SchemaBaseModelState }) => ({
+    pTypeList: project.projectTypeList.map(item => ({ label: item.name, value: item.ID })),
+    base: schemaBase.base
+  })
+)(Index)

+ 2 - 2
src/pages/Schema/Base/model.ts

@@ -40,7 +40,7 @@ const SchemaBaseModel: SchemaBaseType = {
         yield put({
           type: 'save',
           payload: {
-            ...response.data?.[0]
+            ...(response.data || {})
           }
         })
       }
@@ -56,7 +56,7 @@ const SchemaBaseModel: SchemaBaseType = {
     save(state, action) {
       return {
         ...state,
-        base: { ...state?.base, [action.payload.columnType]: action.payload }
+        base: { ...state?.base, [action.payload.columnType]: action.payload?.schema.properties }
       }
     }
 

+ 14 - 2
src/services/api/institution.ts

@@ -25,7 +25,7 @@ export async function addInstitution(params: API.InstitutionAddParams) {
 }
 
 /** 新增企事业单位下账号 */
-export async function queryAcountList(params: API.InstitutionAddParams) {
+export async function queryAcountList(params: API.InstitutionListParams) {
   return request('/account/list', {
     method: 'POST',
     data: params
@@ -33,7 +33,7 @@ export async function queryAcountList(params: API.InstitutionAddParams) {
 }
 
 /** 单位下帐号列表 */
-export async function queryAcountInstitutionList(params: API.AcountInstitutionParams) {
+export async function queryAcountInstitutionList(params: API.AcountInstitutionListParams) {
   return request('/account/institution', {
     method: 'POST',
     data: params
@@ -125,3 +125,15 @@ export async function delOrganizationalStructure(params: API.OrganizationalStruc
     data: params
   })
 }
+
+/** 企事业单位设置 */
+export async function saveInstitutionSetting(params: {
+  ID: string
+  accountID: string
+  memberTotal: string
+}) {
+  return request('/institution/setting', {
+    method: 'POST',
+    data: params
+  })
+}

+ 1 - 1
src/services/api/schema.ts

@@ -2,7 +2,7 @@ import { request } from 'umi'
 
 /** 获取对应类型的的schema */
 export async function getSchemaByColmunType(params: API.SchemaParams) {
-  return request('/BasicConfig/list', {
+  return request('/BasicConfig/detail', {
     method: 'GET',
     params
   })

+ 18 - 6
src/services/api/typings.d.ts

@@ -73,11 +73,20 @@ declare namespace API {
     createdTime: string
     updatedTime: string
     ID: string
+    /** @name 成员总数 */
+    memberTotal: number
+    /** @name 单位管理员 */
+    manager: {
+      ID: string
+      name: string
+    }
   }
 
   type InstitutionListParams = BasicPageParams & {
     search?: string
-    institutionTypeId?: string
+    accountType?: string
+    dataID?: string
+    isCreated?: string
   }
 
   type InstitutionAddParams = Omit<InstitutionListItem, 'createdTime' | 'updatedTime' | 'ID'>
@@ -129,11 +138,14 @@ declare namespace API {
     ID: string
   }
 
-  type AcountInstitutionParams = {
-    name: string
-    key: string
-    value: string
-    children: AccountListItem[]
+  type AcountInstitutionListParams = BasicPageParams & {
+    search?: string
+    /** @name 账号类型(1-企事业账号) ... */
+    accountType: number
+    /** @name  对应类型ID*/
+    dataID?: string
+    /** @name  获得创建人/非创建人 */
+    isCreated?: string
   }
 
   type AccountType = {

+ 0 - 15
src/utils/schema.ts

@@ -1,15 +0,0 @@
-export const projectSchema = {
-  type: 'object',
-  properties: {
-    ID: {
-      type: 'string',
-      title: 'ID',
-      required: true,
-      'x-decorator': 'FormItem',
-      'x-component': 'Input',
-      'x-component-props': {
-        hidden: true
-      }
-    }
-  }
-}

+ 378 - 0
src/utils/schema.tsx

@@ -0,0 +1,378 @@
+import { getAccountTypeList } from '@/services/api/institution'
+import { getProjectTypeList } from '@/services/api/project'
+import { Link } from 'umi'
+import { action } from '@formily/reactive'
+import type { GeneralField } from '@formily/core'
+import consts from './consts'
+
+// 项目schema
+export const projectSchema = {
+  type: 'object',
+  properties: {
+    layout: {
+      type: 'void',
+      'x-component': 'FormLayout',
+      'x-component-props': {
+        labelCol: 6,
+        wrapperCol: 8,
+        layout: 'horizontal'
+      },
+      properties: {
+        ID: {
+          type: 'string',
+          title: 'ID',
+          'x-display': 'none',
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 0
+        },
+        name: {
+          type: 'string',
+          title: '名称',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 1
+        },
+        shortName: {
+          type: 'string',
+          title: '项目简称',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 2
+        },
+        projectTypeID: {
+          type: 'string',
+          title: '项目类型',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Select',
+          'x-index': 3
+        }
+      }
+    }
+  }
+}
+
+// 企事业单位
+export const institutionSchema = {
+  type: 'object',
+  properties: {
+    ID: {
+      type: 'string',
+      title: 'ID',
+      'x-display': 'none',
+      'x-decorator': 'FormItem',
+      'x-component': 'Input',
+      'x-index': 0
+    },
+    name: {
+      type: 'string',
+      title: '企事业单位名称',
+      required: true,
+      'x-decorator': 'FormItem',
+      'x-component': 'Input',
+      'x-decorator-props': {
+        // labelWidth: '131px'
+        labelCol: 4
+      },
+      'x-index': 1
+    },
+    layout: {
+      type: 'void',
+      'x-component': 'FormLayout',
+      'x-component-props': {
+        labelCol: 8,
+        wrapperCol: 16,
+        layout: 'horizontal'
+      },
+      properties: {
+        gird: {
+          type: 'void',
+          'x-component': 'FormGrid',
+          'x-component-props': {
+            minColumns: 1,
+            maxColumns: 2,
+            columnGap: 0
+          },
+          properties: {
+            acronym: {
+              type: 'string',
+              title: '企事业单位简称',
+              required: true,
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 2
+            },
+            enterpriseCode: {
+              type: 'string',
+              title: '企业编码',
+              required: true,
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 3
+            },
+            phone: {
+              type: 'string',
+              title: '办公电话',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 4
+            },
+            address: {
+              type: 'string',
+              title: '地址',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 5
+            },
+            fax: {
+              type: 'string',
+              title: '传真号码',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 6
+            },
+            organizationCode: {
+              type: 'string',
+              title: '组织架构代码',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 7
+            },
+            bank: {
+              type: 'string',
+              title: '银行',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 8
+            },
+            idCard: {
+              type: 'string',
+              title: '身份证号码',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 9
+            },
+            bankAccount: {
+              type: 'string',
+              title: '银行账号',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 10
+            },
+            legalPerson: {
+              type: 'string',
+              title: '法人代表',
+              'x-decorator': 'FormItem',
+              'x-component': 'Input',
+              'x-index': 11
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+// 人员信息
+export const staffSchema = {
+  type: 'object',
+  properties: {
+    layout: {
+      type: 'void',
+      'x-component': 'FormLayout',
+      'x-component-props': {
+        labelCol: 4,
+        wrapperCol: 8,
+        layout: 'horizontal'
+      },
+      properties: {
+        ID: {
+          type: 'string',
+          title: 'ID',
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-display': 'none',
+          'x-index': 0
+        },
+        enable: {
+          type: 'boolean',
+          title: '账号启用',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Switch',
+          'x-index': 1
+        },
+        isCreated: {
+          type: 'boolean',
+          title: '项目创建人',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Switch',
+          'x-index': 2
+        },
+        institutionID: {
+          type: 'string',
+          title: '事业单位',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 3
+        },
+        account: {
+          type: 'string',
+          title: '账号',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 4
+        },
+        name: {
+          type: 'string',
+          title: '姓名',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 5
+        },
+        password: {
+          type: 'string',
+          title: '密码',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 6
+        },
+        accountType: {
+          type: 'string',
+          title: '账号类型',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Select',
+          'x-index': 7,
+          enum: [],
+          'x-reactions': ['{{useAsyncDataSource(loadAccountTypeData)}}']
+        },
+        organizationalStructureID: {
+          type: 'string',
+          title: '组织架构',
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 8
+        },
+        gender: {
+          type: 'string',
+          title: '性别',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Select',
+          'x-index': 9,
+          enum: [
+            { label: '男', value: 0 },
+            { label: '女', value: 1 }
+          ]
+        },
+        phone: {
+          type: 'string',
+          title: '手机',
+          required: true,
+          'x-decorator': 'FormItem',
+          'x-component': 'Input',
+          'x-index': 10
+        }
+      }
+    }
+  }
+}
+
+/** 组合schema */
+export const connectSchema = (initialSchemas, schemas) => {
+  if (!schemas) return initialSchemas
+  let startIdx = Object.keys(initialSchemas.properties).length
+  let i = 0
+  const b = { ...initialSchemas }
+
+  if ('layout' in initialSchemas.properties) {
+    startIdx = Object.keys(initialSchemas.properties.layout.properties).length
+    for (const key in schemas) {
+      if (Object.prototype.hasOwnProperty.call(schemas, key)) {
+        const schema = schemas[key]
+        schema['x-index'] = startIdx + i
+        i++
+      }
+    }
+    const properties = Object.assign(b.properties.layout.properties, schemas)
+    b.properties.layout.properties = properties
+  } else {
+    for (const key in schemas) {
+      if (Object.prototype.hasOwnProperty.call(schemas, key)) {
+        const schema = schemas[key]
+        schema['x-index'] = startIdx + i
+        i++
+      }
+    }
+    b.properties = { ...schemas, ...b.properties }
+  }
+  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 useAsyncDataSource = service => field => {
+  field.loading = true
+  service(field).then(
+    action.bound(data => {
+      field.dataSource = data
+      field.loading = false
+    })
+  )
+}
+
+/** 加载账号类型 */
+export const loadAccountTypeData = async () => {
+  const { code = -1, data = [] } = await getAccountTypeList()
+  if (code === consts.RET_CODE.SUCCESS) {
+    return data.map(item => ({ label: item.name, value: item.value }))
+  }
+  return []
+}
+
+/** 加载项目类型 */
+export const loadProjectTypeData = async () => {
+  const { code = -1, data = [] } = await getProjectTypeList()
+  if (code === consts.RET_CODE.SUCCESS) {
+    return data.map(item => ({ label: item.name, value: item.ID }))
+  }
+  return []
+}