日常开发项目功能点实现
1.日常开发组件封装
1.1单组件封装及使用
// 比如封装个银行列表的组件
import React, { useState, useEffect, forwardRef } from 'react';
import { Select } from 'antd';
import { getBankGetBankListByKey } from '@/services/common';
/**
* 银行下拉
*/
const { Option } = Select;
const AreaSelect = forwardRef((props: any, _ref) => {
const [bankList, setbankList] = useState([]);
useEffect(() => {
getBankGetBankListByKey({
pageNo: 1,
pageSize: 100,
}).then(res => {
if (res.code === 0) {
setbankList(res.data);
}
});
}, []);
return (
<Select {...props} ref={_ref}>
{(bankList || []).map((item: any) => (
<Option key={item.bankID} data-item={item} value={`${item.bankID}|${item.name}`}>
{item.name}
</Option>
))}
</Select>
);
});
export default AreaSelect;
----------------------------------------------------------------------
vue和react一样,只是引用方式不同;vue需要components声明下
A文件:
import BankSelect from '@/components/BankSelect';
<FormItem {...formItemLayout} label="收款银行" className={styles.antFormItem}>
{getFieldDecorator('bankIdAndText', {
initialValue: getBankIdAndText(formObj),
rules: [{ required: true, message: '请选择收款银行' }],
})(
<BankSelect
filterOption={filterOption}
showSearch
placeholder="请选择收款银行"
onChange={(e: any, item: any) => {
onchange(e, 'bankIdAndText', item);
}}
/>,
)}
</FormItem>
1.2.inputNumber封装最大值、最小值组件,点击button进行查询
方法1
# 组件:
import React, { useRef } from 'react';
import { InputNumber, Button, message } from 'antd';
// 输入两个整数,最大值最小值
const BetweenNumber = ({
defaultValue,
onChange,
placeholder,
max,
}: {
defaultValue: number[];
onChange: any;
placeholder: string[];
max: number;
}) => {
const data = useRef({
max: 0,
min: 0,
});
function change(e: any, type: string) {
console.log(e);
data.current[type] = e || 0;
}
function click() {
console.log(data.current);
if (data.current.max < data.current.min) {
message.error('最大值不能小于最小值');
return;
}
onChange([data.current.min, data.current.max]);
}
return (
<React.Fragment>
<InputNumber
min={0}
max={max}
style={{ width: '42%', borderTopRightRadius: '0px', borderBottomRightRadius: '0px' }}
defaultValue={defaultValue[0]}
onChange={(e: any) => change(e, 'min')}
placeholder={placeholder[0] || '最小值'}
/>
<InputNumber
min={0}
max={max}
style={{
width: '42%',
borderRadius: '0px',
borderLeftWidth: '0px',
borderRightWidth: '0px',
}}
defaultValue={defaultValue[1]}
onChange={(e: any) => change(e, 'max')}
placeholder={placeholder[1] || '最大值'}
/>
<Button
type="primary"
style={{
width: '16%',
borderTopLeftRadius: '0px',
borderBottomLeftRadius: '0px',
position: 'relative',
top: '-1px',
}}
icon="search"
onClick={click}
/>
</React.Fragment>
);
};
export default BetweenNumber;
----------------------------------------------------------------------
A文件:
import BetweenNumber from '@/pages/kcmanage/component/BetweenNumber';
<Col md={9} sm={12}>
<BetweenNumber
placeholder={['最小库存天数', '最大库存天数']}
defaultValue={[]}
onChange={(value: any) => handleFilter(value, 'my_age')}
style={{ width: '100%' }}
/>
</Col>
// 筛选fn
const handleFilter = (value: any, key: any, item: any) => {
switch (key) {
// 获取value数组的第一项和第二项也就是最小值和最大值。
case 'my_age':
info.startAge = value[0] || '';
info.endAge = value[1] || '';
break;
default:
info[key] = value;
}
dispatch({
type: 'xxxx/yyyyy',
payload: {
...info,
pageIndex: 1,
pageSize: 20,
},
});
};
方法2
# 组件
import React, { useEffect, useState, useRef } from 'react';
import { InputNumber } from 'antd';
import { InputNumberProps } from 'antd/lib/input-number/index.d';
// 数值区间组件
// 组件限制较少,允许只输入最大值或者最小值,如果同时输入了最大最小会做判断,是否交换值
interface Props
extends Omit<InputNumberProps, 'value' | 'defaultValue' | 'onChange' | 'placeholder'> {
defaultValue?: number[];
value?: number[];
onChange?: (arg: any[]) => void;
placeholder?: string[];
max?: number;
}
interface Data {
max?: number;
min?: number;
}
const styles = { width: '50%', borderTopRightRadius: '0px', borderBottomRightRadius: '0px' };
// 验证数字区间
export const validatorNumberRange = (value, fieldName) => {
if (!value) {
return;
}
let arr = value;
if (!Array.isArray(value)) {
arr = [];
}
if (Number.isNaN(Number(arr[0]))||arr[0]===null) {
return `请填写${fieldName}最小值`;
}
if (Number.isNaN(Number(arr[1]))||arr[1]===null) {
return `请填写${fieldName}最大值`;
}
};
const Index = ({
defaultValue = [],
onChange = () => {},
placeholder = ['最小值', '最大值'],
value = [],
max,
}: Props) => {
const [data, setdata] = useState<Data>({ max: undefined, min: undefined });
const d = useRef<Data>({ max: undefined, min: undefined });
useEffect(() => {
if (Array.isArray(value)) {
const D = { min: value[0], max: value[1] };
setdata(D);
d.current = D;
}
}, [JSON.stringify(value)]);
function change(e: any, type: string) {
const D = { ...data, [type]: !Number.isNaN(e) ? e : undefined };
setdata(D);
d.current = D;
}
function check() {
// 最大最小都有值,判断一下俩值得大小就得了
let { max: currentMax, min: currentMin } = d.current;
currentMax = Number(currentMax);
currentMin = Number(currentMin);
if (!Number.isNaN(currentMax) && !Number.isNaN(currentMin)) {
let D = null;
// 最大值是0,就忽略比较
if (currentMax === 0) {
D = { max: undefined, min: currentMin };
} else if (currentMax! < currentMin!) {
// 大小互换
D = { max: currentMin, min: currentMax };
}
if (D) {
setdata(D);
d.current = D;
}
}
}
const onBlur = () => {
check();
onChange([d.current.min, d.current.max]);
};
return (
<React.Fragment>
<InputNumber
min={0}
max={max}
style={styles}
defaultValue={defaultValue[0]}
onChange={(e: any) => change(e, 'min')}
placeholder={placeholder[0]}
value={data.min}
onBlur={onBlur}
/>
<InputNumber
min={0}
max={max}
style={{ ...styles, borderLeft: '0px' }}
defaultValue={defaultValue[1]}
onChange={(e: any) => change(e, 'max')}
placeholder={placeholder[1]}
value={data.max}
onBlur={onBlur}
/>
</React.Fragment>
);
};
export default Index;
----------------------------------------------------------------------
# A文件:
import NumberRange, { validatorNumberRange } from '@/components/NumberRange';
# 使用:
<FormItem labelCol={{ span: 6 }} wrapperCol={{ span: 15 }} label="允许修改区间">
{form.getFieldDecorator('carOwnerPhone', {
// initialValue: detailInfo.procurementDealer.dealerPhone,
rules: [
{ required: true, message: '请输入允许修改区间!' },
{
validator: (_, value, callBack) => {
callBack(validatorNumberRange(value, '允许修改区间'));
},
},
],
})(<NumberRange placeholder={['最小修改值', '最大修改值']} />)}
</FormItem>
初始值:
const {
minStockAge,
maxStockAge,
...fanalValues1
} = fanalValues;
fanalValues1.stockAge = (minStockAge || maxStockAge) ? [minStockAge, maxStockAge] : undefined;
form.setFieldsValue(fanalValues1);
<Tooltip title="库存天数">
<Col {...cols}>
<Form.Item >
{form.getFieldDecorator('stockAge')(<NumberRange placeholder={['库存天数最小值', '库存天数最大值']} />)}
</Form.Item>
</Col>
</Tooltip>
1.3.Antd结合upload实现文件上传
// service/common
export const uploadFileService = `${HOST['/base']}/apixxxx/yyyyy/uploadSave`;
A文件:
import { uploadFileService } from '@/services/common';
import { Button, Form, Modal, message, Upload, Spin } from 'antd';
const uploadProps = {
name: 'file',
action: uploadFileService,
accept: '.xls,.xlsx,.excel', // 允许上传的文件格式
showUploadList: false,
data: { type }, // 除了file还需传的参数,在这个data里写
headers: {
Authorization: getCookieValue('activePassportID'),
},
onRemove: () => {},
beforeUpload: () => {
// //文件类型校验----由于我这里不需要做太多校验,所以格式上的判断包括文件大小的判断就不额外添加了
// const fileType = info.name.split('.').pop();
// if (fileType !== 'xlsx') {
// message.error(`上传失败:上传文件格式非.xslx`);
// }
// return false;
RefModal = Modal.info({
title: '批量导入中 请勿关闭弹窗...',
content: (
<div style={{ paddingTop: 20 }}>
<Spin />
</div>
),
});
},
onChange: ({ file }) => {
if (file.status === 'done' && file.response.code === 0) {
RefModal.destroy();
RefModal = null;
onUpdate();// 上传接口成功后调刷新列表方法
message.success(`${file.name} - 上传成功`);
} else if (
file.status === 'error' ||
(file.status === 'done' && file?.response?.code !== 0)
) {
message.error(`${file.name} - ${file?.response.message}`);
RefModal.destroy();
RefModal = null;
}
},
};
<Upload {...uploadProps}>
<Button style={styleButtonMargin}>
<icon type="upload" /> 批量导入
</Button>
</Upload>
在上传中会有modal友好提示,让用户稍后再操作
需要注意:上传这样的接口无需套request,否则会出现两个请求,一个是http://xxxx/api/xxx,另一个是localhost:8080/url路由/上传请求