pro-components icon indicating copy to clipboard operation
pro-components copied to clipboard

🐛[BUG] ProTable 搜索按钮抖动

Open codedart2018 opened this issue 3 years ago • 4 comments
trafficstars

🐛 bug 描述

通过路由进入,或者刷新页面会显示感觉到重置 查询按钮抖动,变形!

📷 复现步骤

image

搜索表格过多的情况,很明显 https://user-images.githubusercontent.com/12706830/187642429-164cc3d2-6a52-44d9-9ec7-eb2d91a16676.mov

搜索过少的页面,也有闪动 https://user-images.githubusercontent.com/12706830/187643862-e3c936ea-61eb-4410-ad81-f4946b95b2a9.mov

🏞 期望结果

期望正常不抖动,我默认不增加导出按钮,它也会抖动。

💻 复现代码

我把整个页面代码,贴出来。

import { useRef, useState } from 'react';
import { Tag, Space, Button, Avatar, Badge, Form, Input, Select } from 'antd';
import PageContainer from '@/components/PageContainer';
import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table';
import { TableListItem } from './types';
import { queryMemberList } from './service';
import {
  formatDate,
  getEdu,
  getGender,
  getMarriage,
  getMonthlyIncome,
  getOccupation,
  sourceFormat,
} from '@/utils/tool';
import PopoverSliderForm from '@/components/PopoverSliderForm';
import {
  eduLabel,
  genderLabel,
  loveStatus,
  marriageLabel,
  occupationsLabel,
} from '@/utils/constant';
import DrawerPanel from './DrawerPanel';

