feat: 第三阶段业务模块(服务产康/月嫂/进销存)
- 新增3个migration(15张表): service/nanny/inventory - 新增15个Model + 13个Controller - 新增55条API路由(总计212条) - 新增3个前端API模块 + 11个管理页面 - vite build验证通过
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\Inventory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InventoryController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Inventory::query()->with(['warehouse','material']);
|
||||
$query->when($request->warehouse_id, fn($q, $v) => $q->where('warehouse_id', $v));
|
||||
$query->when($request->material_id, fn($q, $v) => $q->where('material_id', $v));
|
||||
return $this->paginate($query->paginate($request->input('per_page', 50)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\Material;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MaterialController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Material::query();
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
$query->when($request->category, fn($q, $v) => $q->where('category', $v));
|
||||
$query->when($request->code, fn($q, $v) => $q->where('code', 'like', "%{$v}%"));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate(['name'=>'required|string|max:100','code'=>'nullable|string|max:50','category'=>'nullable|string|max:50','unit'=>'nullable|string|max:20','spec'=>'nullable|string|max:100','min_stock'=>'sometimes|integer|min:0','shelf_life_days'=>'nullable|integer|min:1','status'=>'sometimes|integer|in:0,1']);
|
||||
return $this->success(Material::create($v));
|
||||
}
|
||||
public function show(Material $material): JsonResponse { return $this->success($material); }
|
||||
public function update(Request $request, Material $material): JsonResponse { $v = $request->validate(['name'=>'sometimes|string|max:100','code'=>'nullable|string|max:50','category'=>'nullable|string|max:50','unit'=>'nullable|string|max:20','spec'=>'nullable|string|max:100','min_stock'=>'sometimes|integer|min:0','shelf_life_days'=>'nullable|integer|min:1','status'=>'sometimes|integer|in:0,1']); $material->update($v); return $this->success($material); }
|
||||
public function destroy(Material $material): JsonResponse { $material->delete(); return $this->success(null); }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\PurchaseOrder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PurchaseOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = PurchaseOrder::query()->with(['supplier','auditor']);
|
||||
$query->when($request->order_no, fn($q, $v) => $q->where('order_no', 'like', "%{$v}%"));
|
||||
$query->when($request->supplier_id, fn($q, $v) => $q->where('supplier_id', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate(['order_no'=>'required|string|max:50|unique:purchase_orders','supplier_id'=>'nullable|exists:suppliers,id','total_amount'=>'nullable|numeric|min:0','items'=>'nullable|array','remark'=>'nullable|string']);
|
||||
$v['status'] = 0; $v['created_by'] = auth()->id();
|
||||
return $this->success(PurchaseOrder::create($v));
|
||||
}
|
||||
public function show(PurchaseOrder $purchaseOrder): JsonResponse { return $this->success($purchaseOrder->load(['supplier','auditor','creator'])); }
|
||||
public function update(Request $request, PurchaseOrder $purchaseOrder): JsonResponse
|
||||
{
|
||||
if ($purchaseOrder->status >= 2) return $this->error('已审批的采购单不可修改', 40001);
|
||||
$v = $request->validate(['supplier_id'=>'nullable|exists:suppliers,id','total_amount'=>'nullable|numeric|min:0','items'=>'nullable|array','remark'=>'nullable|string']);
|
||||
$purchaseOrder->update($v);
|
||||
return $this->success($purchaseOrder);
|
||||
}
|
||||
public function audit(Request $request, PurchaseOrder $purchaseOrder): JsonResponse
|
||||
{
|
||||
if ($purchaseOrder->status >= 2) return $this->error('已审批', 40001);
|
||||
$v = $request->validate(['status'=>'required|integer|in:2,4']);
|
||||
$purchaseOrder->update(['status'=>$v['status'],'audit_user_id'=>auth()->id(),'audit_at'=>now()]);
|
||||
return $this->success($purchaseOrder);
|
||||
}
|
||||
public function destroy(PurchaseOrder $purchaseOrder): JsonResponse
|
||||
{
|
||||
if ($purchaseOrder->status >= 2) return $this->error('已审批不可删除', 40001);
|
||||
$purchaseOrder->delete(); return $this->success(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\StockMovement;
|
||||
use App\Models\Inventory\Inventory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StockMovementController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = StockMovement::query()->with('warehouse');
|
||||
$query->when($request->warehouse_id, fn($q, $v) => $q->where('warehouse_id', $v));
|
||||
$query->when($request->type, fn($q, $v) => $q->where('type', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate([
|
||||
'warehouse_id'=>'required|exists:warehouses,id','movement_no'=>'required|string|max:50|unique:stock_movements',
|
||||
'type'=>'required|integer|in:1,2,3,4','direction'=>'nullable|integer|in:1,2',
|
||||
'items'=>'nullable|array','related_order'=>'nullable|string|max:50','remark'=>'nullable|string',
|
||||
]);
|
||||
$v['status'] = 0; $v['operator_id'] = auth()->id();
|
||||
return $this->success(StockMovement::create($v));
|
||||
}
|
||||
public function show(StockMovement $stockMovement): JsonResponse { return $this->success($stockMovement->load(['warehouse','operator'])); }
|
||||
public function confirm(StockMovement $stockMovement): JsonResponse
|
||||
{
|
||||
if ($stockMovement->status === 1) return $this->error('已确认', 40001);
|
||||
$stockMovement->update(['status' => 1]);
|
||||
// 更新库存
|
||||
if ($stockMovement->items) {
|
||||
foreach ($stockMovement->items as $item) {
|
||||
$inv = Inventory::firstOrCreate(
|
||||
['warehouse_id'=>$stockMovement->warehouse_id,'material_id'=>$item['material_id'],'batch_no'=>$item['batch_no']??null],
|
||||
['quantity'=>0]
|
||||
);
|
||||
$qty = $item['quantity'] ?? 0;
|
||||
$inv->quantity = $stockMovement->direction === 1 ? $inv->quantity + $qty : $inv->quantity - $qty;
|
||||
$inv->save();
|
||||
}
|
||||
}
|
||||
return $this->success($stockMovement);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\Supplier;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SupplierController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Supplier::query();
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate(['name'=>'required|string|max:100','contact'=>'nullable|string|max:50','phone'=>'nullable|string|max:20','address'=>'nullable|string|max:255','bank_info'=>'nullable|string|max:255','status'=>'sometimes|integer|in:0,1']);
|
||||
return $this->success(Supplier::create($v));
|
||||
}
|
||||
public function show(Supplier $supplier): JsonResponse { return $this->success($supplier); }
|
||||
public function update(Request $request, Supplier $supplier): JsonResponse { $v = $request->validate(['name'=>'sometimes|string|max:100','contact'=>'nullable|string|max:50','phone'=>'nullable|string|max:20','address'=>'nullable|string|max:255','bank_info'=>'nullable|string|max:255','status'=>'sometimes|integer|in:0,1']); $supplier->update($v); return $this->success($supplier); }
|
||||
public function destroy(Supplier $supplier): JsonResponse { $supplier->delete(); return $this->success(null); }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\Warehouse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class WarehouseController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Warehouse::query()->with('manager');
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate(['name'=>'required|string|max:50','manager_id'=>'nullable|exists:users,id','status'=>'sometimes|integer|in:0,1']);
|
||||
return $this->success(Warehouse::create($v));
|
||||
}
|
||||
public function show(Warehouse $warehouse): JsonResponse { return $this->success($warehouse->load('manager')); }
|
||||
public function update(Request $request, Warehouse $warehouse): JsonResponse { $v = $request->validate(['name'=>'sometimes|string|max:50','manager_id'=>'nullable|exists:users,id','status'=>'sometimes|integer|in:0,1']); $warehouse->update($v); return $this->success($warehouse); }
|
||||
public function destroy(Warehouse $warehouse): JsonResponse { $warehouse->delete(); return $this->success(null); }
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Nanny;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Nanny\Nanny;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NannyController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Nanny::query();
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
$query->when($request->level, fn($q, $v) => $q->where('level', $v));
|
||||
$query->when($request->status, fn($q, $v) => $q->where('status', $v));
|
||||
$query->when($request->cooperation_type, fn($q, $v) => $q->where('cooperation_type', $v));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name'=>'required|string|max:50','phone'=>'nullable|string|max:20','id_card'=>'nullable|string|max:20',
|
||||
'level'=>'nullable|integer|in:1,2,3,4','skills'=>'nullable|array','experience_years'=>'nullable|integer|min:0',
|
||||
'health_cert'=>'nullable|string|max:255','cooperation_type'=>'nullable|integer|in:1,2,3',
|
||||
'base_salary'=>'nullable|numeric|min:0','introduction'=>'nullable|string','status'=>'sometimes|integer|in:1,2,3,4',
|
||||
]);
|
||||
return $this->success(Nanny::create($validated));
|
||||
}
|
||||
|
||||
public function show(Nanny $nanny): JsonResponse { return $this->success($nanny->load(['orders.customer','schedules'])); }
|
||||
|
||||
public function update(Request $request, Nanny $nanny): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name'=>'sometimes|string|max:50','phone'=>'nullable|string|max:20','level'=>'nullable|integer|in:1,2,3,4',
|
||||
'skills'=>'nullable|array','experience_years'=>'nullable|integer|min:0','cooperation_type'=>'nullable|integer|in:1,2,3',
|
||||
'base_salary'=>'nullable|numeric|min:0','introduction'=>'nullable|string','status'=>'sometimes|integer|in:1,2,3,4',
|
||||
]);
|
||||
$nanny->update($validated);
|
||||
return $this->success($nanny);
|
||||
}
|
||||
|
||||
public function destroy(Nanny $nanny): JsonResponse
|
||||
{
|
||||
if ($nanny->status === 2) return $this->error('服务中的月嫂无法删除', 40001);
|
||||
$nanny->delete();
|
||||
return $this->success(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Nanny;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Nanny\NannyOrder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NannyOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = NannyOrder::query()->with(['customer','nanny']);
|
||||
$query->when($request->customer_id, fn($q, $v) => $q->where('customer_id', $v));
|
||||
$query->when($request->nanny_id, fn($q, $v) => $q->where('nanny_id', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'customer_id'=>'required|exists:customers,id','nanny_id'=>'nullable|exists:nannies,id',
|
||||
'order_no'=>'required|string|max:50|unique:nanny_orders','service_type'=>'nullable|integer|in:1,2',
|
||||
'start_date'=>'nullable|date','end_date'=>'nullable|date|after_or_equal:start_date',
|
||||
'days'=>'nullable|integer|min:1','price'=>'nullable|numeric|min:0','remark'=>'nullable|string',
|
||||
]);
|
||||
$validated['status'] = 0;
|
||||
$validated['created_by'] = auth()->id();
|
||||
return $this->success(NannyOrder::create($validated));
|
||||
}
|
||||
|
||||
public function show(NannyOrder $nannyOrder): JsonResponse { return $this->success($nannyOrder->load(['customer','nanny','reviews'])); }
|
||||
|
||||
public function update(Request $request, NannyOrder $nannyOrder): JsonResponse
|
||||
{
|
||||
if ($nannyOrder->status >= 4) return $this->error('已完成/取消的订单不可修改', 40001);
|
||||
$validated = $request->validate([
|
||||
'nanny_id'=>'nullable|exists:nannies,id','start_date'=>'nullable|date','end_date'=>'nullable|date',
|
||||
'days'=>'nullable|integer|min:1','price'=>'nullable|numeric|min:0','status'=>'sometimes|integer|in:0,1,2,3,4,5',
|
||||
'match_candidates'=>'nullable|array','remark'=>'nullable|string',
|
||||
]);
|
||||
$nannyOrder->update($validated);
|
||||
if (isset($validated['nanny_id']) && $validated['nanny_id']) {
|
||||
$nannyOrder->nanny->update(['status' => 2]);
|
||||
}
|
||||
return $this->success($nannyOrder);
|
||||
}
|
||||
|
||||
public function destroy(NannyOrder $nannyOrder): JsonResponse
|
||||
{
|
||||
if ($nannyOrder->status >= 2) return $this->error('已签约后不可删除', 40001);
|
||||
$nannyOrder->delete();
|
||||
return $this->success(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Nanny;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Nanny\NannySchedule;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NannyScheduleController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = NannySchedule::query()->with(['nanny','order']);
|
||||
$query->when($request->nanny_id, fn($q, $v) => $q->where('nanny_id', $v));
|
||||
$query->when($request->start_date, fn($q, $v) => $q->where('schedule_date', '>=', $v));
|
||||
$query->when($request->end_date, fn($q, $v) => $q->where('schedule_date', '<=', $v));
|
||||
return $this->paginate($query->orderBy('schedule_date')->paginate($request->input('per_page', 31)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'nanny_id'=>'required|exists:nannies,id','nanny_order_id'=>'nullable|exists:nanny_orders,id',
|
||||
'schedule_date'=>'required|date','type'=>'nullable|integer|in:1,2,3','remark'=>'nullable|string|max:255',
|
||||
]);
|
||||
return $this->success(NannySchedule::create($validated));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Service;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Service\ServiceExecution;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServiceExecutionController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = ServiceExecution::query()->with(['order','serviceItem','customer','technician']);
|
||||
$query->when($request->service_order_id, fn($q, $v) => $q->where('service_order_id', $v));
|
||||
$query->when($request->technician_id, fn($q, $v) => $q->where('technician_id', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'service_order_id'=>'required|exists:service_orders,id','service_item_id'=>'required|exists:service_items,id',
|
||||
'customer_id'=>'required|exists:customers,id','technician_id'=>'nullable|exists:users,id',
|
||||
'scheduled_at'=>'nullable|date','remark'=>'nullable|string',
|
||||
]);
|
||||
$validated['status'] = 0;
|
||||
return $this->success(ServiceExecution::create($validated));
|
||||
}
|
||||
|
||||
public function start(ServiceExecution $serviceExecution): JsonResponse
|
||||
{
|
||||
if ($serviceExecution->status !== 0) return $this->error('只有待执行可开始', 40001);
|
||||
$serviceExecution->update(['status'=>1,'started_at'=>now()]);
|
||||
return $this->success($serviceExecution);
|
||||
}
|
||||
|
||||
public function finish(ServiceExecution $serviceExecution): JsonResponse
|
||||
{
|
||||
if ($serviceExecution->status !== 1) return $this->error('只有执行中可完成', 40001);
|
||||
$serviceExecution->update(['status'=>2,'ended_at'=>now()]);
|
||||
return $this->success($serviceExecution);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Service;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Service\ServiceItem;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServiceItemController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = ServiceItem::query();
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
$query->when($request->category, fn($q, $v) => $q->where('category', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:100',
|
||||
'category' => 'nullable|integer|in:1,2,3,4',
|
||||
'price' => 'required|numeric|min:0',
|
||||
'duration' => 'nullable|integer|min:1',
|
||||
'description' => 'nullable|string',
|
||||
'image' => 'nullable|string|max:255',
|
||||
'status' => 'sometimes|integer|in:0,1',
|
||||
]);
|
||||
return $this->success(ServiceItem::create($validated));
|
||||
}
|
||||
|
||||
public function show(ServiceItem $serviceItem): JsonResponse { return $this->success($serviceItem); }
|
||||
|
||||
public function update(Request $request, ServiceItem $serviceItem): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'sometimes|string|max:100',
|
||||
'category' => 'nullable|integer|in:1,2,3,4',
|
||||
'price' => 'sometimes|numeric|min:0',
|
||||
'duration' => 'nullable|integer|min:1',
|
||||
'description' => 'nullable|string',
|
||||
'image' => 'nullable|string|max:255',
|
||||
'status' => 'sometimes|integer|in:0,1',
|
||||
]);
|
||||
$serviceItem->update($validated);
|
||||
return $this->success($serviceItem);
|
||||
}
|
||||
|
||||
public function destroy(ServiceItem $serviceItem): JsonResponse { $serviceItem->delete(); return $this->success(null); }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Service;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Service\ServiceOrder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServiceOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = ServiceOrder::query()->with(['customer']);
|
||||
$query->when($request->order_no, fn($q, $v) => $q->where('order_no', 'like', "%{$v}%"));
|
||||
$query->when($request->customer_id, fn($q, $v) => $q->where('customer_id', $v));
|
||||
$query->when($request->type, fn($q, $v) => $q->where('type', $v));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'customer_id'=>'required|exists:customers,id','order_no'=>'required|string|max:50|unique:service_orders',
|
||||
'type'=>'nullable|integer|in:1,2,3,4','items'=>'nullable|array',
|
||||
'total_amount'=>'required|numeric|min:0','discount_amount'=>'sometimes|numeric|min:0','actual_amount'=>'required|numeric|min:0',
|
||||
'pay_method'=>'nullable|integer|in:1,2,3,4','remark'=>'nullable|string',
|
||||
]);
|
||||
$validated['status'] = 0;
|
||||
$validated['created_by'] = auth()->id();
|
||||
return $this->success(ServiceOrder::create($validated));
|
||||
}
|
||||
|
||||
public function show(ServiceOrder $serviceOrder): JsonResponse { return $this->success($serviceOrder->load(['customer','executions.serviceItem','executions.technician'])); }
|
||||
|
||||
public function update(Request $request, ServiceOrder $serviceOrder): JsonResponse
|
||||
{
|
||||
if ($serviceOrder->status >= 2) return $this->error('已完成/取消的订单不可修改', 40001);
|
||||
$validated = $request->validate(['items'=>'nullable|array','total_amount'=>'sometimes|numeric|min:0','discount_amount'=>'sometimes|numeric|min:0','actual_amount'=>'sometimes|numeric|min:0','remark'=>'nullable|string']);
|
||||
$serviceOrder->update($validated);
|
||||
return $this->success($serviceOrder);
|
||||
}
|
||||
|
||||
public function destroy(ServiceOrder $serviceOrder): JsonResponse
|
||||
{
|
||||
if ($serviceOrder->status >= 1) return $this->error('已付款的订单不可删除', 40001);
|
||||
$serviceOrder->delete();
|
||||
return $this->success(null);
|
||||
}
|
||||
|
||||
public function pay(Request $request, ServiceOrder $serviceOrder): JsonResponse
|
||||
{
|
||||
if ($serviceOrder->status !== 0) return $this->error('该订单不可付款', 40001);
|
||||
$validated = $request->validate(['pay_method'=>'required|integer|in:1,2,3,4']);
|
||||
$serviceOrder->update(['status'=>1,'pay_method'=>$validated['pay_method'],'paid_at'=>now()]);
|
||||
return $this->success($serviceOrder);
|
||||
}
|
||||
|
||||
public function complete(ServiceOrder $serviceOrder): JsonResponse
|
||||
{
|
||||
if ($serviceOrder->status !== 1) return $this->error('只有已付款的订单可完成', 40001);
|
||||
$serviceOrder->update(['status'=>2]);
|
||||
return $this->success($serviceOrder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Service;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Service\ServicePackage;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ServicePackageController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = ServicePackage::query();
|
||||
$query->when($request->name, fn($q, $v) => $q->where('name', 'like', "%{$v}%"));
|
||||
$query->when($request->has('status'), fn($q) => $q->where('status', $request->status));
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate(['name'=>'required|string|max:100','items'=>'nullable|array','price'=>'required|numeric|min:0','validity_days'=>'nullable|integer|min:1','status'=>'sometimes|integer|in:0,1']);
|
||||
return $this->success(ServicePackage::create($validated));
|
||||
}
|
||||
|
||||
public function show(ServicePackage $servicePackage): JsonResponse { return $this->success($servicePackage); }
|
||||
|
||||
public function update(Request $request, ServicePackage $servicePackage): JsonResponse
|
||||
{
|
||||
$validated = $request->validate(['name'=>'sometimes|string|max:100','items'=>'nullable|array','price'=>'sometimes|numeric|min:0','validity_days'=>'nullable|integer|min:1','status'=>'sometimes|integer|in:0,1']);
|
||||
$servicePackage->update($validated);
|
||||
return $this->success($servicePackage);
|
||||
}
|
||||
|
||||
public function destroy(ServicePackage $servicePackage): JsonResponse { $servicePackage->delete(); return $this->success(null); }
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
@@ -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'); }
|
||||
}
|
||||
@@ -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'); }
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
@@ -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); }
|
||||
}
|
||||
Reference in New Issue
Block a user