Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions client/src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,13 @@ export interface OilCostComparisonRequestDto {
}

export enum CostType {
Charging = 1,
Maintenance = 2,
Insurance = 3,
Parking = 4,
Repair = 5,
Other = 6
Charging = 0,
Maintenance = 1,
Insurance = 2,
Other = 3,
Toll = 4,
Parking = 5,
Repair = 6
}

export enum GasolineGrade {
Expand Down
26 changes: 14 additions & 12 deletions client/src/views/electric-vehicle/costs/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@
placeholder="请选择类型"
style="width: 100%"
>
<el-option label="保养" :value="2" />
<el-option label="保险" :value="3" />
<el-option label="停车" :value="4" />
<el-option label="维修" :value="5" />
<el-option label="其他" :value="6" />
<el-option label="保养" :value="1" />
<el-option label="保险" :value="2" />
<el-option label="其他" :value="3" />
<el-option label="过路费" :value="4" />
<el-option label="停车" :value="5" />
<el-option label="维修" :value="6" />
</el-select>
</el-form-item>
<el-form-item label="车辆" prop="vehicleId">
Expand Down Expand Up @@ -219,12 +220,13 @@ const formRules: FormRules = {

const getCostTypeName = (type: number) => {
const map = {
1: "充电",
2: "保养",
3: "保险",
4: "停车",
5: "维修",
6: "其他"
0: "充电",
1: "保养",
2: "保险",
3: "其他",
4: "过路费",
5: "停车",
6: "维修"
};
return map[type] || "未知";
};
Expand Down Expand Up @@ -286,7 +288,7 @@ const handleCreate = () => {
costDate: new Date().toISOString().split("T")[0],
amount: 0,
isBelongToSelf: true,
costType: 2,
costType: 1,
vehicleId: vehicles.value.length === 1 ? vehicles.value[0].id : undefined,
remark: ""
});
Expand Down
77 changes: 77 additions & 0 deletions sql/18-migrate-electric-vehicle-cost-type.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
-- ============================================================
-- 迁移脚本: 18-migrate-electric-vehicle-cost-type.sql
-- 描述: 统一 AppElectricVehicleCost 表的 CostType 枚举值为 0-based
-- 日期: 2026-04-28
-- ============================================================
--
-- 背景说明:
-- 旧前端 CostType 使用 1-based 枚举:
-- 1=充电, 2=保养, 3=保险, 4=停车, 5=维修, 6=其他
--
-- 后端原来使用 0-based 枚举:
-- 0=充电, 1=保养, 2=保险, 3=其他
--
-- 新的统一 0-based 枚举:
-- 0=充电, 1=保养, 2=保险, 3=其他, 4=过路费, 5=停车, 6=维修
--
-- 数据库中可能存在的情况:
-- 1. 如果后端直接存储了旧前端传来的 1-based 值,则数据库中有 1-6
-- 2. 如果后端使用自己的 0-based 枚举,则数据库中有 0-3
--
-- 迁移策略(安全、幂等):
-- - 对于旧前端 1-based 值(4→停车, 5→维修, 6→其他),映射到新的 0-based 值
-- - 对于后端 0-based 值(0-3),保持不变
-- - 使用 CASE WHEN 确保只迁移需要迁移的值
-- ============================================================

-- 先备份(如果还没备份的话,建议在执行前手动备份 DFApp.db)

-- 步骤1: 查看当前数据分布(仅用于调试,注释掉以避免影响自动化执行)
-- SELECT CostType, COUNT(*) as cnt FROM AppElectricVehicleCost GROUP BY CostType ORDER BY CostType;

-- 步骤2: 如果数据库中有旧前端 1-based 的值,需要迁移
-- 注意:必须先处理值 4/5/6,再处理值 1,避免冲突
-- 使用临时值 -1/-2/-3 避免迁移过程中的主键冲突

-- 旧 4 (停车) → 新 5 (停车)
UPDATE AppElectricVehicleCost
SET CostType = -1
WHERE CostType = 4
AND EXISTS (SELECT 1 FROM AppElectricVehicleCost WHERE CostType = 4);

-- 旧 5 (维修) → 新 6 (维修)
UPDATE AppElectricVehicleCost
SET CostType = -2
WHERE CostType = 5
AND EXISTS (SELECT 1 FROM AppElectricVehicleCost WHERE CostType = 5);

-- 旧 6 (其他) → 新 3 (其他)
UPDATE AppElectricVehicleCost
SET CostType = -3
WHERE CostType = 6
AND EXISTS (SELECT 1 FROM AppElectricVehicleCost WHERE CostType = 6);

-- 旧 1 (充电, 前端1-based) → 新 0 (充电)
-- 只有当数据库中同时存在 CostType=0 和 CostType=1 时,
-- 说明数据库混合了两种编码方式,此时 CostType=1 是旧前端的充电记录
-- 如果数据库中只有 CostType=1 没有 CostType=0,说明后端直接存了前端值,1=充电
-- 如果数据库中只有 CostType=0 没有 CostType=1,说明后端用了自己的枚举,无需迁移
UPDATE AppElectricVehicleCost
SET CostType = -4
WHERE CostType = 1
AND NOT EXISTS (
-- 排除:如果 CostType=1 对应的是后端枚举的"保养"(即后端自己创建的记录)
-- 判断依据:如果数据库中存在 CostType=0(后端枚举的充电),说明后端使用了自己的枚举
-- 此时 CostType=1 是后端的"保养",不应迁移
SELECT 1 FROM AppElectricVehicleCost WHERE CostType = 0
);

-- 步骤3: 将临时值更新为最终目标值
UPDATE AppElectricVehicleCost SET CostType = 5 WHERE CostType = -1;
UPDATE AppElectricVehicleCost SET CostType = 6 WHERE CostType = -2;
UPDATE AppElectricVehicleCost SET CostType = 3 WHERE CostType = -3;
UPDATE AppElectricVehicleCost SET CostType = 0 WHERE CostType = -4;

-- 步骤4: 验证迁移结果
-- SELECT CostType, COUNT(*) as cnt FROM AppElectricVehicleCost GROUP BY CostType ORDER BY CostType;
-- 预期结果:CostType 值应全部在 0-6 范围内,不存在负数或超出范围的值
3 changes: 2 additions & 1 deletion src/DFApp.Web/Background/LotteryResultJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ private async Task ProcessResultsIndividually(List<DFApp.Lottery.ResultItemDto>
}

LotteryResult entity = _mapper.MapToEntityFromExternalResultItem(item);
await _lotteryResultRepository.InsertAsync(entity);
// 使用 InsertReturnIdAsync 获取自增 Id,InsertAsync 不会回填自增主键
entity.Id = await _lotteryResultRepository.InsertReturnIdAsync(entity);
successCount++;

// 同时写入该条结果对应的奖级信息
Expand Down
4 changes: 2 additions & 2 deletions src/DFApp.Web/Background/RssMirrorFetchJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ private async Task FetchRssSource(RssSource source)
}
}

