merge
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MiGu.Server.Dashboard;
|
||||
|
||||
namespace MiGu.Server.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/dashboard")]
|
||||
public class DashboardController : ControllerBase
|
||||
{
|
||||
private readonly DashboardShortcutService _shortcuts;
|
||||
|
||||
public DashboardController(DashboardShortcutService shortcuts) => _shortcuts = shortcuts;
|
||||
|
||||
public sealed record SaveQuickEntriesRequest(List<string>? Keys);
|
||||
|
||||
[HttpGet("quick-entries")]
|
||||
public async Task<IActionResult> GetQuickEntries(CancellationToken ct)
|
||||
{
|
||||
var (userId, scope, err) = ResolveSession();
|
||||
if (err != null) return err;
|
||||
|
||||
var result = await _shortcuts.GetAsync(userId!, scope!, ct);
|
||||
return Ok(new { keys = result.Keys, usingDefaults = result.UsingDefaults });
|
||||
}
|
||||
|
||||
[HttpPut("quick-entries")]
|
||||
public async Task<IActionResult> SaveQuickEntries(
|
||||
[FromBody] SaveQuickEntriesRequest req, CancellationToken ct)
|
||||
{
|
||||
var (userId, scope, err) = ResolveSession();
|
||||
if (err != null) return err;
|
||||
|
||||
var result = await _shortcuts.SaveAsync(userId!, scope!, req.Keys, ct);
|
||||
return Ok(new { keys = result.Keys, usingDefaults = result.UsingDefaults });
|
||||
}
|
||||
|
||||
private (string? UserId, string? Scope, IActionResult? Error) ResolveSession()
|
||||
{
|
||||
var userId = User.FindFirstValue(JwtRegisteredClaimNames.Sub)
|
||||
?? User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
return (null, null, Unauthorized(new { message = "未识别用户" }));
|
||||
|
||||
var scope = User.FindFirstValue("scope");
|
||||
if (string.IsNullOrWhiteSpace(scope))
|
||||
return (null, null, BadRequest(new { message = "会话缺少 scope" }));
|
||||
|
||||
return (userId, scope, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using MiGu.Server.SimpleFields;
|
||||
|
||||
namespace MiGu.Server.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Simple 字段管理 API:按车型维护 site / track / plan / car 四类反射字段的默认值与多语言名称。
|
||||
/// 数据持久化于 <c>platform.db</c> 的 <c>simple_fields</c> 表。
|
||||
///
|
||||
/// 对应前端「字段管理」页(<c>/admin/simple-fields</c>,页面 key <c>admin-simple-fields</c>)。
|
||||
/// 前端主流程为「刷新」读库、「默认」从 SimpleLite 拉取模板、「保存」走 <see cref="SaveBatch"/> 全量替换。
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[TypeFilter(typeof(SimpleFieldExceptionFilter))]
|
||||
[Route("api/simple-fields")]
|
||||
public sealed class SimpleFieldController : ControllerBase
|
||||
{
|
||||
private readonly SimpleFieldService _service;
|
||||
|
||||
public SimpleFieldController(SimpleFieldService service) => _service = service;
|
||||
|
||||
/// <summary>
|
||||
/// 查询字段列表,支持按字段类型、车型与关键字过滤。
|
||||
/// 结果按 car_type → field_type → key 排序。
|
||||
/// </summary>
|
||||
/// <param name="fieldType">字段类型,如 <c>siteFields</c>、<c>carFields</c>。</param>
|
||||
/// <param name="carType">车型唯一标识:<c>assemblyName.shortName</c>。</param>
|
||||
/// <param name="q">关键字,匹配 key / car_type / 中英文名 / 其他语言 / 默认值。</param>
|
||||
[HttpGet]
|
||||
public Task<List<SimpleField>> List([FromQuery] string? fieldType, [FromQuery] string? carType, [FromQuery] string? q) => _service.ListAsync(fieldType, carType, q);
|
||||
|
||||
/// <summary>
|
||||
/// 新增单条字段;同车型 + 字段类型下 key 不可重复
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public Task<SimpleField> Create([FromBody] SimpleFieldRequest req) => _service.SaveAsync(req);
|
||||
|
||||
/// <summary>
|
||||
/// 按 id 更新单条字段
|
||||
/// </summary>
|
||||
[HttpPut("{id:guid}")]
|
||||
public Task<SimpleField> Update(Guid id, [FromBody] SimpleFieldRequest req) => _service.SaveAsync(req with { Id = id });
|
||||
|
||||
/// <summary>
|
||||
/// 按 id 删除单条字段
|
||||
/// </summary>
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id)
|
||||
{
|
||||
await _service.DeleteAsync(id);
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量保存字段
|
||||
/// <paramref name="req"/>.<see cref="SimpleFieldBatchRequest.ReplaceAll"/> 为 <c>true</c> 时先清空表再写入(前端「保存」使用此模式)。
|
||||
/// 返回实际写入条数 <c>{ count }</c>。
|
||||
/// </summary>
|
||||
[HttpPost("batch")]
|
||||
public async Task<IActionResult> SaveBatch([FromBody] SimpleFieldBatchRequest req)
|
||||
{
|
||||
var count = await _service.SaveBatchAsync(req);
|
||||
|
||||
return Ok(new { count });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 <see cref="SimpleFieldException"/> 转为 HTTP 400,响应体 <c>{ message }</c>
|
||||
/// </summary>
|
||||
public sealed class SimpleFieldExceptionFilter : IExceptionFilter
|
||||
{
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
if (context.Exception is not SimpleFieldException ex) { return; }
|
||||
|
||||
context.Result = new BadRequestObjectResult(new { message = ex.Message });
|
||||
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user