# glass-v2 迁移详细计划 ## 📋 概述 将 glass-v2 的 5 个功能模块迁移到 glass 项目,同时适配: 1. 多租户架构(team_id 隔离) 2. Spatie Permission 权限系统 3. Filament 4.x API --- ## 🎯 模块清单 ### 1. 产品分类管理(ProductCategory) #### 数据库 **状态**: glass 项目已有 `categories` 表,需要增强 **已创建的迁移**: - ✅ `2026_02_02_140000_add_icon_and_color_to_categories_table.php` #### 模型适配 **需要**: 创建或更新 `app/Models/Category.php` ```php 'boolean', 'sort_order' => 'integer', ]; // 添加字段以兼容 v2 protected $appends = ['is_active']; public function getIsActiveAttribute(): bool { return $this->status === 'active'; } public function products(): HasMany { return $this->hasMany(Product::class); } protected static function boot() { parent::boot(); static::creating(function ($category) { if (empty($category->slug)) { $category->slug = \Illuminate\Support\Str::slug($category->name); } }); } } ``` #### Filament 资源 **需要创建**: `app/Filament/Resources/Categories/CategoryResource.php` **来源**: v2 的 `ProductCategoryResource.php` **适配点**: 1. 修改命名空间:`ProductCategories` → `Categories` 2. 修改模型:`ProductCategory` → `Category` 3. 修改权限检查: ```php // v2: auth()->user()->is_admin // glass: 使用 Gate 或 Policy public static function canViewAny(): bool { return auth()->user()->can('view_any_categories'); } ``` 4. 修改导航组:'库存与供应链' → 保持 5. 添加团队范围:默认会应用 BelongsToTenant #### Seeder **需要创建**: `database/seeders/CategorySeeder.php` **预置数据**: - 镜架 (heroicon-o-eye, 蓝色 #3b82f6) - 镜片 (heroicon-o-circle-stack, 绿色 #10b981) - 隐形眼镜 (heroicon-o-eye-dropper, 紫色 #8b5cf6) - 护理液 (heroicon-o-beaker, 青色 #06b6d4) - 配件 (heroicon-o-wrench-screwdriver, 橙色 #f59e0b) --- ### 2. 品牌管理(Brand) #### 数据库 **状态**: glass 项目已有 `brands` 表,需要增强 **已创建的迁移**: - ✅ `2026_02_02_140100_add_slug_and_sort_order_to_brands_table.php` #### 模型适配 **需要**: 创建或更新 `app/Models/Brand.php` ```php 'boolean', 'sort_order' => 'integer', ]; protected $appends = ['is_active']; public function getIsActiveAttribute(): bool { return $this->status === 'active'; } public function products(): HasMany { return $this->hasMany(Product::class); } protected static function boot() { parent::boot(); static::creating(function ($brand) { if (empty($brand->slug)) { $brand->slug = \Illuminate\Support\Str::slug($brand->name); } }); } } ``` #### Filament 资源 **需要创建**: `app/Filament/Resources/Brands/BrandResource.php` **来源**: v2 的 `BrandResource.php` **适配点**: 1. 模型名称保持不变 2. 修改权限检查(同上) 3. 确保 logo 上传目录正确:`brands/` #### Seeder **需要创建**: `database/seeders/BrandSeeder.php` **预置数据**: - 雷朋 (Ray-Ban, 意大利) - 暴龙 (Bolon, 中国) - 蔡司 (Zeiss, 德国) - 依视路 (Essilor, 法国) - 强生 (Johnson, 美国) - 博士伦 (Bausch & Lomb, 美国) - 海昌 (Hydron, 中国) --- ### 3. 采购订单管理(PurchaseOrder) #### 数据库 **状态**: glass 项目没有此表 **已创建的迁移**: - ✅ `2026_02_02_140200_create_purchase_orders_table.php` - ✅ `2026_02_02_140300_create_purchase_order_items_table.php` #### 模型 **需要创建**: `app/Models/PurchaseOrder.php` 和 `app/Models/PurchaseOrderItem.php` **来源**: v2 的模型 **适配点**: 1. 添加 `BelongsToTenant` trait 2. 确保所有关系正确 3. 添加团队范围查询 **PurchaseOrderItem**: ```php 'integer', 'received_quantity' => 'integer', 'unit_cost' => 'decimal:2', 'total_cost' => 'decimal:2', ]; public function purchaseOrder(): BelongsTo { return $this->belongsTo(PurchaseOrder::class); } public function product(): BelongsTo { return $this->belongsTo(Product::class); } public function getPendingQuantityAttribute(): int { return $this->quantity - $this->received_quantity; } } ``` #### Filament 资源 **需要创建**: `app/Filament/Resources/PurchaseOrders/PurchaseOrderResource.php` **来源**: v2 的 `PurchaseOrderResource.php` **适配点**: 1. 修改权限检查 2. 确保关联关系正确加载(`with()`) 3. 状态流转逻辑保持不变 #### 权限配置 **需要添加到 RoleAndPermissionSeeder**: ```php $purchasePermissions = [ 'view_any_purchase_orders', 'view_purchase_orders', 'create_purchase_orders', 'update_purchase_orders', 'delete_purchase_orders', 'receive_purchase_orders', 'stock_in_purchase_orders', ]; // 分配角色 $manager->givePermissionTo($purchasePermissions); $warehouseStaff->givePermissionTo(['view_any_purchase_orders', 'view_purchase_orders', 'create_purchase_orders', 'receive_purchase_orders']); ``` --- ### 4. 库存流水管理(InventoryTransaction) #### 数据库 **状态**: glass 项目没有此表 **已创建的迁移**: - ✅ `2026_02_02_140400_create_inventory_transactions_table.php` #### 模型 **需要创建**: `app/Models/InventoryTransaction.php` **来源**: v2 的模型 **适配点**: 1. 添加 `BelongsToTenant` trait 2. 确保多态关联正确 ```php 'integer', 'balance_after' => 'integer', ]; public function product(): BelongsTo { return $this->belongsTo(Product::class); } public function staff(): BelongsTo { return $this->belongsTo(User::class, 'staff_id'); } public function reference(): MorphTo { return $this->morphTo(); } } ``` #### Filament 资源 **需要创建**: `app/Filament/Resources/InventoryTransactions/InventoryTransactionResource.php` **来源**: v2 的 `InventoryTransactionResource.php` **适配点**: 1. 修改权限检查 2. 保持只读(表单禁用) 3. 过滤器适配 Filament 4.x #### 权限配置 **需要添加**: ```php $inventoryPermissions = [ 'view_any_inventory_transactions', 'view_inventory_transactions', ]; // 所有角色都可以查看库存流水 $allRoles->each(fn($role) => $role->givePermissionTo($inventoryPermissions)); ``` --- ### 5. 员工排班管理(StaffSchedule) #### 数据库 **状态**: glass 项目没有此表 **已创建的迁移**: - ✅ `2026_02_02_140500_create_staff_schedules_table.php` #### 模型 **需要创建**: `app/Models/StaffSchedule.php` **来源**: v2 的模型 **适配点**: 1. 添加 `BelongsToTenant` trait 2. 保持所有辅助方法 ```php givePermissionTo($schedulePermissions); $shopOwner->givePermissionTo($schedulePermissions); ``` --- ## 🔧 全局适配步骤 ### 1. 权限系统扩展 在 `database/seeders/RoleAndPermissionSeeder.php` 中添加: ```php // 产品分类和品牌权限 $categoryAndBrandPermissions = [ 'view_any_categories', 'view_categories', 'create_categories', 'update_categories', 'delete_categories', 'view_any_brands', 'view_brands', 'create_brands', 'update_brands', 'delete_brands', ]; // 采购订单权限(已在上方定义) // 库存流水权限(已在上方定义) // 员工排班权限(已在上方定义) // 分配给角色 $shopOwner->givePermissionTo([...$categoryAndBrandPermissions, ...$purchasePermissions, ...$inventoryPermissions, ...$schedulePermissions]); $shopAdmin->givePermissionTo([...$categoryAndBrandPermissions, ...$purchasePermissions, ...$inventoryPermissions]); $manager->givePermissionTo([...$categoryAndBrandPermissions, ...$purchasePermissions, ...$inventoryPermissions]); $warehouseStaff->givePermissionTo(['view_any_categories', 'view_any_brands', ...$purchasePermissions, ...$inventoryPermissions]); ``` ### 2. 中文本地化更新 在 `lang/zh_CN.json` 中添加: ```json { "resources": { "categories": { "label": "产品分类", "plural_label": "产品分类", "navigation_label": "产品分类" }, "brands": { "label": "品牌", "plural_label": "品牌", "navigation_label": "品牌管理" }, "purchase_orders": { "label": "采购单", "plural_label": "采购管理", "navigation_label": "采购订单" }, "inventory_transactions": { "label": "库存记录", "plural_label": "库存交易记录", "navigation_label": "库存" }, "staff_schedules": { "label": "排班", "plural_label": "员工排班管理", "navigation_label": "员工排班" } }, "actions": { "receive": "收货入库", "stock_in": "补入库", "duplicate": "复制到明天" } } ``` ### 3. 导航分组组织 在所有 Resource 中统一导航分组: - 产品分类:`库存与供应链` - 品牌管理:`库存与供应链` - 采购订单:`库存与供应链` - 库存流水:`库存与供应链` - 员工排班:`系统管理` 或保持单独 --- ## ✅ 检查清单 ### 迁移前 - [ ] 备份 glass 项目数据库 - [ ] 确认 glass 项目的数据库连接配置 - [ ] 准备测试数据 ### 数据库迁移 - [ ] 运行所有新迁移文件 - [ ] 验证表结构正确 - [ ] 检查外键约束 ### 模型创建 - [ ] 创建所有模型文件 - [ ] 添加 BelongsToTenant trait - [ ] 测试模型关系 ### Filament 资源 - [ ] 创建所有 Resource 文件 - [ ] 适配权限检查 - [ ] 测试表单和表格 ### Seeder - [ ] 创建 CategorySeeder - [ ] 创建 BrandSeeder - [ ] 运行 Seeder 填充初始数据 ### 测试 - [ ] 测试 CRUD 操作 - [ ] 测试权限隔离 - [ ] 测试跨租户数据隔离 - [ ] 测试采购订单收货流程 - [ ] 测试库存流水自动记录 --- ## 🚀 执行顺序 ### 第一步:数据库结构(30 分钟) ```bash # 所有迁移文件已创建,运行迁移 #(需要先配置数据库连接) php artisan migrate ``` ### 第二步:模型创建(45 分钟) 1. 复制并适配所有模型 2. 添加 BelongsToTenant trait 3. 测试关系 ### 第三步:Filament 资源(1 小时) 1. 复制所有 Resource 文件 2. 适配权限检查 3. 调整导航 ### 第四步:权限和 Seeder(30 分钟) 1. 更新 RoleAndPermissionSeeder 2. 创建 CategorySeeder 和 BrandSeeder 3. 运行 Seeder ### 第五步:测试和调试(30 分钟) 1. 测试所有功能 2. 修复问题 **总预计时间**: 3 小时 --- 美羊羊 🐑