feat(content): 新增首页导航入口独立管理模块
- 新建 home_navigations 表,独立管理首页卡片导航 - 回退 assessment_types 表的 LinkUrl 字段 - 后台管理:ContentController 新增导航 CRUD 接口 - 小程序 API:HomeController 新增 getNavigationList 接口 - 前端:首页改用 navigationList 数据源,支持配置化跳转 - 数据库已插入3条导航记录(多元测评/学业规划/学科测评)
This commit is contained in:
parent
68b5d1d024
commit
7154d7eb01
|
|
@ -400,6 +400,160 @@ public class ContentController : BusinessControllerBase
|
|||
|
||||
#endregion
|
||||
|
||||
#region HomeNavigation 首页导航接口
|
||||
|
||||
/// <summary>
|
||||
/// 获取首页导航列表
|
||||
/// </summary>
|
||||
/// <param name="request">查询参数</param>
|
||||
/// <returns>分页首页导航列表</returns>
|
||||
[HttpGet("navigation/getList")]
|
||||
[BusinessPermission("content:view")]
|
||||
public async Task<IActionResult> GetNavigationList([FromQuery] HomeNavigationQueryRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _contentService.GetNavigationListAsync(request);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "获取首页导航列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建首页导航
|
||||
/// </summary>
|
||||
/// <param name="request">创建请求</param>
|
||||
/// <returns>新创建的导航ID</returns>
|
||||
[HttpPost("navigation/create")]
|
||||
[BusinessPermission("content:create")]
|
||||
public async Task<IActionResult> CreateNavigation([FromBody] CreateHomeNavigationRequest request)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
return ValidationError("导航名称不能为空");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var id = await _contentService.CreateNavigationAsync(request);
|
||||
return Ok(id);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "创建首页导航失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新首页导航
|
||||
/// </summary>
|
||||
/// <param name="request">更新请求</param>
|
||||
/// <returns>更新结果</returns>
|
||||
[HttpPost("navigation/update")]
|
||||
[BusinessPermission("content:update")]
|
||||
public async Task<IActionResult> UpdateNavigation([FromBody] UpdateHomeNavigationRequest request)
|
||||
{
|
||||
if (request.Id <= 0)
|
||||
{
|
||||
return ValidationError("导航ID无效");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
return ValidationError("导航名称不能为空");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _contentService.UpdateNavigationAsync(request);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "更新首页导航失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除首页导航(软删除)
|
||||
/// </summary>
|
||||
/// <param name="request">删除请求</param>
|
||||
/// <returns>删除结果</returns>
|
||||
[HttpPost("navigation/delete")]
|
||||
[BusinessPermission("content:delete")]
|
||||
public async Task<IActionResult> DeleteNavigation([FromBody] DeleteRequest request)
|
||||
{
|
||||
if (request.Id <= 0)
|
||||
{
|
||||
return ValidationError("导航ID无效");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _contentService.DeleteNavigationAsync(request.Id);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "删除首页导航失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新首页导航状态
|
||||
/// </summary>
|
||||
/// <param name="request">状态更新请求</param>
|
||||
/// <returns>更新结果</returns>
|
||||
[HttpPost("navigation/updateStatus")]
|
||||
[BusinessPermission("content:update")]
|
||||
public async Task<IActionResult> UpdateNavigationStatus([FromBody] UpdateStatusRequest request)
|
||||
{
|
||||
if (request.Id <= 0)
|
||||
{
|
||||
return ValidationError("导航ID无效");
|
||||
}
|
||||
|
||||
if (request.Status < 0 || request.Status > 1)
|
||||
{
|
||||
return ValidationError("状态值无效,只能为0(禁用)或1(启用)");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _contentService.UpdateNavigationStatusAsync(request.Id, request.Status);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
return Error(ex.Code, ex.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Error(ErrorCodes.SystemError, "更新首页导航状态失败");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ public class AdminBusinessDbContext : DbContext
|
|||
/// </summary>
|
||||
public DbSet<Promotion> Promotions { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航入口表
|
||||
/// </summary>
|
||||
public DbSet<HomeNavigation> HomeNavigations { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测评管理
|
||||
|
|
|
|||
|
|
@ -36,12 +36,6 @@ public class AssessmentType
|
|||
[MaxLength(500)]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情横幅图URL
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace MiAssessment.Admin.Business.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航入口表
|
||||
/// </summary>
|
||||
[Table("home_navigations")]
|
||||
public class HomeNavigation
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软删除标记
|
||||
/// </summary>
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
|
|
@ -25,11 +25,6 @@ public class AssessmentTypeDto
|
|||
/// </summary>
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情横幅图URL
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,6 @@ public class CreateAssessmentTypeRequest
|
|||
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "跳转链接URL不能超过500个字符")]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情横幅图URL
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@ public class UpdateAssessmentTypeRequest
|
|||
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "跳转链接URL不能超过500个字符")]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情横幅图URL
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace MiAssessment.Admin.Business.Models.Content;
|
||||
|
||||
/// <summary>
|
||||
/// 创建首页导航请求
|
||||
/// </summary>
|
||||
public class CreateHomeNavigationRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 导航名称(必填)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "导航名称不能为空")]
|
||||
[MaxLength(50, ErrorMessage = "导航名称不能超过50个字符")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "跳转链接URL不能超过500个字符")]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; } = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
namespace MiAssessment.Admin.Business.Models.Content;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航入口 DTO
|
||||
/// </summary>
|
||||
public class HomeNavigationDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态名称
|
||||
/// </summary>
|
||||
public string StatusName { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using MiAssessment.Admin.Business.Models.Common;
|
||||
|
||||
namespace MiAssessment.Admin.Business.Models.Content;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航查询请求
|
||||
/// </summary>
|
||||
public class HomeNavigationQueryRequest : PagedRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称筛选
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态筛选
|
||||
/// </summary>
|
||||
public int? Status { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace MiAssessment.Admin.Business.Models.Content;
|
||||
|
||||
/// <summary>
|
||||
/// 更新首页导航请求
|
||||
/// </summary>
|
||||
public class UpdateHomeNavigationRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 导航ID(必填)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "导航ID不能为空")]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航名称(必填)
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "导航名称不能为空")]
|
||||
[MaxLength(50, ErrorMessage = "导航名称不能超过50个字符")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "图片URL不能超过500个字符")]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500, ErrorMessage = "跳转链接URL不能超过500个字符")]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
}
|
||||
|
|
@ -83,7 +83,6 @@ public class AssessmentService : IAssessmentService
|
|||
Name = t.Name,
|
||||
Code = t.Code,
|
||||
ImageUrl = t.ImageUrl,
|
||||
LinkUrl = t.LinkUrl,
|
||||
DetailImageUrl = t.DetailImageUrl,
|
||||
IntroContent = t.IntroContent,
|
||||
Price = t.Price,
|
||||
|
|
@ -110,7 +109,6 @@ public class AssessmentService : IAssessmentService
|
|||
Name = t.Name,
|
||||
Code = t.Code,
|
||||
ImageUrl = t.ImageUrl,
|
||||
LinkUrl = t.LinkUrl,
|
||||
DetailImageUrl = t.DetailImageUrl,
|
||||
IntroContent = t.IntroContent,
|
||||
Price = t.Price,
|
||||
|
|
@ -163,7 +161,6 @@ public class AssessmentService : IAssessmentService
|
|||
Name = request.Name,
|
||||
Code = request.Code,
|
||||
ImageUrl = request.ImageUrl,
|
||||
LinkUrl = request.LinkUrl,
|
||||
DetailImageUrl = request.DetailImageUrl,
|
||||
IntroContent = request.IntroContent,
|
||||
Price = request.Price,
|
||||
|
|
@ -225,7 +222,6 @@ public class AssessmentService : IAssessmentService
|
|||
assessmentType.Name = request.Name;
|
||||
assessmentType.Code = request.Code;
|
||||
assessmentType.ImageUrl = request.ImageUrl;
|
||||
assessmentType.LinkUrl = request.LinkUrl;
|
||||
assessmentType.DetailImageUrl = request.DetailImageUrl;
|
||||
assessmentType.IntroContent = request.IntroContent;
|
||||
assessmentType.Price = request.Price;
|
||||
|
|
|
|||
|
|
@ -555,6 +555,15 @@ public class ContentService : IContentService
|
|||
return PositionNames.TryGetValue(position, out var name) ? name : "未知";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航状态名称映射
|
||||
/// </summary>
|
||||
private static readonly Dictionary<int, string> NavigationStatusNames = new()
|
||||
{
|
||||
{ 0, "即将上线" },
|
||||
{ 1, "已上线" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 验证 Position 值
|
||||
/// </summary>
|
||||
|
|
@ -568,4 +577,166 @@ public class ContentService : IContentService
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HomeNavigation 首页导航操作
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<PagedResult<HomeNavigationDto>> GetNavigationListAsync(HomeNavigationQueryRequest request)
|
||||
{
|
||||
var query = _dbContext.HomeNavigations
|
||||
.AsNoTracking()
|
||||
.Where(n => !n.IsDeleted);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
query = query.Where(n => n.Name.Contains(request.Name));
|
||||
}
|
||||
|
||||
if (request.Status.HasValue)
|
||||
{
|
||||
query = query.Where(n => n.Status == request.Status.Value);
|
||||
}
|
||||
|
||||
var total = await query.CountAsync();
|
||||
|
||||
var items = await query
|
||||
.OrderByDescending(n => n.Sort)
|
||||
.ThenByDescending(n => n.CreateTime)
|
||||
.Skip(request.Skip)
|
||||
.Take(request.PageSize)
|
||||
.Select(n => new HomeNavigationDto
|
||||
{
|
||||
Id = n.Id,
|
||||
Name = n.Name,
|
||||
ImageUrl = n.ImageUrl,
|
||||
LinkUrl = n.LinkUrl,
|
||||
Sort = n.Sort,
|
||||
Status = n.Status,
|
||||
StatusName = NavigationStatusNames.ContainsKey(n.Status) ? NavigationStatusNames[n.Status] : "未知",
|
||||
CreateTime = n.CreateTime
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return PagedResult<HomeNavigationDto>.Create(items, total, request.Page, request.PageSize);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<HomeNavigationDto> GetNavigationByIdAsync(long id)
|
||||
{
|
||||
var nav = await _dbContext.HomeNavigations
|
||||
.AsNoTracking()
|
||||
.Where(n => n.Id == id && !n.IsDeleted)
|
||||
.Select(n => new HomeNavigationDto
|
||||
{
|
||||
Id = n.Id,
|
||||
Name = n.Name,
|
||||
ImageUrl = n.ImageUrl,
|
||||
LinkUrl = n.LinkUrl,
|
||||
Sort = n.Sort,
|
||||
Status = n.Status,
|
||||
StatusName = NavigationStatusNames.ContainsKey(n.Status) ? NavigationStatusNames[n.Status] : "未知",
|
||||
CreateTime = n.CreateTime
|
||||
})
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (nav == null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.ContentNotFound, "首页导航不存在");
|
||||
}
|
||||
|
||||
return nav;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<long> CreateNavigationAsync(CreateHomeNavigationRequest request)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.ParamError, "导航名称不能为空");
|
||||
}
|
||||
|
||||
var entity = new HomeNavigation
|
||||
{
|
||||
Name = request.Name,
|
||||
ImageUrl = request.ImageUrl,
|
||||
LinkUrl = request.LinkUrl,
|
||||
Sort = request.Sort,
|
||||
Status = request.Status,
|
||||
CreateTime = DateTime.Now,
|
||||
UpdateTime = DateTime.Now,
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
_dbContext.HomeNavigations.Add(entity);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("创建首页导航成功,ID: {Id}, 名称: {Name}", entity.Id, entity.Name);
|
||||
return entity.Id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> UpdateNavigationAsync(UpdateHomeNavigationRequest request)
|
||||
{
|
||||
var entity = await _dbContext.HomeNavigations
|
||||
.Where(n => n.Id == request.Id && !n.IsDeleted)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.ContentNotFound, "首页导航不存在");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.Name))
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.ParamError, "导航名称不能为空");
|
||||
}
|
||||
|
||||
entity.Name = request.Name;
|
||||
entity.ImageUrl = request.ImageUrl;
|
||||
entity.LinkUrl = request.LinkUrl;
|
||||
entity.Sort = request.Sort;
|
||||
entity.Status = request.Status;
|
||||
entity.UpdateTime = DateTime.Now;
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("更新首页导航成功,ID: {Id}", entity.Id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> DeleteNavigationAsync(long id)
|
||||
{
|
||||
var entity = await _dbContext.HomeNavigations.FindAsync(id);
|
||||
if (entity == null || entity.IsDeleted) return false;
|
||||
|
||||
entity.IsDeleted = true;
|
||||
entity.UpdateTime = DateTime.Now;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("删除首页导航成功,ID: {Id}", id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> UpdateNavigationStatusAsync(long id, int status)
|
||||
{
|
||||
var entity = await _dbContext.HomeNavigations
|
||||
.Where(n => n.Id == id && !n.IsDeleted)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.ContentNotFound, "首页导航不存在");
|
||||
}
|
||||
|
||||
entity.Status = status;
|
||||
entity.UpdateTime = DateTime.Now;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("更新首页导航状态成功,ID: {Id}, 状态: {Status}", id, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,4 +109,38 @@ public interface IContentService
|
|||
Task<bool> UpdatePromotionStatusAsync(long id, int status);
|
||||
|
||||
#endregion
|
||||
|
||||
#region HomeNavigation 首页导航操作
|
||||
|
||||
/// <summary>
|
||||
/// 获取首页导航列表
|
||||
/// </summary>
|
||||
Task<PagedResult<HomeNavigationDto>> GetNavigationListAsync(HomeNavigationQueryRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取首页导航
|
||||
/// </summary>
|
||||
Task<HomeNavigationDto> GetNavigationByIdAsync(long id);
|
||||
|
||||
/// <summary>
|
||||
/// 创建首页导航
|
||||
/// </summary>
|
||||
Task<long> CreateNavigationAsync(CreateHomeNavigationRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 更新首页导航
|
||||
/// </summary>
|
||||
Task<bool> UpdateNavigationAsync(UpdateHomeNavigationRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 删除首页导航(软删除)
|
||||
/// </summary>
|
||||
Task<bool> DeleteNavigationAsync(long id);
|
||||
|
||||
/// <summary>
|
||||
/// 更新首页导航状态
|
||||
/// </summary>
|
||||
Task<bool> UpdateNavigationStatusAsync(long id, int status);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,32 @@ public class HomeController : ControllerBase
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取首页导航入口列表
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// GET /api/home/getNavigationList
|
||||
///
|
||||
/// 返回所有启用状态的首页导航入口,按Sort降序排列
|
||||
/// 不需要用户登录认证
|
||||
/// </remarks>
|
||||
/// <returns>导航入口列表</returns>
|
||||
[HttpGet("getNavigationList")]
|
||||
[ProducesResponseType(typeof(ApiResponse<List<HomeNavigationDto>>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<List<HomeNavigationDto>>> GetNavigationList()
|
||||
{
|
||||
try
|
||||
{
|
||||
var navigations = await _homeService.GetNavigationListAsync();
|
||||
return ApiResponse<List<HomeNavigationDto>>.Success(navigations);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get navigation list");
|
||||
return ApiResponse<List<HomeNavigationDto>>.Fail("获取导航入口列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取宣传图列表
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using MiAssessment.Model.Models.Home;
|
||||
|
||||
|
||||
namespace MiAssessment.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -25,6 +26,15 @@ public interface IHomeService
|
|||
/// <returns>测评类型列表</returns>
|
||||
Task<List<AssessmentTypeDto>> GetAssessmentListAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 获取首页导航入口列表
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 返回所有启用状态的首页导航入口,按Sort降序排列
|
||||
/// </remarks>
|
||||
/// <returns>导航入口列表</returns>
|
||||
Task<List<HomeNavigationDto>> GetNavigationListAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 获取宣传图列表
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ public class HomeService : IHomeService
|
|||
Name = a.Name,
|
||||
Code = a.Code,
|
||||
ImageUrl = a.ImageUrl ?? string.Empty,
|
||||
LinkUrl = a.LinkUrl,
|
||||
Price = a.Price,
|
||||
Status = a.Status
|
||||
})
|
||||
|
|
@ -76,6 +75,29 @@ public class HomeService : IHomeService
|
|||
return assessmentTypes;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<HomeNavigationDto>> GetNavigationListAsync()
|
||||
{
|
||||
_logger.LogDebug("获取首页导航入口列表");
|
||||
|
||||
var navigations = await _dbContext.HomeNavigations
|
||||
.AsNoTracking()
|
||||
.Where(n => n.Status == 1 && !n.IsDeleted)
|
||||
.OrderByDescending(n => n.Sort)
|
||||
.Select(n => new HomeNavigationDto
|
||||
{
|
||||
Id = n.Id,
|
||||
Name = n.Name,
|
||||
ImageUrl = n.ImageUrl ?? string.Empty,
|
||||
LinkUrl = n.LinkUrl,
|
||||
Status = n.Status
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("获取到 {Count} 条导航入口记录", navigations.Count);
|
||||
return navigations;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<PromotionDto>> GetPromotionListAsync()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiAssessment.Model.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
@ -61,6 +61,8 @@ public partial class MiAssessmentDbContext : DbContext
|
|||
|
||||
public virtual DbSet<Order> Orders { get; set; }
|
||||
|
||||
public virtual DbSet<HomeNavigation> HomeNavigations { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
// Connection string is configured in Program.cs via dependency injection
|
||||
|
|
@ -1009,6 +1011,43 @@ public partial class MiAssessmentDbContext : DbContext
|
|||
entity.Property(e => e.UpdateTime).HasDefaultValueSql("(getdate())");
|
||||
});
|
||||
|
||||
// ==================== 首页导航表配置 ====================
|
||||
modelBuilder.Entity<HomeNavigation>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("pk_home_navigations");
|
||||
|
||||
entity.ToTable("home_navigations", tb => tb.HasComment("首页导航入口表"));
|
||||
|
||||
entity.HasIndex(e => e.Status, "ix_home_navigations_status");
|
||||
entity.HasIndex(e => e.Sort, "ix_home_navigations_sort");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("主键ID");
|
||||
entity.Property(e => e.Name)
|
||||
.HasMaxLength(50)
|
||||
.HasComment("导航名称");
|
||||
entity.Property(e => e.ImageUrl)
|
||||
.HasMaxLength(500)
|
||||
.HasComment("图标图片URL");
|
||||
entity.Property(e => e.LinkUrl)
|
||||
.HasMaxLength(500)
|
||||
.HasComment("跳转链接URL");
|
||||
entity.Property(e => e.Sort)
|
||||
.HasComment("排序,越大越靠前");
|
||||
entity.Property(e => e.Status)
|
||||
.HasDefaultValue(1)
|
||||
.HasComment("状态:0即将上线 1已上线");
|
||||
entity.Property(e => e.CreateTime)
|
||||
.HasDefaultValueSql("(getdate())")
|
||||
.HasComment("创建时间");
|
||||
entity.Property(e => e.UpdateTime)
|
||||
.HasDefaultValueSql("(getdate())")
|
||||
.HasComment("更新时间");
|
||||
entity.Property(e => e.IsDeleted)
|
||||
.HasDefaultValue(false)
|
||||
.HasComment("软删除标记");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,12 +36,6 @@ public class AssessmentType
|
|||
[MaxLength(500)]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情横幅图URL
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace MiAssessment.Model.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航入口表
|
||||
/// </summary>
|
||||
[Table("home_navigations")]
|
||||
public class HomeNavigation
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软删除标记
|
||||
/// </summary>
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
|
|
@ -25,11 +25,6 @@ public class AssessmentTypeDto
|
|||
/// </summary>
|
||||
public string ImageUrl { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 价格
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
namespace MiAssessment.Model.Models.Home;
|
||||
|
||||
/// <summary>
|
||||
/// 首页导航入口数据传输对象
|
||||
/// </summary>
|
||||
public class HomeNavigationDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 导航ID
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导航名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标图片URL
|
||||
/// </summary>
|
||||
public string ImageUrl { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接URL
|
||||
/// </summary>
|
||||
public string? LinkUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态:0即将上线 1已上线
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
}
|
||||
|
|
@ -20,6 +20,14 @@ export function getAssessmentList() {
|
|||
return get('/home/getAssessmentList')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取首页导航入口列表
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export function getNavigationList() {
|
||||
return get('/home/getNavigationList')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宣传图列表
|
||||
* @returns {Promise<Object>}
|
||||
|
|
@ -31,5 +39,6 @@ export function getPromotionList() {
|
|||
export default {
|
||||
getBannerList,
|
||||
getAssessmentList,
|
||||
getNavigationList,
|
||||
getPromotionList
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
</view>
|
||||
|
||||
<!-- 专业测评入口 -->
|
||||
<view class="assessment-section" v-if="assessmentList.length > 0">
|
||||
<view class="assessment-section" v-if="navigationList.length > 0">
|
||||
<view class="section-header">
|
||||
<view class="section-indicator"></view>
|
||||
<text class="section-title">专业测评</text>
|
||||
|
|
@ -52,9 +52,9 @@
|
|||
<view class="assessment-grid">
|
||||
<view
|
||||
class="assessment-card"
|
||||
v-for="(item, index) in assessmentList"
|
||||
v-for="(item, index) in navigationList"
|
||||
:key="index"
|
||||
@click="handleAssessmentClick(item)"
|
||||
@click="handleNavigationClick(item)"
|
||||
>
|
||||
<!-- 即将上线标签 -->
|
||||
<view v-if="item.status === 0" class="coming-soon-tag">
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useUserStore } from '@/store/user.js'
|
||||
import { useNavbar } from '@/composables/useNavbar.js'
|
||||
import { getBannerList, getAssessmentList, getPromotionList } from '@/api/home.js'
|
||||
import { getBannerList, getAssessmentList, getNavigationList, getPromotionList } from '@/api/home.js'
|
||||
import Loading from '@/components/Loading/index.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
|
@ -110,6 +110,7 @@ const pageLoading = ref(true)
|
|||
const isRefreshing = ref(false)
|
||||
const bannerList = ref([])
|
||||
const assessmentList = ref([])
|
||||
const navigationList = ref([])
|
||||
const promotionList = ref([])
|
||||
|
||||
// 导航栏样式已直接在模板中绑定
|
||||
|
|
@ -142,6 +143,20 @@ async function loadAssessmentList() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载首页导航入口数据
|
||||
*/
|
||||
async function loadNavigationList() {
|
||||
try {
|
||||
const res = await getNavigationList()
|
||||
if (res && res.code === 0 && res.data) {
|
||||
navigationList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载导航入口失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载宣传图数据
|
||||
*/
|
||||
|
|
@ -169,6 +184,7 @@ async function initPageData() {
|
|||
await Promise.all([
|
||||
loadBannerList(),
|
||||
loadAssessmentList(),
|
||||
loadNavigationList(),
|
||||
loadPromotionList()
|
||||
])
|
||||
} finally {
|
||||
|
|
@ -203,13 +219,13 @@ function handleBannerClick(item) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 处理测评入口点击
|
||||
* 处理导航入口点击
|
||||
*/
|
||||
function handleAssessmentClick(item) {
|
||||
// 即将上线的测评,弹出提示
|
||||
function handleNavigationClick(item) {
|
||||
// 即将上线的导航,弹出提示
|
||||
if (item.status === 0) {
|
||||
uni.showToast({
|
||||
title: '该测评暂未开放',
|
||||
title: '该功能暂未开放',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
|
|
@ -219,18 +235,11 @@ function handleAssessmentClick(item) {
|
|||
// 根据后台配置的跳转链接进行导航
|
||||
if (!item.linkUrl) return
|
||||
|
||||
// 如果是测评页面,自动拼接 typeId 和 typeName 参数
|
||||
let url = item.linkUrl
|
||||
if (url.includes('/pages/assessment/')) {
|
||||
const separator = url.includes('?') ? '&' : '?'
|
||||
url = `${url}${separator}typeId=${item.id}&typeName=${encodeURIComponent(item.name || '')}`
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url,
|
||||
url: item.linkUrl,
|
||||
fail: () => {
|
||||
// 如果是tabBar页面,使用switchTab
|
||||
uni.switchTab({ url })
|
||||
uni.switchTab({ url: item.linkUrl })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user