389 lines
15 KiB
C#
389 lines
15 KiB
C#
using CampusErrand.Data;
|
|
using CampusErrand.Models;
|
|
using CampusErrand.Models.Dtos;
|
|
using CampusErrand.Helpers;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace CampusErrand.Endpoints;
|
|
|
|
public static class ShopEndpoints
|
|
{
|
|
public static void MapShopEndpoints(this WebApplication app)
|
|
{
|
|
// 前端获取门店列表(仅启用门店,含菜品种类数量)
|
|
app.MapGet("/api/shops", async (AppDbContext db) =>
|
|
{
|
|
var shops = await db.Shops
|
|
.Where(s => s.IsEnabled)
|
|
.Select(s => new ShopListResponse
|
|
{
|
|
Id = s.Id,
|
|
Name = s.Name,
|
|
Photo = s.Photo,
|
|
Location = s.Location,
|
|
DishCount = s.Dishes.Count(d => d.IsEnabled)
|
|
})
|
|
.ToListAsync();
|
|
return Results.Ok(shops);
|
|
});
|
|
|
|
// 前端获取门店详情(含 Banner 和菜品)
|
|
app.MapGet("/api/shops/{id}", async (int id, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops
|
|
.Include(s => s.ShopBanners)
|
|
.Include(s => s.Dishes)
|
|
.FirstOrDefaultAsync(s => s.Id == id);
|
|
|
|
if (shop == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
}
|
|
|
|
var response = new ShopDetailResponse
|
|
{
|
|
Id = shop.Id,
|
|
Name = shop.Name,
|
|
Photo = shop.Photo,
|
|
Location = shop.Location,
|
|
Notice = shop.Notice,
|
|
PackingFeeType = shop.PackingFeeType.ToString(),
|
|
PackingFeeAmount = shop.PackingFeeAmount,
|
|
IsEnabled = shop.IsEnabled,
|
|
Banners = shop.ShopBanners
|
|
.OrderBy(b => b.SortOrder)
|
|
.Select(b => new ShopBannerResponse
|
|
{
|
|
Id = b.Id,
|
|
ImageUrl = b.ImageUrl,
|
|
SortOrder = b.SortOrder
|
|
}).ToList(),
|
|
Dishes = shop.Dishes
|
|
.Where(d => d.IsEnabled)
|
|
.Select(d => new DishResponse
|
|
{
|
|
Id = d.Id,
|
|
ShopId = d.ShopId,
|
|
Name = d.Name,
|
|
Photo = d.Photo,
|
|
Price = d.Price,
|
|
IsEnabled = d.IsEnabled
|
|
}).ToList()
|
|
};
|
|
|
|
return Results.Ok(response);
|
|
});
|
|
|
|
// 管理端获取门店列表(全部)
|
|
app.MapGet("/api/admin/shops", async (AppDbContext db) =>
|
|
{
|
|
var shops = await db.Shops
|
|
.Select(s => new AdminShopResponse
|
|
{
|
|
Id = s.Id,
|
|
Name = s.Name,
|
|
Photo = s.Photo,
|
|
Location = s.Location,
|
|
Notice = s.Notice,
|
|
PackingFeeType = s.PackingFeeType.ToString(),
|
|
PackingFeeAmount = s.PackingFeeAmount,
|
|
IsEnabled = s.IsEnabled,
|
|
DishCount = s.Dishes.Count
|
|
})
|
|
.ToListAsync();
|
|
return Results.Ok(shops);
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 管理端创建门店
|
|
app.MapPost("/api/admin/shops", async (ShopRequest request, AppDbContext db) =>
|
|
{
|
|
var errors = BusinessHelpers.ValidateShopRequest(request);
|
|
if (errors.Count > 0)
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors });
|
|
}
|
|
|
|
if (!Enum.TryParse<PackingFeeType>(request.PackingFeeType, true, out var feeType) || !Enum.IsDefined(feeType))
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors = new[] { new { field = "packingFeeType", message = "打包费类型不合法" } } });
|
|
}
|
|
|
|
var shop = new Shop
|
|
{
|
|
Name = request.Name,
|
|
Photo = request.Photo,
|
|
Location = request.Location,
|
|
Notice = request.Notice,
|
|
PackingFeeType = feeType,
|
|
PackingFeeAmount = request.PackingFeeAmount,
|
|
IsEnabled = request.IsEnabled
|
|
};
|
|
|
|
db.Shops.Add(shop);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.Created($"/api/admin/shops/{shop.Id}", new AdminShopResponse
|
|
{
|
|
Id = shop.Id,
|
|
Name = shop.Name,
|
|
Photo = shop.Photo,
|
|
Location = shop.Location,
|
|
Notice = shop.Notice,
|
|
PackingFeeType = shop.PackingFeeType.ToString(),
|
|
PackingFeeAmount = shop.PackingFeeAmount,
|
|
IsEnabled = shop.IsEnabled,
|
|
DishCount = 0
|
|
});
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 管理端更新门店
|
|
app.MapPut("/api/admin/shops/{id}", async (int id, ShopRequest request, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops.FindAsync(id);
|
|
if (shop == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
}
|
|
|
|
var errors = BusinessHelpers.ValidateShopRequest(request);
|
|
if (errors.Count > 0)
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors });
|
|
}
|
|
|
|
if (!Enum.TryParse<PackingFeeType>(request.PackingFeeType, true, out var feeType) || !Enum.IsDefined(feeType))
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors = new[] { new { field = "packingFeeType", message = "打包费类型不合法" } } });
|
|
}
|
|
|
|
shop.Name = request.Name;
|
|
shop.Photo = request.Photo;
|
|
shop.Location = request.Location;
|
|
shop.Notice = request.Notice;
|
|
shop.PackingFeeType = feeType;
|
|
shop.PackingFeeAmount = request.PackingFeeAmount;
|
|
shop.IsEnabled = request.IsEnabled;
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.Ok(new AdminShopResponse
|
|
{
|
|
Id = shop.Id,
|
|
Name = shop.Name,
|
|
Photo = shop.Photo,
|
|
Location = shop.Location,
|
|
Notice = shop.Notice,
|
|
PackingFeeType = shop.PackingFeeType.ToString(),
|
|
PackingFeeAmount = shop.PackingFeeAmount,
|
|
IsEnabled = shop.IsEnabled,
|
|
DishCount = await db.Dishes.CountAsync(d => d.ShopId == shop.Id)
|
|
});
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 管理端删除门店
|
|
app.MapDelete("/api/admin/shops/{id}", async (int id, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops
|
|
.Include(s => s.Dishes)
|
|
.Include(s => s.ShopBanners)
|
|
.FirstOrDefaultAsync(s => s.Id == id);
|
|
|
|
if (shop == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
}
|
|
|
|
try
|
|
{
|
|
// 先删除订单中引用该门店的菜品项
|
|
var dishIds = shop.Dishes.Select(d => d.Id).ToList();
|
|
db.FoodOrderItems.RemoveRange(db.FoodOrderItems.Where(f => f.ShopId == id || dishIds.Contains(f.DishId)));
|
|
await db.SaveChangesAsync();
|
|
|
|
// 再删除菜品和门店 Banner
|
|
db.Dishes.RemoveRange(shop.Dishes);
|
|
db.ShopBanners.RemoveRange(shop.ShopBanners);
|
|
await db.SaveChangesAsync();
|
|
|
|
// 最后删除门店
|
|
db.Shops.Remove(shop);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.NoContent();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[管理端] 删除门店失败: {ex.InnerException?.Message ?? ex.Message}");
|
|
return Results.BadRequest(new { code = 400, message = $"删除失败: {ex.InnerException?.Message ?? ex.Message}" });
|
|
}
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 获取门店 Banner 列表
|
|
app.MapGet("/api/admin/shops/{shopId}/banners", async (int shopId, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops.FindAsync(shopId);
|
|
if (shop == null)
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
|
|
var banners = await db.ShopBanners
|
|
.Where(b => b.ShopId == shopId)
|
|
.OrderBy(b => b.SortOrder)
|
|
.Select(b => new ShopBannerResponse { Id = b.Id, ImageUrl = b.ImageUrl, SortOrder = b.SortOrder })
|
|
.ToListAsync();
|
|
return Results.Ok(banners);
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 创建门店 Banner
|
|
app.MapPost("/api/admin/shops/{shopId}/banners", async (int shopId, ShopBannerRequest request, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops.FindAsync(shopId);
|
|
if (shop == null)
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
|
|
if (string.IsNullOrWhiteSpace(request.ImageUrl))
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors = new[] { new { field = "imageUrl", message = "图片地址不能为空" } } });
|
|
|
|
var banner = new ShopBanner { ShopId = shopId, ImageUrl = request.ImageUrl, SortOrder = request.SortOrder };
|
|
db.ShopBanners.Add(banner);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.Created($"/api/admin/shops/{shopId}/banners/{banner.Id}",
|
|
new ShopBannerResponse { Id = banner.Id, ImageUrl = banner.ImageUrl, SortOrder = banner.SortOrder });
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 删除门店 Banner
|
|
app.MapDelete("/api/admin/shops/{shopId}/banners/{bannerId}", async (int shopId, int bannerId, AppDbContext db) =>
|
|
{
|
|
var banner = await db.ShopBanners.FirstOrDefaultAsync(b => b.Id == bannerId && b.ShopId == shopId);
|
|
if (banner == null)
|
|
return Results.NotFound(new { code = 404, message = "门店 Banner 不存在" });
|
|
|
|
db.ShopBanners.Remove(banner);
|
|
await db.SaveChangesAsync();
|
|
return Results.NoContent();
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 获取门店菜品列表
|
|
app.MapGet("/api/admin/shops/{shopId}/dishes", async (int shopId, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops.FindAsync(shopId);
|
|
if (shop == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
}
|
|
|
|
var dishes = await db.Dishes
|
|
.Where(d => d.ShopId == shopId)
|
|
.Select(d => new DishResponse
|
|
{
|
|
Id = d.Id,
|
|
ShopId = d.ShopId,
|
|
Name = d.Name,
|
|
Photo = d.Photo,
|
|
Price = d.Price,
|
|
IsEnabled = d.IsEnabled
|
|
})
|
|
.ToListAsync();
|
|
return Results.Ok(dishes);
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 创建菜品
|
|
app.MapPost("/api/admin/shops/{shopId}/dishes", async (int shopId, DishRequest request, AppDbContext db) =>
|
|
{
|
|
var shop = await db.Shops.FindAsync(shopId);
|
|
if (shop == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "门店不存在" });
|
|
}
|
|
|
|
var errors = BusinessHelpers.ValidateDishRequest(request);
|
|
if (errors.Count > 0)
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors });
|
|
}
|
|
|
|
var dish = new Dish
|
|
{
|
|
ShopId = shopId,
|
|
Name = request.Name,
|
|
Photo = request.Photo,
|
|
Price = request.Price,
|
|
IsEnabled = request.IsEnabled
|
|
};
|
|
|
|
db.Dishes.Add(dish);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.Created($"/api/admin/shops/{shopId}/dishes/{dish.Id}", new DishResponse
|
|
{
|
|
Id = dish.Id,
|
|
ShopId = dish.ShopId,
|
|
Name = dish.Name,
|
|
Photo = dish.Photo,
|
|
Price = dish.Price,
|
|
IsEnabled = dish.IsEnabled
|
|
});
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 更新菜品
|
|
app.MapPut("/api/admin/shops/{shopId}/dishes/{dishId}", async (int shopId, int dishId, DishRequest request, AppDbContext db) =>
|
|
{
|
|
var dish = await db.Dishes.FirstOrDefaultAsync(d => d.Id == dishId && d.ShopId == shopId);
|
|
if (dish == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "菜品不存在" });
|
|
}
|
|
|
|
var errors = BusinessHelpers.ValidateDishRequest(request);
|
|
if (errors.Count > 0)
|
|
{
|
|
return Results.BadRequest(new { code = 400, message = "校验失败", errors });
|
|
}
|
|
|
|
dish.Name = request.Name;
|
|
dish.Photo = request.Photo;
|
|
dish.Price = request.Price;
|
|
dish.IsEnabled = request.IsEnabled;
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.Ok(new DishResponse
|
|
{
|
|
Id = dish.Id,
|
|
ShopId = dish.ShopId,
|
|
Name = dish.Name,
|
|
Photo = dish.Photo,
|
|
Price = dish.Price,
|
|
IsEnabled = dish.IsEnabled
|
|
});
|
|
}).RequireAuthorization("AdminOnly");
|
|
|
|
// 删除菜品
|
|
app.MapDelete("/api/admin/shops/{shopId}/dishes/{dishId}", async (int shopId, int dishId, AppDbContext db) =>
|
|
{
|
|
var dish = await db.Dishes.FirstOrDefaultAsync(d => d.Id == dishId && d.ShopId == shopId);
|
|
if (dish == null)
|
|
{
|
|
return Results.NotFound(new { code = 404, message = "菜品不存在" });
|
|
}
|
|
|
|
try
|
|
{
|
|
// 先删除订单中引用该菜品的记录
|
|
db.FoodOrderItems.RemoveRange(db.FoodOrderItems.Where(f => f.DishId == dishId));
|
|
await db.SaveChangesAsync();
|
|
|
|
db.Dishes.Remove(dish);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Results.NoContent();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[管理端] 删除菜品失败: {ex.InnerException?.Message ?? ex.Message}");
|
|
return Results.BadRequest(new { code = 400, message = $"删除失败: {ex.InnerException?.Message ?? ex.Message}" });
|
|
}
|
|
}).RequireAuthorization("AdminOnly");
|
|
}
|
|
}
|