提交一下 换git仓库了

This commit is contained in:
linxd
2025-06-23 21:39:51 +08:00
parent 9eb1bed092
commit c74aefb93d
11 changed files with 741 additions and 672 deletions

View File

@ -1,45 +1,69 @@
import React, { useState, useEffect } from 'react';
import { Form, Input, Select, DatePicker, Row, Col, Card } from 'antd';
import React, { useState, useEffect, useCallback, forwardRef, useImperativeHandle } from 'react';
import { Form, Input, Select, DatePicker, Row, Col, Card, Radio } from 'antd';
import moment from 'moment';
import { getAllTemplates } from '@/servers/api/supplierEvaluate';
import CategorySelector from '@/components/CategorySelector';
import styles from '../supplierTaskManageAdd.less';
import { CategoryLimitationType } from '@/dicts/supplierTemplateDict';
const { Option } = Select;
interface BasicInfoStepProps {
formData: any;
onFormDataChange: (data: any) => void;
formData: Partial<SupplierEvaluate.TaskAddRequest>;
onFormDataChange: (data: Partial<SupplierEvaluate.TaskAddRequest>) => void;
}
interface TemplateItem {
id: string;
templateName: string;
isUnlimitedCategory?: boolean;
categoryLimitation?: string;
}
const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChange }) => {
const BasicInfoStep = forwardRef<any, BasicInfoStepProps>(({ formData, onFormDataChange }, ref) => {
const [form] = Form.useForm();
const [templates, setTemplates] = useState<TemplateItem[]>([]);
const [categoryTemplates, setCategoryTemplates] = useState<any[]>([]);
const [selectedCategoryId, setSelectedCategoryId] = useState<string | undefined>(undefined);
const [loading, setLoading] = useState<boolean>(false);
// 暴露表单方法给父组件
useImperativeHandle(ref, () => ({
validateFields: () => form.validateFields(),
getFieldsValue: () => form.getFieldsValue(),
setFieldsValue: (values: any) => form.setFieldsValue(values),
}));
// 获取模板列表
const fetchTemplates = async () => {
setLoading(true);
try {
const response = await getAllTemplates();
if (response.success && response.data) {
setTemplates(response.data);
} else {
setTemplates([
{ id: '1', templateName: '不限品类模板', categoryLimitation: '0' },
{ id: '2', templateName: '限制品类模板', categoryLimitation: '1' },
]);
}
} catch (error) {
console.error('获取模板列表失败:', error);
// 使用模拟数据
setTemplates([
{ id: '1', templateName: '不限品类模板', categoryLimitation: '0' },
{ id: '2', templateName: '限制品类模板', categoryLimitation: '1' },
]);
} finally {
setLoading(false);
}
};
// 获取评价模板和初始化表单数据
useEffect(() => {
// 模拟API调用获取模板列表
const mockTemplates = [
{ id: '1', templateName: '不限品类', isUnlimitedCategory: true },
{ id: '2', templateName: '按品类', isUnlimitedCategory: false },
];
setTemplates(mockTemplates);
fetchTemplates();
// 初始化表单数据
if (formData) {
const initialValues = {
...formData,
evaluateStartTime: formData.evaluateStartTime ? moment(formData.evaluateStartTime) : undefined,
evaluateEndTime: formData.evaluateEndTime ? moment(formData.evaluateEndTime) : undefined,
};
form.setFieldsValue(initialValues);
form.setFieldsValue(formData);
// 设置已选品类
if (formData.categoryId) {
@ -48,73 +72,61 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
}
}, []);
// 获取品类对应的模板数据
useEffect(() => {
if (selectedCategoryId) {
// 模拟API调用根据品类ID获取对应的模板列表
const mockCategoryTemplates = [
{ id: 'ct1', templateName: '硬件设备评价模板' },
{ id: 'ct2', templateName: '备件评价模板' },
{ id: 'ct3', templateName: '通用备件评价模板' },
];
setCategoryTemplates(mockCategoryTemplates);
} else {
setCategoryTemplates([]);
}
}, [selectedCategoryId]);
// 检查当前选择的模板是否限制品类
const isTemplateUnlimitedCategory = () => {
const templateId = form.getFieldValue('templateId');
const currentTemplate = templates.find(t => t.id === templateId);
return currentTemplate?.isUnlimitedCategory;
};
// 表单值变化时触发
const handleValuesChange = (changedValues: any, allValues: any) => {
// 处理模板变更
if (changedValues.templateId) {
// 如果选择了不限品类的模板,清空品类选择和品类模板选择
if (isTemplateUnlimitedCategory()) {
const template = templates.find((t) => t.id === changedValues.templateId);
if (template) {
form.setFieldsValue({
categoryId: undefined,
categoryTemplateId: undefined
categoryLimitation: template.categoryLimitation || '0',
});
setSelectedCategoryId(undefined);
// 如果选择了不限品类的模板,清空品类选择
if (template.categoryLimitation === '0') {
form.setFieldsValue({
categoryId: undefined,
});
setSelectedCategoryId(undefined);
}
}
}
// 处理品类变更
if (changedValues.categoryId) {
setSelectedCategoryId(changedValues.categoryId?.[0]);
form.setFieldsValue({ categoryTemplateId: undefined });
}
// 将moment对象转换为字符串再传递
// 默认设置weightStatus为0
const formattedValues = {
...allValues,
evaluateStartTime: allValues.evaluateStartTime?.format('YYYY-MM-DD'),
evaluateEndTime: allValues.evaluateEndTime?.format('YYYY-MM-DD'),
weightStatus: 0,
};
onFormDataChange(formattedValues);
};
// 年度选项生成
const yearOptions = () => {
const yearOptions = useCallback(() => {
const currentYear = new Date().getFullYear();
return Array.from({ length: 11 }, (_, i) => currentYear - 5 + i).map(year => (
<Option key={year} value={year.toString()}>{year}</Option>
return Array.from({ length: 11 }, (_, i) => currentYear - 5 + i).map((year) => (
<Option key={year} value={year.toString()}>
{year}
</Option>
));
};
}, []);
// 判断是否显示品类选择器
const shouldShowCategorySelector = () => {
const templateId = form.getFieldValue('templateId');
if (!templateId) return false;
const shouldShowCategorySelector = useCallback(() => {
const categoryLimitation = form.getFieldValue('categoryLimitation');
return categoryLimitation === CategoryLimitationType.LIMITED;
}, [form]);
const currentTemplate = templates.find(t => t.id === templateId);
return currentTemplate && !currentTemplate.isUnlimitedCategory;
};
// 处理品类选择变化
const handleCategoryChange = useCallback((value: string | string[]) => {
const categoryId = Array.isArray(value) ? value[0] : value;
setSelectedCategoryId(categoryId);
}, []);
return (
<div className={styles.basicInfoStep}>
@ -123,7 +135,10 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
form={form}
layout="vertical"
onValuesChange={handleValuesChange}
initialValues={formData}
initialValues={{
...formData,
categoryLimitation: formData.categoryLimitation || '0',
}}
>
<Row gutter={24}>
<Col span={12}>
@ -141,7 +156,7 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
name="evaluateYear"
rules={[{ required: true, message: '请选择评价年度' }]}
>
<Select placeholder="2025" style={{ width: '100%' }}>
<Select placeholder="请选择年度" style={{ width: '100%' }}>
{yearOptions()}
</Select>
</Form.Item>
@ -152,49 +167,42 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
<Col span={12}>
<Form.Item
label="评价开始时间"
name="evaluateStartTime"
name="startTime"
rules={[{ required: true, message: '请选择评价开始时间' }]}
getValueProps={(value) => ({
value: value ? moment(value) : undefined,
})}
normalize={(value) => value && value.format('YYYY-MM-DD')}
>
<DatePicker
style={{ width: '100%' }}
format="YYYY-MM-DD"
placeholder="年/月/日"
/>
<DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" placeholder="年/月/日" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="评价结束时间"
name="evaluateEndTime"
name="endTime"
rules={[{ required: true, message: '请选择评价结束时间' }]}
getValueProps={(value) => ({
value: value ? moment(value) : undefined,
})}
normalize={(value) => value && value.format('YYYY-MM-DD')}
>
<DatePicker
style={{ width: '100%' }}
format="YYYY-MM-DD"
placeholder="年/月/日"
/>
<DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" placeholder="年/月/日" />
</Form.Item>
</Col>
</Row>
<Row gutter={24} align="middle">
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="适用评价模板"
name="templateId"
rules={[{ required: true, message: '请选择适用评价模板' }]}
label="品类限制类型"
name="categoryLimitation"
rules={[{ required: true, message: '请选择品类限制类型' }]}
>
<Select
placeholder="请选择"
style={{ width: '100%' }}
allowClear
>
{templates.map(template => (
<Option key={template.id} value={template.id}>
{template.templateName}
</Option>
))}
</Select>
<Radio.Group>
<Radio value={CategoryLimitationType.UNIVERSAL}></Radio>
<Radio value={CategoryLimitationType.LIMITED}></Radio>
</Radio.Group>
</Form.Item>
</Col>
{shouldShowCategorySelector() && (
@ -204,16 +212,7 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
name="categoryId"
rules={[{ required: true, message: '请选择品类' }]}
>
<CategorySelector
onChange={(values: string[]) => {
const categoryId = values?.[0];
setSelectedCategoryId(categoryId);
if (!categoryId) {
form.setFieldsValue({ categoryTemplateId: undefined });
}
}}
/>
<CategorySelector onChange={handleCategoryChange} />
</Form.Item>
</Col>
)}
@ -223,15 +222,11 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
<Col span={12}>
<Form.Item
label="选择模板"
name="categoryTemplateId"
rules={[{ required: true, message: '请选择模板' }]}
name="templateId"
rules={[{ required: true, message: '请选择适用评价模板' }]}
>
<Select
placeholder="请选择"
style={{ width: '100%' }}
allowClear
>
{categoryTemplates.map(template => (
<Select placeholder="请选择" style={{ width: '100%' }} allowClear loading={loading}>
{templates.map((template) => (
<Option key={template.id} value={template.id}>
{template.templateName}
</Option>
@ -244,6 +239,6 @@ const BasicInfoStep: React.FC<BasicInfoStepProps> = ({ formData, onFormDataChang
</Card>
</div>
);
};
});
export default BasicInfoStep;

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Card, Button, Table, Space, Modal, Tag, Tooltip, Input, Form, InputNumber } from 'antd';
import { UserOutlined, SettingOutlined } from '@ant-design/icons';
import styles from '../supplierTaskManageAdd.less';
@ -25,7 +25,7 @@ interface WeightUnit {
weight: number;
}
const EvaluatorSelectStep: React.FC<EvaluatorSelectStepProps> = ({ formData, onFormDataChange }) => {
const EvaluatorSelectStep = forwardRef<any, EvaluatorSelectStepProps>(({ formData, onFormDataChange }, ref) => {
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [suppliers, setSuppliers] = useState<SupplierItem[]>([]);
const [batchSelectModalVisible, setBatchSelectModalVisible] = useState(false);
@ -41,6 +41,57 @@ const EvaluatorSelectStep: React.FC<EvaluatorSelectStepProps> = ({ formData, onF
]);
const [form] = Form.useForm();
// 暴露表单方法给父组件
useImperativeHandle(ref, () => ({
validateFields: () => {
// 自定义验证逻辑
if (suppliers.length === 0) {
return Promise.reject('请至少添加一个供应商');
}
// 检查是否每个供应商都有评价人员
const hasNoEvaluator = suppliers.some(supplier =>
!supplier.evaluators || supplier.evaluators.length === 0
);
if (hasNoEvaluator) {
return Promise.reject('存在未分配评价人员的供应商');
}
return Promise.resolve();
},
getFieldsValue: () => {
// 构建评价人员列表
const indicatorList = suppliers.flatMap(supplier =>
supplier.evaluators?.map(evaluator => ({
userId: evaluator.id,
type: 0, // 假设按评价单评价
indicatorIds: []
})) || []
);
// 构建供应商ID列表
const supplierIds = suppliers.map(supplier => ({
id: supplier.key,
userIds: supplier.evaluators?.map(e => e.id) || []
}));
return {
indicatorList,
supplierIds,
suppliersWithEvaluators: suppliers
};
},
setFieldsValue: (values: any) => {
if (values.suppliersWithEvaluators) {
setSuppliers(values.suppliersWithEvaluators);
}
if (values.weightUnits) {
setWeightUnits(values.weightUnits);
}
},
}));
// 从上一步获取供应商数据
useEffect(() => {
if (formData.selectedSuppliers) {
@ -75,9 +126,25 @@ const EvaluatorSelectStep: React.FC<EvaluatorSelectStepProps> = ({ formData, onF
// 更新表单数据
const updateFormData = (updatedData: any) => {
// 构建评价人员列表
const indicatorList = suppliers.flatMap(supplier =>
supplier.evaluators?.map(evaluator => ({
userId: evaluator.id,
type: 0, // 假设按评价单评价
indicatorIds: []
})) || []
);
// 构建供应商ID列表
const supplierIds = suppliers.map(supplier => ({
id: supplier.key,
userIds: supplier.evaluators?.map(e => e.id) || []
}));
onFormDataChange({
...formData,
...updatedData
...updatedData,
indicatorList,
supplierIds
});
};
@ -252,122 +319,103 @@ const EvaluatorSelectStep: React.FC<EvaluatorSelectStepProps> = ({ formData, onF
},
];
// 权重表格列定义
const weightColumns = [
{
title: '序号',
dataIndex: 'id',
key: 'id',
width: 80,
render: (_: string, __: any, index: number) => index + 1
},
{
title: '评价单位',
dataIndex: 'name',
key: 'name'
},
{
title: <span style={{ color: 'red' }}>* (%)</span>,
dataIndex: 'weight',
key: 'weight',
render: (_: number, record: WeightUnit) => (
<Form.Item
name={['weightUnits', record.id]}
rules={[
{ required: true, message: '请输入权重' },
{ type: 'number', min: 0, max: 100, message: '权重范围为0-100' },
]}
style={{ margin: 0 }}
>
<InputNumber min={0} max={100} style={{ width: '100%' }} />
</Form.Item>
)
}
];
return (
<div className={styles.evaluatorSelectStep}>
<div className={styles.toolBar}>
<Space>
{selectedRowKeys.length > 0 && (
<Card title="选择评价人员" bordered={false} className="inner-card">
<div className={styles.toolbar}>
<Space>
<Button
type="primary"
icon={<UserOutlined />}
onClick={handleBatchSelect}
disabled={selectedRowKeys.length === 0}
>
</Button>
)}
<Button
icon={<SettingOutlined />}
onClick={handleWeightSetting}
>
</Button>
</Space>
</div>
<Button
icon={<SettingOutlined />}
onClick={handleWeightSetting}
>
</Button>
</Space>
</div>
<Card title="已选供应商列表" bordered={false} className="inner-card">
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={suppliers}
pagination={false}
size="middle"
rowKey="key"
/>
</Card>
{/* 批量选择模态框 */}
<Modal
title="批量选择评价人员"
visible={batchSelectModalVisible}
footer={null}
onCancel={() => setBatchSelectModalVisible(false)}
width={800}
destroyOnClose
>
<EvaluateTaskPersonnelSelector
onSelect={handleBatchEvaluatorSelect}
selectedPersonnel={currentSupplier?.evaluators}
/>
</Modal>
{/* 设置评分单位权重模态框 */}
<Modal
title="评分单位权重设置"
visible={weightSettingModalVisible}
onOk={handleSaveWeights}
onCancel={() => setWeightSettingModalVisible(false)}
width={600}
>
<Form form={form} layout="vertical">
<Table
columns={weightColumns}
dataSource={weightUnits}
pagination={false}
rowKey="id"
bordered
{/* 批量选择评价人员弹窗 */}
<Modal
title="批量选择评价人员"
visible={batchSelectModalVisible}
onCancel={() => setBatchSelectModalVisible(false)}
footer={null}
width={700}
>
<EvaluateTaskPersonnelSelector
onSelect={handleBatchEvaluatorSelect}
selectedPersonnel={[]}
/>
</Form>
</Modal>
</Modal>
{/* 评价人员选择/查看模态框 */}
<Modal
title={currentSupplier?.supplierName + ' - 评价人员选择'}
visible={evaluatorModalVisible}
footer={null}
onCancel={() => setEvaluatorModalVisible(false)}
width={800}
destroyOnClose
>
<EvaluateTaskPersonnelSelector
onSelect={handleEvaluatorSelect}
selectedPersonnel={currentSupplier?.evaluators}
/>
</Modal>
{/* 单个供应商选择评价人员弹窗 */}
<Modal
title={`选择评价人员 - ${currentSupplier?.supplierName || ''}`}
visible={evaluatorModalVisible}
onCancel={() => setEvaluatorModalVisible(false)}
footer={null}
width={700}
>
<EvaluateTaskPersonnelSelector
onSelect={handleEvaluatorSelect}
selectedPersonnel={currentSupplier?.evaluators || []}
/>
</Modal>
{/* 权重设置弹窗 */}
<Modal
title="设置评分单位权重"
visible={weightSettingModalVisible}
onOk={handleSaveWeights}
onCancel={() => setWeightSettingModalVisible(false)}
>
<Form
form={form}
layout="vertical"
>
<Form.Item label="权重设置" required>
<p>100%</p>
{weightUnits.map(unit => (
<Form.Item
key={unit.id}
label={unit.name}
name={['weightUnits', unit.id]}
rules={[{ required: true, message: '请输入权重值' }]}
>
<InputNumber
min={0}
max={100}
formatter={value => `${value}%`}
parser={(value: string | undefined) => {
if (!value) return 0;
const num = Number(value.replace('%', ''));
return num;
}}
style={{ width: '100%' }}
/>
</Form.Item>
))}
</Form.Item>
</Form>
</Modal>
</Card>
</div>
);
};
});
export default EvaluatorSelectStep;

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { Card, Row, Col, Input, Select, Radio, Table, Button, Space, Pagination, Form } from 'antd';
import { SearchOutlined, ArrowRightOutlined } from '@ant-design/icons';
import styles from '../supplierTaskManageAdd.less';
@ -17,7 +17,7 @@ interface SupplierItem {
category: string;
}
const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFormDataChange }) => {
const SupplierSelectStep = forwardRef<any, SupplierSelectStepProps>(({ formData, onFormDataChange }, ref) => {
const [filterForm] = Form.useForm();
const [categoryKeyword, setCategoryKeyword] = useState<string>('');
const [selectedCategory, setSelectedCategory] = useState<string | undefined>(undefined);
@ -33,6 +33,25 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
const [pendingSelectedRowKeys, setPendingSelectedRowKeys] = useState<React.Key[]>([]);
const [selectedSelectedRowKeys, setSelectedSelectedRowKeys] = useState<React.Key[]>([]);
// 暴露表单方法给父组件
useImperativeHandle(ref, () => ({
validateFields: () => {
// 这里可以添加自定义验证逻辑
return Promise.resolve();
},
getFieldsValue: () => {
return {
selectedSuppliers,
supplierIds: selectedSuppliers.map(supplier => ({ id: supplier.key }))
};
},
setFieldsValue: (values: any) => {
if (values.selectedSuppliers) {
setSelectedSuppliers(values.selectedSuppliers);
}
},
}));
// 初始化数据
useEffect(() => {
// 从formData中恢复已选供应商
@ -87,7 +106,10 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
// 更新表单数据
const updateFormData = (suppliers: SupplierItem[]) => {
onFormDataChange({ selectedSuppliers: suppliers });
onFormDataChange({
selectedSuppliers: suppliers,
supplierIds: suppliers.map(supplier => ({ id: supplier.key }))
});
};
// 处理筛选条件变化
@ -242,7 +264,7 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
onValuesChange={handleFilterChange}
>
<Row gutter={24}>
<Col span={12}>
<Col span={8}>
<Form.Item label="选择类别" name="category">
<Select
placeholder="请选择"
@ -254,19 +276,17 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Col span={8}>
<Form.Item label="品类关键字" name="categoryKeyword">
<Input placeholder="请输入" allowClear />
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Col span={8}>
<Form.Item label="品类范围" name="categoryRange">
<Input placeholder="请输入" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Col span={8}>
<Form.Item label="近一年有付款" name="hasPaymentLastYear" initialValue="是">
<Radio.Group>
<Radio value="是"></Radio>
@ -274,9 +294,7 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
</Radio.Group>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Col span={8}>
<Form.Item label="准入部门" name="department">
<Select
placeholder="请选择"
@ -288,7 +306,7 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Col span={8}>
<Form.Item wrapperCol={{ offset: 6, span: 18 }}>
<Button type="primary" onClick={() => filterForm.submit()}>
@ -391,6 +409,6 @@ const SupplierSelectStep: React.FC<SupplierSelectStepProps> = ({ formData, onFor
</Row>
</div>
);
};
});
export default SupplierSelectStep;