feat: 员工自助注册+审核流程
- 新增 registration_packages 表:管理员配置注册套餐(名称/角色) - AuthController 新增 register() 和 registrationPackages() 公开接口 - UserController 新增 approve() / reject() 审核接口 - StoreController 新增 publicList() 公开门店列表 - 前端 /register 注册页:选门店→选岗位套餐→填信息→提交 - 前端 system/registration-packages:套餐 CRUD - 用户管理页:待审核状态展示 + 通过/拒绝快捷操作 - 登录页底部加「申请注册」跳转链接 - 路由白名单加 /register
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\InventoryCheck;
|
||||
use App\Models\Inventory\Inventory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class InventoryCheckController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = InventoryCheck::query()
|
||||
->with(['warehouse', 'operator'])
|
||||
->when($request->warehouse_id, fn($q, $v) => $q->where('warehouse_id', $v))
|
||||
->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([
|
||||
'check_no' => 'required|string|max:50|unique:inventory_checks',
|
||||
'warehouse_id' => 'required|exists:warehouses,id',
|
||||
'items' => 'nullable|array',
|
||||
'remark' => 'nullable|string|max:500',
|
||||
]);
|
||||
$v['status'] = 0;
|
||||
$v['operator_id'] = auth()->id();
|
||||
|
||||
return $this->success(InventoryCheck::create($v));
|
||||
}
|
||||
|
||||
public function show(InventoryCheck $inventoryCheck): JsonResponse
|
||||
{
|
||||
return $this->success($inventoryCheck->load(['warehouse', 'operator']));
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成盘点 — 可选择按实际数量修正库存
|
||||
*/
|
||||
public function complete(InventoryCheck $inventoryCheck, Request $request): JsonResponse
|
||||
{
|
||||
if ($inventoryCheck->status === 2) {
|
||||
return $this->error('已完成', 40001);
|
||||
}
|
||||
|
||||
$v = $request->validate([
|
||||
'items' => 'nullable|array',
|
||||
'finish_remark' => 'nullable|string|max:500',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($inventoryCheck, $v) {
|
||||
$items = $v['items'] ?? $inventoryCheck->items ?? [];
|
||||
|
||||
// 如果有差异且需要调整库存
|
||||
foreach ($items as $item) {
|
||||
if (!isset($item['actual_qty'])) continue;
|
||||
$diff = ($item['actual_qty'] ?? 0) - ($item['book_qty'] ?? 0);
|
||||
if ($diff == 0) continue;
|
||||
|
||||
$inv = Inventory::firstOrCreate(
|
||||
['warehouse_id' => $inventoryCheck->warehouse_id, 'material_id' => $item['material_id'], 'batch_no' => null],
|
||||
['quantity' => 0]
|
||||
);
|
||||
$inv->increment('quantity', $diff);
|
||||
}
|
||||
|
||||
$inventoryCheck->update([
|
||||
'status' => 2,
|
||||
'items' => $items,
|
||||
'finish_remark' => $v['finish_remark'] ?? null,
|
||||
]);
|
||||
});
|
||||
|
||||
return $this->success($inventoryCheck->fresh(['warehouse']));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\Inventory;
|
||||
use App\Models\Inventory\Material;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class StockController extends Controller
|
||||
{
|
||||
/**
|
||||
* 库存台账 — 汇总 inventories 表,关联 material 信息
|
||||
* GET /inventory/stock
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = Inventory::query()
|
||||
->with(['warehouse', 'material'])
|
||||
->when($request->warehouse_id, fn($q, $v) => $q->where('warehouse_id', $v))
|
||||
->when($request->material_id, fn($q, $v) => $q->where('material_id', $v))
|
||||
->when($request->low_stock, fn($q) => $q->whereRaw('quantity <= (SELECT min_stock FROM materials WHERE materials.id = inventories.material_id AND min_stock IS NOT NULL)'));
|
||||
|
||||
return $this->paginate($query->paginate($request->input('per_page', 20)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出库存台账
|
||||
* GET /inventory/stock/export
|
||||
*/
|
||||
public function export(Request $request): JsonResponse
|
||||
{
|
||||
$rows = Inventory::with(['warehouse', 'material'])
|
||||
->when($request->warehouse_id, fn($q, $v) => $q->where('warehouse_id', $v))
|
||||
->get()
|
||||
->map(fn($inv) => [
|
||||
'warehouse' => $inv->warehouse?->name,
|
||||
'material_code' => $inv->material?->code,
|
||||
'material_name' => $inv->material?->name,
|
||||
'unit' => $inv->material?->unit,
|
||||
'quantity' => $inv->quantity,
|
||||
'batch_no' => $inv->batch_no,
|
||||
'expire_date' => $inv->expire_date?->toDateString(),
|
||||
'safety_stock' => $inv->material?->min_stock,
|
||||
'updated_at' => $inv->updated_at?->toDateTimeString(),
|
||||
]);
|
||||
|
||||
return $this->success(['rows' => $rows, 'total' => $rows->count()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Admin\Inventory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Inventory\TransferOrder;
|
||||
use App\Models\Inventory\Inventory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TransferOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$query = TransferOrder::query()
|
||||
->with(['fromWarehouse', 'toWarehouse', 'operator'])
|
||||
->when($request->transfer_no, fn($q, $v) => $q->where('transfer_no', 'like', "%{$v}%"))
|
||||
->when($request->has('status'), fn($q) => $q->where('status', $request->status))
|
||||
->when($request->from_warehouse_id, fn($q, $v) => $q->where('from_warehouse_id', $v));
|
||||
|
||||
return $this->paginate($query->latest()->paginate($request->input('per_page', 15)));
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$v = $request->validate([
|
||||
'transfer_no' => 'required|string|max:50|unique:transfer_orders',
|
||||
'from_warehouse_id' => 'required|exists:warehouses,id',
|
||||
'to_warehouse_id' => 'required|exists:warehouses,id|different:from_warehouse_id',
|
||||
'items' => 'nullable|array',
|
||||
'remark' => 'nullable|string|max:500',
|
||||
]);
|
||||
$v['status'] = 0;
|
||||
$v['operator_id'] = auth()->id();
|
||||
|
||||
return $this->success(TransferOrder::create($v));
|
||||
}
|
||||
|
||||
public function show(TransferOrder $transferOrder): JsonResponse
|
||||
{
|
||||
return $this->success($transferOrder->load(['fromWarehouse', 'toWarehouse', 'operator']));
|
||||
}
|
||||
|
||||
public function confirm(TransferOrder $transferOrder): JsonResponse
|
||||
{
|
||||
if ($transferOrder->status !== 0) {
|
||||
return $this->error('当前状态不可确认', 40001);
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($transferOrder) {
|
||||
$transferOrder->update(['status' => 1]);
|
||||
|
||||
// 调拨:减源仓库、加目标仓库
|
||||
foreach (($transferOrder->items ?? []) as $item) {
|
||||
$materialId = $item['material_id'];
|
||||
$qty = $item['quantity'] ?? 0;
|
||||
|
||||
// 扣减出库仓库
|
||||
Inventory::where('warehouse_id', $transferOrder->from_warehouse_id)
|
||||
->where('material_id', $materialId)
|
||||
->decrement('quantity', $qty);
|
||||
|
||||
// 增加入库仓库
|
||||
$inv = Inventory::firstOrCreate(
|
||||
['warehouse_id' => $transferOrder->to_warehouse_id, 'material_id' => $materialId, 'batch_no' => null],
|
||||
['quantity' => 0]
|
||||
);
|
||||
$inv->increment('quantity', $qty);
|
||||
}
|
||||
});
|
||||
|
||||
return $this->success($transferOrder->fresh(['fromWarehouse', 'toWarehouse']));
|
||||
}
|
||||
|
||||
public function cancel(TransferOrder $transferOrder): JsonResponse
|
||||
{
|
||||
if ($transferOrder->status !== 0) {
|
||||
return $this->error('只有待确认状态可取消', 40001);
|
||||
}
|
||||
$transferOrder->update(['status' => 2]);
|
||||
return $this->success($transferOrder);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user