总览

这里了一些最重要的方法,其他细节放到每个模块中了。

1. 目录导航

  • AntDesign:记录 Ant 控件常用方法
  • ProComponents:记录 Pro 控件常用方法
  • AntDesignPro:记录如何改造AntDesignPro
  • AntChart:记录常用图表的使用方法
  • DUmi:撰写文档的常用方法

2. 动态查询

例如下图,有很多模块需要如下功能,有几个查询条件,可以根据某个字段进行排序。

在实际的过程,希望后台的API接口是一个通用的,可以通过前台传递过去的参数,来生成相应的查询与排序,当然也带分页功能。

所以动态查询是一个前后台贯穿的功能模块。

2.1 后台接口说明

这里只针对单表简单Sql的通用查询接口,简单Sql后台会自动生成相关代码,对复杂Sql,后台需要单独撰写函数。

后台接收的参数有:

  • Select:要查询的字段,如果为空,那么就查询全部,或者后台默认的字段。
  • Where:检索条件,如果为空,就没有检索条件,或者按照默认的检索条件来检索。
  • Order:要排序的条件
  • 分页参数:这里多少了,主要是当前页与每页的代码

后台返回

如果是分页,就返回一个符合 Ant 的分页数据格式,如果不分页,就返回一个数组。

如果是动态的 Select,那么返回的是一个 Map 数组,当然这个 Map 数组在前端会被转换成一个对象数组。

难点是 Where 条件

where 的情况很多,例如有 Like,大于等于,日期区间查询等不同的查询方式,那么就需要后台能只能判断。

所以后台设定了下面的规则:

字段+检索条件 。 例如memberName_liken:'小明' , 会自动转成 member_name liken '%小明%'

参数说明
memberName:'小明'member_name = '小明'
memberName_like:'小明'member_name like '%小明%'
gmtCreate_between:'2021-02-09,2022-02-13'gmt_create BETWEEN '2021-02-09' and '2022-02-13'
storeEndTime_greater: '2019-02-09'store_end_time > '2019-02-09'

2.2 后台 Where 参数

可以输入的后缀:

  • equal

  • nequal

  • greater

  • egreater

  • less

  • eless

  • in

  • nin

  • between

  • nbetween

  • like

  • nlike

  • isnull

  • nisnull

2.3 前端实现案例

例如在列表页中,有一个时间区间查询的功能,现在如何将时间区间查询给实现了。

前提条件是后台的 service 查询函数已经做好的,这个函数一般是用代码生成器生成的。例如:

/**
* 经验值Log列表
* @param data 参数 可以传入分页
*/
export async function getExpPointsLogList(data: API.SearchListParams) {
return request<API.ResponseInfo<API.ResponseListData<API.ExpPointsLog>>>(
`${prifix}/getExpPointsLogList`,
{
method: 'POST',
data,
},
);
}

其中API.SearchListParams 封装了一个通用的查询接口。

下面需要经过如下步骤来实现:

① 引入公用函数

这两个函数,会进行 where 与 order 转换。详细函数说明,见代码。

import { getOrderStr, getWheres } from '@/services/Common';

② 定义 where 转换规则

将 ant 返回的规则,转换成后台可以识别的 where 条件。

方法 1:做一个转换规则

  • memberName按照 like 查询
  • expDesc按照 like 查询
/** 定义一个`whereNameRules` 转换的规则,其中字段名必须与数据库中的一致。 */
const whereNameRules = {
memberName: 'memberName_like',
expDesc: 'expDesc_like',
};

方法 2:在 column 定义中转换

取消默认的查询,然后自定义一个查询条件,并按照特定名称返回。

{
title: '添加时间',
dataIndex: 'gmtCreate',
search: false,
},
{
title: '添加时间',
dataIndex: 'gmtCreate',
valueType: 'dateRange',
hideInTable: true,
search: {
transform: (values) => {
return {
gmtCreate_between: values.join(','),
};
},
},
},

③ 定义 column

按照正常的 column 定义就可以了,除非是想在检索框 自定义内容。 例如下面:

{
{
title: '会员名称',
dataIndex: 'memberName',
},
...........................
{
title: '描述',
dataIndex: 'expDesc',
},
}

④ 调用检索函数

这里使用了getWheresgetOrderStr,将 Ant 的参数,转换成后台可以识别的参数,实现了动态查询。

