Commit 6bd5a22d authored by guang.wu's avatar guang.wu

fix: 添加 proForm 高级表单示例

parent 8ab34711
......@@ -5,20 +5,20 @@ import React from 'react';
import { Modal } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import { apiEnterprisePickSelf } from '../../service';
import { mealSections } from '../../staticData/index';
import { apiEnterprisePickSelf } from './service';
import { mealSections } from './staticData';
// 获取自提点列表
export const getPickSelf = async (setPickSelfList, setVisible) => {
export const getPickSelf = async () => {
const res = await apiEnterprisePickSelf({});
if (res && res.data && res.data.records) {
const data = res.data.records;
const json = {};
data.forEach(item => {
json[item.id] = item.pickselfName;
});
setPickSelfList(json);
setVisible(true);
return data.map(item => ({
label: item.pickselfName,
value: item.id,
}));
}
return [];
};
// 风险提示
......@@ -95,7 +95,7 @@ const transformMealLimit = mealLimit => {
/**
* 3. 数据模型转换-接口获取数据转换为表单数据
*/
export const transformToFormData = data => {
export const transformVOToFormData = data => {
const {
hideImage,
hidePrice,
......@@ -130,15 +130,13 @@ export const transformToFormData = data => {
formData.mealTimePeriod = mealTimePeriodArr;
formData.mealLimit = mealLimitMap;
formData.mealTimePeriodMap = mealTimePeriodMap;
console.log('formData :>> ', formData);
return formData;
};
/*
* 5. 表单数据转换-表单数据转换为接口数据
*/
export const transformToApiParams = async (res, selectedMealTypes, meals) => {
console.log('res :>> ', res);
export const transformFormDataToDTO = async (res, selectedMealTypes, selectedMealSections) => {
const params = {
hideImage: 0, // 隐藏图片:默认0 不隐藏 必传
hidePrice: 0, // 隐藏价格:默认0 不隐藏 必传
......@@ -155,7 +153,7 @@ export const transformToApiParams = async (res, selectedMealTypes, meals) => {
const arr = [];
res.mealTimePeriod &&
res.mealTimePeriod.forEach(item => {
if (item && meals[item.mealPeriodType]) {
if (item && selectedMealSections[item.mealPeriodType]) {
const obj = { ...item };
obj.beginTime = moment(obj.time[0]).format('HH:mm');
obj.endTime = moment(obj.time[1]).format('HH:mm');
......@@ -181,13 +179,11 @@ export const transformToApiParams = async (res, selectedMealTypes, meals) => {
* mealPeriodType 餐段类型:(1早餐,2午餐,4晚餐)
* mealType 餐品类型:(1外卖 2 自助餐 4到店)
*/
console.log('res.mealLimit :>> ', res.mealLimit);
console.log('selectedMealTypes :>> ', selectedMealTypes);
const limits = [];
res.mealLimit &&
Object.keys(res.mealLimit).forEach(item => {
const mealPeriodType = item.replace('limit', '');
if (meals[mealPeriodType]) {
if (selectedMealSections[mealPeriodType]) {
const json = {
mealPeriodType,
limit: [],
......@@ -204,6 +200,5 @@ export const transformToApiParams = async (res, selectedMealTypes, meals) => {
}
});
params.mealLimit = limits;
console.log(params, '.....');
return params;
};
import React from 'react';
import { Checkbox } from 'antd';
import { mealSections } from '../staticData';
const MealCheckbox = props => {
const onChange = e => {
props.onChange(props.field);
props.changeType(e);
};
return (
<Checkbox
onChange={onChange}
checked={props.meals[props.field]}
id={props.field}
label={mealSections[props.field]}
>
{mealSections[props.field]}
</Checkbox>
);
};
export default MealCheckbox;
import React from 'react';
import { Form, Row, Col } from 'antd';
import { mealType, mealSections } from '../../staticData/index';
import MealLimit from '../MealLimit';
import { mealType, mealSections } from '../staticData';
import MealLimit from './MealLimit';
/**
* 渲染 企业单笔消费限额 二维表单项目
......
import React from 'react';
import { Form, InputNumber } from 'antd';
import { validateRequired, isCheckPriceTwoDecimal } from '@/utils/validator';
const MealLimit = props => (
<Form.Item
label={`${props.label}限额`}
name={props.name}
value={props.value}
labelCol={{ span: 10 }}
wrapperCol={{ span: 14 }}
rules={[
{ validator: validateRequired, message: `请输入${props.label}限额` },
{ validator: isCheckPriceTwoDecimal, message: '请输入正确的价格' },
]}
>
<InputNumber addonAfter="元" max={999.99} />
</Form.Item>
);
export default MealLimit;
import React from 'react';
import { Form, Row, Col, TimePicker } from 'antd';
import { mealSections } from '../staticData';
import MealCheckbox from './MealCheckbox';
const MealSection = props => (
<Form.List name="mealTimePeriod">
{fields => (
<>
{Object.keys(mealSections).map((field, i) => (
<Row key={field} align="baseline">
<Col span={4}>
<Form.Item label="" name={[i, 'mealPeriodType']}>
<MealCheckbox
changeType={e => props.onChangeSection(e, props)}
meals={props.meals}
field={field}
/>
</Form.Item>
</Col>
<Col span={18}>
<Form.Item
name={[i, 'time']}
rules={
props.meals[field]
? [
{ type: 'array', required: true, message: '请选择!' },
{ validator: props.validateMeals, message: '时间段不能交叉!' },
]
: []
}
>
<TimePicker.RangePicker format="HH:mm" minuteStep={30} />
</Form.Item>
</Col>
</Row>
))}
</>
)}
</Form.List>
);
export default MealSection;
import React, { useEffect, useRef, useState } from 'react';
import { notification } from 'antd';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { layout } from '../../staticData/index';
import { apiEnterpriseInfo, apiNewEnterprise, apiEditEnterprise } from '../../service';
import { getBaseFormItem } from './staticData';
import { getPickSelf, checkConfirm, transformToApiParams, transformToFormData } from './bll';
import { layout, getBaseFormItem } from './staticData';
import { checkConfirm, transformVOToFormData, transformFormDataToDTO } from './bll';
import { apiEnterpriseInfo, apiNewEnterprise, apiEditEnterprise } from './service';
// 企业客户信息
const CustomerInfo = props => {
const [meals, setMeals] = useState([]); // 选中的餐段
const [selectedMealSections, setSelectedMealSections] = useState([]); // 选中的餐段
const [selectedMealTypes, setSelectedMealTypes] = useState([]); // 选中的餐品类型
const [pickSelfList, setPickSelfList] = useState({}); // 自提点列表
const [visible, setVisible] = useState(false);
const [pageLoading, setPageLoading] = useState(false); // 页面加载状态
const refForm = useRef();
/**
......@@ -23,7 +21,7 @@ const CustomerInfo = props => {
props.onClose(!!isRefresh);
}
setSelectedMealTypes([]);
setMeals({});
setSelectedMealSections({});
refForm.current.setFieldsValue({
mealLimit: [],
});
......@@ -39,9 +37,10 @@ const CustomerInfo = props => {
* 6. 表单提交
*/
const submitForm = async () => {
// 校验表单 并 转换成接口需要的数据
const formData = refForm.current.validateFields();
const data = await transformToApiParams(formData, selectedMealTypes, meals);
// 校验表单
const formData = await refForm.current.validateFields();
// 转换成接口需要的数据
const data = await transformFormDataToDTO(formData, selectedMealTypes, selectedMealSections);
let api = apiNewEnterprise;
// 如果有客户ID 则为编辑
if (props.id) {
......@@ -56,27 +55,31 @@ const CustomerInfo = props => {
}
};
// 改变餐品类型 (选自助餐必选外卖)
const onChangeMealType = async ms => {
/**
* 改变餐品类型 (选自助餐必选外卖,取消外卖必须取消自助餐)
* @param {array} mt 选中的餐品类型 ['1', '2']
* types: { 1: '外卖', 2: '自助餐', 4: '到店' }
*/
const onChangeMealType = async mt => {
try {
// 编辑时,取消餐段需提示用户确认风险
if (props.id && ms.length < selectedMealTypes.length) {
if (props.id && mt.length < selectedMealTypes.length) {
await checkConfirm();
}
// 取消外卖,必须取消自助餐
if (selectedMealTypes.includes('1') && !ms.includes('1')) {
ms = ms.filter(item => item !== '2');
if (selectedMealTypes.includes('1') && !mt.includes('1')) {
mt = mt.filter(item => item !== '2');
}
// 选择自助餐,必须选择外卖
if (!selectedMealTypes.includes('1') && ms.includes('2')) {
ms.push('1');
if (!selectedMealTypes.includes('1') && mt.includes('2')) {
mt.push('1');
}
// 注意 须先set 再from.setFieldsValue 防止丢失数据
setSelectedMealTypes(mt);
refForm.current.setFieldsValue({
mealType: ms,
mealType: mt,
});
setSelectedMealTypes(ms);
} catch {
refForm.current.setFieldsValue({
mealType: selectedMealTypes,
......@@ -86,11 +89,11 @@ const CustomerInfo = props => {
/**
* 改变餐段
* @param {object} e 事件对象
* meals: { 1: '早餐', 2: '午餐', 3: '晚餐' }
* selectedMealSections: { 1: '早餐', 2: '午餐', 4: '晚餐' }
*/
const onChangeMealSection = e => {
const { id, checked, label } = e?.target || {};
const values = Object.assign({}, meals);
const values = Object.assign({}, selectedMealSections);
// 选中则添加到选中餐段中,否则删除
if (checked) {
values[id] = label;
......@@ -98,7 +101,7 @@ const CustomerInfo = props => {
delete values[id];
}
// 设置选中餐段
setMeals(values);
setSelectedMealSections(values);
// 餐段都没选 则设置为空数组
if (Object.keys(values).length === 0) {
refForm.current.setFieldsValue({
......@@ -109,14 +112,21 @@ const CustomerInfo = props => {
refForm.current.validateFields(['mealTimePeriod']);
};
// 获取表单信息
/**
* 获取表单信息
* 把接口数据转换成表单需要的数据格式
*/
const getInfo = async () => {
setPageLoading(true);
const res = await apiEnterpriseInfo(props.id);
setPageLoading(false);
if (res && res.data) {
// 转换成表单需要的数据
const formData = transformToFormData(res.data);
const formData = transformVOToFormData(res.data);
// 选中的餐品类型
setSelectedMealTypes(formData.mealType);
setMeals(formData.mealTimePeriodMap);
// 选中的餐段
setSelectedMealSections(formData.mealTimePeriodMap);
refForm.current.setFieldsValue(formData);
}
};
......@@ -126,13 +136,7 @@ const CustomerInfo = props => {
// 如果有客户ID 则为编辑 需获取表单信息
if (props.id) {
getInfo();
} else {
// 新增的时候才获取自提点列表
getPickSelf(setPickSelfList, setVisible);
}
setVisible(true);
} else {
setVisible(false);
}
}, [props.visible]);
......@@ -140,8 +144,7 @@ const CustomerInfo = props => {
onChangeMealType,
onChangeMealSection,
id: props.id,
pickSelfList,
meals,
selectedMealSections,
selectedMealTypes,
form: refForm.current,
});
......@@ -150,21 +153,17 @@ const CustomerInfo = props => {
<BetaSchemaForm
layoutType="ModalForm"
title="企业客户信息"
open={visible}
open={props.visible}
width="900px"
modalProps={{
maskClosable: false,
destroyOnClose: true,
confirmLoading: pageLoading,
}}
formRef={refForm}
onOpenChange={onOpenChange}
layout="horizontal"
{...layout}
steps={[
{
title: '企业客户信息',
},
]}
onFinish={submitForm}
columns={formItem}
/>
......
import request from '@/utils/request';
import config from '@/../config/env.config';
const { roleApi, apiPrefix } = config;
/**
* 获取企业客户详细
* http://yapi.quantgroups.com/project/389/interface/api/65339
*/
export async function apiEnterpriseInfo(id) {
return request.get(`${apiPrefix}/enterprise/info?id=${id}`, {
prefix: roleApi,
});
}
/**
* 添加企业客户
* http://yapi.quantgroups.com/project/389/interface/api/65329
*/
export async function apiNewEnterprise(data) {
return request.post(`${apiPrefix}/enterprise/save`, {
data,
prefix: roleApi,
});
}
/**
* 编辑企业客户
* http://yapi.quantgroups.com/project/389/interface/api/65334
*/
export async function apiEditEnterprise(data) {
return request.post(`${apiPrefix}/enterprise/update`, {
data,
prefix: roleApi,
});
}
/**
* 查询自提点列表
* http://yapi.quantgroups.com/project/389/interface/api/65494
*/
export async function apiEnterprisePickSelf() {
return request.get(`${apiPrefix}/selfPickUpLocation/list`, {
prefix: roleApi,
});
}
import React from 'react';
import { Input, InputNumber, Select, Checkbox, Radio } from 'antd';
import { jsonToArray } from '@/utils/utils';
import moment from 'moment';
import MealSection from '../MealSection';
import { mealType, boolOptions, hideOptions } from '../../staticData/index';
import MealFormListLimit from './MealFormListLimit';
const CheckboxGroup = Checkbox.Group;
const RadioGroup = Radio.Group;
import MealSection from './components/MealSection';
import MealFormListLimit from './components/MealFormListLimit';
import { getPickSelf } from './bll';
const hideEnums = { hidePrice: '隐藏商品价格', hideImage: '隐藏商品图片' };
const weekEnums = { 1: '', 0: '' };
const weekMap = new Map([[1, ''], [0, '']]);
export const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
// 餐品类型
export const mealType = {
1: '外卖',
2: '自助餐',
4: '到店',
};
// 餐段
export const mealSections = {
1: '早餐',
2: '午餐',
4: '晚餐',
};
// 校验时间
const checkTime = (arr, current) => {
......@@ -23,17 +36,17 @@ const checkTime = (arr, current) => {
return valid;
};
// 验证餐段
const validateMeals = (form, meals) => {
const validateMeals = (form, selectedMealSections) => {
const { mealTimePeriod = [] } = form.getFieldValue();
const arr = [];
let validTime = false;
mealTimePeriod.forEach(item => {
if (item && meals[item.mealPeriodType]) {
if (item && selectedMealSections[item.mealPeriodType]) {
const obj = { ...item };
if (obj.time?.length === 2) {
obj.beginTime = moment(obj.time[0]).format('HH:mm');
obj.endTime = moment(obj.time[1]).format('HH:mm');
if (checkTime(arr, obj.beginTime, meals[item.mealPeriodType])) {
if (checkTime(arr, obj.beginTime, selectedMealSections[item.mealPeriodType])) {
validTime = true;
}
arr.push(obj);
......@@ -47,103 +60,14 @@ const validateMeals = (form, meals) => {
return Promise.resolve();
};
export const getFormItem = options => {
const { id, pickSelfList, onChangeMealType, onChangeMealSection, meals, form } = options;
return [
{
type: 'Form.Item',
label: '企业名称',
name: 'name',
wrapperCol: { span: 20 },
rules: [{ required: true, message: '请输入企业名称' }],
component: <Input placeholder="请输入企业名称" />,
},
{
type: 'Form.Item',
disabled: id,
label: '企业取餐点',
wrapperCol: { span: 20 },
name: 'pickSelfIds',
rules: [{ required: true, message: '请选择企业取餐点' }],
component: (
<Select
options={pickSelfList}
mode="multiple"
showSearch
filterOption={(v, option) =>
(option?.label ?? '').toLowerCase().includes(v.toLowerCase())
}
/>
),
},
{
type: 'Form.Item',
label: '企业截止时间',
wrapperCol: { span: 20 },
name: 'endOrderTime',
rules: [{ required: true, message: '请输入企业截止时间' }],
component: <InputNumber min={0} max={600} addonAfter="分钟" />,
extra: <span>企业员工下单的截至时间,仅支持正整数,单位为分钟。</span>,
},
{
type: 'Form.Item',
label: '餐品类型',
wrapperCol: { span: 20 },
name: 'mealType',
rules: [{ required: true, message: '请选择餐品类型' }],
component: <CheckboxGroup options={jsonToArray(mealType)} onChange={onChangeMealType} />,
},
{
type: 'Form.Item',
label: '餐段配置',
wrapperCol: { span: 12 },
name: 'mealTimePeriod',
rules: [{ required: true, message: '请选择餐段配置' }],
component: (
<MealSection
meals={meals}
validateMeals={() => validateMeals(form, meals)}
onChange={onChangeMealSection}
/>
),
},
{
name: 'Divider',
type: 'Divider',
component: '企业单笔消费限额',
},
{
name: 'Form.List',
type: 'Form.List',
component: '',
},
{
type: 'Form.Item',
label: '商品隐藏信息',
wrapperCol: { span: 20 },
name: 'hideInfo',
component: <CheckboxGroup options={hideOptions} />,
},
{
type: 'Form.Item',
label: '是否周预览',
wrapperCol: { span: 20 },
name: 'weekPreview',
rules: [{ required: true, message: '请选择是否周预览' }],
component: <RadioGroup options={boolOptions} />,
},
];
};
// 获取 schemaForm 的 columns
export const getBaseFormItem = options => {
const {
id,
pickSelfList,
selectedMealTypes,
onChangeMealType,
selectedMealSections,
onChangeMealSection,
meals,
form,
} = options;
......@@ -160,10 +84,10 @@ export const getBaseFormItem = options => {
title: '企业取餐点',
dataIndex: 'pickSelfIds',
valueType: 'select',
valueEnum: pickSelfList,
fieldProps: {
mode: 'multiple',
},
request: getPickSelf,
formItemProps: {
rules: [{ required: true, message: '请选择企业取餐点' }],
},
......@@ -204,8 +128,8 @@ export const getBaseFormItem = options => {
},
renderFormItem: () => (
<MealSection
meals={meals}
validateMeals={() => validateMeals(form, meals)}
meals={selectedMealSections}
validateMeals={() => validateMeals(form, selectedMealSections)}
onChangeSection={onChangeMealSection}
/>
),
......@@ -229,7 +153,7 @@ export const getBaseFormItem = options => {
labelCol: { span: 0 },
wrapperCol: { span: 24 },
},
renderFormItem: () => MealFormListLimit(meals, selectedMealTypes),
renderFormItem: () => MealFormListLimit(selectedMealSections, selectedMealTypes),
},
{
title: '商品隐藏信息',
......@@ -240,10 +164,12 @@ export const getBaseFormItem = options => {
{
title: '是否周预览',
dataIndex: 'weekPreview',
formItemProps: {
rules: [{ required: true, message: '请选择是否周预览' }],
},
valueType: 'radio',
valueEnum: weekEnums,
convertValue: v => `${v}`,
valueEnum: weekMap,
// convertValue: v => `${v}`, // 从接口获取的数据做简单转换
},
];
return baseColumn;
......
......@@ -5,7 +5,7 @@ import { PlusOutlined } from '@ant-design/icons';
import { customerColumn } from './staticData/index';
// import CustomerInfo from './components/CustomerInfoCopy';
// import CustomerInfo from './components/CustomerInfo';
import CustomerInfo from './components/SchemaForm/CustomerBase';
import CustomerInfo from '@/example/proForm/ModalForm/index';
import utilStyle from '@/utils/utils.less';
import { stringOrObjectTrim } from '@/utils/utils';
import { apiEnterpriseList } from './service';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment