using System.Text.Json; using BoardApp.Config; using BoardApp.Models; using BoardApp.Services; using BoardApp.Session; using Microsoft.AspNetCore.Mvc; namespace BoardApp.Controllers; public sealed class BoardController : Controller { private readonly BoardConfigLoader _cfg; private readonly ScenarioService _scenarios; private readonly UserScenarioService _userScenarios; private readonly WarehouseCalendarService _warehouse; public BoardController( BoardConfigLoader cfg, ScenarioService scenarios, UserScenarioService userScenarios, WarehouseCalendarService warehouse) { _cfg = cfg; _scenarios = scenarios; _userScenarios = userScenarios; _warehouse = warehouse; } private string BasePath => (Request.PathBase.HasValue ? Request.PathBase.Value! : "/board"); private SessionUser CurrentUser() => HttpContext.Session.GetJson("user") ?? new SessionUser(); [HttpGet("/check/")] public IActionResult Check() { var u = HttpContext.Session.GetJson("user"); if (u is not null && !string.IsNullOrWhiteSpace(u.Username)) { return Content("ok", "text/plain"); } return StatusCode(401, "unauthorized"); } [HttpGet("/login")] public IActionResult Login() { var u = HttpContext.Session.GetJson("user"); if (u is not null && !string.IsNullOrWhiteSpace(u.Username)) { return Redirect(BasePath + "/"); } return View("Login", new LoginViewModel { BasePath = BasePath }); } [HttpGet("/")] public IActionResult Home() { var username = CurrentUser().Username; var categories = _scenarios.LoadHomeCatalogForUser(username); var imgMap = _scenarios.BuildScenarioImageMapForUser(username); var vm = new HomeViewModel { BasePath = BasePath, Username = username, Categories = categories, ScenarioImagesJson = JsonSerializer.Serialize(imgMap) }; return View("Home", vm); } [HttpGet("/config/scenarios")] public IActionResult UserScenarios() { var username = CurrentUser().Username; var pages = _cfg.LoadPagesConfig().Pages; var userScenarios = _userScenarios.ListUserScenarios(username); return View("UserScenarios", new UserScenariosViewModel { BasePath = BasePath, Username = username, AllPages = pages, UserScenarios = userScenarios, StaytimeMin = UserScenarioService.StaytimeMin, StaytimeMax = UserScenarioService.StaytimeMax }); } private static (int year, int month) ShiftMonth(int year, int month, int delta) { var d = new DateTime(year, month, 1).AddMonths(delta); return (d.Year, d.Month); } [HttpGet("/warehouse-calendar")] public async Task WarehouseCalendar([FromQuery] int? year, [FromQuery] int? month) { var now = DateTime.Now; var y = year.HasValue && year.Value >= 2000 && year.Value <= 2100 ? year.Value : now.Year; var m = month.HasValue && month.Value >= 1 && month.Value <= 12 ? month.Value : now.Month; var monthTitle = new DateTime(y, m, 1).ToString("yyyy年M月", System.Globalization.CultureInfo.GetCultureInfo("zh-CN")); var prev = ShiftMonth(y, m, -1); var next = ShiftMonth(y, m, 1); var todayKey = WarehouseCalendarService.FormatDateKey(now.Year, now.Month, now.Day); var vm = new WarehouseCalendarViewModel { BasePath = BasePath, Username = CurrentUser().Username, Year = y, Month = m, MonthTitle = monthTitle, TodayKey = todayKey, PrevYear = prev.year, PrevMonth = prev.month, NextYear = next.year, NextMonth = next.month, WeekdayLabels = new List { "一", "二", "三", "四", "五", "六", "日" } }; try { var plans = await _warehouse.LoadWarehousePlansGroupedByDate(y, m); vm.Rows = WarehouseCalendarService.BuildMonthRows(y, m, plans); vm.DataError = null; return View("WarehouseCalendar", vm); } catch (Exception ex) { vm.Rows = WarehouseCalendarService.BuildMonthRows(y, m, new Dictionary>()); vm.DataError = $"数据加载失败:{ex.Message}"; Response.StatusCode = 503; return View("WarehouseCalendar", vm); } } private ScenarioViewModel? BuildScenarioViewSlides(string username, string scenarioId, string pageIdHint) { var appCfg = HttpContext.Items["BoardAppConfig"] as AppConfig ?? _cfg.LoadAppConfig(); var resolved = _scenarios.ResolveScenarioForUser(username, scenarioId); if (resolved is null) return null; var sc = resolved.Scenario; var slides = sc.Pages.Select(p => new ViewSlide { Id = p.Id, Title = p.Title, Staytime = p.Staytime > 0 ? p.Staytime : 30, BoardUrl = BoardUrlResolver.ResolveBoardUrl(appCfg.DataEasePublicBase, p.BoardUrl) }).ToList(); var startIndex = 0; if (!string.IsNullOrWhiteSpace(pageIdHint)) { var idx = slides.FindIndex(p => string.Equals(p.Id, pageIdHint, StringComparison.Ordinal)); if (idx >= 0) startIndex = idx; } return new ScenarioViewModel { BasePath = BasePath, DocumentTitle = sc.Name, ScenarioId = sc.Id, ScenarioName = sc.Name, ScenarioImage = sc.Image, Slides = slides, SlidesJson = JsonSerializer.Serialize(slides), StartIndex = startIndex }; } [HttpGet("/view")] public IActionResult ViewScenario([FromQuery] string scenarioId, [FromQuery] string? pageId) { var username = CurrentUser().Username; var data = BuildScenarioViewSlides(username, scenarioId ?? "", pageId ?? ""); if (data is null) return NotFound("场景不存在"); return View("View", data); } [HttpGet("/view-i")] public IActionResult ViewScenarioI([FromQuery] string scenarioId, [FromQuery] string? pageId) { var username = CurrentUser().Username; var data = BuildScenarioViewSlides(username, scenarioId ?? "", pageId ?? ""); if (data is null) return NotFound("场景不存在"); return View("ViewI", data); } [HttpGet("/view-tabs")] public IActionResult ViewTabsCompat() { var q = Request.QueryString.HasValue ? Request.QueryString.Value : ""; return Redirect(BasePath + "/view" + (q ?? "")); } }