tmp
This commit is contained in:
@@ -6,7 +6,8 @@ public class TransactionCategoryController(
|
||||
ITransactionCategoryRepository categoryRepository,
|
||||
ITransactionRecordRepository transactionRecordRepository,
|
||||
ILogger<TransactionCategoryController> logger,
|
||||
IBudgetRepository budgetRepository
|
||||
IBudgetRepository budgetRepository,
|
||||
IOpenAiService openAiService
|
||||
) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -199,6 +200,125 @@ public class TransactionCategoryController(
|
||||
return $"批量创建分类失败: {ex.Message}".Fail<int>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为指定分类生成新的SVG图标
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<BaseResponse<string>> GenerateIconAsync([FromBody] GenerateIconDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var category = await categoryRepository.GetByIdAsync(dto.CategoryId);
|
||||
if (category == null)
|
||||
{
|
||||
return "分类不存在".Fail<string>();
|
||||
}
|
||||
|
||||
// 使用AI生成简洁的SVG图标
|
||||
var systemPrompt = @"你是一个SVG图标生成专家。请生成简洁、现代的单色SVG图标。
|
||||
要求:
|
||||
1. 只返回<svg>标签及其内容,不要其他说明文字
|
||||
2. viewBox=""0 0 24 24""
|
||||
3. 尺寸为24x24
|
||||
4. 使用单色,fill=""currentColor""
|
||||
5. 简洁的设计,适合作为应用图标";
|
||||
|
||||
var userPrompt = $"为分类"{category.Name}"({(category.Type == TransactionType.Expense ? "支出" : category.Type == TransactionType.Income ? "收入" : "不计收支")})生成一个SVG图标";
|
||||
|
||||
var svgContent = await openAiService.ChatAsync(systemPrompt, userPrompt, timeoutSeconds: 30);
|
||||
if (string.IsNullOrWhiteSpace(svgContent))
|
||||
{
|
||||
return "AI生成图标失败".Fail<string>();
|
||||
}
|
||||
|
||||
// 提取SVG标签内容
|
||||
var svgMatch = System.Text.RegularExpressions.Regex.Match(svgContent, @"<svg[^>]*>.*?</svg>",
|
||||
System.Text.RegularExpressions.RegexOptions.Singleline);
|
||||
|
||||
if (!svgMatch.Success)
|
||||
{
|
||||
return "生成的内容不包含有效的SVG标签".Fail<string>();
|
||||
}
|
||||
|
||||
var svg = svgMatch.Value;
|
||||
|
||||
// 解析现有图标数组
|
||||
var icons = string.IsNullOrWhiteSpace(category.Icon)
|
||||
? new List<string>()
|
||||
: JsonSerializer.Deserialize<List<string>>(category.Icon) ?? new List<string>();
|
||||
|
||||
// 添加新图标
|
||||
icons.Add(svg);
|
||||
|
||||
// 更新数据库
|
||||
category.Icon = JsonSerializer.Serialize(icons);
|
||||
category.UpdateTime = DateTime.Now;
|
||||
|
||||
var success = await categoryRepository.UpdateAsync(category);
|
||||
if (!success)
|
||||
{
|
||||
return "更新分类图标失败".Fail<string>();
|
||||
}
|
||||
|
||||
return svg.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "生成图标失败, CategoryId: {CategoryId}", dto.CategoryId);
|
||||
return $"生成图标失败: {ex.Message}".Fail<string>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新分类的选中图标索引
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<BaseResponse> UpdateSelectedIconAsync([FromBody] UpdateSelectedIconDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var category = await categoryRepository.GetByIdAsync(dto.CategoryId);
|
||||
if (category == null)
|
||||
{
|
||||
return "分类不存在".Fail();
|
||||
}
|
||||
|
||||
// 验证索引有效性
|
||||
if (string.IsNullOrWhiteSpace(category.Icon))
|
||||
{
|
||||
return "该分类没有可用图标".Fail();
|
||||
}
|
||||
|
||||
var icons = JsonSerializer.Deserialize<List<string>>(category.Icon);
|
||||
if (icons == null || dto.SelectedIndex < 0 || dto.SelectedIndex >= icons.Count)
|
||||
{
|
||||
return "无效的图标索引".Fail();
|
||||
}
|
||||
|
||||
// 这里可以添加一个SelectedIconIndex字段到实体中,或者将选中的图标移到数组第一位
|
||||
// 暂时采用移动到第一位的方式
|
||||
var selectedIcon = icons[dto.SelectedIndex];
|
||||
icons.RemoveAt(dto.SelectedIndex);
|
||||
icons.Insert(0, selectedIcon);
|
||||
|
||||
category.Icon = JsonSerializer.Serialize(icons);
|
||||
category.UpdateTime = DateTime.Now;
|
||||
|
||||
var success = await categoryRepository.UpdateAsync(category);
|
||||
if (success)
|
||||
{
|
||||
return "更新图标成功".Ok();
|
||||
}
|
||||
|
||||
return "更新图标失败".Fail();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "更新选中图标失败, Dto: {@Dto}", dto);
|
||||
return $"更新选中图标失败: {ex.Message}".Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,3 +336,18 @@ public record UpdateCategoryDto(
|
||||
long Id,
|
||||
string Name
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 生成图标DTO
|
||||
/// </summary>
|
||||
public record GenerateIconDto(
|
||||
long CategoryId
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 更新选中图标DTO
|
||||
/// </summary>
|
||||
public record UpdateSelectedIconDto(
|
||||
long CategoryId,
|
||||
int SelectedIndex
|
||||
);
|
||||
|
||||
@@ -66,6 +66,17 @@ public static class Expand
|
||||
.WithIdentity("LogCleanupTrigger")
|
||||
.WithCronSchedule("0 0 2 * * ?") // 每天凌晨2点执行
|
||||
.WithDescription("每天凌晨2点执行日志清理(保留30天)"));
|
||||
|
||||
// 配置分类图标生成任务 - 每24小时执行一次
|
||||
var categoryIconJobKey = new JobKey("CategoryIconGenerationJob");
|
||||
q.AddJob<CategoryIconGenerationJob>(opts => opts
|
||||
.WithIdentity(categoryIconJobKey)
|
||||
.WithDescription("分类图标生成任务"));
|
||||
q.AddTrigger(opts => opts
|
||||
.ForJob(categoryIconJobKey)
|
||||
.WithIdentity("CategoryIconGenerationTrigger")
|
||||
.WithCronSchedule("0 0 0 * * ?") // 每24小时执行一次
|
||||
.WithDescription("每24小时扫描并为无图标分类生成SVG图标"));
|
||||
});
|
||||
|
||||
// 添加 Quartz Hosted Service
|
||||
|
||||
Reference in New Issue
Block a user