const MemberList = () => {
  const actionRef = useRef<ActionType>();
  const [visible, setVisible] = useState(false);

  const showDrawer = () => {
    setVisible(true);
  };

  const columns: ProColumns<TableListItem>[] = [
    {
      title: '关键词',
      hideInTable: true,
      colSize: 2,
      renderFormItem: () => {
        return (
          <Form.Item label="" noStyle>
            <Input.Group compact>
              <Form.Item name={['keywords', 'type']} noStyle initialValue={0}>
                <Select placeholder="请选择" style={{ width: '40%' }}>
                  <Select.Option value={0}>按呢称搜</Select.Option>
                  <Select.Option value={1}>按姓名搜</Select.Option>
                  <Select.Option value={2}>按手机号搜</Select.Option>
                  <Select.Option value={3}>按ID搜</Select.Option>
                </Select>
              </Form.Item>
              <Form.Item name={['keywords', 'name']} noStyle>
                <Input style={{ width: '60%' }} placeholder="请输入关键词" />
              </Form.Item>
            </Input.Group>
          </Form.Item>
        );
      },
    },
    {
      dataIndex: 'love_id',
      title: '用户ID',
      search: false,
      align: 'center',
      width: 100,
    },
    {
      dataIndex: 'avatar',
      title: '头像',
      search: false,
      align: 'center',
      width: 60,
      render: (_, row) => {
        return (
          <Avatar
            shape="square"
            size={48}
            src={sourceFormat(row.avatar, { m: 1, w: 200, h: 200 })}
          />
        );
      },
    },
    {
      title: '资料',
      search: false,
      align: 'center',
      width: 330,
      render: (_, row) => {
        return (
          <div className="text-left f-12">
            <div className="text-left">
              <div className="d-flex align-items-end">
                <span className="f-w f-14 mr-10">{row.nickname}</span>
                <div
                  className={row.gender === 1 ? 'col-nan' : row.gender === 2 ? 'col-hot-pink' : ''}
                >
                  {getGender(row.gender)}
                </div>
                {row.marriage > 0 && <span className="ml-10">{getMarriage(row.marriage)}</span>}
              </div>
              <div className="col-6">
                <Space>
                  {row.age > 0 && <span>{row.age}岁</span>}
                  {row.height > 0 && <span>{row.height}cm</span>}
                  {row.weight > 0 && <span>{row.weight}kg</span>}
                  {row.education > 0 && <span>{getEdu(row.education)}</span>}
                  {row.occupation > 0 && <span>{getOccupation(row.occupation)}</span>}
                  {row.monthly_income > 0 && <span>{getMonthlyIncome(row.monthly_income)}</span>}
                </Space>
                <br />
                <Space>
                  <span>籍贯:重庆市 永川区</span>
                  <span>现居:重庆市 永川区</span>
                </Space>
              </div>
            </div>
          </div>
        );
      },
    },
    {
      title: '微信/手机号',
      dataIndex: 'mobile',
      // hideInTable: true,
      width: 130,
      align: 'center',
      search: false,
      formItemProps: {
        label: '手机号',
      },
      render: (val, row) => {
        return (
          <Space direction="vertical">
            <span>{row.wechat ? row.wechat : '-'}</span>
            <span>{val ? val : '-'}</span>
          </Space>
        );
      },
    },
    {
      title: '性别',
      dataIndex: 'gender',
      hideInTable: true,
      valueType: 'select',
      request: async () => genderLabel,
    },
    {
      title: '实名',
      dataIndex: 'auth_realname',
      hideInTable: true,
      valueType: 'select',
      request: async () => [
        { label: '已实名', value: 1 },
        { label: '未实名', value: 0 },
      ],
    },
    {
      title: '婚况',
      dataIndex: 'marriage',
      hideInTable: true,
      valueType: 'select',
      request: async () => marriageLabel,
      // renderFormItem: ()=> {}
    },
    {
      title: '学历',
      dataIndex: 'education',
      hideInTable: true,
      valueType: 'select',
      request: async () => eduLabel,
    },
    {
      title: '职业',
      dataIndex: 'job',
      hideInTable: true,
      valueType: 'select',
      request: async () => occupationsLabel,
    },
    {
      title: '收入',
      dataIndex: 'salary',
      hideInTable: true,
      valueType: 'select',
      request: async () => [
        { label: '未婚', value: 1 },
        { label: '离异', value: 2 },
        { label: '丧偶', value: 3 },
      ],
    },
    {
      title: '年龄',
      dataIndex: 'age',
      hideInTable: true,
      renderFormItem: () => {
        return (
          <PopoverSliderForm typeName="年龄" min={18} max={45} unit="岁" defaultVal={[20, 25]} />
        );
      },
    },
    {
      title: '身高',
      dataIndex: 'height',
      hideInTable: true,
      renderFormItem: () => {
        return (
          <PopoverSliderForm
            typeName="身高"
            min={150}
            max={200}
            unit="CM"
            defaultVal={[158, 175]}
          />
        );
      },
    },
    {
      title: '体重',
      dataIndex: 'weight',
      hideInTable: true,
      renderFormItem: () => {
        return (
          <PopoverSliderForm typeName="体重" min={40} max={100} unit="KG" defaultVal={[45, 65]} />
        );
      },
    },
    {
      title: '购房',
      dataIndex: 'house',
      hideInTable: true,
      valueType: 'select',
      request: async () => [
        { label: '已购房(居家)', value: 1 },
        { label: '已购房(多套)', value: 2 },
        { label: '暂未购房', value: 3 },
        { label: '随时可购置', value: 4 },
      ],
    },
    {
      dataIndex: 'integral',
      title: '积分',
      search: false,
      align: 'center',
    },
    {
      title: '实名',
      dataIndex: 'mobile',
      // hideInTable: true,
      width: 80,
      align: 'center',
      search: false,
      render: () => {
        return <Tag color="success">已实名</Tag>;
      },
    },
    {
      dataIndex: 'love_status',
      title: '相亲状态',
      width: 100,
      align: 'center',
      valueType: 'select',
      request: async () => loveStatus,
      render: (_, row) => {
        switch (row.love_status as number) {
          case 1:
            return <Tag color="success">公开相亲</Tag>;
          case 2:
            return <Tag color="gold">委托红娘</Tag>;
          case 3:
            return <Tag color="magenta">已脱单</Tag>;
          default:
            return <Tag>关闭相亲</Tag>;
        }
      },
    },
    {
      dataIndex: 'matchmaker',
      title: '红娘',
      align: 'center',
      request: async () => [{ label: '番茄', value: 1 }],
      width: 100,
      valueType: 'select',
    },
    {
      dataIndex: 'status',
      title: '状态',
      align: 'center',
      formItemProps: {
        label: '用户状态',
      },
      request: async () => [
        { label: '正常', value: 1 },
        { label: '审核中', value: 2 },
        { label: '异常用户', value: 3 },
        { label: '黑名单', value: 4 },
      ],
      width: 100,
      render: () => {
        return <Tag color="success">正常</Tag>;
      },
    },
    {
      title: '注册时间',
      dataIndex: 'create_time',
      valueType: 'date',
      width: 190,
      align: 'center',
      render: (_, record) => {
        return (
          <Space direction="vertical">
            <div className="col-6">公众号</div>
            <div>{formatDate(record.create_time)}</div>
          </Space>
        );
      },
    },
    {
      title: '操作',
      width: 80,
      search: false,
      align: 'center',
      render: () => {
        return (
          <Space className="mt-6">
            <Badge count={2} style={{ display: 'none' }}>
              <Button size="small" type="primary" ghost style={{ display: 'none' }}>
                服务跟进
              </Button>
            </Badge>
            <Badge count={2} style={{ display: 'none' }}>
              <Button size="small" type="primary" ghost style={{ display: 'none' }}>
                牵线记录
              </Button>
            </Badge>
            <Button size="small" type="primary" onClick={showDrawer}>
              详细资料
            </Button>
          </Space>
        );
      },
    },
  ];

  return (
    <>
      <PageContainer>
        <ProTable<TableListItem>
          headerTitle="用户列表"
          actionRef={actionRef}
          rowKey="id"
          columns={columns}
          rowSelection={{}}
          search={{
            labelWidth: 'auto',
            span: 4,
            collapsed: false,
            collapseRender: false,
            optionRender: (searchConfig, formProps, dom) => [
              <Button key='out' onClick={() => {
                //searchConfig?.form?.getFieldsValue()
              }}>
                导出
              </Button>,
              ...dom
            ]
          }}
          // columnsState={}
          request={async (params) => {
            const res = await queryMemberList({ ...params });
            return {
              data: res.result.data,
              success: true,
              total: res.result.total,
            };
          }}
        />
      </PageContainer>
      <DrawerPanel visible={visible} />
    </>
  );
};