<ProTable<API.ExpPointsLog>
columns={columns}
rowKey="expId"
// getWheres 与 getOrderStr 这两个函数,会按照规则,转换成后台能统一识别的查询条件
request={async (params, sort) => {
const result = await getExpPointsLogList({
current: params.current,
pageSize: params.pageSize,
wheres: getWheres(params, whereNameRules),
order: getOrderStr(sort),
});
return result.data;
}}
/>

3. 重载 AntDesign 样式

这里的重载,是局部重载,不是全局化的重载 AntDesign 样式。

刚开始不熟悉,使用了很多中方案,不同方案有不同的使用场景。

名称应用场景特点
方案一很多 page 会用到全局,需指定 class 名才生效
方案二很少 page 会用到,page 中的相同组件样式一样局部,无需指定 class 名,就可生效
方案三很少 page 会用到,page 中相同组件的样式需要单独定制局部,需指定 class 名才生效

如果是很少 page 用到,为了安全,可以使用方案三

方案一:全局设置-有类名

global.less中设置,然后在tsx文件中,直接使用className就可以了。例如:

// 感觉pro-card作为搜索框,太宽了,所以修改了宽度
.customProCard {
.ant-pro-card-body {
padding-top: 20px;
padding-bottom: 1px;
}
}

使用方法:直接引用就可以了

<ProCard className="customProCard">
..............
</ProCard>

方案二:单独设置-无类名

不修改总体的样式,而是自有模块的 less 中单独配置

定义方法

src\pages\dashboard\summarize\components\IntroduceRow\index.less 可以看这个文件.

// 重载了ant-pro-card-body的样式
:global(.ant-pro-card-body) {
padding-top: 20px !important;
padding-bottom: 8px !important;
}

使用方法:直接 import 就可以了

import styles from './index.less';

方案三:单独设置-有类名

与上面的方案唯一的区别是,需要手工输入类名才生效。为啥会用到这种模式,看下图:

有两个card,想让两个card下边框对齐,但是由于右侧添加了按钮,所以无法对齐。这时候需要单独修改左侧card的样式,这时候要手工的指定样式,另外这个样式不会被广泛使用,所以就放在了自己单独的 less 文件中了。

定义的方法

在方案二的外围又包了一层 class 名称

@import '~antd/es/style/themes/default.less';
.customerAntCardExtra {
:global {
.ant-card-extra {
padding: 10px 0 10px 0;
}
}
}

使用方法

return (
<Card
title="销售额类别占比"
style={{ height: '100%' }}
bordered={false}
className={styles.customerAntCardExtra}
extra={
<div>
<Radio.Group
value={salesType}
onChange={e => {
radioChange(e.target.value);
}}
>
<Radio.Button value="all">全部渠道</Radio.Button>
<Radio.Button value="online">线上</Radio.Button>
<Radio.Button value="stores">门店</Radio.Button>
</Radio.Group>
</div>
}
>
<div>销售额</div>
<PieSales data={salesPieData} />
</Card>
);

4. 样式变量

本章节的应用背景,这种用法比较复杂,使用过程中,要多实验几次。

这种情况在Antchart中会常用,经常将一个css变量传入到组件中,例如下面例子:

<StatisticCard
statistic={{
title: <Title title="总销售额" desc="指标说明" />,
value: 126560,
valueStyle,
prefix: '¥',
description: (
<Space>
<Statistic title="实际完成度" value="82.3%" />
<Statistic title="当前目标" value="¥6000" />
</Space>
),
}}
style={{ width: 268 }}
/>

① 普通模式

less中定义,然后在tsx中引用

index.less

.total {
height: 38px;
margin-top: 4px;
margin-bottom: 0;
overflow: hidden;
color: @heading-color; // 这里不能有变量,不然后报错,后面会将如何引入变量
font-size: 30px;
line-height: 38px;
white-space: nowrap;
text-overflow: ellipsis;
word-break: break-all;
}

如何引用index.less 中的 totla呢?

import styles from './index.less';
// 在上面的例子中,可以将valueStyle赋值
valueStyle: styles.total;

② 变量模式

tsx中定义一个变量,然后在后面就可以使用了。

const valueStyle: React.CSSProperties = {
height: 38,
marginTop: 4,
marginBottom: 0,
overflow: 'hidden',
fontSize: 30,
fontWeight: 450,
};

③ less 中使用变量

如果在less中引用antDesign的变量,如何使用呢?

/* style.less */
@import '~antd/es/style/themes/default.less';
:export {
headingColor: @heading-color;
}
// index.js
import styles from './style.less';
const valueStyle = {
height: 38,
marginTop: 4,
marginBottom: 0,
overflow: 'hidden',
fontSize: 30,
fontWeight: 450,
color: styles.headingColor;
};