Add detailed migration plan for glass-v2 features
This commit is contained in:
parent
0777d5f341
commit
0dad5f9fbf
580
projects/glass-v2-migration-detailed-plan.md
Normal file
580
projects/glass-v2-migration-detailed-plan.md
Normal 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. 调整导航
|
||||
|
||||
### 第四步:权限和 Seeder(30 分钟)
|
||||
1. 更新 RoleAndPermissionSeeder
|
||||
2. 创建 CategorySeeder 和 BrandSeeder
|
||||
3. 运行 Seeder
|
||||
|
||||
### 第五步:测试和调试(30 分钟)
|
||||
1. 测试所有功能
|
||||
2. 修复问题
|
||||
|
||||
**总预计时间**: 3 小时
|
||||
|
||||
---
|
||||
|
||||
美羊羊 🐑
|
||||
Loading…
Reference in New Issue
Block a user