1
1
This commit is contained in:
170
src/App.tsx
170
src/App.tsx
@ -74,6 +74,7 @@ export default function App() {
|
||||
const WEEKEND_DAYS_FIELD_ID = 'fld2BvjbIN'; // 休息日字段ID(多选项:0-6代表周一到周日)
|
||||
const START_DATE_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
|
||||
@ -217,7 +218,6 @@ export default function App() {
|
||||
weekendDaysConfig: [],
|
||||
matchedLabels: [],
|
||||
skippedWeekends: 0,
|
||||
skippedHolidays: 0,
|
||||
actualDays: undefined,
|
||||
startDateRule: undefined,
|
||||
dateAdjustmentRule: undefined,
|
||||
@ -269,19 +269,7 @@ export default function App() {
|
||||
// 起始时间字段(货期记录表新增)
|
||||
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();
|
||||
@ -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 {
|
||||
const startDate = typeof startDateStr === 'string' ? new Date(startDateStr) : startDateStr;
|
||||
const endDate = typeof endDateStr === 'string' ? new Date(endDateStr) : endDateStr;
|
||||
const start = typeof startDate === 'string' ? parseDate(startDate) : startDate;
|
||||
const end = typeof endDate === 'string' ? parseDate(endDate) : endDate;
|
||||
|
||||
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
||||
return 0;
|
||||
if (!start || !end || isNaN(start.getTime()) || isNaN(end.getTime())) {
|
||||
return { count: 0, dates: [] };
|
||||
}
|
||||
|
||||
if (typeof startDateStr === 'string' && (startDateStr.includes('未找到') || startDateStr.includes('时效值为0'))) {
|
||||
return 0;
|
||||
}
|
||||
const actualExcludedDates: string[] = [];
|
||||
|
||||
if (typeof endDateStr === 'string' && (endDateStr.includes('未找到') || endDateStr.includes('时效值为0'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
let currentDate = new Date(startDate);
|
||||
|
||||
while (currentDate <= endDate) {
|
||||
if (isChineseHoliday(currentDate)) {
|
||||
count++;
|
||||
for (const excludedDateStr of excludedDates) {
|
||||
const excludedDate = parseDate(excludedDateStr);
|
||||
if (excludedDate && excludedDate >= start && excludedDate <= end) {
|
||||
actualExcludedDates.push(excludedDateStr);
|
||||
}
|
||||
currentDate = addDays(currentDate, 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
return { count: actualExcludedDates.length, dates: actualExcludedDates };
|
||||
} 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 => {
|
||||
@ -473,9 +448,15 @@ export default function App() {
|
||||
return weekendDays.includes(date.getDay());
|
||||
};
|
||||
|
||||
// 判断是否为工作日 - 只排除法定节假日和表格配置的休息日
|
||||
const isBusinessDay = (date: Date, weekendDays: number[] = []): boolean => {
|
||||
return !isCustomWeekend(date, weekendDays) && !isChineseHoliday(date);
|
||||
// 判断是否为工作日 - 排除表格休息日、以及节点自定义不参与计算日期
|
||||
const isBusinessDay = (date: Date, weekendDays: number[] = [], excludedDates: string[] = []): boolean => {
|
||||
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);
|
||||
|
||||
if (calculationMethod === '内部') {
|
||||
@ -591,8 +572,8 @@ export default function App() {
|
||||
result.setDate(result.getDate() + 1);
|
||||
}
|
||||
|
||||
// 找到下一个工作日
|
||||
while (!isBusinessDay(result, [])) {
|
||||
// 找到下一个工作日(考虑休息日和自定义跳过日期)
|
||||
while (!isBusinessDay(result, weekendDays, excludedDates)) {
|
||||
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);
|
||||
let remainingDays = businessDays;
|
||||
|
||||
@ -615,7 +596,7 @@ export default function App() {
|
||||
|
||||
while (addedDays < wholeDays) {
|
||||
result.setDate(result.getDate() + 1);
|
||||
if (isBusinessDay(result, weekendDays)) {
|
||||
if (isBusinessDay(result, weekendDays, excludedDates)) {
|
||||
addedDays++;
|
||||
}
|
||||
}
|
||||
@ -634,7 +615,7 @@ export default function App() {
|
||||
} else if (currentHour >= 18) {
|
||||
// 跳到下一个工作日的9:00
|
||||
result.setDate(result.getDate() + 1);
|
||||
while (!isBusinessDay(result, weekendDays)) {
|
||||
while (!isBusinessDay(result, weekendDays, excludedDates)) {
|
||||
result.setDate(result.getDate() + 1);
|
||||
}
|
||||
currentHour = 9;
|
||||
@ -653,7 +634,7 @@ export default function App() {
|
||||
|
||||
// 跳到下一个工作日
|
||||
result.setDate(result.getDate() + 1);
|
||||
while (!isBusinessDay(result, weekendDays)) {
|
||||
while (!isBusinessDay(result, weekendDays, excludedDates)) {
|
||||
result.setDate(result.getDate() + 1);
|
||||
}
|
||||
|
||||
@ -666,8 +647,8 @@ export default function App() {
|
||||
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);
|
||||
let addedDays = 0;
|
||||
|
||||
@ -678,7 +659,7 @@ export default function App() {
|
||||
// 添加整数工作日
|
||||
while (addedDays < wholeDays) {
|
||||
result.setDate(result.getDate() + 1);
|
||||
if (isBusinessDay(result, weekendDays)) {
|
||||
if (isBusinessDay(result, weekendDays, excludedDates)) {
|
||||
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) {
|
||||
// 获取起始日期调整规则
|
||||
const startDateRule = fields[START_DATE_RULE_FIELD_ID];
|
||||
@ -1041,6 +1043,7 @@ export default function App() {
|
||||
matchedLabels: matchedLabels,
|
||||
processOrder: orderValue, // 添加流程顺序
|
||||
weekendDays: weekendDays, // 添加休息日配置
|
||||
excludedDates: excludedDates, // 添加自定义跳过日期
|
||||
startDateRule: startDateRule, // 添加起始日期调整规则
|
||||
dateAdjustmentRule: dateAdjustmentRule // 添加JSON格式日期调整规则
|
||||
});
|
||||
@ -1324,15 +1327,15 @@ export default function App() {
|
||||
// 计算当前节点的开始和完成时间(使用工作日计算)
|
||||
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;
|
||||
if (calculationMethod === '内部') {
|
||||
// 使用内部工作时间计算
|
||||
endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays);
|
||||
endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
|
||||
} else {
|
||||
// 使用原有的24小时制计算
|
||||
endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays);
|
||||
endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -1410,11 +1413,11 @@ export default function App() {
|
||||
|
||||
let nodeEndTime: Date;
|
||||
if (timelineValue) {
|
||||
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod);
|
||||
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
|
||||
if (nodeCalculationMethod === '内部') {
|
||||
nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays);
|
||||
nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
|
||||
} else {
|
||||
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays);
|
||||
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
|
||||
}
|
||||
} else {
|
||||
nodeEndTime = new Date(nodeStartTime);
|
||||
@ -1422,9 +1425,11 @@ export default function App() {
|
||||
|
||||
// 计算跳过的天数
|
||||
const skippedWeekends = calculateSkippedWeekends(nodeStartTime, nodeEndTime, processNode.weekendDays);
|
||||
const skippedHolidays = calculateSkippedHolidays(timelineResult.startDate, timelineResult.endDate);
|
||||
const actualDays = calculateActualDays(timelineResult.startDate, timelineResult.endDate);
|
||||
|
||||
// 计算时间范围内实际跳过的自定义日期
|
||||
const excludedDatesInRange = calculateExcludedDatesInRange(nodeStartTime, nodeEndTime, processNode.excludedDates || []);
|
||||
|
||||
results.push({
|
||||
processOrder: processNode.processOrder,
|
||||
nodeName: processNode.nodeName,
|
||||
@ -1445,10 +1450,13 @@ export default function App() {
|
||||
// 新增:标识是否为累加处理
|
||||
isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1,
|
||||
weekendDaysConfig: processNode.weekendDays, // 新增:保存休息日配置用于显示
|
||||
excludedDates: processNode.excludedDates || [], // 新增:保存不参与计算日期用于显示与快照
|
||||
// 新增:保存时间范围内实际跳过的日期
|
||||
actualExcludedDates: excludedDatesInRange.dates,
|
||||
actualExcludedDatesCount: excludedDatesInRange.count,
|
||||
calculationMethod: nodeCalculationMethod, // 新增:保存计算方式
|
||||
ruleDescription: ruleDescription, // 新增:保存规则描述
|
||||
skippedWeekends: skippedWeekends,
|
||||
skippedHolidays: skippedHolidays,
|
||||
actualDays: actualDays,
|
||||
// 新增:保存调整规则用于重新计算
|
||||
startDateRule: processNode.startDateRule,
|
||||
@ -1571,25 +1579,28 @@ export default function App() {
|
||||
const nodeCalculationMethod = result.calculationMethod || '外部'; // 获取节点的计算方式
|
||||
|
||||
let nodeEndTime: Date;
|
||||
const nodeExcludedDates = Array.isArray(result.excludedDates) ? result.excludedDates : [];
|
||||
if (adjustedTimelineValue > 0) {
|
||||
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod);
|
||||
const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
|
||||
if (nodeCalculationMethod === '内部') {
|
||||
nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays);
|
||||
nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
|
||||
} else {
|
||||
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays);
|
||||
nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
|
||||
}
|
||||
} else {
|
||||
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 estimatedStartStr = formatDate(adjustedStartTime);
|
||||
const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
|
||||
const skippedHolidays = calculateSkippedHolidays(estimatedStartStr, estimatedEndStr);
|
||||
const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
|
||||
|
||||
// 计算时间范围内实际跳过的自定义日期
|
||||
const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
|
||||
|
||||
// 更新结果
|
||||
updatedResults[i] = {
|
||||
...result,
|
||||
@ -1599,8 +1610,10 @@ export default function App() {
|
||||
adjustment: adjustment,
|
||||
calculationMethod: nodeCalculationMethod, // 保持计算方式
|
||||
skippedWeekends: skippedWeekends,
|
||||
skippedHolidays: skippedHolidays,
|
||||
actualDays: actualDays,
|
||||
// 更新时间范围内实际跳过的日期
|
||||
actualExcludedDates: excludedDatesInRange.dates,
|
||||
actualExcludedDatesCount: excludedDatesInRange.count,
|
||||
adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
|
||||
ruleDescription: ruleDescription // 添加更新后的规则描述
|
||||
};
|
||||
@ -2981,11 +2994,14 @@ export default function App() {
|
||||
backgroundColor: '#f0f0f0',
|
||||
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>
|
||||
</Text>
|
||||
<div style={{ fontSize: '12px', color: '#666', marginTop: '2px' }}>
|
||||
<Text>跳过日期:{(result.actualExcludedDatesCount && result.actualExcludedDatesCount > 0) ? `${result.actualExcludedDatesCount} 天` : '无'}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@ -3006,7 +3022,7 @@ export default function App() {
|
||||
<br />
|
||||
• 根据每个节点的休息日配置自动跳过相应的休息日
|
||||
<br />
|
||||
• 自动跳过中国法定节假日(元旦、春节、清明、劳动节、端午、中秋、国庆等)
|
||||
• 可为每个节点配置“跳过日期”,这些日期将不参与工作日计算
|
||||
<br />
|
||||
• 时效值以"工作日"为单位计算,确保预期时间的准确性
|
||||
<br />
|
||||
|
||||
Reference in New Issue
Block a user