13 KiB
glass-v2 迁移详细计划
📋 概述
将 glass-v2 的 5 个功能模块迁移到 glass 项目,同时适配:
- 多租户架构(team_id 隔离)
- Spatie Permission 权限系统
- 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
namespace App\Models;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Category extends Model
{
use BelongsToTenant;
protected $fillable = [
'name',
'name_en',
'slug',
'icon',
'color',
'description',
'sort_order',
'status', // 'active' or 'inactive' (改为 is_active)
];
protected $casts = [
'status' => '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
适配点:
- 修改命名空间:
ProductCategories→Categories - 修改模型:
ProductCategory→Category - 修改权限检查:
// v2: auth()->user()->is_admin // glass: 使用 Gate 或 Policy public static function canViewAny(): bool { return auth()->user()->can('view_any_categories'); } - 修改导航组:'库存与供应链' → 保持
- 添加团队范围:默认会应用 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
namespace App\Models;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Brand extends Model
{
use BelongsToTenant;
protected $fillable = [
'name',
'name_en',
'slug',
'logo',
'description',
'website',
'country',
'sort_order',
'status',
];
protected $casts = [
'status' => '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
适配点:
- 模型名称保持不变
- 修改权限检查(同上)
- 确保 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 的模型
适配点:
- 添加
BelongsToTenanttrait - 确保所有关系正确
- 添加团队范围查询
PurchaseOrderItem:
<?php
namespace App\Models;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PurchaseOrderItem extends Model
{
use BelongsToTenant;
protected $fillable = [
'purchase_order_id',
'product_id',
'quantity',
'received_quantity',
'unit_cost',
'total_cost',
'note',
];
protected $casts = [
'quantity' => '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
适配点:
- 修改权限检查
- 确保关联关系正确加载(
with()) - 状态流转逻辑保持不变
权限配置
需要添加到 RoleAndPermissionSeeder:
$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 的模型
适配点:
- 添加
BelongsToTenanttrait - 确保多态关联正确
<?php
namespace App\Models;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class InventoryTransaction extends Model
{
use BelongsToTenant;
protected $fillable = [
'product_id',
'type', // 'in', 'out', 'adjust'
'quantity',
'reference_type',
'reference_id',
'staff_id',
'balance_after',
'note',
];
protected $casts = [
'quantity' => '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
适配点:
- 修改权限检查
- 保持只读(表单禁用)
- 过滤器适配 Filament 4.x
权限配置
需要添加:
$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 的模型
适配点:
- 添加
BelongsToTenanttrait - 保持所有辅助方法
<?php
namespace App\Models;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class StaffSchedule extends Model
{
use BelongsToTenant;
public const SHIFT_MORNING = 'morning';
public const SHIFT_AFTERNOON = 'afternoon';
public const SHIFT_FULL_DAY = 'full_day';
public const SHIFT_CUSTOM = 'custom';
// ... 其余代码保持不变 ...
}
Filament 资源
需要创建: app/Filament/Resources/StaffSchedules/StaffScheduleResource.php
来源: v2 的 StaffScheduleResource.php
适配点:
- 修改权限检查
- 移除 v2 特定的导航组(或保持"系统管理")
权限配置
需要添加:
$schedulePermissions = [
'view_any_staff_schedules',
'view_staff_schedules',
'create_staff_schedules',
'update_staff_schedules',
'delete_staff_schedules',
];
// 管理权限角色
$manager->givePermissionTo($schedulePermissions);
$shopOwner->givePermissionTo($schedulePermissions);
🔧 全局适配步骤
1. 权限系统扩展
在 database/seeders/RoleAndPermissionSeeder.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 中添加:
{
"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 分钟)
# 所有迁移文件已创建,运行迁移
#(需要先配置数据库连接)
php artisan migrate
第二步:模型创建(45 分钟)
- 复制并适配所有模型
- 添加 BelongsToTenant trait
- 测试关系
第三步:Filament 资源(1 小时)
- 复制所有 Resource 文件
- 适配权限检查
- 调整导航
第四步:权限和 Seeder(30 分钟)
- 更新 RoleAndPermissionSeeder
- 创建 CategorySeeder 和 BrandSeeder
- 运行 Seeder
第五步:测试和调试(30 分钟)
- 测试所有功能
- 修复问题
总预计时间: 3 小时
美羊羊 🐑