diff --git a/app/Http/Controllers/Admin/WorkOrderController.php b/app/Http/Controllers/Admin/WorkOrderController.php index 73b9662..7136865 100644 --- a/app/Http/Controllers/Admin/WorkOrderController.php +++ b/app/Http/Controllers/Admin/WorkOrderController.php @@ -91,7 +91,6 @@ public function update(Request $request, WorkOrder $workOrder): RedirectResponse */ public function destroy(WorkOrder $workOrder): RedirectResponse { - // try { $workOrder->safeDelete(); } catch (CommonException $e) { diff --git a/app/Http/Controllers/Api/ReplyController.php b/app/Http/Controllers/Api/ReplyController.php index 322f6b0..1565710 100644 --- a/app/Http/Controllers/Api/ReplyController.php +++ b/app/Http/Controllers/Api/ReplyController.php @@ -7,7 +7,6 @@ use App\Models\WorkOrder\WorkOrder; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Http\Response; use function auth; class ReplyController extends Controller @@ -19,11 +18,7 @@ class ReplyController extends Controller */ public function index(WorkOrder $workOrder) { - if (auth()->id() !== $workOrder->user_id) { - return $this->notFound('无法找到对应的工单。'); - } - - $replies = Reply::workOrderId($workOrder->id)->simplePaginate(100); + $replies = Reply::workOrderId($workOrder->id)->with(['module', 'user'])->simplePaginate(100); return $this->success($replies); } @@ -34,25 +29,34 @@ public function index(WorkOrder $workOrder) * @param Request $request * @param WorkOrder $workOrder * - * @return JsonResponse|Response + * @return JsonResponse */ public function store(Request $request, WorkOrder $workOrder) { - if (auth()->id() !== $workOrder->user_id) { - return $this->notFound('无法找到对应的工单。'); - } - - // add reply $this->validate($request, [ 'content' => 'string|required|min:1|max:1000', ]); + if ($workOrder->isFailure()) { + return $this->error('工单状态异常,无法进行回复。请尝试重新建立工单。'); + } - $reply = Reply::create([ + $create = [ 'content' => $request->input('content'), 'work_order_id' => $workOrder->id, - ]); + ]; + if (auth('sanctum')->check()) { + $create['user_id'] = auth('sanctum')->id(); + } else { + $this->validate($request, [ + 'name' => 'string|required|min:1|max:255', + ]); + + $create['name'] = $request->input('name'); + } + + $reply = Reply::create($create); return $this->success($reply); } diff --git a/app/Http/Controllers/Api/WorkOrderController.php b/app/Http/Controllers/Api/WorkOrderController.php index 58075c0..1c935bc 100644 --- a/app/Http/Controllers/Api/WorkOrderController.php +++ b/app/Http/Controllers/Api/WorkOrderController.php @@ -7,7 +7,6 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Validation\ValidationException; -use function auth; class WorkOrderController extends Controller { @@ -31,15 +30,20 @@ public function store(Request $request) ]); // module_id 和 host_id 必须有个要填写 - if (isset($request->module_id) && isset($request->host_id)) { - return $this->error('module_id 和 host_id 至少要填写一个'); + if ($request->input('module_id') === null && $request->input('host_id') === null) { + $message = 'module_id 和 host_id 必须有个要填写'; + + throw ValidationException::withMessages([ + 'module_id' => $message, + 'host_id' => $message, + ]); } $workOrder = WorkOrder::create([ - 'title' => $request->title, + 'title' => $request->input('title'), 'content' => $request->input('content'), - 'module_id' => $request->module_id, - 'host_id' => $request->host_id, + 'module_id' => $request->input('module_id'), + 'host_id' => $request->input('host_id'), 'status' => 'pending', ]); @@ -48,11 +52,8 @@ public function store(Request $request) public function show(WorkOrder $workOrder): JsonResponse { - if (auth()->id() !== $workOrder->user_id) { - return $this->notFound('无法找到对应的工单。'); - } - $workOrder->load(['module', 'host']); + return $this->success($workOrder); } @@ -61,15 +62,12 @@ public function show(WorkOrder $workOrder): JsonResponse */ public function update(Request $request, WorkOrder $workOrder) { - if (auth()->id() !== $workOrder->user_id) { - return $this->notFound('无法找到对应的工单。'); - } - $this->validate($request, [ 'status' => 'nullable|sometimes|string|in:closed', ]); $workOrder->update($request->only('status')); + return $this->success($workOrder); } } diff --git a/app/Http/Controllers/Modules/ReplyController.php b/app/Http/Controllers/Modules/ReplyController.php index 7993206..c158681 100644 --- a/app/Http/Controllers/Modules/ReplyController.php +++ b/app/Http/Controllers/Modules/ReplyController.php @@ -19,8 +19,8 @@ class ReplyController extends Controller */ public function index(Request $request): JsonResponse { - // $replies = Reply::workOrderId($request->route('work_order'))->simplePaginate(10); + return $this->success($replies); } @@ -33,19 +33,14 @@ public function store(Request $request, WorkOrder $work_order): JsonResponse { $this->validate($request, [ 'content' => 'required|string|max:255', - 'work_order_id' => 'required|integer|exists:work_orders,id', + 'name' => 'required|string|max:255', ]); - if ($work_order->module_id !== auth('module')->id()) { - return $this->error('您没有权限回复此工单。'); - } - - // 需要转换成数组 - $request_array = $request->all(); - $reply = Reply::create([ - 'content' => $request_array['content'], - 'work_order_id' => $request_array['work_order_id'], + 'content' => $request->input('content'), + 'work_order_id' => $work_order->id, + 'module_id' => $work_order->module_id, + 'name' => $request->input('name'), ]); return $this->success($reply); diff --git a/app/Http/Controllers/Modules/WorkOrderController.php b/app/Http/Controllers/Modules/WorkOrderController.php index 7d04d0d..575c94a 100644 --- a/app/Http/Controllers/Modules/WorkOrderController.php +++ b/app/Http/Controllers/Modules/WorkOrderController.php @@ -6,7 +6,6 @@ use App\Http\Requests\Remote\WorkOrderRequest; use App\Models\WorkOrder\WorkOrder; use Illuminate\Http\JsonResponse; -use Illuminate\Http\Request; use Illuminate\Validation\ValidationException; class WorkOrderController extends Controller @@ -18,12 +17,8 @@ public function index(WorkOrder $workOrder): JsonResponse return $this->success($workOrder); } - public function show(Request $request, WorkOrder $workOrder): JsonResponse + public function show(WorkOrder $workOrder): JsonResponse { - if ($workOrder->module_id !== $request->user('module')->id) { - return $this->error('您没有权限查看此工单。'); - } - return $this->success($workOrder); } @@ -33,10 +28,11 @@ public function show(Request $request, WorkOrder $workOrder): JsonResponse public function update(WorkOrderRequest $request, WorkOrder $workOrder): JsonResponse { $this->validate($request, [ - 'status' => 'nullable|sometimes|string|in:open,closed,on_hold,in_progress', + 'status' => 'nullable|sometimes|string|in:open,closed,on_hold,in_progress,read', ]); $workOrder->update($request->only('status')); + return $this->success($workOrder); } } diff --git a/app/Models/WorkOrder/Reply.php b/app/Models/WorkOrder/Reply.php index 0d5c631..a6cb91a 100644 --- a/app/Models/WorkOrder/Reply.php +++ b/app/Models/WorkOrder/Reply.php @@ -4,6 +4,7 @@ use App\Events\UserEvent; use App\Exceptions\CommonException; +use App\Models\Module; use App\Models\User; use Eloquent; use GeneaLabs\LaravelModelCaching\CachedBuilder; @@ -66,13 +67,15 @@ class Reply extends Model 'content', 'work_order_id', 'user_id', + 'name', + 'module_id', 'is_pending', ]; protected static function boot() { parent::boot(); - static::creating(function ($model) { + static::creating(function (self $model) { $model->is_pending = 1; // load work order @@ -82,10 +85,11 @@ protected static function boot() if (is_null($model->workOrder)) { throw new CommonException('Work order not found'); } - throw_if($model->workOrder->status == 'pending' || $model->workOrder->status == 'error', CommonException::class, '工单状态不正确'); + + throw_if($model->workOrder->isFailure(), CommonException::class, '工单还没有就绪。'); // change work order status - if (auth()->check()) { + if (auth('sanctum')->check()) { $model->user_id = auth()->id(); $model->workOrder->status = 'user_replied'; } @@ -116,6 +120,11 @@ public function workOrder(): BelongsTo return $this->belongsTo(WorkOrder::class, 'work_order_id', 'id'); } + public function module(): BelongsTo + { + return $this->belongsTo(Module::class); + } + public function user(): BelongsTo { return $this->belongsTo(User::class); @@ -123,7 +132,6 @@ public function user(): BelongsTo // before create - public function scopeWorkOrderId($query, $work_order_id) { return $query->where('work_order_id', $work_order_id); diff --git a/app/Models/WorkOrder/WorkOrder.php b/app/Models/WorkOrder/WorkOrder.php index dff80b0..1ba5c82 100644 --- a/app/Models/WorkOrder/WorkOrder.php +++ b/app/Models/WorkOrder/WorkOrder.php @@ -15,6 +15,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Carbon; +use Illuminate\Support\Str; /** * App\Models\WorkOrder\WorkOrder @@ -87,32 +88,33 @@ protected static function boot() { parent::boot(); - static::creating(function ($model) { + static::creating(function (self $model) { + // 生成 uuid + $model->uuid = Str::uuid()->toString(); if ($model->host_id) { $model->load(['host']); $model->module_id = $model->host->module_id; } - // if logged - if (auth()->check()) { + if (auth('sanctum')->check()) { $model->user_id = auth()->id(); if ($model->host_id) { - if (!$model->user_id === $model->host->user_id) { + if (!$model->user_id == $model->host->user_id) { throw new CommonException('user_id not match host user_id'); } } } else { - throw new CommonException('user_id is required'); + if (!$model->user_id) { + throw new CommonException('user_id is required'); + } } - if ($model->host_id) { $model->host->load('module'); $module = $model->host->module; - if ($module === null) { $model->status = 'open'; } else { @@ -127,6 +129,41 @@ protected static function boot() }); } + public function scopeThisModule($query) + { + return $query->where('module_id', auth('module')->id()); + } + + public function scopeThisUser($query) + { + return $query->where('user_id', auth()->id()); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } + + public function replies(): HasMany + { + return $this->hasMany(Reply::class); + } + + public function host(): BelongsTo + { + return $this->belongsTo(Host::class); + } + + public function module(): BelongsTo + { + return $this->belongsTo(Module::class); + } + + public function isFailure(): bool + { + return $this->status === 'pending' || $this->status === 'error'; + } + /** * @throws CommonException */ @@ -140,43 +177,4 @@ public function safeDelete(): bool return true; } - - // replies - - public function user(): BelongsTo - { - return $this->belongsTo(User::class); - } - - // host - - public function replies(): HasMany - { - return $this->hasMany(Reply::class); - } - - public function host(): BelongsTo - { - return $this->belongsTo(Host::class); - } - - // scope - - public function module(): BelongsTo - { - return $this->belongsTo(Module::class); - } - - public function scopeThisModule($query) - { - return $query->where('module_id', auth('module')->id()); - } - - - // on create - - public function scopeThisUser($query) - { - return $query->where('user_id', auth()->id()); - } } diff --git a/app/Observers/WorkOrder/ReplyObserver.php b/app/Observers/WorkOrder/ReplyObserver.php index 2aefd04..70e0a50 100644 --- a/app/Observers/WorkOrder/ReplyObserver.php +++ b/app/Observers/WorkOrder/ReplyObserver.php @@ -28,7 +28,7 @@ public function created(Reply $reply) * * @return void */ - public function updated(Reply $reply) + public function updated(Reply $reply): void { // } @@ -40,7 +40,7 @@ public function updated(Reply $reply) * * @return void */ - public function deleted(Reply $reply) + public function deleted(Reply $reply): void { // } @@ -52,20 +52,9 @@ public function deleted(Reply $reply) * * @return void */ - public function restored(Reply $reply) + public function restored(Reply $reply): void { // } - /** - * Handle the Reply "force deleted" event. - * - * @param Reply $reply - * - * @return void - */ - public function forceDeleted(Reply $reply) - { - // - } } diff --git a/app/Observers/WorkOrder/WorkOrderObserver.php b/app/Observers/WorkOrder/WorkOrderObserver.php index 829c102..9ab1d1d 100644 --- a/app/Observers/WorkOrder/WorkOrderObserver.php +++ b/app/Observers/WorkOrder/WorkOrderObserver.php @@ -4,7 +4,6 @@ use App\Models\WorkOrder\WorkOrder; use App\Notifications\WorkOrderNotification; -use Illuminate\Support\Facades\Log; class WorkOrderObserver { @@ -31,11 +30,9 @@ public function created(WorkOrder $workOrder) */ public function updated(WorkOrder $workOrder) { - - Log::debug('workOrder updated', ['workOrder' => $workOrder]); - // - return (new WorkOrderNotification()) - ->toGroup($workOrder); + return; + // return (new WorkOrderNotification()) + // ->toGroup($workOrder); } /** @@ -45,7 +42,7 @@ public function updated(WorkOrder $workOrder) * * @return void */ - public function deleted(WorkOrder $workOrder) + public function deleted(WorkOrder $workOrder): void { // } @@ -57,20 +54,9 @@ public function deleted(WorkOrder $workOrder) * * @return void */ - public function restored(WorkOrder $workOrder) + public function restored(WorkOrder $workOrder): void { // } - /** - * Handle the WorkOrder "force deleted" event. - * - * @param WorkOrder $workOrder - * - * @return void - */ - public function forceDeleted(WorkOrder $workOrder) - { - // - } } diff --git a/app/Policies/WorkOrder/ReplyPolicy.php b/app/Policies/WorkOrder/ReplyPolicy.php new file mode 100644 index 0000000..12f2d6e --- /dev/null +++ b/app/Policies/WorkOrder/ReplyPolicy.php @@ -0,0 +1,66 @@ +id === $workOrder->module_id; + } + + return true; + } + + /** + * Determine whether the user can update the model. + * + * @param User|Module $user + * @param WorkOrder $workOrder + * + * @return Response|bool + */ + public function update(User|Module $user, WorkOrder $workOrder): Response|bool + { + if ($user instanceof Module) { + return $user->id === $workOrder->module_id; + } + + return true; + } + + /** + * Determine whether the user can delete the model. + * + * @param User|Module $user + * @param WorkOrder $workOrder + * + * @return Response|bool + */ + public function delete(User|Module $user, WorkOrder $workOrder): Response|bool + { + if ($user instanceof Module) { + return $user->id === $workOrder->module_id; + } + + return $user->id === $workOrder->user_id + ? Response::allow() + : Response::deny('You do not own this work order.'); + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 33b83f5..dd3595c 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -3,25 +3,30 @@ namespace App\Providers; // use Illuminate\Support\Facades\Gate; +use App\Models\WorkOrder\Reply; +use App\Models\WorkOrder\WorkOrder; +use App\Policies\WorkOrder\ReplyPolicy; +use App\Policies\WorkOrder\WorkOrderPolicy; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider { /** - * The model to policy mappings for the application. + * 应用程序的策略映射。 * * @var array */ protected $policies = [ - // 'App\Models\Model' => 'App\Policies\ModelPolicy', + WorkOrder::class => WorkOrderPolicy::class, + Reply::class => ReplyPolicy::class, ]; /** - * Register any authentication / authorization services. + * 注册任何应用程序 身份验证 / 授权服务。 * * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); diff --git a/app/View/Components/WorkOrderStatus.php b/app/View/Components/WorkOrderStatus.php index a6a607e..b7bab34 100644 --- a/app/View/Components/WorkOrderStatus.php +++ b/app/View/Components/WorkOrderStatus.php @@ -2,14 +2,12 @@ namespace App\View\Components; -use Illuminate\Contracts\Foundation\Application; -use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\View; use Illuminate\View\Component; class WorkOrderStatus extends Component { - public $status = null; + public string|null $status = null; /** * Create a new component instance. @@ -18,17 +16,15 @@ class WorkOrderStatus extends Component */ public function __construct($status) { - // - $this->status = $status; } /** * Get the view / contents that represent the component. * - * @return Application|Factory|View + * @return View */ - public function render() + public function render(): View { $this->status = match ($this->status) { 'pending' => '推送中', diff --git a/database/migrations/2023_01_01_171554_add_uuid_to_work_orders_table.php b/database/migrations/2023_01_01_171554_add_uuid_to_work_orders_table.php new file mode 100644 index 0000000..17040b4 --- /dev/null +++ b/database/migrations/2023_01_01_171554_add_uuid_to_work_orders_table.php @@ -0,0 +1,39 @@ +uuid('uuid')->nullable()->after('id')->index()->unique(); + }); + + // 为每个工单生成一个 uuid 安静更改 + WorkOrder::query()->chunk(100, function ($workOrders) { + foreach ($workOrders as $workOrder) { + $workOrder->uuid = Str::uuid(); + $workOrder->saveQuietly(); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + return; + } +}; diff --git a/database/migrations/2023_01_01_180855_add_name_to_work_order_replies_table.php b/database/migrations/2023_01_01_180855_add_name_to_work_order_replies_table.php new file mode 100644 index 0000000..8efb61a --- /dev/null +++ b/database/migrations/2023_01_01_180855_add_name_to_work_order_replies_table.php @@ -0,0 +1,48 @@ +string('name')->nullable()->after('user_id'); + + // module_id + $table->string('module_id')->nullable()->after('name')->index(); + $table->foreign('module_id')->references('id')->on('modules')->cascadeOnDelete(); + }); + + // 为每个工单回复生成一个 module_id 安静更改 + Reply::whereNull('module_id')->with('workOrder')->chunk(100, function ($replies) { + foreach ($replies as $reply) { + $reply->module_id = $reply->workOrder->module_id; + $reply->saveQuietly(); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + Schema::table('work_order_replies', function (Blueprint $table) { + Schema::hasColumn('work_order_replies', 'name') && $table->dropColumn('name'); + + $table->dropForeign(['module_id']); + $table->dropColumn('module_id'); + }); + } +}; diff --git a/resources/views/admin/work-orders/show.blade.php b/resources/views/admin/work-orders/show.blade.php index 04a9973..33738b9 100644 --- a/resources/views/admin/work-orders/show.blade.php +++ b/resources/views/admin/work-orders/show.blade.php @@ -14,11 +14,19 @@ @foreach($replies as $reply)
-
+
@if ($reply->user_id) {{ $workOrder->user->name }} + @elseif($reply->module_id) + {{ $workOrder->module->name }} + @if ($reply->name) + 的 {{ $reply->name }} + @endif + + @elseif ($reply->name === null && $reply->user_id === null && $reply->module_id === null) + {{ config('app.display_name') }} @else - {{ $workOrder->module->name }} + {{ $reply->name }} @endif {{ $reply->created_at }} @@ -37,7 +45,8 @@ {{-- label --}}
- +
diff --git a/routes/api.php b/routes/api.php index bf567ad..587abf3 100644 --- a/routes/api.php +++ b/routes/api.php @@ -29,9 +29,14 @@ Route::get('hosts/usages', [HostController::class, 'usages']); Route::apiResource('hosts', HostController::class); -Route::apiResource('work-orders', WorkOrderController::class)->only(['index', 'store', 'show', 'update']); +Route::apiResource('work-orders', WorkOrderController::class)->only(['index', 'store', 'update']); -Route::apiResource('work-orders.replies', ReplyController::class)->only(['index', 'store']); +Route::withoutMiddleware('auth:sanctum')->prefix('work-orders')->group(function () { + Route::get('{workOrder:uuid}', [WorkOrderController::class, 'show']); + + Route::get('{workOrder:uuid}/replies', [ReplyController::class, 'index']); + Route::post('{workOrder:uuid}/replies', [ReplyController::class, 'store']); +}); Route::any('modules/{module}/{path?}', [ModuleController::class, 'call']) ->where('path', '.*');