对接评价模板新增和修改

This commit is contained in:
linxd
2025-06-23 20:29:01 +08:00
parent b9bbc906bf
commit 9eb1bed092
7 changed files with 664 additions and 124 deletions

View File

@ -21,15 +21,17 @@ import {
} from '@ant-design/icons';
import { getDictList, DictItem } from '@/servers/api/dicts';
import { StarLevel, StarLevelText } from '@/dicts/supplierTemplateDict';
import { generateUUID } from '@/utils/utils';
import './EvaluateTemplateTable.less';
// 注意:这里我们使用any类型是为了灵活处理多种数据格式
// 实际上API的类型定义在 src/servers/api/typings.d.ts 中的 SupplierEvaluate 命名空间下
// 包含了 IndicatorStItem 和 IndicatorNdItem 类型
// 注意:这里我们使用SupplierEvaluate命名空间中的类型
// 类型定义已移动到 src/typings.d.ts 文件中
const { Option } = Select;
const { TextArea } = Input;
// 移除类型定义,使用全局命名空间中的类型
interface EvaluateTemplateTableProps {
value?: any[];
onChange?: (value: any[]) => void;
@ -86,17 +88,12 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
// 检查数据是否已经是扁平化的表格数据格式
if (apiData.length > 0 && 'subIndicator' in apiData[0]) {
return apiData.map((item, index) => ({
key: item.id || `row-${index}`,
stId: item.stId,
...item,
key: item.id || `row-${generateUUID(16)}-${index}`,
ndId: item.id,
baseIndicator: item.baseIndicator || '',
descIndicator: item.descIndicator || '',
stScore: item.stScore || '0',
indicatorType: item.indicatorType || '',
subIndicator: item.subIndicator || '',
ndScore: item.score || '0',
isStar: item.isStar || StarLevel.NO,
desc: item.desc || '',
orderBy: typeof item.stOrderBy === 'string' ? parseInt(item.stOrderBy) : item.stOrderBy,
ndOrderBy: typeof item.orderBy === 'string' ? parseInt(item.orderBy) : item.orderBy
}));
@ -106,7 +103,7 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
if (apiData.length > 0 && 'indicatorNdList' in apiData[0]) {
const flattenedData: TableRowItem[] = [];
apiData.forEach((stItem: any) => {
apiData.forEach((stItem: any, stIndex: number) => {
stItem.indicatorNdList.forEach((ndItem: any, ndIndex: number) => {
flattenedData.push({
key: ndItem.id || `${stItem.id}-${ndIndex}`,
@ -118,7 +115,7 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
indicatorType: stItem.indicatorType,
subIndicator: ndItem.subIndicator,
ndScore: ndItem.score,
isStar: ndItem.isStar,
isStar: ndItem.isStar || StarLevel.NO,
desc: ndItem.desc,
orderBy: typeof stItem.orderBy === 'string' ? parseInt(stItem.orderBy) : stItem.orderBy,
ndOrderBy: typeof ndItem.orderBy === 'string' ? parseInt(ndItem.orderBy) : ndItem.orderBy
@ -129,25 +126,6 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
return flattenedData;
}
// 如果是旧格式,尝试兼容处理
if (apiData.length > 0 && 'level1Name' in apiData[0]) {
return apiData.map((item, index) => ({
key: item.key || `legacy-${index}`,
stId: item._originalData?.stItem?.id,
ndId: item._originalData?.ndItem?.id,
baseIndicator: item.level1Name || '',
descIndicator: item.level1Description || '',
stScore: item.level1Score?.toString() || '0',
indicatorType: item.indicator_type || '',
subIndicator: item.level2Name || '',
ndScore: item.level2Score?.toString() || '0',
isStar: item.isStar || StarLevel.NO,
desc: item.desc_score || '',
orderBy: typeof item.orderBy === 'string' ? parseInt(item.orderBy) : (item.orderBy || 0),
ndOrderBy: typeof item.ndOrderBy === 'string' ? parseInt(item.ndOrderBy) : (item.ndOrderBy || 0)
}));
}
return [];
};
@ -155,40 +133,46 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
const convertTableDataToApiData = (tableData: TableRowItem[]): any[] => {
// 按一级指标分组
const groupedByLevel1 = tableData.reduce((acc: Record<string, TableRowItem[]>, item: TableRowItem) => {
const baseIndicator = item.baseIndicator;
if (!baseIndicator) return acc;
// 为空的baseIndicator也需要分组,使用特殊键标识 - 这是关键修复
const groupKey = item.baseIndicator || `empty-${item.key}`;
if (!acc[baseIndicator]) {
acc[baseIndicator] = [];
if (!acc[groupKey]) {
acc[groupKey] = [];
}
acc[baseIndicator].push(item);
acc[groupKey].push(item);
return acc;
}, {});
// 转换为API需要的格式
return Object.keys(groupedByLevel1).map((baseIndicator, stIndex) => {
const level1Items = groupedByLevel1[baseIndicator];
return Object.keys(groupedByLevel1).map((groupKey, stIndex) => {
const level1Items = groupedByLevel1[groupKey];
const firstItem = level1Items[0];
// 使用any类型避免类型错误
const stItem: any = {
id: firstItem.stId,
baseIndicator,
descIndicator: firstItem.descIndicator,
score: firstItem.stScore,
orderBy: firstItem.orderBy || stIndex + 1,
indicatorType: firstItem.indicatorType,
indicatorNdList: level1Items.map((item, ndIndex) => ({
id: item.ndId,
subIndicator: item.subIndicator,
score: item.ndScore,
isStar: item.isStar,
orderBy: item.ndOrderBy || ndIndex + 1,
desc: item.desc
}))
};
// 生成唯一的临时ID
const tempStId = `temp-st-${generateUUID(16)}-${stIndex}`;
return stItem;
// 简化数据转换,使用可选链和短路评估
return {
id: firstItem.stId || tempStId,
baseIndicator: firstItem.baseIndicator || '',
descIndicator: firstItem.descIndicator || '',
score: firstItem.stScore || '0',
orderBy: firstItem.orderBy || stIndex + 1,
indicatorType: firstItem.indicatorType || '',
indicatorNdList: level1Items.map((item, ndIndex) => {
// 生成唯一的临时ID
const tempNdId = `temp-nd-${generateUUID(16)}-${stIndex}-${ndIndex}`;
return {
id: item.ndId || tempNdId,
subIndicator: item.subIndicator || '',
score: item.ndScore || '0',
isStar: item.isStar || StarLevel.NO,
orderBy: item.ndOrderBy || ndIndex + 1,
desc: item.desc || ''
};
})
};
});
};
@ -196,20 +180,180 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
useEffect(() => {
// 获取指标类型字典
fetchIndicatorTypes();
}, []);
// 初始化表格数据
// 单独处理value变化
useEffect(() => {
// 初始化表格数据或value变化时更新
if (value && value.length > 0) {
const tableData = convertApiDataToTableData(value);
setDataSource(tableData);
console.log('useEffect中接收到的value:', value);
// 避免不必要的状态更新,比较新旧数据是否相同
const currentValueStr = JSON.stringify(value);
// 注意当dataSource为空时避免调用convertTableDataToApiData
const currentDataSourceApiStr = dataSource.length > 0 ?
JSON.stringify(convertTableDataToApiData(dataSource)) : '';
if (currentValueStr !== currentDataSourceApiStr) {
const tableData = convertApiDataToTableData(value);
console.log('转换后的tableData:', tableData);
console.log('转换后的tableData key列表:', tableData.map(item => item.key));
// 保留现有项的key确保稳定性
if (dataSource && dataSource.length > 0) {
console.log('现有dataSource:', dataSource);
console.log('现有dataSource key列表:', dataSource.map(item => item.key));
// 检查现有dataSource中是否有重复的key
const existingKeyMap = new Map<string, boolean>();
const duplicateKeys = dataSource.filter(item => {
if (existingKeyMap.has(item.key)) {
return true;
}
existingKeyMap.set(item.key, true);
return false;
}).map(item => item.key);
if (duplicateKeys.length > 0) {
console.error('现有dataSource中发现重复的key:', duplicateKeys);
}
const updatedTableData = tableData.map((newItem, index) => {
// 尝试查找对应的现有项通过stId和ndId匹配
const existingItem = dataSource.find(existing =>
(existing.stId === newItem.stId && existing.ndId === newItem.ndId) ||
(existing.baseIndicator === newItem.baseIndicator && existing.subIndicator === newItem.subIndicator)
);
// 如果找到现有项保留其key
if (existingItem) {
console.log(`保留现有项的key: ${existingItem.key}`);
return { ...newItem, key: existingItem.key };
}
// 生成唯一的key
const uniqueKey = `init-${generateUUID(32)}-${index}`;
console.log(`为新项生成key: ${uniqueKey}`);
return { ...newItem, key: uniqueKey };
});
console.log('更新后的tableData:', updatedTableData);
console.log('更新后的tableData key列表:', updatedTableData.map(item => item.key));
// 再次检查是否有重复的key
const finalKeyMap = new Map<string, boolean>();
const finalData = updatedTableData.map((item, index) => {
if (finalKeyMap.has(item.key)) {
// 如果仍然有重复的key强制生成新的key
console.warn(`useEffect中仍然发现重复的key: ${item.key},强制重新生成`);
const forceNewKey = `force-${generateUUID(32)}-${index}-${Date.now()}`;
return {
...item,
key: forceNewKey
};
} else {
finalKeyMap.set(item.key, true);
return item;
}
});
console.log('最终的tableData:', finalData);
console.log('最终的tableData key列表:', finalData.map(item => item.key));
setDataSource(finalData);
} else {
// 确保初始数据的每一项都有唯一的key
const keyMap = new Map<string, boolean>();
const dataWithUniqueKeys = tableData.map((item, index) => {
const key = item.key || `init-${generateUUID(32)}-${index}`;
if (keyMap.has(key)) {
// 如果key重复生成新的key
const newKey = `unique-${generateUUID(32)}-${index}`;
console.log(`初始化时发现重复的key: ${key}生成新key: ${newKey}`);
keyMap.set(newKey, true);
return { ...item, key: newKey };
} else {
keyMap.set(key, true);
return { ...item, key };
}
});
console.log('初始化的dataWithUniqueKeys:', dataWithUniqueKeys);
console.log('初始化的key列表:', dataWithUniqueKeys.map(item => item.key));
setDataSource(dataWithUniqueKeys);
}
}
} else if (value && value.length === 0 && dataSource.length > 0) {
// 如果value被清空也清空dataSource
setDataSource([]);
}
}, [value]);
// 更新数据源
const updateDataSource = (newData: TableRowItem[]) => {
setDataSource(newData);
console.log('updateDataSource接收到的数据:', newData);
console.log('updateDataSource接收到的key列表:', newData.map(item => item.key));
// 检查是否有重复的key
const keyMap = new Map<string, number>();
newData.forEach(item => {
if (keyMap.has(item.key)) {
keyMap.set(item.key, keyMap.get(item.key)! + 1);
} else {
keyMap.set(item.key, 1);
}
});
// 打印重复的key
const duplicateKeys = Array.from(keyMap.entries())
.filter(([_, count]) => count > 1)
.map(([key]) => key);
if (duplicateKeys.length > 0) {
console.error('发现重复的key:', duplicateKeys);
console.error('重复key的详细信息:', newData.filter(item => duplicateKeys.includes(item.key)));
}
// 确保每行都有唯一稳定的key
const dataWithStableKeys = newData.map((item, index) => {
// 如果key不存在、包含undefined或者是重复的key使用工具函数生成新key
if (!item.key || item.key.includes('undefined') || duplicateKeys.includes(item.key)) {
console.log(`为项 ${index} 重新生成key原key: ${item.key}`);
const newKey = `fixed-${generateUUID(32)}-${index}`;
return {
...item,
key: newKey
};
}
return item;
});
// 再次检查是否有重复的key
const finalKeyMap = new Map<string, boolean>();
const finalData = dataWithStableKeys.map((item, index) => {
if (finalKeyMap.has(item.key)) {
// 如果仍然有重复的key强制生成新的key
console.warn(`仍然发现重复的key: ${item.key},强制重新生成`);
const forceNewKey = `force-${generateUUID(32)}-${index}-${Date.now()}`;
return {
...item,
key: forceNewKey
};
} else {
finalKeyMap.set(item.key, true);
return item;
}
});
console.log('最终的数据源:', finalData);
console.log('最终的key列表:', finalData.map(item => item.key));
setDataSource(finalData);
if (onChange) {
// 转换回API格式再传递给父组件
const apiData = convertTableDataToApiData(newData);
const apiData = convertTableDataToApiData(finalData);
onChange(apiData);
}
};
@ -269,7 +413,10 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
// 添加一级指标
const addLevel1Indicator = (currentRecord?: TableRowItem) => {
const newKey = `level1-${Date.now()}`;
// 使用改进后的工具函数生成唯一key不再需要额外的时间戳和随机数
const newKey = `level1-${generateUUID(32)}`;
console.log('添加一级指标生成的key:', newKey);
console.log('当前数据源:', dataSource);
const newItem: TableRowItem = {
key: newKey,
@ -277,13 +424,16 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
descIndicator: '',
stScore: '0',
indicatorType: '',
subIndicator: '',
subIndicator: '', // 注意二级指标需要为空字符串不能为undefined
ndScore: '0',
isStar: StarLevel.NO,
desc: '',
orderBy: dataSource.length + 1, // 确保正确的排序
ndOrderBy: 1 // 设置二级指标初始排序
};
console.log('新建的一级指标项:', newItem);
// 找到当前记录所在的位置
// 制作数据源的副本,避免直接修改状态
const newData = [...dataSource];
// 找到当前记录所在的一级指标组的最后一行
@ -293,9 +443,11 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
const sameGroup = newData.filter((item) => item.baseIndicator === currentRecord.baseIndicator);
const lastOfGroup = sameGroup[sameGroup.length - 1];
insertIndex = newData.findIndex((item) => item.key === lastOfGroup.key);
console.log('插入位置(相同baseIndicator):', insertIndex);
} else if (currentRecord && currentRecord.key) {
// 如果是新增的空白行,直接在其后插入
insertIndex = newData.findIndex((item) => item.key === currentRecord.key);
console.log('插入位置(空白行后):', insertIndex);
}
// 如果找到了位置,在该位置后插入,否则添加到末尾
@ -304,6 +456,8 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
} else {
newData.push(newItem);
}
console.log('插入后的数据源:', newData);
console.log('插入后的数据源中的key列表:', newData.map(item => item.key));
updateDataSource(newData);
};
@ -324,7 +478,9 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
// 添加二级指标
const addSubIndicator = (parentKey: string) => {
const newKey = `level2-${Date.now()}`;
// 使用工具函数生成唯一key
const newKey = `level2-${generateUUID(16)}`;
const parent = dataSource.find((item) => item.key === parentKey);
if (!parent || !parent.baseIndicator) {
@ -342,6 +498,7 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
ndScore: '0',
isStar: StarLevel.NO,
desc: '',
ndOrderBy: dataSource.filter(item => item.baseIndicator === parent.baseIndicator).length + 1
};
// 找到当前记录所在的位置
@ -532,7 +689,9 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
<Button
type="text"
icon={<PlusCircleOutlined />}
onClick={() => addLevel1Indicator(record)}
onClick={() => {
addLevel1Indicator(record);
}}
title="添加一级指标"
/>
<Button
@ -668,6 +827,31 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
return (
<div className="evaluate-template-table">
{console.log('渲染Table前的dataSource:', dataSource)}
{console.log('渲染Table前的dataSource中的key列表:', dataSource.map(item => item.key))}
{(() => {
// 检查是否有重复的key
const keyMap = new Map<string, number>();
dataSource.forEach(item => {
if (keyMap.has(item.key)) {
keyMap.set(item.key, keyMap.get(item.key)! + 1);
} else {
keyMap.set(item.key, 1);
}
});
// 打印重复的key
const duplicateKeys = Array.from(keyMap.entries())
.filter(([_, count]) => count > 1)
.map(([key]) => key);
if (duplicateKeys.length > 0) {
console.error('渲染Table前发现重复的key:', duplicateKeys);
console.error('重复key的详细信息:', dataSource.filter(item => duplicateKeys.includes(item.key)));
}
return null;
})()}
<Table
columns={columns}
dataSource={dataSource}
@ -678,23 +862,13 @@ const EvaluateTemplateTable: React.FC<EvaluateTemplateTableProps> = ({
scroll={{ x: 'max-content' }}
locale={{ emptyText: '无数据' }}
/>
{!isDetail && dataSource.length > 0 && (
{!isDetail && (
<div className="add-button-row">
<Button
type="dashed"
onClick={() => addLevel1Indicator()}
style={{ width: '100%', marginTop: 16 }}
icon={<PlusOutlined />}
>
</Button>
</div>
)}
{!isDetail && dataSource.length === 0 && (
<div className="add-button-row">
<Button
type="dashed"
onClick={() => addLevel1Indicator()}
onClick={() => {
addLevel1Indicator();
}}
style={{ width: '100%', marginTop: 16 }}
icon={<PlusOutlined />}
>

View File

@ -0,0 +1,145 @@
# EvaluateTemplateTable 组件使用指南
## 组件简介
EvaluateTemplateTable 是一个用于管理供应商评价模板指标的表格组件,支持以下功能:
- 添加/删除一级指标
- 添加/删除二级指标
- 设置指标类型、分值、星号项等
- 支持详情模式查看
## 使用方式
### 基本用法
```jsx
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import { Form } from 'antd';
const YourComponent = () => {
const [form] = Form.useForm();
return (
<Form form={form}>
<Form.Item name="indicatorList">
<EvaluateTemplateTable />
</Form.Item>
</Form>
);
};
```
### 详情模式
```jsx
<EvaluateTemplateTable value={detailData} isDetail={true} />
```
## 接口对接指南
EvaluateTemplateTable 组件使用了全局命名空间 SupplierEvaluate 中的类型定义,可以用于新增和修改操作。
### 新增模板接口
#### 1. 引入类型
```typescript
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import { createTemplate } from '@/servers/api/supplierEvaluate'; // 假设这是API请求函数
```
#### 2. 表单提交示例
```typescript
const handleSubmit = async (values) => {
// 这里的values.indicatorList就是EvaluateTemplateTable组件通过onChange输出的indicatorStList数据
const requestData: SupplierEvaluate.TemplateCreateRequest = {
categoryId: values.categoryId,
categoryLimitation: values.categoryLimitation || '0',
indicatorNdMore: values.indicatorNdMore || '0',
indicatorStList: values.indicatorList,
indicatorStMore: values.indicatorStMore || '0',
indicatorTypeMore: values.indicatorTypeMore || '0',
status: values.status,
templateName: values.templateName,
templateType: values.templateType,
};
try {
const res = await createTemplate(requestData);
if (res.success) {
message.success('创建成功');
// 其他操作...
}
} catch (error) {
console.error('创建模板失败:', error);
message.error('创建失败');
}
};
```
### 修改模板接口
#### 1. 引入类型
```typescript
import EvaluateTemplateTable from '@/components/EvaluateTemplateTable';
import { updateTemplate } from '@/servers/api/supplierEvaluate'; // 假设这是API请求函数
```
#### 2. 表单提交示例
```typescript
const handleSubmit = async (values) => {
const requestData: SupplierEvaluate.TemplateUpdateRequest = {
id: values.id, // 模板ID
categoryId: values.categoryId,
categoryLimitation: values.categoryLimitation,
indicatorStList: values.indicatorList,
status: values.status,
templateName: values.templateName,
templateType: values.templateType,
};
try {
const res = await updateTemplate(requestData);
if (res.success) {
message.success('修改成功');
// 其他操作...
}
} catch (error) {
console.error('修改模板失败:', error);
message.error('修改失败');
}
};
```
### 数据预处理
如果后端返回的数据格式与组件需要的格式不完全一致,可能需要进行预处理:
```typescript
// 加载详情数据示例
const fetchTemplateDetail = async (id) => {
try {
const res = await getTemplateDetail(id);
if (res.success && res.data) {
// 如果需要,这里可以对数据进行预处理
form.setFieldsValue({
...res.data,
indicatorList: res.data.indicatorStList, // 将indicatorStList映射到表单的indicatorList字段
});
}
} catch (error) {
console.error('获取模板详情失败:', error);
message.error('获取详情失败');
}
};
```
## 注意事项
1. 表格组件内部将值输出为标准的API格式无需额外转换
2. 创建新模板时需要设置Edit相关字段这些在表格组件中没有UI界面
3. 修改操作需要保持ID字段以便后端识别哪些指标需要更新
4. 表格组件对空baseIndicator的行会特殊处理确保添加一级指标功能正常工作

View File

@ -27,7 +27,12 @@ import {
StarLevel,
IndicatorAddOption
} from '@/dicts/supplierTemplateDict';
import { getTemplateDetail, getAllTemplates } from '@/servers/api/supplierEvaluate';
import {
getTemplateDetail,
getAllTemplates,
updateTemplate,
addTemplate
} from '@/servers/api/supplierEvaluate';
import './supplierTemplateManage.less';
const { Option } = Select;
@ -37,29 +42,6 @@ interface LocationState {
editData?: SupplierEvaluate.TemplateRecord;
}
// 模板列表项类型
interface TemplateItem {
categoryId?: string;
categoryLimitation?: string;
copyTemplateId?: null;
createBy?: string;
createDate?: null;
createTime?: string;
deleteFlag?: null;
delFlag?: string;
id: string;
lastUpdateTime?: null;
status?: string;
templateName?: string;
templateType?: string;
tenantId?: null;
tenantName?: null;
updateBy?: string;
updateDate?: null;
updateTime?: string;
[property: string]: any;
}
const { Title } = Typography;
const SupplierTemplateManageAdd: React.FC = () => {
@ -68,7 +50,7 @@ const SupplierTemplateManageAdd: React.FC = () => {
const [templateData, setTemplateData] = useState<any[]>([]);
const [isEdit, setIsEdit] = useState<boolean>(false);
const [templateDetail, setTemplateDetail] = useState<SupplierEvaluate.TemplateDetail | null>(null);
const [templateList, setTemplateList] = useState<TemplateItem[]>([]);
const [templateList, setTemplateList] = useState<SupplierEvaluate.TemplateItem[]>([]);
// 添加控制开关的状态
const [indicatorStMore, setIndicatorStMore] = useState<string>(IndicatorAddOption.CAN_ADD);
@ -163,6 +145,8 @@ const SupplierTemplateManageAdd: React.FC = () => {
...values,
templateType: selectedTemplate?.templateType || '', // 添加templateType
indicatorStList: templateData, // 直接使用模板数据,无需转换
indicatorTypeMore: IndicatorAddOption.CAN_ADD, // 默认可以增加对应指标类型
status: parseInt(values.status, 10) // 确保status是数字类型
};
// 如果是编辑模式添加ID
@ -172,16 +156,25 @@ const SupplierTemplateManageAdd: React.FC = () => {
setLoading(true);
try {
// 模拟提交
console.log('提交数据:', submitData);
setTimeout(() => {
// 调用API接口
let res;
if (isEdit) {
res = await updateTemplate(submitData);
} else {
// 使用addTemplate函数这是原始的API接口
res = await addTemplate(submitData);
}
if (res.success) {
message.success(isEdit ? '模板更新成功' : '模板保存成功');
setLoading(false);
history.goBack();
}, 1000);
} else {
message.error(res.message || (isEdit ? '模板更新失败' : '模板保存失败'));
}
} catch (error) {
console.error('提交失败:', error);
message.error('提交失败');
} finally {
setLoading(false);
}
};
@ -319,7 +312,6 @@ const SupplierTemplateManageAdd: React.FC = () => {
<Form.Item
label="选择模版"
name="copyTemplateId"
rules={[{ required: true, message: '请选择模版' }]}
>
<Select
placeholder="选择模版"

View File

@ -10,8 +10,11 @@ export async function getAllTemplates() {
});
}
// 模板管理接口
// 获取模板列表
/**
* 获取模板列表
* @param params 查询参数
* @returns Promise
*/
export async function getTemplateList(params: SupplierEvaluate.TemplateRequest) {
return request<SupplierEvaluate.TemplateResponse>('/coscoEvaluate/template/getPage', {
method: 'POST',
@ -19,14 +22,22 @@ export async function getTemplateList(params: SupplierEvaluate.TemplateRequest)
});
}
// 获取模板详情
/**
* 获取模板详情
* @param id 模板ID
* @returns Promise
*/
export async function getTemplateDetail(id: string) {
return request<SupplierEvaluate.TemplateDetailResponse>(`/coscoEvaluate/template/${id}`, {
method: 'GET',
});
}
// 新增模板
/**
* 新增模板
* @param params 模板数据
* @returns Promise
*/
export async function addTemplate(params: SupplierEvaluate.TemplateAddRequest) {
return request<API.APIResponse<any>>('/coscoEvaluate/template', {
method: 'POST',
@ -34,7 +45,12 @@ export async function addTemplate(params: SupplierEvaluate.TemplateAddRequest) {
});
}
// 更新模板
/**
* 更新评价模板
* @param params 模板数据
* @returns Promise
*/
export async function updateTemplate(params: SupplierEvaluate.TemplateUpdateRequest) {
return request<API.APIResponse<any>>('/coscoEvaluate/template', {
method: 'PUT',
@ -42,7 +58,11 @@ export async function updateTemplate(params: SupplierEvaluate.TemplateUpdateRequ
});
}
// 删除模板
/**
* 删除评价模板
* @param id 模板ID
* @returns Promise
*/
export async function deleteTemplate(id: string) {
return request<API.APIResponse<any>>('/coscoEvaluate/template/delete', {
method: 'POST',
@ -50,7 +70,11 @@ export async function deleteTemplate(id: string) {
});
}
// 启用模板
/**
* 启用评价模板
* @param id 模板ID
* @returns Promise
*/
export async function enableTemplate(id: string) {
return request<API.APIResponse<any>>('/coscoEvaluate/template/enable', {
method: 'POST',
@ -58,7 +82,11 @@ export async function enableTemplate(id: string) {
});
}
// 禁用模板
/**
* 禁用评价模板
* @param id 模板ID
* @returns Promise
*/
export async function disableTemplate(id: string) {
return request<API.APIResponse<any>>('/coscoEvaluate/template/disable', {
method: 'POST',
@ -66,24 +94,32 @@ export async function disableTemplate(id: string) {
});
}
// 获取品类列表
/**
* 获取品类列表
* @returns Promise
*/
export async function getCategoryList() {
return request<API.APIResponse<any>>('/coscoEvaluate/category/list', {
method: 'GET',
});
}
// 获取品类树
/**
* 获取品类树
* @returns Promise
*/
export async function getCategoryTree() {
return request<SupplierEvaluate.CategoryTreeResponse>('/cosco/category/categoryTree', {
method: 'GET',
});
}
// 获取部门列表
/**
* 获取部门列表
* @returns Promise
*/
export async function getDepartmentList() {
return request<API.APIResponse<any>>('/coscoEvaluate/dept/list', {
method: 'GET',
});
}

View File

@ -708,7 +708,28 @@ declare namespace SupplierEvaluate {
updateTime: string;
[property: string]: any;
}
// 模板列表项类型
export type TemplateItem = {
categoryId?: string;
categoryLimitation?: string;
copyTemplateId?: null;
createBy?: string;
createDate?: null;
createTime?: string;
deleteFlag?: null;
delFlag?: string;
id: string;
lastUpdateTime?: null;
status?: string;
templateName?: string;
templateType?: string;
tenantId?: null;
tenantName?: null;
updateBy?: string;
updateDate?: null;
updateTime?: string;
[property: string]: any;
};
// 一级指标项
export type IndicatorStItem = {
baseIndicator: string;

138
src/typings.d.ts vendored
View File

@ -227,6 +227,144 @@ declare namespace SupplierEvaluate {
evaluator: string;
evaluateTime: string;
};
// 从EvaluateTemplateTable组件移动过来的类型定义
export interface IndicatorNdItem {
/**
* 细分指标是否可编辑(0.是、1.否)
*/
baseIndicatorEdit?: string;
/**
* 该一级指标是否可编辑(0.是、1.否)
*/
indicatorNdEdit?: string;
/**
* 是否设置星号项(0.否、1.是)
*/
isStar: string;
/**
* 星号项是否可编辑(0.是、1.否)
*/
isStarEdit?: string;
/**
* 排序
*/
orderBy: number;
/**
* 分值
*/
score: string;
/**
* 分值是否可编辑(0.是、1.否)
*/
scoreEdit?: string;
/**
* 细分指标
*/
subIndicator: string;
/**
* 二级指标ID修改时需要
*/
id?: string;
/**
* 描述
*/
desc?: string;
[property: string]: any;
}
export interface IndicatorStItem {
/**
* 基本指标
*/
baseIndicator: string;
/**
* 基本指标是否可编辑(0.是、1.否)
*/
baseIndicatorEdit?: string;
/**
* 指标说明
*/
descIndicator: string;
/**
* 指标说明是否可编辑(0.是、1.否)
*/
descIndicatorEdit?: string;
indicatorNdList: IndicatorNdItem[];
/**
* 该一级指标是否可编辑(0.是、1.否)
*/
indicatorStEdit?: string;
/**
* 指标类型(数据字典 通用指标、技术指标)
*/
indicatorType: string;
/**
* 排序
*/
orderBy: number;
/**
* 分值
*/
score: string;
/**
* 分值是否可编辑(0.是、1.否)
*/
scoreEdit?: string;
/**
* 一级指标ID修改时需要
*/
id?: string;
[property: string]: any;
}
export interface TemplateCreateRequest {
/**
* 品类id(cosco_category表主键)
*/
categoryId: string;
/**
* 品类限制类型0.通用不限品类、1.限制品类)
*/
categoryLimitation: string;
/**
* 二级指标是否可增加
*/
indicatorNdMore: string;
indicatorStList: IndicatorStItem[];
/**
* 一级指标是否可增加
*/
indicatorStMore: string;
/**
* 是否可增加对应指标类型(数据字典 通用指标、技术指标)
*/
indicatorTypeMore: string;
/**
* 是否启用(0.草稿、1.启用、2.禁用)
*/
status: number;
/**
* 模板名称
*/
templateName: string;
/**
* 评价模板类型(数据字典code)
*/
templateType: string;
[property: string]: any;
}
export interface TemplateUpdateRequest {
categoryId: string;
categoryLimitation: string;
id: string;
indicatorStList: IndicatorStItem[];
status: number;
templateName: string;
templateType: string;
[property: string]: any;
}
}
declare module '*.css';

View File

@ -32,3 +32,37 @@ export const validateFileSize = (file: File, maxSize: number,type: string[]) =>
}
return isValidFormat && isLtMaxSize;
};
// 生成固定位数的 UUID
export const generateUUID = (length: number) => {
// 使用更复杂的字符集
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
// 使用加密安全的随机数生成(如果可用)
let array;
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
array = new Uint8Array(length);
window.crypto.getRandomValues(array);
} else {
array = new Uint8Array(length);
for (let i = 0; i < length; i++) {
array[i] = Math.floor(Math.random() * 256);
}
}
// 生成UUID
const timestamp = Date.now().toString(36);
let result = '';
// 添加时间戳前缀最多6个字符
result += timestamp.substring(timestamp.length - Math.min(6, length / 3));
// 添加随机字符
for (let i = 0; i < length - result.length; i++) {
const randomIndex = array[i % array.length] % characters.length;
result += characters.charAt(randomIndex);
}
return result;
};