This commit is contained in:
linxd
2025-06-27 17:15:45 +08:00
parent ad241f7adb
commit 5c54182ca1
33 changed files with 2648 additions and 315 deletions

View File

@ -0,0 +1,495 @@
import React, { useState, useEffect } from 'react';
import {
Card,
Form,
Input,
Select,
Radio,
Button,
message,
Row,
Col,
Divider,
Space,
Switch,
Typography,
Spin,
Table,
Popconfirm,
Modal,
} from 'antd';
import { history, useLocation } from 'umi';
import {
ArrowLeftOutlined,
SaveOutlined,
PlusOutlined,
DeleteOutlined,
StarFilled,
StarOutlined
} from '@ant-design/icons';
import CategorySelector from '@/components/CategorySelector';
import {
AnnualTemplateStatus,
AnnualTemplateStatusText,
} from '@/dicts/supplierAnnualDict';
import {
addAnnualTemplate,
updateAnnualTemplate,
getAnnualTemplateDetail,
getAllAnnualTemplates
} from '@/servers/api/supplierAnnual';
import styles from './supplierAnnualTemplateManage.less';
const { Option } = Select;
interface LocationState {
isEdit?: boolean;
editData?: supplierAnnualTemplateManage.TemplateRecord;
}
// 模板记录类型 - 使用实际API接口类型
const { Title } = Typography;
// 品类限制类型常量
const CategoryLimitationType = {
UNIVERSAL: '0', // 不限
LIMITED: '1', // 限制
};
// 品类限制类型文本
const CategoryLimitationTypeText = {
[CategoryLimitationType.UNIVERSAL]: '不限',
[CategoryLimitationType.LIMITED]: '限制',
};
// 是否星号项常量
const StarOptions = {
YES: '1',
NO: '0',
};
// 是否星号项文本
const StarOptionsText = {
[StarOptions.YES]: '是',
[StarOptions.NO]: '否',
};
const SupplierAnnualTemplateManageAdd: React.FC = () => {
const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(false);
const [isEdit, setIsEdit] = useState<boolean>(false);
const [templateDetail, setTemplateDetail] = useState<supplierAnnualTemplateManage.TemplateDetailData | null>(null);
const [templateList, setTemplateList] = useState<supplierAnnualTemplateManage.TemplateRecord[]>([]);
const [indicatorList, setIndicatorList] = useState<supplierAnnualTemplateManage.IndicatorItem[]>([]);
// 获取路由传递的数据
const location = useLocation<LocationState>();
// 获取所有模板列表
const fetchTemplateList = async () => {
try {
setLoading(true);
const res = await getAllAnnualTemplates();
if (res.success && res.data) {
setTemplateList(res.data);
} else {
message.error(res.message || '获取模板列表失败');
}
setLoading(false);
} catch (error) {
console.error('获取模板列表失败:', error);
message.error('获取模板列表失败');
setLoading(false);
}
};
// 获取模板详情
const fetchTemplateDetail = async (templateId: string) => {
try {
setLoading(true);
const res = await getAnnualTemplateDetail(templateId);
if (res.success && res.data) {
setTemplateDetail(res.data);
// 设置表单数据
form.setFieldsValue({
templateName: res.data.templateName,
categoryLimitation: res.data.categoryLimitation,
categoryId: res.data.categoryId,
status: res.data.status,
copyTemplateId: res.data.templateType,
});
// 设置指标数据
if (res.data.indicatorList && res.data.indicatorList.length > 0) {
setIndicatorList(res.data.indicatorList);
}
} else {
message.error(res.message || '获取模板详情失败');
}
setLoading(false);
} catch (error) {
console.error('获取模板详情失败:', error);
message.error('获取模板详情失败');
setLoading(false);
}
};
// 初始化编辑数据
useEffect(() => {
// 获取所有模板列表
fetchTemplateList();
// 如果是编辑模式,加载编辑数据
if (location.state?.isEdit && location.state?.editData) {
setIsEdit(true);
// 获取模板详情
if (location.state.editData.id) {
fetchTemplateDetail(location.state.editData.id);
}
} else {
// 非编辑模式,默认添加一条空指标
const newIndicator: supplierAnnualTemplateManage.IndicatorItem = {
orderBy: '1',
itemName: '',
isStar: StarOptions.NO,
};
setIndicatorList([newIndicator]);
}
}, []);
// 处理返回
const handleBack = () => {
history.goBack();
};
// 实际提交数据的函数
const submitFormData = async (submitData: supplierAnnualTemplateManage.AddTemplateRequest) => {
setLoading(true);
try {
// 调用API接口
let res;
if (isEdit) {
res = await updateAnnualTemplate(submitData);
} else {
res = await addAnnualTemplate(submitData);
}
if (res && res.success) {
message.success(isEdit ? '模板更新成功' : '模板保存成功');
history.goBack();
} else {
message.error(res?.message || (isEdit ? '模板更新失败' : '模板保存失败'));
}
} catch (error) {
console.error('提交失败:', error);
message.error('提交失败');
} finally {
setLoading(false);
}
};
// 处理表单提交前的验证
const handleSubmit = async (values: any) => {
// 检查指标列表
if (!indicatorList || indicatorList.length === 0) {
message.error('至少需要添加一项指标');
return;
}
// 检查指标名称不能为空
const emptyNameIndex = indicatorList.findIndex(item => !item.itemName);
if (emptyNameIndex !== -1) {
message.error(`${emptyNameIndex + 1} 项指标名称不能为空`);
return;
}
// 准备提交数据
const submitData: supplierAnnualTemplateManage.AddTemplateRequest = {
...values,
indicatorList,
templateType: values.copyTemplateId || '1', // 默认类型
};
// 如果是编辑模式添加ID
if (isEdit && templateDetail) {
submitData.id = templateDetail.id;
}
// 显示确认弹框
Modal.confirm({
title: '确认提交',
content: isEdit ? '确定要更新此模板吗?' : '确定要保存此模板吗?',
okText: '确定',
cancelText: '取消',
onOk: async () => {
await submitFormData(submitData);
}
});
};
// 处理模板选择
const handleTemplateSelect = async (templateId: string) => {
// 如果是新建模式,并且选择了模板,获取模板详情作为基础数据
if (!isEdit && templateId) {
try {
setLoading(true);
const res = await getAnnualTemplateDetail(templateId);
if (res.success && res.data) {
// 设置品类限制和品类信息
form.setFieldsValue({
categoryLimitation: res.data.categoryLimitation,
categoryId: res.data.categoryId,
});
// 复制指标列表
if (res.data.indicatorList && res.data.indicatorList.length > 0) {
const copiedList = JSON.parse(JSON.stringify(res.data.indicatorList)).map((item: any) => {
// 删除id防止ID冲突
delete item.id;
return item;
});
setIndicatorList(copiedList);
}
} else {
message.error(res.message || '获取模板详情失败');
}
setLoading(false);
} catch (error) {
console.error('获取模板详情失败:', error);
message.error('获取模板详情失败');
setLoading(false);
}
}
};
// 处理添加指标
const handleAddIndicator = () => {
const newIndicator: supplierAnnualTemplateManage.IndicatorItem = {
orderBy: String(indicatorList.length + 1),
itemName: '',
isStar: StarOptions.NO,
};
setIndicatorList([...indicatorList, newIndicator]);
};
// 处理删除指标
const handleDeleteIndicator = (index: number) => {
const newList = [...indicatorList];
newList.splice(index, 1);
// 更新序号
const updatedList = newList.map((item, idx) => ({
...item,
orderBy: String(idx + 1),
}));
setIndicatorList(updatedList);
};
// 处理指标项修改
const handleIndicatorChange = (index: number, key: string, value: string) => {
const newList = [...indicatorList];
newList[index][key] = value;
setIndicatorList(newList);
};
// 指标表格列定义
const columns = [
{
title: '序号',
dataIndex: 'orderBy',
key: 'orderBy',
width: 80,
render: (_: string, __: any, index: number) => index + 1,
},
{
title: '检查项目',
dataIndex: 'itemName',
key: 'itemName',
render: (text: string, record: supplierAnnualTemplateManage.IndicatorItem, index: number) => (
<Input
value={text}
onChange={(e) => handleIndicatorChange(index, 'itemName', e.target.value)}
placeholder="请输入检查项目名称"
/>
),
},
{
title: '星号项',
dataIndex: 'isStar',
key: 'isStar',
width: 120,
render: (text: string, record: supplierAnnualTemplateManage.IndicatorItem, index: number) => (
<Select
value={text}
onChange={(value) => handleIndicatorChange(index, 'isStar', value)}
className={styles.starSelector}
>
<Option value={StarOptions.YES}>{StarOptionsText[StarOptions.YES]}</Option>
<Option value={StarOptions.NO}>{StarOptionsText[StarOptions.NO]}</Option>
</Select>
),
},
{
title: '操作',
key: 'action',
width: 120,
render: (_: any, __: supplierAnnualTemplateManage.IndicatorItem, index: number) => (
<Space>
{index === indicatorList.length - 1 && (
<Button
type="link"
icon={<PlusOutlined />}
onClick={handleAddIndicator}
title="添加指标"
/>
)}
<Popconfirm
title="确定要删除此指标吗?"
onConfirm={() => handleDeleteIndicator(index)}
okText="确定"
cancelText="取消"
>
<Button type="link" danger icon={<DeleteOutlined />} title="删除指标" />
</Popconfirm>
</Space>
),
},
];
return (
<div className="common-container">
<div className={styles.pageHeader}>
<Title level={4} style={{ margin: 0 }}>
{isEdit ? '编辑年度模板' : '新增年度模板'}
</Title>
<Button type="link" icon={<ArrowLeftOutlined />} onClick={handleBack}>
</Button>
</div>
<Form
form={form}
onFinish={handleSubmit}
initialValues={{
categoryLimitation: CategoryLimitationType.UNIVERSAL,
status: AnnualTemplateStatus.DRAFT,
}}
labelCol={{ span: 7 }}
wrapperCol={{ span: 17 }}
>
<Spin spinning={loading}>
<Card title="基础信息" bordered={false} className={styles.innerCard}>
<Row gutter={24}>
<Col span={8}>
<Form.Item
label="模板名称"
name="templateName"
rules={[{ required: true, message: '请输入模板名称' }]}
>
<Input placeholder="请输入模板名称" maxLength={50} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label="是否限品类"
name="categoryLimitation"
rules={[{ required: true, message: '请选择是否限品类' }]}
>
<Radio.Group>
<Radio value={CategoryLimitationType.UNIVERSAL}>{CategoryLimitationTypeText[CategoryLimitationType.UNIVERSAL]}</Radio>
<Radio value={CategoryLimitationType.LIMITED}>{CategoryLimitationTypeText[CategoryLimitationType.LIMITED]}</Radio>
</Radio.Group>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) =>
prevValues.categoryLimitation !== currentValues.categoryLimitation
}
>
{({ getFieldValue }) => {
const categoryLimitation = getFieldValue('categoryLimitation');
return categoryLimitation === CategoryLimitationType.LIMITED ? (
<Form.Item
label="选择品类"
name="categoryId"
rules={[{ required: true, message: '请选择品类' }]}
>
<CategorySelector multiple={false} />
</Form.Item>
) : null;
}}
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={8}>
<Form.Item
label="选择模版"
name="copyTemplateId"
>
<Select
placeholder="选择模版"
loading={templateList.length === 0}
onSelect={handleTemplateSelect}
>
{templateList.map(template => (
template.id ? (
<Option key={template.id} value={template.id}>
{template.templateName}
</Option>
) : null
))}
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label="模板状态"
name="status"
rules={[{ required: true, message: '请选择模板状态' }]}
>
<Radio.Group>
<Radio value={AnnualTemplateStatus.DRAFT}>{AnnualTemplateStatusText[AnnualTemplateStatus.DRAFT]}</Radio>
<Radio value={AnnualTemplateStatus.ENABLED}>{AnnualTemplateStatusText[AnnualTemplateStatus.ENABLED]}</Radio>
<Radio value={AnnualTemplateStatus.DISABLED}>{AnnualTemplateStatusText[AnnualTemplateStatus.DISABLED]}</Radio>
</Radio.Group>
</Form.Item>
</Col>
</Row>
</Card>
<Divider />
<Card title="指标信息" bordered={false} className={styles.innerCard}>
<Table
columns={columns}
dataSource={indicatorList}
bordered
rowKey="orderBy"
size="middle"
pagination={false}
locale={{ emptyText: '暂无指标数据' }}
className={styles.indicatorTable}
/>
</Card>
</Spin>
<div className={styles.formActions}>
<Space>
<Button onClick={handleBack}></Button>
<Button type="primary" htmlType="submit" loading={loading} icon={<SaveOutlined />}>
{isEdit ? '更新' : '保存'}
</Button>
</Space>
</div>
</Form>
</div>
);
};
export default SupplierAnnualTemplateManageAdd;