// 逐个插入镜像条目(确保自增ID回填)
// 逐个插入镜像条目,确保自增 Id 回填
foreach (var item in newItems)
{
await _rssMirrorItemRepository.InsertAsync(item);
item.Id = await _rssMirrorItemRepository.InsertReturnIdAsync(item);
}

// 插入分词数据
Expand Down
7 changes: 7 additions & 0 deletions src/DFApp.Web/Data/ISqlSugarRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ namespace DFApp.Web.Data;
/// <returns>插入的行数</returns>
Task<int> InsertAsync(T entity);

/// <summary>
/// 插入实体并返回自增主键 ID
/// </summary>
/// <param name="entity">实体</param>
/// <returns>自增主键 ID</returns>
Task<long> InsertReturnIdAsync(T entity);

/// <summary>
/// 批量插入实体
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/DFApp.Web/Data/SqlSugarRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ public async Task<int> InsertAsync(T entity)
return await _db.Insertable(entity).ExecuteCommandAsync();
}

/// <summary>
/// 插入实体并返回自增主键 ID
/// </summary>
/// <param name="entity">实体</param>
/// <returns>自增主键 ID</returns>
public async Task<long> InsertReturnIdAsync(T entity)
{
return await _db.Insertable(entity).ExecuteReturnBigIdentityAsync();
}

