Add detailed migration plan for glass-v2 features

This commit is contained in:
Ubuntu 2026-02-02 14:37:19 +08:00
parent 0777d5f341
commit 0dad5f9fbf

View File

@ -0,0 +1,580 @@
# 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
<?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`
**适配点**:
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
<?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`
**适配点**:
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
<?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`
**适配点**:
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
<?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`
**适配点**:
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
<?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`
**适配点**:
1. 修改权限检查
2. 移除 v2 特定的导航组(或保持"系统管理"
#### 权限配置
**需要添加**:
```php
$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` 中添加:
```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. 调整导航
### 第四步:权限和 Seeder30 分钟)
1. 更新 RoleAndPermissionSeeder
2. 创建 CategorySeeder 和 BrandSeeder
3. 运行 Seeder
### 第五步测试和调试30 分钟)
1. 测试所有功能
2. 修复问题
**总预计时间**: 3 小时
---
美羊羊 🐑