Files
yuezi-saas/backend/database/seeders/InitSeeder.php
T
li 4a68855a88 fix: 全链路运行时修复 — 登录/路由/菜单/门店CRUD
登录流程:
- login() 不再设置 userInfo,由 router guard 触发 getInfo() + 路由生成
- validate() 从 callback 改为 Promise 式,修复异步链断裂
- getInfo() 适配 /auth/me 扁平响应结构

动态路由:
- import.meta.glob 替代 Vite 不支持的多级动态 import
- 目录菜单检测: !component || 'Layout' 而非仅 'Layout'
- resolveComponent 支持多种 key 格式 + 后缀匹配兜底

侧边栏:
- menu.title → menu.name (匹配后端字段)
- 空 path 目录节点加 fallback index

门店管理:
- StoreController: region_id 改 nullable, 新增 contact/capacity/description 验证
- has('status') → filled('status') 修复空字符串导致列表为空
- capacity null → 0 兜底,避免 NOT NULL 约束报错
- 前端: capacity 初始值 '' → 1, handleSubmit 过滤冗余字段
- region 列渲染 region.name 而非 [object Object]
- 新增 stores 表迁移: contact/capacity/description 列

种子数据:
- DatabaseSeeder 改用 InitSeeder
- createMenus() 补全 52 个叶子页面菜单 (13 模块)
- 目录菜单添加 path 属性

其他:
- vite proxy 端口 8000 → 8001
- request.js 添加 Accept: application/json
- UserStatus 枚举值对齐 (Active=1, Disabled=0)
- 新增 positions/index.vue 页面
2026-03-13 23:53:30 +08:00

322 lines
20 KiB
PHP