export default MemberList;

整个package.json

{
  "name": "jilian",
  "version": "5.2.0",
  "private": true,
  "description": "An out-of-box UI solution for enterprise applications",
  "scripts": {
    "analyze": "cross-env ANALYZE=1 umi build",
    "build": "umi build",
    "deploy": "npm run build && npm run gh-pages",
    "dev": "npm run start:dev",
    "gh-pages": "gh-pages -d dist",
    "i18n-remove": "pro i18n-remove --locale=zh-CN --write",
    "postinstall": "umi g tmp",
    "lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier && npm run tsc",
    "lint-staged": "lint-staged",
    "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
    "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
    "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
    "lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto",
    "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
    "openapi": "umi openapi",
    "playwright": "playwright install && playwright test",
    "prepare": "husky install",
    "prettier": "prettier -c --write \"src/**/*\"",
    "serve": "umi-serve",
    "start": "cross-env UMI_ENV=dev umi dev",
    "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev",
    "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev",
    "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev",
    "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev",
    "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev",
    "test": "umi test",
    "test:component": "umi test ./src/components",
    "test:e2e": "node ./tests/run-tests.js",
    "tsc": "tsc --noEmit"
  },
  "lint-staged": {
    "**/*.less": "stylelint --syntax less",
    "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
    "**/*.{js,jsx,tsx,ts,less,md,json}": [
      "prettier --write"
    ]
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 10"
  ],
  "dependencies": {
    "@ant-design/charts": "^1.4.2",
    "@ant-design/icons": "^4.7.0",
    "@ant-design/pro-components": "^1.1.21",
    "@umijs/route-utils": "^2.0.0",
    "antd": "^4.20.0",
    "classnames": "^2.3.0",
    "lodash": "^4.17.0",
    "moment": "^2.29.0",
    "omit.js": "^2.0.2",
    "rc-menu": "^9.1.0",
    "rc-util": "^5.16.0",
    "react": "^17.0.0",
    "react-dev-inspector": "^1.7.0",
    "react-dom": "^17.0.0",
    "react-helmet-async": "^1.2.0",
    "umi": "^3.5.0"
  },
  "devDependencies": {
    "@ant-design/pro-cli": "^2.1.0",
    "@playwright/test": "^1.17.0",
    "@types/classnames": "^2.3.1",
    "@types/express": "^4.17.0",
    "@types/history": "^4.7.0",
    "@types/jest": "^26.0.0",
    "@types/lodash": "^4.14.0",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@types/react-helmet": "^6.1.0",
    "@umijs/fabric": "^2.11.1",
    "@umijs/openapi": "^1.6.0",
    "@umijs/plugin-blocks": "^2.2.0",
    "@umijs/plugin-esbuild": "^1.4.0",
    "@umijs/plugin-openapi": "^1.3.3",
    "@umijs/preset-ant-design-pro": "^1.3.0",
    "@umijs/preset-dumi": "^1.1.0",
    "@umijs/preset-react": "^2.1.0",
    "compression-webpack-plugin": "^10.0.0",
    "cross-env": "^7.0.0",
    "cross-port-killer": "^1.3.0",
    "detect-installer": "^1.0.0",
    "eslint": "^7.32.0",
    "file-loader": "^6.2.0",
    "gh-pages": "^3.2.0",
    "husky": "^7.0.4",
    "jsdom-global": "^3.0.0",
    "lint-staged": "^10.0.0",
    "mockjs": "^1.1.0",
    "prettier": "^2.5.0",
    "stylelint": "^13.0.0",
    "swagger-ui-dist": "^4.12.0",
    "typescript": "^4.5.0",
    "umi-serve": "^1.9.10",
    "url-loader": "^4.1.1"
  },
  "engines": {
    "node": ">=12.0.0"
  }
}

