在列表中新增修改很常见,react中在新增修改弹窗信息的时候很多时候会遇到点击了列表信息但是弹窗信息还是展示的第一次点击的那条信息,数据并没有更新,点击新增的时候数据也没有清除。在不了解react机制的时候这会带来很大的麻烦和不便,下面我就用两种方式来实现点击列表更新弹窗的信息
import {
addOrUpdSysUser,
assignUserRoles,
deleteUser,
getUserList,
} from '@/pages/Configurate/service';
import { PlusOutlined } from '@ant-design/icons';
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { Button, message, Modal, Space, Tag } from 'antd';
import React, { useRef, useState } from 'react';
import UserForm from '../components/UserForm';
import * as LIST from '../data';
const User: React.FC<Partial<LIST.UserItem>> = () => {
const actionRef = useRef<ActionType>(null);
const [formValue, setFormValue] = useState<Partial<LIST.UserItem>>({});
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [isModalOpenState, setIsModalOpenState] = useState<boolean>(false);
const [isModalOpenAccess, setIsModalOpenAccess] = useState<boolean>(false);
const [role, setRole] = useState<string[]>([]);
const [formAccess, setFormAccess] = useState<Record<string, any>>({});
const columns: ProColumns<LIST.UserItem>[] = [
{
dataIndex: 'index',
valueType: 'indexBorder',
width: 48,
},
{
title: '用户名称',
dataIndex: 'username',
copyable: true,
ellipsis: true,
},
{
title: '联系方式',
dataIndex: 'phone',
ellipsis: true,
search: false,
},
{
title: '昵称',
dataIndex: 'nickname',
ellipsis: true,
search: false,
},
{
title: 'openid',
dataIndex: 'openid',
ellipsis: true,
search: false,
},
{
title: '邀请码',
dataIndex: 'code',
ellipsis: true,
search: false,
},
{
title: '权限',
dataIndex: 'sysRoleList',
ellipsis: true,
search: false,
render: (_, record) => (
<Space>
{record.sysRoleList &&
record.sysRoleList.map(({ roleName, roleKey }, index) => (
<Tag color={roleKey ? 'success' : 'processing'} key={index}>
{roleName}
</Tag>
))}
</Space>
),
},
{
title: '更新时间',
dataIndex: 'createTime',
valueType: 'dateTime',
ellipsis: true,
search: false,
},
{
title: '操作',
valueType: 'option',
key: 'option',
width: 166,
search: false,
render: (text, record) => [
<a
key="editablee"
disabled={record.roleIdList.filter((item) => item === '1').length > 0 ? true : false}
onClick={() => {
setFormAccess({ roleList: record.roleIdList, userId: record.id });
setIsModalOpenAccess(true);
let arr: string[] = [];
arr = record.roleIdList.filter((item) => item === '1' || item === '5');
setRole(arr);
}}
>
权限
</a>,
<a
key="editable"
onClick={() => {
setFormValue(record);
setIsModalOpenState(true);
}}
>
编辑
</a>,
<a
onClick={() => {
Modal.confirm({
title: '删除',
content: '确认要删除此数据吗?',
okText: '确定',
cancelText: '取消',
onOk: async () => {
const { code } = await deleteUser(record.id as number);
if (code === 200) {
message.success('删除成功');
actionRef?.current?.reload();
}
},
});
}}
key="view"
>
删除
</a>,
],
},
];
return (
<>
<PageContainer title={false}>
<ProTable<LIST.UserItem>
columns={columns}
actionRef={actionRef}
cardBordered
//自定义参数
request={async (params = {}) => {
const { data } = await getUserList(params);
return data;
}}
editable={{
type: 'multiple',
}}
columnsState={{
persistenceKey: 'pro-table-singe-demos',
persistenceType: 'localStorage',
onChange(value) {
console.log('value: ', value);
},
}}
rowKey="id"
search={{
labelWidth: 'auto',
}}
options={{
setting: {
listsHeight: 400,
},
}}
form={{
syncToUrl: (values, type) => {
if (type === 'get') {
return {
...values,
};
}
return values;
},
}}
pagination={{
defaultPageSize: 10,
onChange: (page) => console.log(page),
}}
dateFormatter="string"
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
setFormValue({});
setIsModalOpen(true);
}}
type="primary"
>
新建
</Button>,
]}
/>
<UserForm
value={{}}
handleCancel={(flag) => {
setFormValue({});
setIsModalOpen(flag);
}}
handleOk={async (arg) => {
const { code, msg } = await addOrUpdSysUser(arg);
if (code === 200) {
message.success(msg);
setIsModalOpen(false);
//重置form表单数据触发render函数
setFormValue({});
if (actionRef?.current) {
actionRef.current.reload();
}
}
}}
isModalOpen={isModalOpen}
/>
{formValue && Object.keys(formValue).length ? (
<UserForm
handleCancel={(flag) => {
setIsModalOpenState(flag);
setFormValue({});
}}
handleOk={async (arg) => {
const { code, msg } = await addOrUpdSysUser(arg);
if (code === 200) {
message.success(msg);
setIsModalOpenState(false);
//重置form表单数据触发render函数
setFormValue({});
if (actionRef?.current) {
actionRef.current.reload();
}
}
}}
isModalOpen={isModalOpenState}
value={formValue}
/>
) : null}
</PageContainer>
</>
);
};
export default User;
/*
* @Date: 2023-05-16 17:39:50
* @Auth: [email protected]
* @LastEditors: [email protected]
* @LastEditTime: 2023-05-29 14:46:15
* @FilePath: \aggregation-system\src\pages\Configurate\components\UserForm.tsx
*/
import { Checkbox, Form, Input, Modal, Select } from 'antd';
import React, { useState } from 'react';
export type IProps = {
isModalOpen: boolean;
handleOk: (value: any) => Promise<void>;
handleCancel: (flag: boolean) => void;
value: any;
};
const { Option } = Select;
const UserForm: React.FC<IProps> = (props) => {
const { value, handleOk: handleOk, handleCancel: handleCancel, isModalOpen } = props;
const [form] = Form.useForm();
const [roleIdList, setRoleList] = useState<Array<any>>(value.roleIdList);
const handleSubmit = async () => {
const res: Record<string, any> = await form.validateFields();
handleOk({ ...value, ...res });
};
const getContent = () => {
return (
<>
<Form.Item
label="用户名"
hasFeedback
name="username"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item
label="手机号"
hasFeedback
name="phone"
rules={[{ required: false, message: '请输入手机号' }]}
>
<Input placeholder="请输入手机号" />
</Form.Item>
<Form.Item
label="城市"
hasFeedback
name="city"
rules={[{ required: false, message: '请输入城市' }]}
>
<Input placeholder="请输入城市" />
</Form.Item>
{roleIdList && roleIdList.length > 0 && roleIdList.includes('5') ? (
<Form.Item
label="内外部"
hasFeedback
name="label"
rules={[{ required: false, message: '请选择类型' }]}
>
<Select placeholder="请选择类型">
<Option value={1}>内部</Option>
<Option value={2}>外部</Option>
</Select>
</Form.Item>
) : null}
<Form.Item name="roleIdList" label="权限">
<Checkbox.Group
onChange={(arg) => {
setRoleList(arg);
}}
>
{value.roleIdList &&
value.roleIdList.length &&
(value.roleIdList.includes('2') ||
value.roleIdList.includes('3') ||
value.roleIdList.includes('4')) ? (
<>
<Checkbox value="2" style={{ lineHeight: '32px' }}>
商户
</Checkbox>
<Checkbox value="3" style={{ lineHeight: '32px' }}>
司机
</Checkbox>
<Checkbox value="4" style={{ lineHeight: '32px' }}>
游客
</Checkbox>
</>
) : (
<>
<Checkbox value="1" style={{ lineHeight: '32px' }}>
超级管理员
</Checkbox>
<Checkbox value="5" style={{ lineHeight: '32px' }}>
业务员
</Checkbox>
</>
)}
</Checkbox.Group>
</Form.Item>
</>
);
};
return (
<>
<Modal
title={value.id ? '修改' : '新增'}
width="50%"
open={isModalOpen}
onOk={handleSubmit}
destroyOnClose
onCancel={() => handleCancel(false)}
>
<Form
name="basic"
labelCol={{ span: 5 }}
wrapperCol={{ span: 15 }}
initialValues={value}
autoComplete="off"
form={form}
>
{getContent()}
</Form>
</Modal>
</>
);
};
export default UserForm;
这种方式就是通过判断在点击修改的数据对formValue的值判断只有这个值的key长度不为零才渲染修改的组件,这里采用了两个同一个组件的方式,通过不同的弹窗状态去判断显示是新增还是修。
弹窗中就设置form的initValues就是穿过来的formValue的值,如果是新增的时候就是一个空对象,然后新增的每一项的值填写一个才有一个,如果需要默认值的话就需要设置对象合并{默认值,…value}。
import { PlusOutlined } from '@ant-design/icons';
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { Button, Image, message, Modal, Space, Tag } from 'antd';
import React, { useRef, useState } from 'react';
import setting from '../../../../config/defaultSettings';
import * as LIST from '../data';
import { addOrUpdGoods, deleteGood, putOrLower, queryGoodsList } from '../service';
import MallForm from './components/MallForm';
const Car: React.FC<Partial<LIST.GoodItem>> = () => {
const actionRef = useRef<ActionType>(null);
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [formValue, setFormValue] = useState();
const columns: ProColumns<LIST.GoodItem>[] = [
{
dataIndex: 'index',
valueType: 'indexBorder',
width: 48,
},
{
title: '商品名称',
dataIndex: 'title',
key: 'condition',
copyable: true,
ellipsis: true,
},
{
title: '商品封面',
dataIndex: 'coverImg',
ellipsis: true,
search: false,
render: (text, record) => {
let srcImage = record.coverImg || '';
if (srcImage?.indexOf('http') > -1) {
srcImage = srcImage?.substring(srcImage?.indexOf('profile') - 1);
}
return (
<>
<Image width={30} src={setting.url + srcImage} />
</>
);
},
},
{
title: '商品详情',
dataIndex: 'description',
ellipsis: true,
search: false,
},
{
title: '商品数量',
dataIndex: 'num',
ellipsis: true,
search: false,
},
{
title: '兑换积分个数',
dataIndex: 'score',
ellipsis: true,
search: false,
},
{
title: '商品剩余库存',
dataIndex: 'stockNum',
ellipsis: true,
search: false,
},
{
title: '是否限制商品兑换时间',
dataIndex: 'isLimit',
ellipsis: true,
search: false,
width: 162,
render: (_, record) => (
<span color="success">{record.isLimit === '1' ? '限制' : '不限制'}</span>
),
},
{
title: '商品状态',
dataIndex: 'goodsState',
ellipsis: true,
valueType: 'select',
valueEnum: {
'': { text: '全部', status: '' },
'1': { text: '上架', status: '1' },
'2': { text: '下架', status: '2' },
},
render: (_, record) => (
<Space>
<Tag color="success">{record.goodsState === '1' ? '上架' : '下架'}</Tag>
</Space>
),
},
{
title: '兑换开始时间',
dataIndex: 'convertStartTime',
valueType: 'dateTime',
ellipsis: true,
search: false,
width: 162,
},
{
title: '兑换结束时间',
dataIndex: 'convertEndTime',
valueType: 'dateTime',
ellipsis: true,
search: false,
width: 162,
},
{
title: '预约时间',
valueType: 'dateTimeRange',
ellipsis: true,
hideInTable: true,
width: 162,
search: {
transform: (value) => {
if (!value) {
return '';
}
return {
startTime: value[0],
endTime: value[1],
};
},
},
},
{
title: '备注',
dataIndex: 'remark',
ellipsis: true,
search: false,
},
{
title: '操作',
valueType: 'option',
key: 'option',
width: 126,
render: (text, record) => [
<a
onClick={() => {
setFormValue(record as any);
// setIsModalOpenState(true);
setIsModalOpen(true);
}}
key="view"
>
编辑
</a>,
<a
key="editablee"
style={{ color: 'red' }}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定要删除此条数据?',
okText: '确定',
cancelText: '取消',
onOk: async () => {
const { code } = await deleteGood(record?.id);
if (code === 200) {
message.success('删除成功');
actionRef?.current?.reload();
}
},
});
}}
>
删除
</a>,
<>
<a
onClick={() => {
Modal.confirm({
title: `${record.goodsState === '1' ? '下架' : '上架'}`,
content: `确定要${record.goodsState === '1' ? '下架' : '上架'}?`,
okText: '确定',
cancelText: '取消',
onOk: async () => {
const { code } = await putOrLower(record?.id);
if (code === 200) {
message.success(`${record.goodsState === '1' ? '下架' : '上架'}成功`);
actionRef?.current?.reload();
}
},
});
}}
key="viewe"
>
{record.goodsState === '1' ? '下架' : '上架'}
</a>
</>,
],
},
];
return (
<>
<PageContainer title={false}>
<ProTable<LIST.GoodItem>
columns={columns}
actionRef={actionRef}
cardBordered
//自定义参数
params={{}}
request={async (params = {}) => {
const { data } = await queryGoodsList(params);
return data;
}}
editable={{
type: 'multiple',
}}
columnsState={{
persistenceKey: 'pro-table-singe-demos',
persistenceType: 'localStorage',
onChange(value) {
console.log('value: ', value);
},
}}
rowKey="id"
search={{
labelWidth: 'auto',
}}
options={{
setting: {
listsHeight: 400,
},
}}
form={{
syncToUrl: (values, type) => {
if (type === 'get') {
return {
...values,
};
}
return values;
},
}}
pagination={{
defaultPageSize: 10,
onChange: (page) => console.log(page),
}}
dateFormatter="string"
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
setFormValue(undefined);
setIsModalOpen(true);
}}
type="primary"
>
新建
</Button>,
]}
/>
<MallForm
value={formValue || {}}
isModalOpen={isModalOpen}
handleCancel={(arg) => {
setIsModalOpen(arg);
setFormValue(undefined);
}}
handleSubmit={async (arg, resetFields) => {
console.log(arg);
const { code, msg } = await addOrUpdGoods({ ...arg });
if (code === 200) {
message.success(msg);
setIsModalOpen(false);
setFormValue(undefined);
resetFields();
if (actionRef?.current) {
actionRef.current.reload();
}
}
}}
/>
</PageContainer>
</>
);
};
export default Car;
import NumericInput from '@/components/Input/input';
import Tage from '@/components/Tag/index';
import Upcload from '@/components/upcload';
import type { RadioChangeEvent } from 'antd';
import { DatePicker, Form, Input, Modal, Radio, Select } from 'antd';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import React, { useEffect, useState } from 'react';
import * as LIST from '../../data';
export type IProps = {
value: Partial<LIST.GoodItem>;
isModalOpen: boolean;
handleCancel: (flag: boolean) => void;
handleSubmit: (arg: Partial<LIST.GoodItem>, resetFields: () => void) => Promise<void>;
};
const { Option } = Select;
const CarForm: React.FC<IProps> = (props) => {
const { value, isModalOpen, handleCancel, handleSubmit } = props;
const [isLimit, setIsLimit] = useState<string>('1');
const [form] = Form.useForm();
const resetFields = () => {
form.resetFields();
};
useEffect(() => {
setIsLimit(value.isLimit ? value.isLimit : '1');
}, [value]);
useEffect(() => {
resetFields();
form.setFieldsValue({
labelList: [],
...value,
convertStartTime: value.convertStartTime ? dayjs(value.convertStartTime) : '',
convertEndTime: value.convertEndTime ? dayjs(value.convertEndTime) : '',
num: value.num ? value.num + '' : '',
stockNum: value.stockNum ? value.num + '' : '',
});
}, [isModalOpen, value]);
//清除验证数据
const handleSubmitOk = () => {
form.validateFields().then((res: Record<string, any>) => {
//验证通过后form获取值的数据
if (res.isLimit === '1') {
handleSubmit(
{
...value,
...res,
convertStartTime: res['convertStartTime'].format('YYYY-MM-DD HH:mm:ss'),
convertEndTime: res['convertEndTime'].format('YYYY-MM-DD HH:mm:ss'),
},
resetFields,
);
} else {
handleSubmit(
{
...value,
...res,
},
resetFields,
);
}
});
};
const handleOnChangeLimit = (arg: RadioChangeEvent) => {
// setFormValue({ ...formValue, isLimit: arg?.target?.value });
setIsLimit(arg?.target.value);
};
const getContent = (value: Partial<LIST.GoodItem>) => {
console.log(value);
return (
<>
<Form.Item
label="商品名称"
hasFeedback
name="title"
rules={[{ required: true, message: '请输入商品名称' }]}
>
<Input placeholder="请输入商品名称" />
</Form.Item>
<Form.Item
label="商品详情"
hasFeedback
name="description"
rules={[{ required: true, message: '请输入商品详情' }]}
>
<Input placeholder="请输入商品详情" />
</Form.Item>
<Form.Item
label="商品数量"
hasFeedback
name="num"
rules={[{ required: true, message: '请输入商品数量' }]}
>
<NumericInput placeholder="请输入商品数量" value={value.num + ''} />
</Form.Item>
<Form.Item
label="兑换积分个数"
hasFeedback
name="score"
rules={[{ required: true, message: '请输入兑换积分个数' }]}
>
<NumericInput placeholder="请输入兑换积分个数" value={value.score + ''} />
</Form.Item>
<Form.Item
label="商品状态"
hasFeedback
name="goodsState"
rules={[{ required: true, message: '商品状态' }]}
>
<Select placeholder="请选择商品状态">
<Option value="1">上架</Option>
<Option value="2">下架</Option>
</Select>
</Form.Item>
<Form.Item
label="商品封面"
name="coverImg"
rules={[{ required: true, message: '商品封面' }]}
>
<Upcload type="string" fileNumber={2} />
</Form.Item>
<Form.Item
label="商品图片集合"
name="goodsImgList"
rules={[{ required: true, message: '商品图片集合' }]}
>
<Upcload fileNumber={1} />
</Form.Item>
<Form.Item
label="标签"
hasFeedback
name="labelList"
rules={[{ required: false, message: '请输入标签' }]}
>
<Tage />
</Form.Item>
<Form.Item name="isLimit" initialValue="1" label="是否限制商品兑换时间">
<Radio.Group onChange={(arg) => handleOnChangeLimit(arg)}>
<Radio value="1">限制</Radio>
<Radio value="-1">不限制</Radio>
</Radio.Group>
</Form.Item>
{isLimit === '1' ? (
<>
<Form.Item
rules={[{ required: isLimit === '1', message: '商品兑换开始时间' }]}
name="convertStartTime"
label="商品兑换开始时间"
>
<DatePicker style={{ width: '100%' }} showTime format="YYYY-MM-DD HH:mm:ss" />
</Form.Item>
<Form.Item
rules={[{ required: isLimit === '1', message: '商品兑换结束时间' }]}
name="convertEndTime"
label="商品兑换结束时间"
>
<DatePicker style={{ width: '100%' }} showTime format="YYYY-MM-DD HH:mm:ss" />
</Form.Item>
</>
) : null}
<Form.Item
label="备注"
hasFeedback
name="remark"
rules={[{ required: false, message: '请输入备注' }]}
>
<Input placeholder="请输入备注" />
</Form.Item>
</>
);
};
return (
<>
<Modal
title={value.id ? '修改' : '新增'}
open={isModalOpen}
width="50%"
destroyOnClose
onOk={handleSubmitOk}
onCancel={() => handleCancel?.(false)}
>
<Form
name="basic"
labelCol={{ span: 5 }}
wrapperCol={{ span: 15 }}
autoComplete="off"
form={form}
// initialValues={formValue}
// onValuesChange={onValuesChange}
>
{getContent(value)}
</Form>
</Modal>
</>
);
};
export default CarForm;
这种方式通过form.resetFields();form.setFieldsValue方式设置form的值