<?php
namespace Database\Seeders;
use App\Models\Department;
use App\Models\Menu;
use App\Models\Permission;
use App\Models\Region;
use App\Models\Role;
use App\Models\Store;
use App\Models\User;
use Illuminate\Database\Seeder;
class InitSeeder extends Seeder
{
public function run(): void
{
// 1. 创建默认区域
$region = Region::create(['name' => '默认区域', 'sort' => 0, 'status' => 1]);
// 2. 创建默认门店
$store = Store::create([
'region_id' => $region->id,
'name' => '宫中有喜总店',
'code' => 'HQ001',
'status' => 1,
]);
// 3. 创建默认部门
Department::create(['store_id' => $store->id, 'name' => '管理层', 'sort' => 0]);
// 4. 创建超级管理员
$admin = User::create([
'store_id' => $store->id,
'username' => 'admin',
'password' => 'admin123',
'name' => '超级管理员',
'status' => 1,
'is_super' => 1,
]);
// 5. 创建默认角色
$superRole = Role::create([
'name' => '超级管理员',
'code' => 'super_admin',
'description' => '系统最高权限',
'is_system' => 1,
]);
$storeAdmin = Role::create([
'store_id' => $store->id,
'name' => '门店管理员',
'code' => 'store_admin',
'description' => '门店最高权限',
'is_system' => 1,
]);
$admin->roles()->attach($superRole->id);
// 6. 创建权限
$this->createPermissions();
// 7. 创建菜单
$this->createMenus();
// 8. 门店管理员分配所有权限
$allPermissions = Permission::pluck('id')->toArray();
$storeAdmin->permissions()->sync($allPermissions);
}
private function createPermissions(): void
{
$modules = [
['name' => 'CRM管理', 'code' => 'crm', 'children' => [
['name' => '线索管理', 'code' => 'crm.lead', 'children' => [
['name' => '查看', 'code' => 'crm.lead.view', 'type' => 2],
['name' => '新建', 'code' => 'crm.lead.create', 'type' => 2],
['name' => '编辑', 'code' => 'crm.lead.update', 'type' => 2],
['name' => '删除', 'code' => 'crm.lead.delete', 'type' => 2],
]],
['name' => '客户管理', 'code' => 'crm.customer', 'children' => [
['name' => '查看', 'code' => 'crm.customer.view', 'type' => 2],
['name' => '新建', 'code' => 'crm.customer.create', 'type' => 2],
['name' => '编辑', 'code' => 'crm.customer.update', 'type' => 2],
['name' => '删除', 'code' => 'crm.customer.delete', 'type' => 2],
]],
['name' => '合同管理', 'code' => 'crm.contract', 'children' => [
['name' => '查看', 'code' => 'crm.contract.view', 'type' => 2],
['name' => '新建', 'code' => 'crm.contract.create', 'type' => 2],
['name' => '审批', 'code' => 'crm.contract.approve', 'type' => 2],
]],
]],
['name' => '房务管理', 'code' => 'room', 'children' => [
['name' => '房间管理', 'code' => 'room.room', 'children' => [
['name' => '查看', 'code' => 'room.room.view', 'type' => 2],
['name' => '编辑', 'code' => 'room.room.update', 'type' => 2],
]],
['name' => '预定管理', 'code' => 'room.reservation', 'children' => [
['name' => '查看', 'code' => 'room.reservation.view', 'type' => 2],
['name' => '新建', 'code' => 'room.reservation.create', 'type' => 2],
['name' => '操作', 'code' => 'room.reservation.operate', 'type' => 2],
]],
]],
['name' => '护理管理', 'code' => 'care', 'children' => [
['name' => '护理档案', 'code' => 'care.profile', 'children' => [
['name' => '查看', 'code' => 'care.profile.view', 'type' => 2],
['name' => '编辑', 'code' => 'care.profile.update', 'type' => 2],
]],
['name' => '护理记录', 'code' => 'care.record', 'children' => [
['name' => '查看', 'code' => 'care.record.view', 'type' => 2],
['name' => '新建', 'code' => 'care.record.create', 'type' => 2],
]],
]],
['name' => '月子餐管理', 'code' => 'meal', 'children' => [
['name' => '菜品管理', 'code' => 'meal.dish', 'children' => [
['name' => '查看', 'code' => 'meal.dish.view', 'type' => 2],
['name' => '编辑', 'code' => 'meal.dish.update', 'type' => 2],
]],
['name' => '排餐管理', 'code' => 'meal.plan', 'children' => [
['name' => '查看', 'code' => 'meal.plan.view', 'type' => 2],
['name' => '编辑', 'code' => 'meal.plan.update', 'type' => 2],
]],
]],
['name' => '服务产康', 'code' => 'service', 'children' => [
['name' => '服务项目', 'code' => 'service.item', 'children' => [
['name' => '查看', 'code' => 'service.item.view', 'type' => 2],
['name' => '编辑', 'code' => 'service.item.update', 'type' => 2],
]],
]],
['name' => '月嫂管理', 'code' => 'nanny', 'children' => [
['name' => '月嫂档案', 'code' => 'nanny.profile', 'children' => [
['name' => '查看', 'code' => 'nanny.profile.view', 'type' => 2],
['name' => '编辑', 'code' => 'nanny.profile.update', 'type' => 2],
]],
]],
['name' => '进销存', 'code' => 'stock', 'children' => [
['name' => '库存管理', 'code' => 'stock.inventory', 'children' => [
['name' => '查看', 'code' => 'stock.inventory.view', 'type' => 2],
['name' => '操作', 'code' => 'stock.inventory.operate', 'type' => 2],
]],
]],
['name' => '财务管理', 'code' => 'finance', 'children' => [
['name' => '收支管理', 'code' => 'finance.record', 'children' => [
['name' => '查看', 'code' => 'finance.record.view', 'type' => 2],
['name' => '新建', 'code' => 'finance.record.create', 'type' => 2],
['name' => '审核', 'code' => 'finance.record.approve', 'type' => 2],
]],
]],
['name' => '人事薪资', 'code' => 'hr', 'children' => [
['name' => '员工管理', 'code' => 'hr.employee', 'children' => [
['name' => '查看', 'code' => 'hr.employee.view', 'type' => 2],
['name' => '编辑', 'code' => 'hr.employee.update', 'type' => 2],
]],
]],
['name' => '办公协同', 'code' => 'office', 'children' => [
['name' => '审批管理', 'code' => 'office.approval', 'children' => [
['name' => '查看', 'code' => 'office.approval.view', 'type' => 2],
['name' => '审批', 'code' => 'office.approval.operate', 'type' => 2],
]],
]],
['name' => '统计报表', 'code' => 'report', 'children' => [
['name' => '查看报表', 'code' => 'report.view', 'type' => 2],
['name' => '导出报表', 'code' => 'report.export', 'type' => 2],
]],
['name' => '知识库', 'code' => 'kb', 'children' => [
['name' => '文章管理', 'code' => 'kb.article', 'children' => [
['name' => '查看', 'code' => 'kb.article.view', 'type' => 2],
['name' => '编辑', 'code' => 'kb.article.update', 'type' => 2],
]],
]],
['name' => '系统设置', 'code' => 'system', 'children' => [
['name' => '门店管理', 'code' => 'system.store', 'type' => 2],
['name' => '用户管理', 'code' => 'system.user', 'type' => 2],
['name' => '角色管理', 'code' => 'system.role', 'type' => 2],
['name' => '菜单管理', 'code' => 'system.menu', 'type' => 2],
['name' => '字典管理', 'code' => 'system.dict', 'type' => 2],
['name' => '操作日志', 'code' => 'system.log', 'type' => 2],
]],
];
$this->insertPermissions($modules);
}
private function insertPermissions(array $items, int $parentId = 0, int &$sort = 0): void
{
foreach ($items as $item) {
$children = $item['children'] ?? [];
unset($item['children']);
$item['parent_id'] = $parentId;
$item['type'] = $item['type'] ?? 1;
$item['module'] = explode('.', $item['code'])[0];
$item['sort'] = $sort++;
$permission = Permission::create($item);
if ($children) {
$this->insertPermissions($children, $permission->id, $sort);
}
}
}
private function createMenus(): void
{
$menus = [
['name' => '首页', 'path' => '/dashboard', 'component' => 'dashboard/index', 'icon' => 'HomeFilled', 'sort' => 0],
['name' => 'CRM管理', 'path' => '/crm', 'icon' => 'User', 'sort' => 1, 'permission_code' => 'crm', 'children' => [
['name' => '渠道管理', 'path' => '/crm/channels', 'component' => 'crm/channels/index', 'permission_code' => 'crm'],
['name' => '线索管理', 'path' => '/crm/leads', 'component' => 'crm/leads/index', 'permission_code' => 'crm.lead'],
['name' => '客户管理', 'path' => '/crm/customers', 'component' => 'crm/customers/index', 'permission_code' => 'crm.customer'],
['name' => '合同管理', 'path' => '/crm/contracts', 'component' => 'crm/contracts/index', 'permission_code' => 'crm.contract'],
['name' => '投诉管理', 'path' => '/crm/complaints', 'component' => 'crm/complaints/index', 'permission_code' => 'crm'],
]],
['name' => '房务管理', 'path' => '/room', 'icon' => 'House', 'sort' => 2, 'permission_code' => 'room', 'children' => [
['name' => '房型管理', 'path' => '/room/room-types', 'component' => 'room/room-types/index', 'permission_code' => 'room.room'],
['name' => '房间管理', 'path' => '/room/rooms', 'component' => 'room/rooms/index', 'permission_code' => 'room.room'],
['name' => '预定管理', 'path' => '/room/reservations', 'component' => 'room/reservations/index', 'permission_code' => 'room.reservation'],
]],
['name' => '护理管理', 'path' => '/care', 'icon' => 'FirstAidKit', 'sort' => 3, 'permission_code' => 'care', 'children' => [
['name' => '护理档案', 'path' => '/care/profiles', 'component' => 'care/profiles/index', 'permission_code' => 'care.profile'],
['name' => '护理计划', 'path' => '/care/plans', 'component' => 'care/plans/index', 'permission_code' => 'care.profile'],
['name' => '护理记录', 'path' => '/care/records', 'component' => 'care/records/index', 'permission_code' => 'care.record'],
]],
['name' => '月子餐', 'path' => '/meal', 'icon' => 'Bowl', 'sort' => 4, 'permission_code' => 'meal', 'children' => [
['name' => '菜品管理', 'path' => '/meal/dishes', 'component' => 'meal/dishes/index', 'permission_code' => 'meal.dish'],
['name' => '每日排餐', 'path' => '/meal/daily-plans', 'component' => 'meal/daily-plans/index', 'permission_code' => 'meal.plan'],
]],
['name' => '服务产康', 'path' => '/service', 'icon' => 'Promotion', 'sort' => 5, 'permission_code' => 'service', 'children' => [
['name' => '服务项目', 'path' => '/service/items', 'component' => 'service/items/index', 'permission_code' => 'service.item'],
['name' => '服务套餐', 'path' => '/service/packages', 'component' => 'service/packages/index', 'permission_code' => 'service.item'],
['name' => '服务订单', 'path' => '/service/orders', 'component' => 'service/orders/index', 'permission_code' => 'service.item'],
]],
['name' => '月嫂管理', 'path' => '/nanny', 'icon' => 'Avatar', 'sort' => 6, 'permission_code' => 'nanny', 'children' => [
['name' => '月嫂信息', 'path' => '/nanny/nannies', 'component' => 'nanny/nannies/index', 'permission_code' => 'nanny.profile'],
['name' => '月嫂订单', 'path' => '/nanny/orders', 'component' => 'nanny/orders/index', 'permission_code' => 'nanny.profile'],
['name' => '月嫂排班', 'path' => '/nanny/schedules', 'component' => 'nanny/schedules/index', 'permission_code' => 'nanny.profile'],
]],
['name' => '进销存', 'path' => '/inventory', 'icon' => 'Box', 'sort' => 7, 'permission_code' => 'stock', 'children' => [
['name' => '仓库管理', 'path' => '/inventory/warehouses', 'component' => 'inventory/warehouses/index', 'permission_code' => 'stock.inventory'],
['name' => '供应商管理', 'path' => '/inventory/suppliers', 'component' => 'inventory/suppliers/index', 'permission_code' => 'stock.inventory'],
['name' => '物料管理', 'path' => '/inventory/materials', 'component' => 'inventory/materials/index', 'permission_code' => 'stock.inventory'],
['name' => '采购订单', 'path' => '/inventory/purchase-orders', 'component' => 'inventory/purchase-orders/index', 'permission_code' => 'stock.inventory'],
['name' => '出入库流水', 'path' => '/inventory/stock-movements', 'component' => 'inventory/stock-movements/index', 'permission_code' => 'stock.inventory'],
]],
['name' => '财务管理', 'path' => '/finance', 'icon' => 'Money', 'sort' => 8, 'permission_code' => 'finance', 'children' => [
['name' => '收支分类', 'path' => '/finance/categories', 'component' => 'finance/categories/index', 'permission_code' => 'finance.record'],
['name' => '收支记录', 'path' => '/finance/records', 'component' => 'finance/records/index', 'permission_code' => 'finance.record'],
['name' => '客户账户', 'path' => '/finance/accounts', 'component' => 'finance/accounts/index', 'permission_code' => 'finance.record'],
['name' => '储值卡', 'path' => '/finance/prepaid-cards', 'component' => 'finance/prepaid-cards/index', 'permission_code' => 'finance.record'],
['name' => '发票管理', 'path' => '/finance/invoices', 'component' => 'finance/invoices/index', 'permission_code' => 'finance.record'],
]],
['name' => '人事薪资', 'path' => '/hr', 'icon' => 'Stamp', 'sort' => 9, 'permission_code' => 'hr', 'children' => [
['name' => '员工档案', 'path' => '/hr/profiles', 'component' => 'hr/profiles/index', 'permission_code' => 'hr.employee'],
['name' => '排班管理', 'path' => '/hr/schedules', 'component' => 'hr/schedules/index', 'permission_code' => 'hr.employee'],
['name' => '考勤管理', 'path' => '/hr/attendances', 'component' => 'hr/attendances/index', 'permission_code' => 'hr.employee'],
['name' => '请假管理', 'path' => '/hr/leaves', 'component' => 'hr/leaves/index', 'permission_code' => 'hr.employee'],
['name' => '工资管理', 'path' => '/hr/salaries', 'component' => 'hr/salaries/index', 'permission_code' => 'hr.employee'],
]],
['name' => '办公协同', 'path' => '/office', 'icon' => 'ChatDotRound', 'sort' => 10, 'permission_code' => 'office', 'children' => [
['name' => '审批模板', 'path' => '/office/approval-templates', 'component' => 'office/approval-templates/index', 'permission_code' => 'office.approval'],
['name' => '审批管理', 'path' => '/office/approvals', 'component' => 'office/approvals/index', 'permission_code' => 'office.approval'],
['name' => '公告管理', 'path' => '/office/announcements', 'component' => 'office/announcements/index', 'permission_code' => 'office.approval'],
['name' => '交接班', 'path' => '/office/handovers', 'component' => 'office/handovers/index', 'permission_code' => 'office.approval'],
['name' => '消息通知', 'path' => '/office/notifications', 'component' => 'office/notifications/index', 'permission_code' => 'office.approval'],
]],
['name' => '统计报表', 'path' => '/report', 'icon' => 'DataAnalysis', 'sort' => 11, 'permission_code' => 'report', 'children' => [
['name' => '数据概览', 'path' => '/report/overview', 'component' => 'report/overview/index', 'permission_code' => 'report.view'],
['name' => '导出记录', 'path' => '/report/exports', 'component' => 'report/exports/index', 'permission_code' => 'report.export'],
]],
['name' => '知识库', 'path' => '/kb', 'icon' => 'Reading', 'sort' => 12, 'permission_code' => 'kb', 'children' => [
['name' => '知识分类', 'path' => '/kb/categories', 'component' => 'kb/categories/index', 'permission_code' => 'kb.article'],
['name' => '知识文章', 'path' => '/kb/articles', 'component' => 'kb/articles/index', 'permission_code' => 'kb.article'],
]],
['name' => '系统设置', 'path' => '/system', 'icon' => 'Setting', 'sort' => 99, 'permission_code' => 'system', 'children' => [
['name' => '门店管理', 'path' => '/system/stores', 'component' => 'system/stores/index', 'permission_code' => 'system.store'],
['name' => '部门管理', 'path' => '/system/departments', 'component' => 'system/departments/index', 'permission_code' => 'system.store'],
['name' => '职务管理', 'path' => '/system/positions', 'component' => 'system/positions/index', 'permission_code' => 'system.store'],
['name' => '用户管理', 'path' => '/system/users', 'component' => 'system/users/index', 'permission_code' => 'system.user'],
['name' => '角色管理', 'path' => '/system/roles', 'component' => 'system/roles/index', 'permission_code' => 'system.role'],
['name' => '菜单管理', 'path' => '/system/menus', 'component' => 'system/menus/index', 'permission_code' => 'system.menu'],
['name' => '字典管理', 'path' => '/system/dictionaries', 'component' => 'system/dictionaries/index', 'permission_code' => 'system.dict'],
['name' => '操作日志', 'path' => '/system/logs', 'component' => 'system/logs/index', 'permission_code' => 'system.log'],
]],
];
$this->insertMenus($menus);
}
private function insertMenus(array $items, int $parentId = 0): void
{
foreach ($items as $index => $item) {
$children = $item['children'] ?? [];
unset($item['children']);
$item['parent_id'] = $parentId;
$item['type'] = isset($item['component']) ? 2 : 1; // 有 component = 菜单,否则目录
$item['sort'] = $item['sort'] ?? $index;
$item['visible'] = 1;
$item['status'] = 1;
$menu = Menu::create($item);
if ($children) {
$this->insertMenus($children, $menu->id);
}
}
}
}