© 版本信息

  • ProComponents 版本: [1.1.21]
  • umi 版本: [3.5.32]
  • 浏览器环境
  • 开发环境 [e.g. mac OS]

codedart2018 avatar Aug 31 '22 09:08 codedart2018

以下的 Issues 可能会帮助到你 / The following issues may help you

  • [#5348][ProTable][85%]

github-actions[bot] avatar Aug 31 '22 09:08 github-actions[bot]

看了下是request loading数据的时候 button 组件上有loading撑起,导致抖动撑坏页面。希望给个参数让button变化的情况下不要变大或缩小。或者加载的时候直接用disabled把它禁用掉。禁止二次点击!

codedart2018 avatar Sep 01 '22 02:09 codedart2018

没有人关注嘛!@chenshuai2144

codedart2018 avatar Sep 06 '22 07:09 codedart2018

没人嘛!

codedart2018 avatar Sep 17 '22 07:09 codedart2018

按钮宽度边框导致的,你把查询按钮所占的格子弄得大一点

chenshuai2144 avatar Dec 27 '22 15:12 chenshuai2144

按钮宽度边框导致的,你把查询按钮所占的格子弄得大一点

具体怎么设置,感谢

YM-20191008 avatar Dec 28 '22 12:12 YM-20191008

这就关闭了?弄格子不现实,是你们loading撑坏的。可不可以手动控制loging样式不显示!

codedart2018 avatar Jan 03 '23 11:01 codedart2018