1
This commit is contained in:
2025-10-27 11:46:57 +08:00
parent 37dcd00919
commit c5f1611f3a

View File

@ -74,6 +74,7 @@ export default function App() {
const WEEKEND_DAYS_FIELD_ID = 'fld2BvjbIN'; // 休息日字段ID多选项0-6代表周一到周日 const WEEKEND_DAYS_FIELD_ID = 'fld2BvjbIN'; // 休息日字段ID多选项0-6代表周一到周日
const START_DATE_RULE_FIELD_ID = 'fld0KsQ2j3'; // 起始日期调整规则字段ID const START_DATE_RULE_FIELD_ID = 'fld0KsQ2j3'; // 起始日期调整规则字段ID
const DATE_ADJUSTMENT_RULE_FIELD_ID = 'fld0KsQ2j3'; // 日期调整规则字段ID const DATE_ADJUSTMENT_RULE_FIELD_ID = 'fld0KsQ2j3'; // 日期调整规则字段ID
const EXCLUDED_DATES_FIELD_ID = 'fldGxzC5uG'; // 不参与计算日期多选格式yyyy-MM-dd
// 时效数据表相关常量 // 时效数据表相关常量
const TIMELINE_TABLE_ID = 'tblPnQscqwqopJ8V'; // 时效数据表ID const TIMELINE_TABLE_ID = 'tblPnQscqwqopJ8V'; // 时效数据表ID
@ -217,7 +218,6 @@ export default function App() {
weekendDaysConfig: [], weekendDaysConfig: [],
matchedLabels: [], matchedLabels: [],
skippedWeekends: 0, skippedWeekends: 0,
skippedHolidays: 0,
actualDays: undefined, actualDays: undefined,
startDateRule: undefined, startDateRule: undefined,
dateAdjustmentRule: undefined, dateAdjustmentRule: undefined,
@ -269,19 +269,7 @@ export default function App() {
// 起始时间字段(货期记录表新增) // 起始时间字段(货期记录表新增)
const DELIVERY_START_TIME_FIELD_ID = 'fld727qCAv'; const DELIVERY_START_TIME_FIELD_ID = 'fld727qCAv';
// 中国法定节假日配置需要手动维护或使用API // 已移除中国法定节假日相关常量和配置
const CHINESE_HOLIDAYS = [
'2024-01-01', // 元旦
'2024-02-10', '2024-02-11', '2024-02-12', // 春节
'2024-04-04', '2024-04-05', '2024-04-06', // 清明节
'2024-05-01', '2024-05-02', '2024-05-03', // 劳动节
'2024-06-10', // 端午节
'2024-09-15', '2024-09-16', '2024-09-17', // 中秋节
'2024-10-01', '2024-10-02', '2024-10-03', // 国庆节
// ... 其他节假日
];
// 已移除未使用的 fetchHolidays 函数
// 这个变量声明也不需要了 // 这个变量声明也不需要了
// const nodeNameToOptionId = new Map(); // const nodeNameToOptionId = new Map();
@ -420,52 +408,39 @@ export default function App() {
} }
}; };
// 计算跳过的法定节假日天数 // 计算时间范围内实际跳过的自定义日期
const calculateSkippedHolidays = (startDateStr: string | Date, endDateStr: string | Date): number => { const calculateExcludedDatesInRange = (startDate: Date | string, endDate: Date | string, excludedDates: string[] = []): { count: number, dates: string[] } => {
if (!excludedDates || excludedDates.length === 0) {
return { count: 0, dates: [] };
}
try { try {
const startDate = typeof startDateStr === 'string' ? new Date(startDateStr) : startDateStr; const start = typeof startDate === 'string' ? parseDate(startDate) : startDate;
const endDate = typeof endDateStr === 'string' ? new Date(endDateStr) : endDateStr; const end = typeof endDate === 'string' ? parseDate(endDate) : endDate;
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { if (!start || !end || isNaN(start.getTime()) || isNaN(end.getTime())) {
return 0; return { count: 0, dates: [] };
} }
if (typeof startDateStr === 'string' && (startDateStr.includes('未找到') || startDateStr.includes('时效值为0'))) { const actualExcludedDates: string[] = [];
return 0;
for (const excludedDateStr of excludedDates) {
const excludedDate = parseDate(excludedDateStr);
if (excludedDate && excludedDate >= start && excludedDate <= end) {
actualExcludedDates.push(excludedDateStr);
}
} }
if (typeof endDateStr === 'string' && (endDateStr.includes('未找到') || endDateStr.includes('时效值为0'))) { return { count: actualExcludedDates.length, dates: actualExcludedDates };
return 0;
}
let count = 0;
let currentDate = new Date(startDate);
while (currentDate <= endDate) {
if (isChineseHoliday(currentDate)) {
count++;
}
currentDate = addDays(currentDate, 1);
}
return count;
} catch (error) { } catch (error) {
return 0; console.error('计算跳过日期失败:', error);
return { count: 0, dates: [] };
} }
}; };
// 判断是否为中国节假日 // 已移除法定节假日跳过统计函数
const isChineseHoliday = (date: Date, holidays: string[] = CHINESE_HOLIDAYS): boolean => {
try { // 已移除中国节假日判断函数
if (isNaN(date.getTime())) {
return false;
}
const dateStr = format(date, 'yyyy-MM-dd');
return holidays.includes(dateStr);
} catch (error) {
return false;
}
};
// 判断是否为自定义周末 - 支持空的休息日配置 // 判断是否为自定义周末 - 支持空的休息日配置
const isCustomWeekend = (date: Date, weekendDays: number[] = []): boolean => { const isCustomWeekend = (date: Date, weekendDays: number[] = []): boolean => {
@ -473,9 +448,15 @@ export default function App() {
return weekendDays.includes(date.getDay()); return weekendDays.includes(date.getDay());
}; };
// 判断是否为工作日 - 只排除法定节假日和表格配置的休息日 // 判断是否为工作日 - 排除表格休息日、以及节点自定义不参与计算日期
const isBusinessDay = (date: Date, weekendDays: number[] = []): boolean => { const isBusinessDay = (date: Date, weekendDays: number[] = [], excludedDates: string[] = []): boolean => {
return !isCustomWeekend(date, weekendDays) && !isChineseHoliday(date); try {
const dateStr = format(date, 'yyyy-MM-dd');
const isExcluded = Array.isArray(excludedDates) && excludedDates.includes(dateStr);
return !isCustomWeekend(date, weekendDays) && !isExcluded;
} catch {
return !isCustomWeekend(date, weekendDays);
}
}; };
// 日期调整函数 // 日期调整函数
@ -577,7 +558,7 @@ export default function App() {
}; };
// 调整到下一个工作时间开始点 // 调整到下一个工作时间开始点
const adjustToNextWorkingHour = (date: Date, calculationMethod: string): Date => { const adjustToNextWorkingHour = (date: Date, calculationMethod: string, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
const result = new Date(date); const result = new Date(date);
if (calculationMethod === '内部') { if (calculationMethod === '内部') {
@ -591,8 +572,8 @@ export default function App() {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
} }
// 找到下一个工作日 // 找到下一个工作日(考虑休息日和自定义跳过日期)
while (!isBusinessDay(result, [])) { while (!isBusinessDay(result, weekendDays, excludedDates)) {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
} }
@ -605,7 +586,7 @@ export default function App() {
}; };
// 内部工作时间计算函数 // 内部工作时间计算函数
const addInternalBusinessTime = (startDate: Date, businessDays: number, weekendDays: number[] = []): Date => { const addInternalBusinessTime = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
const result = new Date(startDate); const result = new Date(startDate);
let remainingDays = businessDays; let remainingDays = businessDays;
@ -615,7 +596,7 @@ export default function App() {
while (addedDays < wholeDays) { while (addedDays < wholeDays) {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
if (isBusinessDay(result, weekendDays)) { if (isBusinessDay(result, weekendDays, excludedDates)) {
addedDays++; addedDays++;
} }
} }
@ -634,7 +615,7 @@ export default function App() {
} else if (currentHour >= 18) { } else if (currentHour >= 18) {
// 跳到下一个工作日的9:00 // 跳到下一个工作日的9:00
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
while (!isBusinessDay(result, weekendDays)) { while (!isBusinessDay(result, weekendDays, excludedDates)) {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
} }
currentHour = 9; currentHour = 9;
@ -653,7 +634,7 @@ export default function App() {
// 跳到下一个工作日 // 跳到下一个工作日
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
while (!isBusinessDay(result, weekendDays)) { while (!isBusinessDay(result, weekendDays, excludedDates)) {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
} }
@ -666,8 +647,8 @@ export default function App() {
return result; return result;
}; };
// 添加工作日 - 使用表格配置的休息日 // 添加工作日 - 使用表格配置的休息日与节点自定义跳过日期
const addBusinessDaysWithHolidays = (startDate: Date, businessDays: number, weekendDays: number[] = []): Date => { const addBusinessDaysWithHolidays = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
const result = new Date(startDate); const result = new Date(startDate);
let addedDays = 0; let addedDays = 0;
@ -678,7 +659,7 @@ export default function App() {
// 添加整数工作日 // 添加整数工作日
while (addedDays < wholeDays) { while (addedDays < wholeDays) {
result.setDate(result.getDate() + 1); result.setDate(result.getDate() + 1);
if (isBusinessDay(result, weekendDays)) { if (isBusinessDay(result, weekendDays, excludedDates)) {
addedDays++; addedDays++;
} }
} }
@ -1028,6 +1009,27 @@ export default function App() {
// 如果表格中没有配置休息日或配置为空,则该节点没有固定休息日 // 如果表格中没有配置休息日或配置为空,则该节点没有固定休息日
// 这样就完全依赖表格数据,不会有任何硬编码的默认值 // 这样就完全依赖表格数据,不会有任何硬编码的默认值
// 处理不参与计算日期(自定义跳过日期)
let excludedDates: string[] = [];
const excludedDatesField = fields[EXCLUDED_DATES_FIELD_ID];
if (excludedDatesField) {
console.log('原始不参与计算日期字段数据:', excludedDatesField);
if (Array.isArray(excludedDatesField)) {
excludedDates = excludedDatesField.map(item => {
if (item && typeof item === 'object') {
const val = item.text || item.name || item.value || item.id || '';
return String(val).trim();
}
return String(item).trim();
}).filter(d => !!d);
} else if (typeof excludedDatesField === 'string') {
excludedDates = excludedDatesField.split(/[\,\s]+/).map(s => s.trim()).filter(Boolean);
} else if (excludedDatesField && typeof excludedDatesField === 'object' && excludedDatesField.text) {
excludedDates = [String(excludedDatesField.text).trim()].filter(Boolean);
}
console.log('解析后的不参与计算日期:', excludedDates);
}
if (isMatched) { if (isMatched) {
// 获取起始日期调整规则 // 获取起始日期调整规则
const startDateRule = fields[START_DATE_RULE_FIELD_ID]; const startDateRule = fields[START_DATE_RULE_FIELD_ID];
@ -1041,6 +1043,7 @@ export default function App() {
matchedLabels: matchedLabels, matchedLabels: matchedLabels,
processOrder: orderValue, // 添加流程顺序 processOrder: orderValue, // 添加流程顺序
weekendDays: weekendDays, // 添加休息日配置 weekendDays: weekendDays, // 添加休息日配置
excludedDates: excludedDates, // 添加自定义跳过日期
startDateRule: startDateRule, // 添加起始日期调整规则 startDateRule: startDateRule, // 添加起始日期调整规则
dateAdjustmentRule: dateAdjustmentRule // 添加JSON格式日期调整规则 dateAdjustmentRule: dateAdjustmentRule // 添加JSON格式日期调整规则
}); });
@ -1324,15 +1327,15 @@ export default function App() {
// 计算当前节点的开始和完成时间(使用工作日计算) // 计算当前节点的开始和完成时间(使用工作日计算)
const calculateTimeline = (startDate: Date, timelineValue: number, calculationMethod: string = '外部') => { const calculateTimeline = (startDate: Date, timelineValue: number, calculationMethod: string = '外部') => {
// 根据计算方式调整开始时间 // 根据计算方式调整开始时间
const adjustedStartDate = adjustToNextWorkingHour(startDate, calculationMethod); const adjustedStartDate = adjustToNextWorkingHour(startDate, calculationMethod, processNode.weekendDays, processNode.excludedDates || []);
let endDate: Date; let endDate: Date;
if (calculationMethod === '内部') { if (calculationMethod === '内部') {
// 使用内部工作时间计算 // 使用内部工作时间计算
endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays); endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
} else { } else {
// 使用原有的24小时制计算 // 使用原有的24小时制计算
endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays); endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
} }
return { return {
@ -1410,11 +1413,11 @@ export default function App() {
let nodeEndTime: Date; let nodeEndTime: Date;
if (timelineValue) { if (timelineValue) {
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod); const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
if (nodeCalculationMethod === '内部') { if (nodeCalculationMethod === '内部') {
nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays); nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
} else { } else {
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays); nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
} }
} else { } else {
nodeEndTime = new Date(nodeStartTime); nodeEndTime = new Date(nodeStartTime);
@ -1422,9 +1425,11 @@ export default function App() {
// 计算跳过的天数 // 计算跳过的天数
const skippedWeekends = calculateSkippedWeekends(nodeStartTime, nodeEndTime, processNode.weekendDays); const skippedWeekends = calculateSkippedWeekends(nodeStartTime, nodeEndTime, processNode.weekendDays);
const skippedHolidays = calculateSkippedHolidays(timelineResult.startDate, timelineResult.endDate);
const actualDays = calculateActualDays(timelineResult.startDate, timelineResult.endDate); const actualDays = calculateActualDays(timelineResult.startDate, timelineResult.endDate);
// 计算时间范围内实际跳过的自定义日期
const excludedDatesInRange = calculateExcludedDatesInRange(nodeStartTime, nodeEndTime, processNode.excludedDates || []);
results.push({ results.push({
processOrder: processNode.processOrder, processOrder: processNode.processOrder,
nodeName: processNode.nodeName, nodeName: processNode.nodeName,
@ -1445,10 +1450,13 @@ export default function App() {
// 新增:标识是否为累加处理 // 新增:标识是否为累加处理
isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1, isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1,
weekendDaysConfig: processNode.weekendDays, // 新增:保存休息日配置用于显示 weekendDaysConfig: processNode.weekendDays, // 新增:保存休息日配置用于显示
excludedDates: processNode.excludedDates || [], // 新增:保存不参与计算日期用于显示与快照
// 新增:保存时间范围内实际跳过的日期
actualExcludedDates: excludedDatesInRange.dates,
actualExcludedDatesCount: excludedDatesInRange.count,
calculationMethod: nodeCalculationMethod, // 新增:保存计算方式 calculationMethod: nodeCalculationMethod, // 新增:保存计算方式
ruleDescription: ruleDescription, // 新增:保存规则描述 ruleDescription: ruleDescription, // 新增:保存规则描述
skippedWeekends: skippedWeekends, skippedWeekends: skippedWeekends,
skippedHolidays: skippedHolidays,
actualDays: actualDays, actualDays: actualDays,
// 新增:保存调整规则用于重新计算 // 新增:保存调整规则用于重新计算
startDateRule: processNode.startDateRule, startDateRule: processNode.startDateRule,
@ -1571,25 +1579,28 @@ export default function App() {
const nodeCalculationMethod = result.calculationMethod || '外部'; // 获取节点的计算方式 const nodeCalculationMethod = result.calculationMethod || '外部'; // 获取节点的计算方式
let nodeEndTime: Date; let nodeEndTime: Date;
const nodeExcludedDates = Array.isArray(result.excludedDates) ? result.excludedDates : [];
if (adjustedTimelineValue > 0) { if (adjustedTimelineValue > 0) {
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod); const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
if (nodeCalculationMethod === '内部') { if (nodeCalculationMethod === '内部') {
nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays); nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
} else { } else {
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays); nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
} }
} else { } else {
nodeEndTime = new Date(nodeStartTime); nodeEndTime = new Date(nodeStartTime);
} }
// 计算跳过的天数 // 计算跳过的天数
const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod) : nodeStartTime; const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates) : nodeStartTime;
const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays); const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays);
const estimatedStartStr = formatDate(adjustedStartTime); const estimatedStartStr = formatDate(adjustedStartTime);
const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0'; const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
const skippedHolidays = calculateSkippedHolidays(estimatedStartStr, estimatedEndStr);
const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr); const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
// 计算时间范围内实际跳过的自定义日期
const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
// 更新结果 // 更新结果
updatedResults[i] = { updatedResults[i] = {
...result, ...result,
@ -1599,8 +1610,10 @@ export default function App() {
adjustment: adjustment, adjustment: adjustment,
calculationMethod: nodeCalculationMethod, // 保持计算方式 calculationMethod: nodeCalculationMethod, // 保持计算方式
skippedWeekends: skippedWeekends, skippedWeekends: skippedWeekends,
skippedHolidays: skippedHolidays,
actualDays: actualDays, actualDays: actualDays,
// 更新时间范围内实际跳过的日期
actualExcludedDates: excludedDatesInRange.dates,
actualExcludedDatesCount: excludedDatesInRange.count,
adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述 adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
ruleDescription: ruleDescription // 添加更新后的规则描述 ruleDescription: ruleDescription // 添加更新后的规则描述
}; };
@ -2981,11 +2994,14 @@ export default function App() {
backgroundColor: '#f0f0f0', backgroundColor: '#f0f0f0',
border: '1px solid #d9d9d9' border: '1px solid #d9d9d9'
}} }}
title={`计算方式详情:\n${result.calculationMethod === '内部' ? '内部计算 (9小时工作制)' : '外部计算 (24小时制)'}${result.ruleDescription ? `\n应用规则${result.ruleDescription}` : ''}\n已跳过周末${result.skippedWeekends || 0}\n已跳过法定节假日:${result.skippedHolidays || 0}\n${result.weekendDaysConfig && result.weekendDaysConfig.length > 0 ? `休息日配置:${result.weekendDaysConfig.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(', ')}` : '休息日配置:无固定休息日'}${result.calculationMethod === '内部' ? '\n工作时间9:00-18:00 (9小时制)' : ''}`} title={`计算方式详情:\n${result.calculationMethod === '内部' ? '内部计算 (9小时工作制)' : '外部计算 (24小时制)'}${result.ruleDescription ? `\n应用规则${result.ruleDescription}` : ''}\n已跳过周末${result.skippedWeekends || 0}\n${result.weekendDaysConfig && result.weekendDaysConfig.length > 0 ? `休息日配置:${result.weekendDaysConfig.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(', ')}` : '休息日配置:无固定休息日'}${result.calculationMethod === '内部' ? '\n工作时间9:00-18:00 (9小时制)' : ''}${(Array.isArray(result.actualExcludedDates) && result.actualExcludedDates.length > 0) ? `\n\n跳过的具体日期\n${result.actualExcludedDates.join('\n')}` : ''}`}
> >
? ?
</span> </span>
</Text> </Text>
<div style={{ fontSize: '12px', color: '#666', marginTop: '2px' }}>
<Text>{(result.actualExcludedDatesCount && result.actualExcludedDatesCount > 0) ? `${result.actualExcludedDatesCount}` : '无'}</Text>
</div>
</div> </div>
</div> </div>
</Card> </Card>
@ -3006,7 +3022,7 @@ export default function App() {
<br /> <br />
<br /> <br />
<br /> <br />
"工作日" "工作日"
<br /> <br />