Files
F8WebAI/backend/AgriculturalPlatform.Api/Data/DbSeeder.cs
T

346 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using AgriculturalPlatform.Api.Models;
namespace AgriculturalPlatform.Api.Data;
/// <summary>初始化数据(仅在空库时执行)</summary>
public static class DbSeeder
{
public static void Seed(AppDbContext db)
{
if (db.Users.Any()) return;
var now = DateTime.Now;
// ---------- 组织 ----------
var company = new Organization
{
Type = OrgType.Company,
Name = "绿源农产品收购有限公司",
ContactPerson = "王建国",
Phone = "13800000001",
Address = "河南省郑州市中牟县官渡大道66号",
TaxNo = "91410100MA3X8K7Q2B",
CreatedAt = now
};
var stationEast = new Organization
{
Type = OrgType.Station,
Name = "城东收购站",
ContactPerson = "李强",
Phone = "13800000002",
Address = "中牟县官渡镇城东村",
CreatedAt = now
};
var stationWest = new Organization
{
Type = OrgType.Station,
Name = "城西收购站",
ContactPerson = "赵敏",
Phone = "13800000003",
Address = "中牟县韩寺镇城西村",
CreatedAt = now
};
var individual = new Organization
{
Type = OrgType.Individual,
Name = "张伟(个体收购)",
ContactPerson = "张伟",
Phone = "13800000004",
Address = "中牟县刁家乡",
TaxNo = "410122197501011234",
CreatedAt = now
};
db.Organizations.AddRange(company, stationEast, stationWest, individual);
db.SaveChanges();
stationEast.ParentId = company.Id;
stationWest.ParentId = company.Id;
db.SaveChanges();
// ---------- 角色(RBAC ----------
var roleAdmin = new SysRole { Name = "超级管理员", Code = "super_admin", Description = "系统内置:拥有全部权限", IsSystem = true, CreatedAt = now };
var roleCompany = new SysRole { Name = "公司管理员", Code = "company_admin", Description = "管理本公司及下属收购站业务", IsSystem = true, CreatedAt = now };
var roleStation = new SysRole { Name = "收购站员工", Code = "station_staff", Description = "负责过磅称重、收购单录入", IsSystem = true, CreatedAt = now };
var roleIndividual = new SysRole { Name = "收购个体", Code = "individual", Description = "个体收购户", IsSystem = true, CreatedAt = now };
db.SysRoles.AddRange(roleAdmin, roleCompany, roleStation, roleIndividual);
db.SaveChanges();
// ---------- 菜单/权限(RBAC 资源,Path 与前端路由一致) ----------
var menus = new List<SysMenu>
{
// 首页
new() { Name = "首页", Path = "/home", Component = "views/Home.vue", Icon = "HomeFilled", Type = "menu", Permission = "home:view", Sort = 1, CreatedAt = now },
// 收购业务
new() { Name = "收购业务", Path = "/weighing", Icon = "Van", Type = "directory", Sort = 2, CreatedAt = now },
new() { Name = "过磅称重", Path = "/weighing", Component = "views/weighing/WeighingList.vue", Icon = "Odometer", Type = "menu", Permission = "weighing:list", Sort = 1, CreatedAt = now },
new() { Name = "触摸屏过磅", Path = "/weighing/touch", Component = "views/weighing/WeighingTouch.vue", Icon = "Iphone", Type = "menu", Permission = "weighing:touch", Sort = 2, CreatedAt = now },
new() { Name = "电子支付", Path = "/payments", Component = "views/payments/PaymentList.vue", Icon = "Wallet", Type = "menu", Permission = "payment:list", Sort = 3, CreatedAt = now },
new() { Name = "反向开票", Path = "/invoices", Component = "views/invoices/InvoiceList.vue", Icon = "Tickets", Type = "menu", Permission = "invoice:list", Sort = 4, CreatedAt = now },
// 基础资料
new() { Name = "基础资料", Path = "/base", Icon = "FolderOpened", Type = "directory", Sort = 3, CreatedAt = now },
new() { Name = "农户管理", Path = "/farmers", Component = "views/farmers/FarmerList.vue", Icon = "User", Type = "menu", Permission = "farmer:list", Sort = 1, CreatedAt = now },
new() { Name = "品种管理", Path = "/products", Component = "views/products/ProductList.vue", Icon = "Goods", Type = "menu", Permission = "product:list", Sort = 2, CreatedAt = now },
// 统计报表
new() { Name = "统计报表", Path = "/reports", Icon = "DataAnalysis", Type = "directory", Sort = 4, CreatedAt = now },
new() { Name = "收购报表", Path = "/reports/purchase", Component = "views/reports/ReportPurchase.vue", Icon = "TrendCharts", Type = "menu", Permission = "report:purchase", Sort = 1, CreatedAt = now },
new() { Name = "付款报表", Path = "/reports/payment", Component = "views/reports/ReportPayment.vue", Icon = "Money", Type = "menu", Permission = "report:payment", Sort = 2, CreatedAt = now },
new() { Name = "开票报表", Path = "/reports/invoice", Component = "views/reports/ReportInvoice.vue", Icon = "Document", Type = "menu", Permission = "report:invoice", Sort = 3, CreatedAt = now },
// 系统管理
new() { Name = "系统管理", Path = "/system", Icon = "Setting", Type = "directory", Sort = 5, CreatedAt = now },
new() { Name = "组织管理", Path = "/orgs", Component = "views/orgs/OrgList.vue", Icon = "OfficeBuilding", Type = "menu", Permission = "system:org:list", Sort = 1, CreatedAt = now },
new() { Name = "用户管理", Path = "/users", Component = "views/users/UserList.vue", Icon = "Avatar", Type = "menu", Permission = "system:user:list", Sort = 2, CreatedAt = now },
new() { Name = "角色权限", Path = "/system/roles", Component = "views/system/RoleList.vue", Icon = "UserFilled", Type = "menu", Permission = "system:role:list", Sort = 3, CreatedAt = now },
new() { Name = "菜单管理", Path = "/system/menus", Component = "views/system/MenuList.vue", Icon = "Menu", Type = "menu", Permission = "system:menu:list", Sort = 4, CreatedAt = now },
new() { Name = "数据字典", Path = "/system/dicts", Component = "views/system/DictList.vue", Icon = "Notebook", Type = "menu", Permission = "system:dict:list", Sort = 5, CreatedAt = now },
// 通知公告
new() { Name = "通知公告", Path = "/notify", Icon = "Bell", Type = "directory", Sort = 6, CreatedAt = now },
new() { Name = "公告管理", Path = "/notify/announcements", Component = "views/notify/AnnouncementList.vue", Icon = "Bell", Type = "menu", Permission = "announcement:list", Sort = 1, CreatedAt = now },
// 关于
new() { Name = "关于系统", Path = "/about", Component = "views/about/About.vue", Icon = "InfoFilled", Type = "menu", Permission = "about:view", Sort = 7, CreatedAt = now },
};
db.SysMenus.AddRange(menus);
db.SaveChanges();
// 目录菜单的父级关系(按路径匹配;目录路径与子菜单路径相同时以 Type 区分)
SetChild(menus, "/weighing", "/weighing");
SetChild(menus, "/weighing/touch", "/weighing");
SetChild(menus, "/payments", "/weighing");
SetChild(menus, "/invoices", "/weighing");
SetChild(menus, "/farmers", "/base");
SetChild(menus, "/products", "/base");
SetChild(menus, "/reports/purchase", "/reports");
SetChild(menus, "/reports/payment", "/reports");
SetChild(menus, "/reports/invoice", "/reports");
SetChild(menus, "/orgs", "/system");
SetChild(menus, "/users", "/system");
SetChild(menus, "/system/roles", "/system");
SetChild(menus, "/system/menus", "/system");
SetChild(menus, "/system/dicts", "/system");
SetChild(menus, "/notify/announcements", "/notify");
db.SaveChanges();
// 给超级管理员分配全部菜单;收购站员工分配常用菜单
var allMenuIds = menus.Select(m => m.Id).ToArray();
db.SysRoleMenus.AddRange(allMenuIds.Select(mid => new SysRoleMenu { RoleId = roleAdmin.Id, MenuId = mid }));
var stationMenuIds = menus.Where(m => m.Type == "menu" && m.Permission is "home:view" or "weighing:list" or "weighing:touch" or "farmer:list" or "about:view").Select(m => m.Id);
db.SysRoleMenus.AddRange(stationMenuIds.Select(mid => new SysRoleMenu { RoleId = roleStation.Id, MenuId = mid }));
// 公司管理员:除系统管理外的全部业务菜单
var companyMenuIds = menus.Where(m => m.Type == "menu" && !m.Permission.StartsWith("system:")).Select(m => m.Id);
db.SysRoleMenus.AddRange(companyMenuIds.Select(mid => new SysRoleMenu { RoleId = roleCompany.Id, MenuId = mid }));
db.SaveChanges();
// ---------- 用户(默认密码均为 123456 ----------
var users = new List<User>
{
new() { Username = "admin", PasswordHash = BCrypt.Net.BCrypt.HashPassword("123456"), RealName = "系统管理员", Phone = "13800000000", Role = UserRole.SuperAdmin, RoleId = roleAdmin.Id, CreatedAt = now },
new() { Username = "company", PasswordHash = BCrypt.Net.BCrypt.HashPassword("123456"), RealName = "王建国", Phone = "13800000001", Role = UserRole.CompanyAdmin, RoleId = roleCompany.Id, OrgId = company.Id, CreatedAt = now },
new() { Username = "station1", PasswordHash = BCrypt.Net.BCrypt.HashPassword("123456"), RealName = "李强", Phone = "13800000002", Role = UserRole.StationStaff, RoleId = roleStation.Id, OrgId = stationEast.Id, CreatedAt = now },
new() { Username = "station2", PasswordHash = BCrypt.Net.BCrypt.HashPassword("123456"), RealName = "赵敏", Phone = "13800000003", Role = UserRole.StationStaff, RoleId = roleStation.Id, OrgId = stationWest.Id, CreatedAt = now },
new() { Username = "individual", PasswordHash = BCrypt.Net.BCrypt.HashPassword("123456"), RealName = "张伟", Phone = "13800000004", Role = UserRole.Individual, RoleId = roleIndividual.Id, OrgId = individual.Id, CreatedAt = now }
};
db.Users.AddRange(users);
db.SaveChanges();
// ---------- 品种 ----------
var products = new List<Product>
{
new() { Name = "小麦", Category = "粮食", Unit = "公斤", Spec = "水分≤13%,容重≥750g/L", Price = 2.42m },
new() { Name = "玉米", Category = "粮食", Unit = "公斤", Spec = "水分≤14%,杂质≤1%", Price = 2.18m },
new() { Name = "水稻", Category = "粮食", Unit = "公斤", Spec = "出糙率≥77%", Price = 2.68m },
new() { Name = "花生", Category = "油料", Unit = "公斤", Spec = "果仁饱满,出仁率≥70%", Price = 7.80m },
new() { Name = "大蒜", Category = "蔬菜", Unit = "公斤", Spec = "5cm以上,干度达标", Price = 4.50m },
new() { Name = "西红柿", Category = "蔬菜", Unit = "公斤", Spec = "一级果,单果150g以上", Price = 2.60m },
new() { Name = "苹果", Category = "水果", Unit = "公斤", Spec = "红富士,直径75mm以上", Price = 5.20m },
new() { Name = "棉花", Category = "经济作物", Unit = "公斤", Spec = "衣分≥38%", Price = 15.60m }
};
db.Products.AddRange(products);
db.SaveChanges();
// ---------- 农户 ----------
var farmers = new List<Farmer>
{
new() { Name = "刘老汉", IdCard = "410122197003120011", Gender = "男", Phone = "13911110001", Village = "城东村一组", Address = "城东村一组12号", BankName = "中牟农商银行", BankAccount = "6228480012345678901", CreditScore = 92 },
new() { Name = "陈秀英", IdCard = "410122196806250022", Gender = "女", Phone = "13911110002", Village = "城东村二组", Address = "城东村二组8号", BankName = "中牟农商银行", BankAccount = "6228480012345678902", CreditScore = 88 },
new() { Name = "张铁柱", IdCard = "410122198204170033", Gender = "男", Phone = "13911110003", Village = "城西村一组", Address = "城西村一组21号", BankName = "农业银行", BankAccount = "6228480012345678903", CreditScore = 85 },
new() { Name = "王翠花", IdCard = "410122197512080044", Gender = "女", Phone = "13911110004", Village = "城西村三组", Address = "城西村三组5号", BankName = "邮政储蓄银行", BankAccount = "6228480012345678904", CreditScore = 90 },
new() { Name = "赵大勇", IdCard = "410122199003300055", Gender = "男", Phone = "13911110005", Village = "官渡镇贾庄村", Address = "贾庄村16号", BankName = "中牟农商银行", BankAccount = "6228480012345678905", CreditScore = 82 },
new() { Name = "孙秀兰", IdCard = "410122196511150066", Gender = "女", Phone = "13911110006", Village = "韩寺镇马家村", Address = "马家村9号", BankName = "农业银行", BankAccount = "6228480012345678906", CreditScore = 78 },
new() { Name = "李保田", IdCard = "410122197807210077", Gender = "男", Phone = "13911110007", Village = "刁家乡水沱寨村", Address = "水沱寨村3号", BankName = "邮政储蓄银行", BankAccount = "6228480012345678907", CreditScore = 86 },
new() { Name = "周桂芳", IdCard = "410122198906060088", Gender = "女", Phone = "13911110008", Village = "官渡镇前于村", Address = "前于村28号", BankName = "中牟农商银行", BankAccount = "6228480012345678908", CreditScore = 91 }
};
db.Farmers.AddRange(farmers);
db.SaveChanges();
// ---------- 历史收购单(近30天,用于报表与大屏演示) ----------
var rnd = new Random(20260812);
var purchaserIds = new[] { company.Id, stationEast.Id, stationWest.Id, individual.Id };
var productIds = products.Select(p => p.Id).ToArray();
var farmerIds = farmers.Select(f => f.Id).ToArray();
var userIds = users.Select(u => u.Id).ToArray();
var orders = new List<PurchaseOrder>();
for (int day = 29; day >= 0; day--)
{
int count = rnd.Next(3, 8);
for (int i = 0; i < count; i++)
{
var createAt = now.Date.AddDays(-day).AddHours(rnd.Next(7, 18)).AddMinutes(rnd.Next(0, 59));
var productId = productIds[rnd.Next(productIds.Length)];
var gross = rnd.Next(5000, 32000);
var tare = rnd.Next(3200, 9000);
var net = gross - tare;
if (net <= 0) continue;
var price = products.First(p => p.Id == productId).Price + (decimal)rnd.Next(-10, 10) / 10m;
orders.Add(new PurchaseOrder
{
OrderNo = $"CG{createAt:yyyyMMdd}-{(day * 10 + i):D4}",
FarmerId = farmerIds[rnd.Next(farmerIds.Length)],
ProductId = productId,
PurchaserOrgId = purchaserIds[rnd.Next(purchaserIds.Length)],
Grade = new[] { "一等", "二等", "三等" }[rnd.Next(3)],
Unit = "公斤",
UnitPrice = price,
GrossWeight = gross,
TareWeight = tare,
NetWeight = net,
Amount = Math.Round(net * price, 2),
WeighCount = 2,
Status = PurchaseStatus.Completed,
OperatorId = userIds[rnd.Next(userIds.Length)],
WeighInAt = createAt,
WeighOutAt = createAt.AddMinutes(rnd.Next(15, 50)),
CreatedAt = createAt,
UpdatedAt = createAt
});
}
}
db.PurchaseOrders.AddRange(orders);
db.SaveChanges();
// ---------- 数据字典(收购等级 / 价格类型 / 票据格式 / 公告类型) ----------
var dicts = new List<SysDict>
{
new() { Name = "收购等级", Code = "purchase_grade", Remark = "收购单磅次等级", IsSystem = true, Sort = 1, CreatedAt = now,
Items =
{
new() { Label = "一等", Value = "一等", IsDefault = true, Sort = 1 },
new() { Label = "二等", Value = "二等", Sort = 2 },
new() { Label = "三等", Value = "三等", Sort = 3 },
new() { Label = "级外", Value = "级外", Sort = 4 },
}
},
new() { Name = "价格类型", Code = "price_type", Remark = "过磅计价方式", IsSystem = true, Sort = 2, CreatedAt = now,
Items =
{
new() { Label = "固定价格", Value = "Fixed", Ext = "按产品默认价", IsDefault = true, Sort = 1 },
new() { Label = "现场议价", Value = "Manual", Ext = "与农户协商价", Sort = 2 },
new() { Label = "价格区间", Value = "Range", Ext = "区间内浮动价", Sort = 3 },
}
},
new() { Name = "票据格式", Code = "receipt_format", Remark = "小票/票据打印格式", IsSystem = true, Sort = 3, CreatedAt = now,
Items =
{
new() { Label = "58mm 热敏小票", Value = "thermal_58", Ext = "58mm", IsDefault = true, Sort = 1 },
new() { Label = "80mm 热敏小票", Value = "thermal_80", Ext = "80mm", Sort = 2 },
new() { Label = "三等分针式票据", Value = "dotmatrix_3part", Ext = "241mm×139.7mm/联", Sort = 3 },
new() { Label = "A5 激光打印", Value = "laser_a5", Ext = "A5", Sort = 4 },
}
},
new() { Name = "公告类型", Code = "announcement_type", Remark = "通知公告类型", IsSystem = true, Sort = 4, CreatedAt = now,
Items =
{
new() { Label = "通知", Value = "notice", Sort = 1 },
new() { Label = "公告", Value = "announce", Sort = 2 },
new() { Label = "价格行情", Value = "price", Sort = 3 },
new() { Label = "政策法规", Value = "policy", Sort = 4 },
}
},
new() { Name = "系统图标", Code = "system_logo", Remark = "主标题系统图标,可选大部分农产品图标", IsSystem = true, Sort = 5, CreatedAt = now,
Items =
{
new() { Label = "苹果", Value = "Apple", IsDefault = true, Sort = 1 },
new() { Label = "葡萄", Value = "Grape", Sort = 2 },
new() { Label = "西瓜", Value = "Watermelon", Sort = 3 },
new() { Label = "樱桃", Value = "Cherry", Sort = 4 },
new() { Label = "梨", Value = "Pear", Sort = 5 },
new() { Label = "桃", Value = "Peach", Sort = 6 },
new() { Label = "橙子", Value = "Orange", Sort = 7 },
new() { Label = "农作物", Value = "Food", Sort = 8 },
new() { Label = "时蔬", Value = "Dish", Sort = 9 },
new() { Label = "牛奶", Value = "Milk", Sort = 10 },
new() { Label = "冰淇淋", Value = "IceCream", Sort = 11 },
new() { Label = "生鲜礼盒", Value = "TakeawayBox", Sort = 12 },
}
},
};
db.SysDicts.AddRange(dicts);
db.SaveChanges();
// ---------- 通知公告(演示数据) ----------
var announcements = new List<Announcement>
{
new() { Title = "欢迎使用农易富农产品收购交易平台", Content = "系统已完成升级,新增数据字典、角色权限、通知公告等功能。默认账号 admin / 123456。", Type = "announce", IsPinned = true, PublisherId = users[0].Id, PublishedAt = now, CreatedAt = now },
new() { Title = "关于2026年夏季收购价格调整的通知", Content = "自8月15日起,一等品收购价调整为每公斤3.6元,请各收购站及时更新价格配置。", Type = "price", PublisherId = users[0].Id, PublishedAt = now.AddHours(-3), CreatedAt = now.AddHours(-3) },
new() { Title = "电子秤串口连接使用说明", Content = "请在收购单新建界面点击电子秤区域连接串口,支持标准ASCII输出协议(如 ST,GS,+00123.45kg)。无串口设备时可使用手动输入模式。", Type = "notice", PublisherId = users[0].Id, PublishedAt = now.AddDays(-1), CreatedAt = now.AddDays(-1) },
};
db.Announcements.AddRange(announcements);
db.SaveChanges();
// ---------- 历史付款(对应部分订单) ----------
var payOrders = orders.Where(o => o.Status == PurchaseStatus.Completed)
.OrderBy(o => o.CreatedAt).Take(120).ToList();
var methods = new[] { PayMethod.Wechat, PayMethod.Alipay, PayMethod.BankTransfer, PayMethod.Cash };
var payments = payOrders.Select((o, idx) => new PaymentRecord
{
PayNo = $"ZF{o.CreatedAt:yyyyMMdd}-{idx + 1:D4}",
PurchaseOrderId = o.Id,
FarmerId = o.FarmerId,
Amount = o.Amount,
Method = methods[rnd.Next(methods.Length)],
Status = PayStatus.Success,
TradeNo = $"TRADE{rnd.Next(100000000, 999999999)}",
OperatorId = o.OperatorId,
PaidAt = o.WeighOutAt,
CreatedAt = o.WeighOutAt!.Value,
Notes = $"收购单 {o.OrderNo} 货款结算"
}).ToList();
db.PaymentRecords.AddRange(payments);
db.SaveChanges();
// ---------- 历史发票(对应部分订单,反向开票) ----------
var invoiceOrders = orders.Where(o => o.Status == PurchaseStatus.Completed)
.OrderByDescending(o => o.CreatedAt).Take(80).ToList();
var invoices = invoiceOrders.Select((o, idx) => new Invoice
{
InvoiceNo = $"FP{o.CreatedAt:yyyyMMdd}-{idx + 1:D4}",
InvoiceKind = "农产品收购发票",
FarmerId = o.FarmerId,
PurchaserOrgId = o.PurchaserOrgId,
PurchaseOrderId = o.Id,
ProductId = o.ProductId,
Quantity = o.NetWeight,
Unit = o.Unit,
UnitPrice = o.UnitPrice,
Amount = o.Amount,
TaxRate = 0m,
TaxAmount = 0m,
IssueDate = o.WeighOutAt ?? o.CreatedAt,
Status = InvoiceStatus.Issued,
OperatorId = o.OperatorId,
CreatedAt = o.WeighOutAt ?? o.CreatedAt
}).ToList();
db.Invoices.AddRange(invoices);
db.SaveChanges();
}
private static void SetChild(List<SysMenu> menus, string childPath, string parentPath)
{
var parent = menus.FirstOrDefault(m => m.Type == "directory" && m.Path == parentPath);
if (parent is null) return;
foreach (var child in menus.Where(m => m.Type != "directory" && m.Path == childPath && m.ParentId == null))
child.ParentId = parent.Id;
}
}