diff --git a/backend/services/mining-admin-service/src/application/services/batch-mining.service.ts b/backend/services/mining-admin-service/src/application/services/batch-mining.service.ts index 007537c6..c1291185 100644 --- a/backend/services/mining-admin-service/src/application/services/batch-mining.service.ts +++ b/backend/services/mining-admin-service/src/application/services/batch-mining.service.ts @@ -252,49 +252,81 @@ export class BatchMiningService { /** * 解析 Excel 文件数据 * Excel 格式: - * 序号 | 注册ID | 认种量(棵)| 挖矿开始时间 | 批次 | 授权提前挖的天数 | 备注 + * 用户ID | 认种数量 | 认种时间 | 挖矿开始时间 | 批次 | 授权提前挖的天数(可选) + * + * 注意:preMineDays (挖矿天数) 根据"挖矿开始时间"到今天自动计算 */ parseExcelData(rows: any[]): BatchMiningItem[] { this.logger.log(`[parseExcelData] 开始解析 Excel 数据, 总行数: ${rows.length}`); const items: BatchMiningItem[] = []; + const today = new Date(); + today.setHours(0, 0, 0, 0); for (let i = 0; i < rows.length; i++) { const row = rows[i]; - // 跳过标题行和汇总行 - if (!row || typeof row[1] !== 'string' || row[1] === '注册ID' || row[1] === '合计') { - this.logger.debug(`[parseExcelData] 跳过行 ${i + 1}: 标题行或汇总行`); + // 跳过空行 + if (!row || !row[0]) { + this.logger.debug(`[parseExcelData] 跳过行 ${i + 1}: 空行`); continue; } - // 跳过认种量为 0 或无效的行 - const treeCount = parseInt(row[2], 10); - if (isNaN(treeCount) || treeCount <= 0) { - this.logger.debug(`[parseExcelData] 跳过行 ${i + 1}: 认种量无效 (${row[2]})`); + // 跳过标题行 + const firstCell = String(row[0]).trim(); + if (firstCell === '用户ID' || firstCell === '注册ID' || firstCell === '序号') { + this.logger.debug(`[parseExcelData] 跳过行 ${i + 1}: 标题行`); continue; } - // 确保注册 ID 格式正确(补全 D 前缀) - let accountSequence = String(row[1]); + // 获取用户ID (第一列) + let accountSequence = String(row[0]).trim(); if (!accountSequence.startsWith('D')) { accountSequence = 'D' + accountSequence; } - const batch = parseInt(row[4], 10); - const preMineDays = parseInt(row[5], 10); + // 获取认种量 (第二列) + const treeCount = parseInt(row[1], 10); + if (isNaN(treeCount) || treeCount <= 0) { + this.logger.debug(`[parseExcelData] 跳过行 ${i + 1}: 认种量无效 (${row[1]})`); + continue; + } - if (isNaN(batch) || isNaN(preMineDays) || preMineDays <= 0) { - this.logger.warn(`[parseExcelData] 跳过行 ${i + 1}: 批次或提前天数无效 (batch=${row[4]}, preMineDays=${row[5]})`); + // 获取挖矿开始时间 (第四列,索引3) + const miningStartDateStr = String(row[3] || '').trim(); + if (!miningStartDateStr) { + this.logger.warn(`[parseExcelData] 跳过行 ${i + 1}: 挖矿开始时间为空`); + continue; + } + + // 解析挖矿开始时间 (格式: 2025.11.8 或 2025-11-08) + const miningStartDate = this.parseDate(miningStartDateStr); + if (!miningStartDate) { + this.logger.warn(`[parseExcelData] 跳过行 ${i + 1}: 挖矿开始时间格式无效 (${miningStartDateStr})`); + continue; + } + + // 计算从挖矿开始到今天的天数 + const diffTime = today.getTime() - miningStartDate.getTime(); + const preMineDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); + if (preMineDays <= 0) { + this.logger.warn(`[parseExcelData] 跳过行 ${i + 1}: 挖矿天数<=0 (开始日期: ${miningStartDateStr}, 天数: ${preMineDays})`); + continue; + } + + // 获取批次 (第五列,索引4) + const batch = parseInt(row[4], 10); + if (isNaN(batch) || batch <= 0) { + this.logger.warn(`[parseExcelData] 跳过行 ${i + 1}: 批次无效 (${row[4]})`); continue; } items.push({ accountSequence, treeCount, - miningStartDate: String(row[3] || ''), + miningStartDate: miningStartDateStr, batch, preMineDays, - remark: row[6] ? String(row[6]) : undefined, + remark: row[5] ? String(row[5]) : undefined, }); } @@ -306,4 +338,31 @@ export class BatchMiningService { return items; } + + /** + * 解析日期字符串 + * 支持格式: 2025.11.8, 2025-11-08, 2025/11/8 + */ + private parseDate(dateStr: string): Date | null { + // 尝试不同格式 + const formats = [ + /^(\d{4})\.(\d{1,2})\.(\d{1,2})$/, // 2025.11.8 + /^(\d{4})-(\d{1,2})-(\d{1,2})$/, // 2025-11-08 + /^(\d{4})\/(\d{1,2})\/(\d{1,2})$/, // 2025/11/8 + ]; + + for (const format of formats) { + const match = dateStr.match(format); + if (match) { + const year = parseInt(match[1], 10); + const month = parseInt(match[2], 10) - 1; // 月份从0开始 + const day = parseInt(match[3], 10); + const date = new Date(year, month, day); + date.setHours(0, 0, 0, 0); + return date; + } + } + + return null; + } }