feat: 第三阶段业务模块(服务产康/月嫂/进销存)

- 新增3个migration(15张表): service/nanny/inventory
- 新增15个Model + 13个Controller
- 新增55条API路由(总计212条)
- 新增3个前端API模块 + 11个管理页面
- vite build验证通过
This commit is contained in:
li
2026-03-13 20:29:45 +08:00
parent 16bcd9bcf0
commit e7d4d9b414
46 changed files with 2573 additions and 0 deletions
@@ -0,0 +1,13 @@
<?php
namespace App\Models\Inventory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Inventory extends Model
{
const CREATED_AT = null;
protected $table = 'inventories';
protected $fillable = ['warehouse_id','material_id','quantity','batch_no','expire_date'];
protected function casts(): array { return ['quantity'=>'decimal:2','expire_date'=>'date']; }
public function warehouse(): BelongsTo { return $this->belongsTo(Warehouse::class); }
public function material(): BelongsTo { return $this->belongsTo(Material::class); }
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models\Inventory;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
class Material extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','code','category','unit','spec','min_stock','shelf_life_days','status'];
protected function casts(): array { return ['min_stock'=>'integer','shelf_life_days'=>'integer','status'=>'integer']; }
}
@@ -0,0 +1,15 @@
<?php
namespace App\Models\Inventory;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PurchaseOrder extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','order_no','supplier_id','total_amount','status','items','audit_user_id','audit_at','remark','created_by'];
protected function casts(): array { return ['total_amount'=>'decimal:2','status'=>'integer','items'=>'array','audit_at'=>'datetime']; }
public function supplier(): BelongsTo { return $this->belongsTo(Supplier::class); }
public function auditor(): BelongsTo { return $this->belongsTo(User::class, 'audit_user_id'); }
public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); }
}
@@ -0,0 +1,14 @@
<?php
namespace App\Models\Inventory;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class StockMovement extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','warehouse_id','movement_no','type','direction','items','related_order','status','operator_id','remark'];
protected function casts(): array { return ['type'=>'integer','direction'=>'integer','items'=>'array','status'=>'integer']; }
public function warehouse(): BelongsTo { return $this->belongsTo(Warehouse::class); }
public function operator(): BelongsTo { return $this->belongsTo(User::class, 'operator_id'); }
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models\Inventory;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
class Supplier extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','contact','phone','address','bank_info','status'];
protected function casts(): array { return ['status'=>'integer']; }
}
@@ -0,0 +1,13 @@
<?php
namespace App\Models\Inventory;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Warehouse extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','manager_id','status'];
protected function casts(): array { return ['status'=>'integer']; }
public function manager(): BelongsTo { return $this->belongsTo(User::class, 'manager_id'); }
}
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace App\Models\Nanny;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Nanny extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','phone','id_card','avatar','level','skills','experience_years','health_cert','cooperation_type','base_salary','introduction','status'];
protected function casts(): array { return ['level'=>'integer','skills'=>'array','experience_years'=>'integer','cooperation_type'=>'integer','base_salary'=>'decimal:2','status'=>'integer']; }
public function orders(): HasMany { return $this->hasMany(NannyOrder::class); }
public function schedules(): HasMany { return $this->hasMany(NannySchedule::class); }
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace App\Models\Nanny;
use App\Models\Crm\Customer;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class NannyOrder extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','customer_id','nanny_id','order_no','service_type','start_date','end_date','days','price','status','match_candidates','remark','created_by'];
protected function casts(): array { return ['service_type'=>'integer','start_date'=>'date','end_date'=>'date','days'=>'integer','price'=>'decimal:2','status'=>'integer','match_candidates'=>'array']; }
public function customer(): BelongsTo { return $this->belongsTo(Customer::class); }
public function nanny(): BelongsTo { return $this->belongsTo(Nanny::class); }
public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); }
public function reviews(): HasMany { return $this->hasMany(NannyReview::class); }
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\Models\Nanny;
use App\Models\Crm\Customer;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class NannyReview extends Model
{
const UPDATED_AT = null;
protected $fillable = ['nanny_order_id','customer_id','nanny_id','score','content'];
protected function casts(): array { return ['score'=>'integer']; }
public function order(): BelongsTo { return $this->belongsTo(NannyOrder::class, 'nanny_order_id'); }
public function customer(): BelongsTo { return $this->belongsTo(Customer::class); }
public function nanny(): BelongsTo { return $this->belongsTo(Nanny::class); }
}
@@ -0,0 +1,12 @@
<?php
namespace App\Models\Nanny;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class NannySchedule extends Model
{
const UPDATED_AT = null;
protected $fillable = ['nanny_id','nanny_order_id','schedule_date','type','remark'];
protected function casts(): array { return ['schedule_date'=>'date','type'=>'integer']; }
public function nanny(): BelongsTo { return $this->belongsTo(Nanny::class); }
public function order(): BelongsTo { return $this->belongsTo(NannyOrder::class, 'nanny_order_id'); }
}
@@ -0,0 +1,15 @@
<?php
namespace App\Models\Service;
use App\Models\Crm\Customer;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ServiceExecution extends Model
{
protected $fillable = ['service_order_id','service_item_id','customer_id','technician_id','scheduled_at','started_at','ended_at','status','remark'];
protected function casts(): array { return ['scheduled_at'=>'datetime','started_at'=>'datetime','ended_at'=>'datetime','status'=>'integer']; }
public function order(): BelongsTo { return $this->belongsTo(ServiceOrder::class, 'service_order_id'); }
public function serviceItem(): BelongsTo { return $this->belongsTo(ServiceItem::class); }
public function customer(): BelongsTo { return $this->belongsTo(Customer::class); }
public function technician(): BelongsTo { return $this->belongsTo(User::class, 'technician_id'); }
}
@@ -0,0 +1,10 @@
<?php
namespace App\Models\Service;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
class ServiceItem extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','category','price','duration','description','image','status'];
protected function casts(): array { return ['category'=>'integer','price'=>'decimal:2','duration'=>'integer','status'=>'integer']; }
}
@@ -0,0 +1,17 @@
<?php
namespace App\Models\Service;
use App\Models\Crm\Customer;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ServiceOrder extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','customer_id','order_no','type','items','total_amount','discount_amount','actual_amount','status','pay_method','paid_at','created_by'];
protected function casts(): array { return ['type'=>'integer','items'=>'array','total_amount'=>'decimal:2','discount_amount'=>'decimal:2','actual_amount'=>'decimal:2','status'=>'integer','pay_method'=>'integer','paid_at'=>'datetime']; }
public function customer(): BelongsTo { return $this->belongsTo(Customer::class); }
public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); }
public function executions(): HasMany { return $this->hasMany(ServiceExecution::class); }
}
@@ -0,0 +1,10 @@
<?php
namespace App\Models\Service;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
class ServicePackage extends Model
{
use BelongsToStore;
protected $fillable = ['store_id','name','items','price','validity_days','status'];
protected function casts(): array { return ['items'=>'array','price'=>'decimal:2','validity_days'=>'integer','status'=>'integer']; }
}
@@ -0,0 +1,13 @@
<?php
namespace App\Models\Service;
use App\Models\Crm\Customer;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ServiceReview extends Model
{
const UPDATED_AT = null;
protected $fillable = ['service_order_id','service_execution_id','customer_id','score','content'];
protected function casts(): array { return ['score'=>'integer']; }
public function order(): BelongsTo { return $this->belongsTo(ServiceOrder::class, 'service_order_id'); }
public function customer(): BelongsTo { return $this->belongsTo(Customer::class); }
}