feat(admin): 客服中心工单骨架(模型/迁移/路由/菜单/页面)
This commit is contained in:
21
app/Http/Controllers/Admin/SupportTicketController.php
Normal file
21
app/Http/Controllers/Admin/SupportTicketController.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Concerns\ResolvesPlatformAdminContext;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class SupportTicketController extends Controller
|
||||||
|
{
|
||||||
|
use ResolvesPlatformAdminContext;
|
||||||
|
|
||||||
|
public function index(Request $request): View
|
||||||
|
{
|
||||||
|
$this->ensurePlatformAdmin($request);
|
||||||
|
|
||||||
|
// 当前阶段:先做最小骨架页,后续再接入列表/筛选/创建/指派/SLA/升级。
|
||||||
|
return view('admin.support_tickets.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/Models/SupportTicket.php
Normal file
31
app/Models/SupportTicket.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SupportTicket extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'scope',
|
||||||
|
'scope_id',
|
||||||
|
'merchant_id',
|
||||||
|
'buyer_id',
|
||||||
|
'order_id',
|
||||||
|
'platform_order_id',
|
||||||
|
'site_subscription_id',
|
||||||
|
'platform_lead_id',
|
||||||
|
'ticket_no',
|
||||||
|
'category',
|
||||||
|
'priority',
|
||||||
|
'status',
|
||||||
|
'subject',
|
||||||
|
'content',
|
||||||
|
'assigned_admin_id',
|
||||||
|
'closed_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'closed_at' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('support_tickets', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
// scope:用于多层级隔离(platform/site/merchant)
|
||||||
|
$table->string('scope', 20)->default('platform');
|
||||||
|
$table->unsignedBigInteger('scope_id')->nullable();
|
||||||
|
|
||||||
|
// 关联对象(用于“收费闭环/治理串联”)
|
||||||
|
$table->unsignedBigInteger('merchant_id')->nullable();
|
||||||
|
$table->unsignedBigInteger('buyer_id')->nullable();
|
||||||
|
$table->unsignedBigInteger('order_id')->nullable();
|
||||||
|
$table->unsignedBigInteger('platform_order_id')->nullable();
|
||||||
|
$table->unsignedBigInteger('site_subscription_id')->nullable();
|
||||||
|
$table->unsignedBigInteger('platform_lead_id')->nullable();
|
||||||
|
|
||||||
|
// 工单基础字段
|
||||||
|
$table->string('ticket_no', 50)->unique();
|
||||||
|
$table->string('category', 50)->default('general');
|
||||||
|
$table->string('priority', 20)->default('normal');
|
||||||
|
$table->string('status', 20)->default('open');
|
||||||
|
$table->string('subject', 200)->default('');
|
||||||
|
$table->text('content')->nullable();
|
||||||
|
|
||||||
|
// 指派与时间
|
||||||
|
$table->unsignedBigInteger('assigned_admin_id')->nullable();
|
||||||
|
$table->timestamp('closed_at')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->index(['scope', 'scope_id']);
|
||||||
|
$table->index(['merchant_id']);
|
||||||
|
$table->index(['platform_order_id']);
|
||||||
|
$table->index(['site_subscription_id']);
|
||||||
|
$table->index(['platform_lead_id']);
|
||||||
|
$table->index(['status', 'priority']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('support_tickets');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -43,6 +43,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details class="topnav-item nav-group" data-role="topnav-group">
|
||||||
|
<summary class="topnav-summary nav-group-title">客服中心</summary>
|
||||||
|
<div class="topnav-dropdown">
|
||||||
|
<a href="/admin/support-tickets" class="topnav-sub nav-item nav-item--sub">工单</a>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
<details class="topnav-item nav-group" data-role="topnav-group">
|
<details class="topnav-item nav-group" data-role="topnav-group">
|
||||||
<summary class="topnav-summary nav-group-title">系统</summary>
|
<summary class="topnav-summary nav-group-title">系统</summary>
|
||||||
<div class="topnav-dropdown">
|
<div class="topnav-dropdown">
|
||||||
|
|||||||
16
resources/views/admin/support_tickets/index.blade.php
Normal file
16
resources/views/admin/support_tickets/index.blade.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
|
@section('title', '客服中心 / 工单')
|
||||||
|
@section('page_title', '客服中心 / 工单')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="card mb-20">
|
||||||
|
<p class="muted muted-tight">客服中心(工单)骨架页:用于后续接入“对账异常/退款异常/续费缺订阅”等治理工单闭环。</p>
|
||||||
|
<p class="muted">当前阶段仅做信息架构占位与路由/权限/数据模型埋口,避免后续大改。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h3>工单列表(占位)</h3>
|
||||||
|
<p class="muted">下一步将接入:筛选(scope/状态/优先级/关联对象)、创建工单、指派、SLA、升级链路与审计。</p>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -10,6 +10,7 @@ use App\Http\Controllers\Admin\ProductCategoryController as AdminProductCategory
|
|||||||
use App\Http\Controllers\Admin\ProductController as AdminProductController;
|
use App\Http\Controllers\Admin\ProductController as AdminProductController;
|
||||||
use App\Http\Controllers\Admin\MerchantController as AdminMerchantController;
|
use App\Http\Controllers\Admin\MerchantController as AdminMerchantController;
|
||||||
use App\Http\Controllers\Admin\SiteSubscriptionController;
|
use App\Http\Controllers\Admin\SiteSubscriptionController;
|
||||||
|
use App\Http\Controllers\Admin\SupportTicketController;
|
||||||
use App\Http\Controllers\Front\H5Controller;
|
use App\Http\Controllers\Front\H5Controller;
|
||||||
use App\Http\Controllers\Front\PlatformController as FrontPlatformController;
|
use App\Http\Controllers\Front\PlatformController as FrontPlatformController;
|
||||||
use App\Http\Controllers\MerchantAdmin\AuthController as MerchantAdminAuthController;
|
use App\Http\Controllers\MerchantAdmin\AuthController as MerchantAdminAuthController;
|
||||||
@@ -155,6 +156,9 @@ Route::prefix('admin')->group(function () {
|
|||||||
|
|
||||||
Route::get('/platform-leads', [\App\Http\Controllers\Admin\PlatformLeadController::class, 'index']);
|
Route::get('/platform-leads', [\App\Http\Controllers\Admin\PlatformLeadController::class, 'index']);
|
||||||
Route::post('/platform-leads/{lead}/set-status', [\App\Http\Controllers\Admin\PlatformLeadController::class, 'setStatus']);
|
Route::post('/platform-leads/{lead}/set-status', [\App\Http\Controllers\Admin\PlatformLeadController::class, 'setStatus']);
|
||||||
|
|
||||||
|
// 客服中心(工单)- 先做骨架与扩展点埋口
|
||||||
|
Route::get('/support-tickets', [SupportTicketController::class, 'index']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AdminSupportTicketIndexPageShouldRenderTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
protected function loginAsPlatformAdmin(): void
|
||||||
|
{
|
||||||
|
$this->seed();
|
||||||
|
|
||||||
|
$this->post('/admin/login', [
|
||||||
|
'email' => 'platform.admin@demo.local',
|
||||||
|
'password' => 'Platform@123456',
|
||||||
|
])->assertRedirect('/admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_support_ticket_index_page_should_render(): void
|
||||||
|
{
|
||||||
|
$this->loginAsPlatformAdmin();
|
||||||
|
|
||||||
|
$res = $this->get('/admin/support-tickets');
|
||||||
|
$res->assertOk();
|
||||||
|
|
||||||
|
$res->assertSee('客服中心', false);
|
||||||
|
$res->assertSee('工单列表', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AdminTopNavShouldContainSupportCenterLinkTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
protected function loginAsPlatformAdmin(): void
|
||||||
|
{
|
||||||
|
$this->seed();
|
||||||
|
|
||||||
|
$this->post('/admin/login', [
|
||||||
|
'email' => 'platform.admin@demo.local',
|
||||||
|
'password' => 'Platform@123456',
|
||||||
|
])->assertRedirect('/admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_topnav_should_contain_support_tickets_link(): void
|
||||||
|
{
|
||||||
|
$this->loginAsPlatformAdmin();
|
||||||
|
|
||||||
|
$res = $this->get('/admin');
|
||||||
|
$res->assertOk();
|
||||||
|
|
||||||
|
$res->assertSee('客服中心', false);
|
||||||
|
$res->assertSee('/admin/support-tickets', false);
|
||||||
|
$res->assertSee('工单', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user