Antd Pro + TS + umi 遇到的问题

1,158 阅读2分钟

此篇文章用于记录 Ant Design Pro 项目在开发过程中遇到的一些问题。

umi 版本: ^4
antd 版本: 5
antd pro 版本:^2
react 版本: 18

一、设置紧凑布局

1.1 构建时配置

1.1.1 compact
// config/config.ts
export default defineConfig({
   antd: {
       compact: true
   }
})

antd 里有个 compact 属性,能够直接开启紧凑主题,但是在开启后在项目构建过程中会报错(如下图),但是具体原因还未找到,社区里有很多人也在问这个问题,但是官方貌似还没有给出回应(如果有,请敲🔨我一下~):

image.png

所以可以尝试使用方法2👇。

1.1.2 configProvider

配置 antd 的 configProvider:

// config/config.ts
import { theme } from 'antd';
export default defineConfig({
   configProvider: {
      theme: {
        algorithm: theme.compactAlgorithm,
      }
    }
})

但是发现单单在构建过程中配置还是不生效,那我们就在运行中也配置上。

1.2 运行时配置

// src/app.tsx
import { theme } from 'antd';
import type { RuntimeAntdConfig } from '@umijs/max';

export const antd: RuntimeAntdConfig = (memo) => {
  memo.theme ||= {};
  memo.theme.algorithm = theme.compactAlgorithm;
  return memo;
};

注意:运行和构建都要添加配置,仅配置一个是不生效的。

具体配置请查看umi官方文档,在这里

二、上传图片到阿里云 OSS

三、表单规则校验

3.1 手机号校验

<ProFormText
  rules={[
    {
      message: '请输入手机号',
      required: true
    },
    {
      pattern: /^1[3|4|5|7|8][0-9]\d{8}$/,
      message: '手机号格式错误'
    }
  ]}
  name="mobile"
  label="手机号"
  placeholder="请输入手机号"
/>

3.2 名称限制只能使用中英文和数字

<ProFormText
  rules={[
    {
      pattern: /^[\u4e00-\u9fa5_a-zA-Z0-9]+$/,
      message: '只能输入中英文和数字'
    }
  ]}
  name="name"
  label="姓名"
  placeholder="请输入姓名"
/>

3.3 验证两次输入的密码是否一致

<ProFormText.Password
  name="password"
  label="密码"
  placeholder="请输入密码"
  fieldProps={{
    visibilityToggle: false  // 是否显示切换按钮或者控制密码显隐
  }}
/>
<ProFormText.Password
  rules={[
    ({getFieldValue}) => ({
      validator(_, value) {
        if (!value || getFieldValue('password') === value) {
          return Promise.resolve();
        }
        return Promise.reject(new Error('两次输入的密码不一致'));
      },
    })
  ]}
  name="rePassword"
  label="确认密码"
  placeholder="请输入确认密码"
  fieldProps={{
    visibilityToggle: false
  }}
/>

3.4 校验身份证号

<ProFormText
  rules={[
    {
      message: '请输入身份证号',
      required: true,
    },
    {
      pattern: new RegExp(/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,'g'),
      message: '请输入正确的身份证号',
    },
  ]}
  name="idNumber"
  label="身份证号"
  placeholder="请输入身份证号"
/>

四、根据权限进行菜单的展示和路由重定向

// routes.ts
export default [
  {
    name: '运营管理',
    path: '/operateManage',
    // 控制菜单是否展示
    access: 'canService',
    routes: [
      {
        path: '/operateManage',
        wrappers: [
          '@/wrappers/auth',
        ],
      }
    ]
  }
]

// src/wrappers/auth.ts
import { history, useModel } from '@umijs/max';

export default () => {
  const { initialState } = useModel('@@initialState');
  const { currentUser } = initialState || {};
  const isService = currentUser?.access === 'service';
  const path = isService ? '/operateManage/account/master' : '/operateManage/account/user';
  return history.push(path);
}

// src/access.ts
export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
  const { currentUser } = initialState ?? {};
  return {
    canService: currentUser && (currentUser.access === 'admin' || currentUser.access === 'service'),
    canAdmin: currentUser && currentUser.access === 'admin'
  };
}

五、表单赋值问题

5.1 第一次打开弹窗时,表单使用 formRef.current.setFieldsValue(values) 赋值不成功

原因: 在 Modal 打开(visible 设置为 true)的时候,form 表单还未渲染,所以 formRef.currentundefined

解决方法:

  • 方案1:加个 setTimeout 才能拿到 FormRef
  const handleOpenEdit = (record: BMECAPI.AreaListItem) => {
    setIsOpen(true);
    setTimeout(() => {
      formRef.current?.setFieldsValue(record); 
    });
  };
  • 方案2:Form 有个 onInit 属性(但是这个属性在官文中并未标识),可以用来初始化表单数据(👍 最优解

image.png

const formRef = useRef<ProFormInstance>();
<ProForm
  onInit={() => formRef.current?.setFieldsValue(record)}
  formRef={formRef}
>
</ProForm>

相同 issue 参考

持续更新中⌛️~