/// <summary>
/// 批量插入实体
/// </summary>
Expand Down
17 changes: 16 additions & 1 deletion src/DFApp.Web/Domain/ElectricVehicle/ElectricVehicleEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,22 @@ public enum CostType
/// <summary>
/// 其他费用
/// </summary>
Other
Other = 3,

/// <summary>
/// 过路费
/// </summary>
Toll = 4,

/// <summary>
/// 停车费
/// </summary>
Parking = 5,

/// <summary>
/// 维修费
/// </summary>
Repair = 6
}

/// <summary>
Expand Down
7 changes: 4 additions & 3 deletions src/DFApp.Web/Services/Aria2/Aria2Manager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ private async Task SaveTellStatusResultAsync(ResponseBase response)
var filesItemRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<FilesItem, int>>();
var urisItemRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<UrisItem, short>>();

// 保存主记录
await resultRepository.InsertAsync(tellStatusResult);
// 保存主记录,使用 InsertReturnIdAsync 获取自增 Id
tellStatusResult.Id = await resultRepository.InsertReturnIdAsync(tellStatusResult);

// 解析并保存文件列表
if (resultElement.TryGetProperty("files", out var filesElement) && filesElement.ValueKind == JsonValueKind.Array)
Expand All @@ -201,7 +201,8 @@ private async Task SaveTellStatusResultAsync(ResponseBase response)
Selected = fileElement.TryGetProperty("selected", out var selected) ? GetBoolValue(selected) : null
};

await filesItemRepository.InsertAsync(filesItem);
// 使用 InsertReturnIdAsync 获取自增 Id,用于子表外键关联
filesItem.Id = (int)await filesItemRepository.InsertReturnIdAsync(filesItem);

_logger.LogInformation(" 文件[{Index}]: {Path}, 长度: {Length}, 已完成: {CompletedLength}",
filesItem.Index, filesItem.Path, filesItem.Length, filesItem.CompletedLength);
Expand Down
7 changes: 5 additions & 2 deletions src/DFApp.Web/Services/Lottery/LotteryDataFetchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ public async Task<LotteryDataFetchResponseDto> FetchLotteryData(LotteryDataFetch
results.Add(lotteryResult);
}

// 先保存 LotteryResult
await _lotteryResultRepository.InsertAsync(results);
// 逐条保存 LotteryResult,确保自增 Id 正确回填
foreach (var result in results)
{
result.Id = await _lotteryResultRepository.InsertReturnIdAsync(result);
}
response.SavedCount = results.Count;

// 保存关联的 Prizegrades
Expand Down
6 changes: 4 additions & 2 deletions src/DFApp.Web/Services/Media/ExternalLinkService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ public Task<bool> GetExternalLink()
IsExternalLinkGenerated = true,
IsDownloadCompleted = true,
};
await mediaInfoRepository.InsertAsync(zipMediaInfo);
// 使用 InsertReturnIdAsync 获取自增 Id,InsertAsync 不会回填自增主键
zipMediaInfo.Id = await mediaInfoRepository.InsertReturnIdAsync(zipMediaInfo);
temp.Add(zipMediaInfo);
}

Expand Down Expand Up @@ -211,7 +212,8 @@ public Task<bool> GetExternalLink()
});
}

await externalLinkRepository.InsertAsync(mediaExternalLink);
// 使用 InsertReturnIdAsync 获取自增 Id,InsertAsync 不会回填自增主键
mediaExternalLink.Id = await externalLinkRepository.InsertReturnIdAsync(mediaExternalLink);

// 插入后获取外链 ID,为子记录赋值并批量插入
foreach (var item in mediaExternalLinkMediaIds)
Expand Down
Loading