chore: init saasshop repo + sql migrations runner + gitee go
This commit is contained in:
25
resources/views/merchant_admin/auth/login.blade.php
Normal file
25
resources/views/merchant_admin/auth/login.blade.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>商家后台登录 - SaaSShop</title>
|
||||
<link rel="stylesheet" href="/css/admin-base.css">
|
||||
<link rel="stylesheet" href="/css/merchant-admin.css">
|
||||
</head>
|
||||
<body class="login-page">
|
||||
<div class="card-login">
|
||||
<h1>商家后台登录</h1>
|
||||
<p class="muted">仅商家管理员可登录。演示账号:merchant.admin@demo.local / Merchant@123456</p>
|
||||
@if ($errors->any())
|
||||
<div class="error">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
<form method="post" action="/merchant-admin/login">
|
||||
@csrf
|
||||
<input type="email" name="email" placeholder="邮箱" value="{{ old('email', 'merchant.admin@demo.local') }}">
|
||||
<input type="password" name="password" placeholder="密码" value="Merchant@123456">
|
||||
<button type="submit">登录商家后台</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
19
resources/views/merchant_admin/dashboard.blade.php
Normal file
19
resources/views/merchant_admin/dashboard.blade.php
Normal file
@@ -0,0 +1,19 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家后台仪表盘')
|
||||
@section('page_title', '商家后台仪表盘')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p>当前商家:<strong>{{ $merchant->name }}</strong>({{ $merchant->slug }})。这里是商家运营视角后台,只展示当前商家范围内的数据。</p>
|
||||
</div>
|
||||
<div class="card mb-20">
|
||||
<div class="muted">缓存状态:当前仪表盘统计已接入缓存,缓存驱动 {{ $cacheMeta['store'] }},TTL {{ $cacheMeta['ttl'] }}。</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="card"><div class="muted">商家用户</div><div class="num">{{ $stats['users'] }}</div></div>
|
||||
<div class="card"><div class="muted">商家商品</div><div class="num">{{ $stats['products'] }}</div></div>
|
||||
<div class="card"><div class="muted">商家订单</div><div class="num">{{ $stats['orders'] }}</div></div>
|
||||
<div class="card"><div class="muted">待处理订单</div><div class="num">{{ $stats['pending_orders'] }}</div></div>
|
||||
</div>
|
||||
@endsection
|
||||
58
resources/views/merchant_admin/layouts/app.blade.php
Normal file
58
resources/views/merchant_admin/layouts/app.blade.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>@yield('title', 'SaaSShop 商家后台')</title>
|
||||
<link rel="stylesheet" href="/css/admin-base.css">
|
||||
<link rel="stylesheet" href="/css/merchant-admin.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar">
|
||||
<h2 class="sidebar-title">SaaSShop</h2>
|
||||
<div class="muted">商家后台 / Merchant Console</div>
|
||||
|
||||
<div class="group-title">总览</div>
|
||||
<a href="/merchant-admin">商家仪表盘</a>
|
||||
|
||||
<div class="group-title">店铺运营</div>
|
||||
<a href="/merchant-admin/products">商品管理</a>
|
||||
<a href="/merchant-admin/product-categories">商品分类</a>
|
||||
<a href="/merchant-admin/orders">订单管理</a>
|
||||
<a href="/merchant-admin/users">用户管理</a>
|
||||
|
||||
<div class="group-title">切换入口</div>
|
||||
<a href="/admin">总台管理</a>
|
||||
<a href="/">返回首页</a>
|
||||
<form method="post" action="/merchant-admin/logout" class="logout-form">@csrf <button type="submit">退出登录</button></form>
|
||||
</aside>
|
||||
<main class="content">
|
||||
<div class="top">
|
||||
<div>
|
||||
<h1 class="page-title">@yield('page_title', '商家后台')</h1>
|
||||
<div class="muted">当前登录:{{ session('admin_name') }}({{ session('admin_email') }}) / 商家 ID:{{ session('admin_merchant_id') }}</div>
|
||||
<div class="badge">当前作用域:商家管理员</div>
|
||||
</div>
|
||||
</div>
|
||||
@if(session('success'))
|
||||
<div class="flash">{{ session('success') }}</div>
|
||||
@endif
|
||||
@if(session('warning'))
|
||||
<div class="warning">{{ session('warning') }}</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="error-box">
|
||||
<strong>提交失败:</strong>
|
||||
<ul class="list-indent">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
117
resources/views/merchant_admin/orders/index.blade.php
Normal file
117
resources/views/merchant_admin/orders/index.blade.php
Normal file
@@ -0,0 +1,117 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家订单管理')
|
||||
@section('page_title', '商家订单管理')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p class="muted muted-tight">当前订单列表已按登录商家过滤,商家管理员只能处理自己店铺的数据。</p>
|
||||
<p class="muted">当前订单列表已接入缓存:{{ $cacheMeta['store'] }} / TTL {{ $cacheMeta['ttl'] }}。</p>
|
||||
@php
|
||||
$exportQuery = http_build_query(array_filter($filters, fn ($value) => $value !== null && $value !== ''));
|
||||
@endphp
|
||||
<div class="mb-12"><a href="{{ '/merchant-admin/orders/export' . ($exportQuery ? ('?' . $exportQuery) : '') }}">导出当前筛选结果 CSV</a></div>
|
||||
<h3>筛选条件</h3>
|
||||
@if(!empty($filters['validation_errors']))
|
||||
<div class="filter-error"><strong>筛选条件有误:</strong><ul class="list-indent">@foreach($filters['validation_errors'] as $validationError)<li>{{ $validationError }}</li>@endforeach</ul></div>
|
||||
@endif
|
||||
<form method="get" action="/merchant-admin/orders">
|
||||
<div class="grid-5">
|
||||
<select name="status"><option value="">全部状态</option>@foreach($filterOptions['statuses'] as $status)<option value="{{ $statusLabels[$status] ?? $status }}" @selected($filters['status'] === $status)>{{ $statusLabels[$status] ?? $status }}</option>@endforeach</select>
|
||||
<select name="payment_status"><option value="">全部支付状态</option>@foreach($filterOptions['paymentStatuses'] as $paymentStatus)<option value="{{ $paymentStatusLabels[$paymentStatus] ?? $paymentStatus }}" @selected($filters['payment_status'] === $paymentStatus)>{{ $paymentStatusLabels[$paymentStatus] ?? $paymentStatus }}</option>@endforeach</select>
|
||||
<select name="platform"><option value="">全部平台</option>@foreach($filterOptions['platforms'] as $platform)<option value="{{ $platformLabels[$platform] ?? $platform }}" @selected($filters['platform'] === $platform)>{{ $platformLabels[$platform] ?? $platform }}</option>@endforeach</select>
|
||||
<select name="device_type"><option value="">全部设备类型</option>@foreach($filterOptions['deviceTypes'] as $deviceType)<option value="{{ $deviceType }}" @selected($filters['device_type'] === $deviceType)>{{ $deviceTypeLabels[$deviceType] ?? $deviceType }}</option>@endforeach</select>
|
||||
<select name="payment_channel"><option value="">全部支付渠道</option>@foreach($filterOptions['paymentChannels'] as $paymentChannel)<option value="{{ $paymentChannel }}" @selected($filters['payment_channel'] === $paymentChannel)>{{ $paymentChannelLabels[$paymentChannel] ?? $paymentChannel }}</option>@endforeach</select>
|
||||
<input name="keyword" placeholder="订单号 / 买家 / 手机 / 邮箱" value="{{ $filters['keyword'] }}">
|
||||
<select name="time_range">@foreach($filterOptions['timeRanges'] as $timeRangeValue => $timeRangeLabel)<option value="{{ $timeRangeValue }}" @selected(($filters['time_range'] ?? 'all') === $timeRangeValue)>{{ $timeRangeLabel }}</option>@endforeach</select>
|
||||
<input type="date" name="start_date" value="{{ $filters['start_date'] }}">
|
||||
<input type="date" name="end_date" value="{{ $filters['end_date'] }}">
|
||||
<input type="number" step="0.01" min="0" name="min_pay_amount" placeholder="最低实付金额" value="{{ $filters['min_pay_amount'] }}">
|
||||
<input type="number" step="0.01" min="0" name="max_pay_amount" placeholder="最高实付金额" value="{{ $filters['max_pay_amount'] }}">
|
||||
<select name="sort">@foreach($filterOptions['sortOptions'] as $sortValue => $sortLabel)<option value="{{ $sortValue }}" @selected(($filters['sort'] ?? 'latest') === $sortValue)>{{ $sortLabel }}</option>@endforeach</select>
|
||||
<div class="actions"><button type="submit">筛选</button><a href="/merchant-admin/orders">重置</a></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card section-dark mb-20"><h3 class="mt-0">当前筛选摘要</h3><div class="grid-3">@foreach($activeFilterSummary as $summaryLabel => $summaryValue)<div class="summary-box"><div class="muted">{{ $summaryLabel }}</div><strong class="num-md">{{ $summaryValue }}</strong></div>@endforeach</div></div>
|
||||
|
||||
<div class="card mb-20"><h3 class="mt-0">订单汇总</h3><div class="grid-5"><div class="stat-box-light"><div class="muted">订单总数</div><strong class="num-md">{{ $summaryStats['total_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">实付总额</div><strong class="num-md">¥{{ number_format($summaryStats['total_pay_amount'] ?? 0, 2) }}</strong></div><div class="stat-box-light"><div class="muted">平均客单价</div><strong class="num-md">¥{{ number_format($summaryStats['average_order_amount'] ?? 0, 2) }}</strong></div><div class="stat-box-light"><div class="muted">待支付金额</div><strong class="num-md">¥{{ number_format($summaryStats['unpaid_pay_amount'] ?? 0, 2) }}</strong></div><div class="stat-box-light"><div class="muted">已支付金额</div><strong class="num-md">¥{{ number_format($summaryStats['paid_pay_amount'] ?? 0, 2) }}</strong></div><div class="stat-box-light"><div class="muted">已支付订单数</div><strong class="num-md">{{ $summaryStats['paid_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">支付率</div><strong class="num-md">{{ number_format($summaryStats['payment_rate'] ?? 0, 2) }}%</strong></div><div class="stat-box-light"><div class="muted">退款订单数</div><strong class="num-md">{{ $summaryStats['refunded_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">退款率</div><strong class="num-md">{{ number_format($summaryStats['refund_rate'] ?? 0, 2) }}%</strong></div><div class="stat-box-light"><div class="muted">待发货订单数</div><strong class="num-md">{{ $summaryStats['pending_shipment_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">完成率</div><strong class="num-md">{{ number_format($summaryStats['completion_rate'] ?? 0, 2) }}%</strong></div><div class="stat-box-light"><div class="muted">支付失败订单</div><strong class="num-md">{{ $summaryStats['failed_payment_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">已取消订单</div><strong class="num-md">{{ $summaryStats['cancelled_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">取消率</div><strong class="num-md">{{ number_format($summaryStats['cancellation_rate'] ?? 0, 2) }}%</strong></div></div></div>
|
||||
|
||||
<div class="card mb-20"><h3 class="mt-0">时间趋势指标</h3><div class="grid-5"><div class="stat-box-light"><div class="muted">今日订单数</div><strong class="num-md">{{ $trendStats['today_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">今日实付金额</div><strong class="num-md">¥{{ number_format($trendStats['today_pay_amount'] ?? 0, 2) }}</strong></div><div class="stat-box-light"><div class="muted">近7天订单数</div><strong class="num-md">{{ $trendStats['last_7_days_orders'] ?? 0 }}</strong></div><div class="stat-box-light"><div class="muted">近7天实付金额</div><strong class="num-md">¥{{ number_format($trendStats['last_7_days_pay_amount'] ?? 0, 2) }}</strong></div></div></div>
|
||||
|
||||
<div class="card section-dark card-spaced">
|
||||
<h3 class="mt-0">运营关注项</h3>
|
||||
<div class="grid-3">
|
||||
<div class="focus-box">
|
||||
<div class="muted">订单盘面</div>
|
||||
<strong class="text-md">{{ $operationsFocus['headline'] ?? '当前商家订单运营信息已就绪。' }}</strong>
|
||||
<div class="muted mt-8">建议动作</div>
|
||||
<div class="inline-links mt-6">
|
||||
@foreach(($operationsFocus['actions'] ?? []) as $action)
|
||||
<a href="{{ $action['url'] }}">{{ $action['label'] }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus-box">
|
||||
<div class="muted">当前信号</div>
|
||||
<div class="grid-3 mt-8">
|
||||
@foreach(($operationsFocus['signals'] ?? []) as $label => $value)
|
||||
<div class="summary-box"><div class="muted">{{ $label }}</div><strong class="num-sm">{{ $value }}</strong></div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus-box">
|
||||
<div class="muted">工作台导航</div>
|
||||
<div class="inline-links mt-8">
|
||||
@foreach(($operationsFocus['workbench'] ?? []) as $label => $url)
|
||||
<a href="{{ $url }}">{{ $label }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-20">
|
||||
<h3 class="mt-0">状态统计</h3>
|
||||
@php
|
||||
$baseQuery = [
|
||||
'payment_status' => $filters['payment_status'] ?: null,
|
||||
'platform' => $filters['platform'] ?: null,
|
||||
'device_type' => $filters['device_type'] ?: null,
|
||||
'payment_channel' => $filters['payment_channel'] ?: null,
|
||||
'keyword' => $filters['keyword'] ?: null,
|
||||
'start_date' => $filters['start_date'] ?: null,
|
||||
'end_date' => $filters['end_date'] ?: null,
|
||||
'min_pay_amount' => $filters['min_pay_amount'] ?: null,
|
||||
'max_pay_amount' => $filters['max_pay_amount'] ?: null,
|
||||
'time_range' => ($filters['time_range'] ?? 'all') !== 'all' ? $filters['time_range'] : null,
|
||||
'sort' => ($filters['sort'] ?? 'latest') !== 'latest' ? $filters['sort'] : null,
|
||||
];
|
||||
@endphp
|
||||
<div class="grid-6">
|
||||
<a href="{{ '/merchant-admin/orders?' . http_build_query(array_filter($baseQuery, fn ($value) => $value !== null && $value !== '')) }}" class="status-link-light {{ $filters['status'] === '' ? 'is-active-light' : '' }}"><div class="muted">全部</div><strong class="num-md">{{ $statusStats['all'] ?? 0 }}</strong></a>
|
||||
@foreach($filterOptions['statuses'] as $status)
|
||||
<a href="{{ '/merchant-admin/orders?' . http_build_query(array_filter(array_merge($baseQuery, ['status' => $status]), fn ($value) => $value !== null && $value !== '')) }}" class="status-link-light {{ $filters['status'] === $status ? 'is-active-light' : '' }}"><div class="muted">{{ $statusLabels[$status] ?? $status }}</div><strong class="num-md">{{ $statusStats[$status] ?? 0 }}</strong></a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>订单列表</h3>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>订单号</th><th>平台</th><th>买家</th><th>支付</th><th>金额</th><th>创建时间</th><th>支付时间</th><th>发货时间</th><th>完成时间</th><th>状态</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
@forelse($orders as $order)
|
||||
<tr>
|
||||
<td>{{ $order->id }}</td><td><a href="/merchant-admin/orders/{{ $order->id }}">{{ $order->order_no }}</a></td><td>{{ $platformLabels[$order->platform] ?? $order->platform }}</td><td>{{ $order->buyer_name }}</td><td><div>{{ $paymentChannelLabels[$order->payment_channel] ?? $order->payment_channel }}</div><div class="muted">{{ $paymentStatusLabels[$order->payment_status] ?? $order->payment_status }}</div></td><td>¥{{ number_format($order->pay_amount, 2) }}</td><td>{{ $order->created_at?->format('Y-m-d H:i') }}</td><td>{{ $order->paid_at?->format('Y-m-d H:i') ?? '-' }}</td><td>{{ $order->shipped_at?->format('Y-m-d H:i') ?? '-' }}</td><td>{{ $order->completed_at?->format('Y-m-d H:i') ?? '-' }}</td><td>{{ $statusLabels[$order->status] ?? $order->status }}</td><td><form class="inline" method="post" action="/merchant-admin/orders/{{ $order->id }}/status">@csrf <select name="status"><option value="pending" @selected($order->status==='pending')>待处理</option><option value="paid" @selected($order->status==='paid')>已支付</option><option value="shipped" @selected($order->status==='shipped')>已发货</option><option value="completed" @selected($order->status==='completed')>已完成</option><option value="cancelled" @selected($order->status==='cancelled')>已取消</option></select><button type="submit">更新</button></form></td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="12" class="muted text-center">暂无订单</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">{{ $orders->links() }}</div>
|
||||
@endsection
|
||||
46
resources/views/merchant_admin/orders/show.blade.php
Normal file
46
resources/views/merchant_admin/orders/show.blade.php
Normal file
@@ -0,0 +1,46 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家订单详情')
|
||||
@section('page_title', '商家订单详情')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<h3>订单 {{ $order->order_no }}</h3>
|
||||
<table>
|
||||
<tr><th>ID</th><td>{{ $order->id }}</td></tr>
|
||||
<tr><th>平台</th><td>{{ $order->platform }}</td></tr>
|
||||
<tr><th>订单状态</th><td>{{ $order->status }}</td></tr>
|
||||
<tr><th>支付渠道</th><td>{{ $order->payment_channel }}</td></tr>
|
||||
<tr><th>支付状态</th><td>{{ $order->payment_status }}</td></tr>
|
||||
<tr><th>买家</th><td>{{ $order->buyer_name }}</td></tr>
|
||||
<tr><th>手机</th><td>{{ $order->buyer_phone }}</td></tr>
|
||||
<tr><th>邮箱</th><td>{{ $order->buyer_email }}</td></tr>
|
||||
<tr><th>应付金额</th><td>¥{{ number_format($order->pay_amount, 2) }}</td></tr>
|
||||
<tr><th>备注</th><td>{{ $order->remark }}</td></tr>
|
||||
<tr><th>创建时间</th><td>{{ $order->created_at }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>订单明细</h3>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>商品</th><th>SKU</th><th>单价</th><th>数量</th><th>小计</th><th>快照</th></tr></thead>
|
||||
<tbody>
|
||||
@forelse($order->items as $item)
|
||||
<tr>
|
||||
<td>{{ $item->id }}</td>
|
||||
<td>{{ $item->product_title }}</td>
|
||||
<td>{{ $item->product_sku }}</td>
|
||||
<td>¥{{ number_format($item->product_price, 2) }}</td>
|
||||
<td>{{ $item->quantity }}</td>
|
||||
<td>¥{{ number_format($item->line_total_amount, 2) }}</td>
|
||||
<td>@if(!empty($item->snapshot)) 分类:{{ $item->snapshot['category'] ?? '-' }} @else - @endif</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="7" class="muted">暂无订单明细</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="mt-16"><a href="/merchant-admin/orders">返回订单列表</a></p>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,48 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家商品分类')
|
||||
@section('page_title', '商家商品分类')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p class="muted muted-tight">这里是当前商家的商品分类管理入口,分类数据天然受商家作用域限制。</p>
|
||||
<p class="muted">当前分类列表已接入缓存:{{ $cacheMeta['store'] }} / TTL {{ $cacheMeta['ttl'] }}。</p>
|
||||
<h3>新增分类</h3>
|
||||
<form method="post" action="/merchant-admin/product-categories">
|
||||
@csrf
|
||||
<div class="grid-3">
|
||||
<input name="name" placeholder="分类名称" value="{{ old('name') }}">
|
||||
<input name="slug" placeholder="slug" value="{{ old('slug') }}">
|
||||
<select name="status">
|
||||
<option value="active" @selected(old('status', 'active') === 'active')>active</option>
|
||||
<option value="inactive" @selected(old('status') === 'inactive')>inactive</option>
|
||||
</select>
|
||||
<input name="sort" placeholder="排序" value="{{ old('sort', 0) }}">
|
||||
<input name="description" placeholder="分类说明" class="span-2" value="{{ old('description') }}">
|
||||
</div>
|
||||
<div class="mt-12"><button type="submit">创建分类</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>分类列表</h3>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>名称</th><th>Slug</th><th>状态</th><th>排序</th><th>说明</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
@foreach($categories as $category)
|
||||
<tr>
|
||||
<td>{{ $category->id }}</td>
|
||||
<td><form method="post" action="/merchant-admin/product-categories/{{ $category->id }}" class="actions">@csrf <input name="name" value="{{ $category->name }}"></td>
|
||||
<td><input name="slug" value="{{ $category->slug }}"></td>
|
||||
<td><select name="status"><option value="active" @selected($category->status==='active')>active</option><option value="inactive" @selected($category->status==='inactive')>inactive</option></select></td>
|
||||
<td><input name="sort" value="{{ $category->sort }}" class="w-90"></td>
|
||||
<td><input name="description" value="{{ $category->description }}"></td>
|
||||
<td><button type="submit">更新</button></form><form method="post" action="/merchant-admin/product-categories/{{ $category->id }}/delete" class="inline" onsubmit="return confirm('确定删除这个分类?');">@csrf <button type="submit">删除</button></form></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">{{ $categories->links() }}</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,101 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家商品导入历史')
|
||||
@section('page_title', '商家商品导入历史')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<p class="muted muted-tight">这里集中查看当前商家范围内的商品导入历史,便于复盘成功率、失败批次与 failure CSV 保留情况。</p>
|
||||
|
||||
@php
|
||||
$exportHistoryQuery = http_build_query(array_filter([
|
||||
'import_result_status' => $importHistoryFilters['result_status'] ?? 'all',
|
||||
'import_time_range' => $importHistoryFilters['time_range'] ?? 'all',
|
||||
'start_date' => $importHistoryFilters['start_date'] ?? '',
|
||||
'end_date' => $importHistoryFilters['end_date'] ?? '',
|
||||
'import_sort' => $importHistoryFilters['sort'] ?? 'latest',
|
||||
], fn ($value, $key) => match ($key) {
|
||||
'start_date', 'end_date' => $value !== null && $value !== '',
|
||||
default => $value !== null && $value !== '' && $value !== 'all' && $value !== 'latest',
|
||||
}, ARRAY_FILTER_USE_BOTH));
|
||||
@endphp
|
||||
<form method="get" action="/merchant-admin/products/import-histories" class="mb-12">
|
||||
<div class="actions">
|
||||
<select name="import_result_status">
|
||||
<option value="all" @selected(($importHistoryFilters['result_status'] ?? 'all') === 'all')>全部导入结果</option>
|
||||
<option value="success_only" @selected(($importHistoryFilters['result_status'] ?? 'all') === 'success_only')>仅看成功导入</option>
|
||||
<option value="has_failures" @selected(($importHistoryFilters['result_status'] ?? 'all') === 'has_failures')>仅看含失败导入</option>
|
||||
</select>
|
||||
<select name="import_time_range">
|
||||
<option value="all" @selected(($importHistoryFilters['time_range'] ?? 'all') === 'all')>全部时间</option>
|
||||
<option value="today" @selected(($importHistoryFilters['time_range'] ?? 'all') === 'today')>今天</option>
|
||||
<option value="last_7_days" @selected(($importHistoryFilters['time_range'] ?? 'all') === 'last_7_days')>近7天</option>
|
||||
<option value="custom" @selected(($importHistoryFilters['time_range'] ?? 'all') === 'custom')>自定义区间</option>
|
||||
</select>
|
||||
<input type="date" name="start_date" value="{{ $importHistoryFilters['start_date'] ?? '' }}">
|
||||
<span class="muted">至</span>
|
||||
<input type="date" name="end_date" value="{{ $importHistoryFilters['end_date'] ?? '' }}">
|
||||
<select name="import_sort">
|
||||
@foreach(($importHistoryFilterOptions['sorts'] ?? []) as $sortValue => $sortLabel)
|
||||
<option value="{{ $sortValue }}" @selected(($importHistoryFilters['sort'] ?? 'latest') === $sortValue)>{{ $sortLabel }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit">筛选导入历史</button>
|
||||
<a href="{{ '/merchant-admin/products/import-histories/export' . ($exportHistoryQuery ? ('?' . $exportHistoryQuery) : '') }}">导出当前筛选 CSV</a>
|
||||
<a href="/merchant-admin/products/import-histories">清空筛选</a>
|
||||
<a href="/merchant-admin/products">返回商品页</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if(!empty($importHistoryFilters['date_errors']))
|
||||
<div class="info-warning">
|
||||
@foreach($importHistoryFilters['date_errors'] as $dateError)
|
||||
<div>{{ $dateError }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="grid-4 mb-12">
|
||||
<div class="stat-box"><div class="muted">累计导入批次</div><strong class="num-sm">{{ $importHistoryStats['total_imports'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">累计成功商品</div><strong class="num-sm">{{ $importHistoryStats['total_success'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">累计失败商品</div><strong class="num-sm">{{ $importHistoryStats['total_failed'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">含失败批次</div><strong class="num-sm">{{ $importHistoryStats['warning_imports'] ?? 0 }}</strong></div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>导入时间</th><th>上传文件</th><th>结果</th><th>成功</th><th>失败</th><th>操作者</th><th>失败明细</th></tr></thead>
|
||||
<tbody>
|
||||
@forelse($importHistories as $history)
|
||||
<tr>
|
||||
<td>{{ $history->id }}</td>
|
||||
<td>{{ $history->imported_at?->format('Y-m-d H:i:s') }}</td>
|
||||
<td>{{ $history->file_name }}</td>
|
||||
<td>
|
||||
@if(($history->failed_count ?? 0) > 0)
|
||||
<span class="result-warning">部分失败</span>
|
||||
@else
|
||||
<span class="result-success">成功</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $history->success_count }}</td>
|
||||
<td>{{ $history->failed_count }}</td>
|
||||
<td>{{ $history->admin?->name ?? '-' }}</td>
|
||||
<td>
|
||||
@if($history->failure_file && ($history->failure_file_available ?? false))
|
||||
<a href="/merchant-admin/products/import-failures/{{ $history->failure_file }}">下载 failure CSV</a>
|
||||
@elseif($history->failure_file)
|
||||
<span class="muted">文件已过保留期</span>
|
||||
@else
|
||||
<span class="muted">无</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="8" class="muted">暂无导入记录</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="pagination-wrap">{{ $importHistories->links() }}</div>
|
||||
</div>
|
||||
@endsection
|
||||
203
resources/views/merchant_admin/products/index.blade.php
Normal file
203
resources/views/merchant_admin/products/index.blade.php
Normal file
@@ -0,0 +1,203 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家商品管理')
|
||||
@section('page_title', '商家商品管理')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p class="muted muted-tight">当前商品列表已按登录商家过滤,新增、编辑、删除商品都会限制在当前商家作用域内。</p>
|
||||
<p class="muted">当前已接入缓存:商品列表使用 {{ $cacheMeta['store'] }},TTL {{ $cacheMeta['ttl'] }};商品变更后会自动失效。</p>
|
||||
@php
|
||||
$exportQuery = http_build_query(array_filter($filters, fn ($value) => $value !== null && $value !== ''));
|
||||
@endphp
|
||||
<div class="card my-16">
|
||||
<h3 class="mt-0">批量导入商品</h3>
|
||||
<p class="muted">先下载模板,按模板填写后上传 CSV。商家模板不需要填写 `merchant_id`,系统会自动归属到当前登录商家。</p>
|
||||
<div class="card-link-list mb-12">
|
||||
<a href="/merchant-admin/products/import-template">下载导入模板</a>
|
||||
<a href="{{ '/merchant-admin/products/export' . ($exportQuery ? ('?' . $exportQuery) : '') }}">导出当前筛选结果 CSV</a>
|
||||
<a href="/merchant-admin/products/import-histories">查看独立导入历史页</a>
|
||||
</div>
|
||||
@if(session('import_result'))
|
||||
@php $importResult = session('import_result'); @endphp
|
||||
<div class="card section-dark mb-12">
|
||||
<div><strong>导入结果:</strong>成功 {{ $importResult['success'] ?? 0 }} 条,失败 {{ $importResult['failed'] ?? 0 }} 条。</div>
|
||||
@if(!empty($importResult['messages']))
|
||||
<div class="muted mt-8">失败原因预览:</div>
|
||||
<ul class="list-indent">@foreach($importResult['messages'] as $message)<li>{{ $message }}</li>@endforeach</ul>
|
||||
@endif
|
||||
@if(!empty($importResult['failure_file']))
|
||||
<div class="mt-10"><a href="/merchant-admin/products/import-failures/{{ $importResult['failure_file'] }}">下载失败明细 CSV</a></div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<form method="post" action="/merchant-admin/products/import" enctype="multipart/form-data">@csrf <div class="actions"><input type="file" name="import_file" accept=".csv,text/csv"><button type="submit">开始导入</button></div></form>
|
||||
|
||||
<div class="mt-16">
|
||||
<div class="actions-spread mb-10">
|
||||
<div><h4 class="mb-6">导入历史摘要</h4><div class="muted">商品页仅保留摘要与最近 5 条记录;完整筛选、分页与复盘请前往独立导入历史页。</div></div>
|
||||
<a href="/merchant-admin/products/import-histories">进入完整导入历史页</a>
|
||||
</div>
|
||||
<div class="grid-4 mb-12">
|
||||
<div class="stat-box"><div class="muted">累计导入批次</div><strong class="num-sm">{{ $importHistoryStats['total_imports'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">累计成功商品</div><strong class="num-sm">{{ $importHistoryStats['total_success'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">累计失败商品</div><strong class="num-sm">{{ $importHistoryStats['total_failed'] ?? 0 }}</strong></div>
|
||||
<div class="stat-box"><div class="muted">含失败批次</div><strong class="num-sm">{{ $importHistoryStats['warning_imports'] ?? 0 }}</strong></div>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>导入时间</th><th>上传文件</th><th>结果</th><th>失败明细</th></tr></thead>
|
||||
<tbody>
|
||||
@forelse($importHistories->take(5) as $history)
|
||||
<tr>
|
||||
<td>{{ $history->id }}</td><td>{{ $history->imported_at?->format('Y-m-d H:i:s') }}</td><td>{{ $history->file_name }}</td><td>@if(($history->failed_count ?? 0) > 0)<span class="result-warning">部分失败({{ $history->failed_count }})</span>@else<span class="result-success">成功</span>@endif</td>
|
||||
<td>@if($history->failure_file && ($history->failure_file_available ?? false))<a href="/merchant-admin/products/import-failures/{{ $history->failure_file }}">下载</a>@elseif($history->failure_file)<span class="muted">已过保留期</span>@else<span class="muted">无</span>@endif</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="5" class="muted">暂无导入记录</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3>商品分类</h3>
|
||||
<table class="mb-20">
|
||||
<thead><tr><th>ID</th><th>分类名称</th><th>Slug</th><th>状态</th><th>排序</th><th>说明</th></tr></thead>
|
||||
<tbody>
|
||||
@forelse($categories as $category)
|
||||
<tr><td>{{ $category->id }}</td><td>{{ $category->name }}</td><td>{{ $category->slug }}</td><td>{{ $category->status }}</td><td>{{ $category->sort }}</td><td>{{ $category->description }}</td></tr>
|
||||
@empty
|
||||
<tr><td colspan="6" class="muted">暂无分类</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>筛选条件</h3>
|
||||
<form method="get" action="/merchant-admin/products" class="mb-20">
|
||||
<div class="grid-4">
|
||||
<select name="category_id"><option value="">全部分类</option>@foreach($categories as $category)<option value="{{ $category->id }}" @selected($filters['category_id'] === (string) $category->id)>{{ $category->name }}</option>@endforeach</select>
|
||||
<select name="status"><option value="">全部状态</option>@foreach($filterOptions['statuses'] as $status)<option value="{{ $statusLabels[$status] ?? $status }}" @selected($filters['status'] === $status)>{{ $statusLabels[$status] ?? $status }}</option>@endforeach</select>
|
||||
<input name="keyword" placeholder="标题 / slug / SKU" value="{{ $filters['keyword'] }}">
|
||||
<input type="number" step="0.01" min="0" name="min_price" placeholder="最低价格" value="{{ $filters['min_price'] }}">
|
||||
<input type="number" step="0.01" min="0" name="max_price" placeholder="最高价格" value="{{ $filters['max_price'] }}">
|
||||
<input type="number" min="0" name="min_stock" placeholder="最低库存" value="{{ $filters['min_stock'] }}">
|
||||
<input type="number" min="0" name="max_stock" placeholder="最高库存" value="{{ $filters['max_stock'] }}">
|
||||
<select name="sort">@foreach($filterOptions['sortOptions'] as $sortValue => $sortLabel)<option value="{{ $sortValue }}" @selected(($filters['sort'] ?? 'latest') === $sortValue)>{{ $sortLabel }}</option>@endforeach</select>
|
||||
</div>
|
||||
<div class="mt-12 actions"><button type="submit">筛选</button><a href="/merchant-admin/products">重置</a></div>
|
||||
</form>
|
||||
|
||||
<div class="card section-dark my-20"><h3 class="mt-0">当前筛选摘要</h3><div class="grid-4">@foreach($activeFilterSummary as $summaryLabel => $summaryValue)<div class="summary-box"><div class="muted">{{ $summaryLabel }}</div><strong class="num-md">{{ $summaryValue }}</strong></div>@endforeach</div></div>
|
||||
|
||||
<div class="card my-20"><h3 class="mt-0">商品运营汇总</h3><div class="grid-4"><div class="stat-box"><div class="muted">商品总数</div><strong class="num-md">{{ $summaryStats['total_products'] ?? 0 }}</strong></div><div class="stat-box"><div class="muted">总库存</div><strong class="num-md">{{ $summaryStats['total_stock'] ?? 0 }}</strong></div><div class="stat-box"><div class="muted">总货值</div><strong class="num-md">¥{{ number_format($summaryStats['total_stock_value'] ?? 0, 2) }}</strong></div><div class="stat-box"><div class="muted">平均售价</div><strong class="num-md">¥{{ number_format($summaryStats['average_price'] ?? 0, 2) }}</strong></div></div></div>
|
||||
|
||||
<div class="card section-dark card-spaced">
|
||||
<h3 class="mt-0">运营关注项</h3>
|
||||
<div class="grid-3">
|
||||
<div class="focus-box">
|
||||
<div class="muted">商品盘面</div>
|
||||
<strong class="text-md">{{ $operationsFocus['headline'] ?? '当前商家商品运营信息已就绪。' }}</strong>
|
||||
<div class="muted mt-8">建议动作</div>
|
||||
<div class="inline-links mt-6">
|
||||
@foreach(($operationsFocus['actions'] ?? []) as $action)
|
||||
<a href="{{ $action['url'] }}">{{ $action['label'] }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus-box">
|
||||
<div class="muted">当前信号</div>
|
||||
<div class="grid-3 mt-8">
|
||||
@foreach(($operationsFocus['signals'] ?? []) as $label => $value)
|
||||
<div class="summary-box"><div class="muted">{{ $label }}</div><strong class="num-sm">{{ $value }}</strong></div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus-box">
|
||||
<div class="muted">工作台导航</div>
|
||||
<div class="inline-links mt-8">
|
||||
@foreach(($operationsFocus['workbench'] ?? []) as $label => $url)
|
||||
<a href="{{ $url }}">{{ $label }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card section-dark my-20">
|
||||
<h3 class="mt-0">商品状态统计</h3>
|
||||
@php
|
||||
$productBaseQuery = [
|
||||
'category_id' => $filters['category_id'] ?: null,
|
||||
'keyword' => $filters['keyword'] ?: null,
|
||||
'min_price' => $filters['min_price'] ?: null,
|
||||
'max_price' => $filters['max_price'] ?: null,
|
||||
'min_stock' => $filters['min_stock'] ?: null,
|
||||
'max_stock' => $filters['max_stock'] ?: null,
|
||||
'sort' => $filters['sort'] ?: 'latest',
|
||||
];
|
||||
@endphp
|
||||
<div class="grid-4">
|
||||
<a href="{{ '/merchant-admin/products?' . http_build_query(array_filter($productBaseQuery, fn ($value) => $value !== null && $value !== '')) }}" class="status-link {{ $filters['status'] === '' ? 'is-active-dark' : '' }}"><div class="muted">全部</div><strong class="num-md">{{ $statusStats['all'] ?? 0 }}</strong></a>
|
||||
@foreach($filterOptions['statuses'] as $status)
|
||||
<a href="{{ '/merchant-admin/products?' . http_build_query(array_filter(array_merge($productBaseQuery, ['status' => $status]), fn ($value) => $value !== null && $value !== '')) }}" class="status-link {{ $filters['status'] === $status ? 'is-active-dark' : '' }}"><div class="muted">{{ $statusLabels[$status] ?? $status }}</div><strong class="num-md">{{ $statusStats[$status] ?? 0 }}</strong></a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>新增商品</h3>
|
||||
<form method="post" action="/merchant-admin/products">
|
||||
@csrf
|
||||
<div class="grid-3">
|
||||
<input name="title" placeholder="商品标题" value="{{ old('title') }}">
|
||||
<input name="slug" placeholder="slug" value="{{ old('slug') }}">
|
||||
<input name="sku" placeholder="SKU" value="{{ old('sku') }}">
|
||||
<select name="category_id"><option value="">选择分类(可留空)</option>@foreach($categories as $category)<option value="{{ $category->id }}" @selected((string) old('category_id') === (string) $category->id)>{{ $category->name }}</option>@endforeach</select>
|
||||
<input name="price" placeholder="价格" value="{{ old('price') }}">
|
||||
<input name="stock" placeholder="库存" value="{{ old('stock') }}">
|
||||
<input name="summary" placeholder="简介" value="{{ old('summary') }}">
|
||||
</div>
|
||||
<div class="mt-12"><button type="submit">创建商品</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>商品列表</h3>
|
||||
<form id="merchant-batch-form" method="post" action="/merchant-admin/products/batch" onsubmit="return confirm('确认执行本次批量操作?');">@csrf <input type="hidden" name="return_url" value="{{ request()->fullUrl() }}"><div class="actions mb-12"><select name="action"><option value="change_status">批量改状态</option><option value="change_category">批量改分类</option></select><select name="status"><option value="">选择状态(用于批量改状态)</option>@foreach($filterOptions['statuses'] as $status)<option value="{{ $statusLabels[$status] ?? $status }}">{{ $statusLabels[$status] ?? $status }}</option>@endforeach</select><select name="category_id"><option value="">清空分类 / 不指定(用于批量改分类)</option>@foreach($categories as $category)<option value="{{ $category->id }}">{{ $category->name }}</option>@endforeach</select><button type="submit">执行批量操作</button></div></form>
|
||||
<p class="muted muted-tight">批量操作只会作用于当前登录商家可见商品,越权或已删除数据会被拦截。</p>
|
||||
<table>
|
||||
<thead><tr><th><input type="checkbox" data-check-all="merchant-products"></th><th>ID</th><th>标题</th><th>分类</th><th>SKU</th><th>售价/原价</th><th>库存</th><th>创建时间</th><th>更新时间</th><th>状态</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
@foreach($products as $product)
|
||||
<tr>
|
||||
<td><input type="checkbox" name="product_ids[]" value="{{ $product->id }}" data-check-item="merchant-products" form="merchant-batch-form"></td>
|
||||
<td>{{ $product->id }}</td>
|
||||
<td><form method="post" action="/merchant-admin/products/{{ $product->id }}" class="actions">@csrf <input name="title" value="{{ $product->title }}"></td>
|
||||
<td><select name="category_id"><option value="">未分类</option>@foreach($categories as $category)<option value="{{ $category->id }}" @selected($product->category_id === $category->id)>{{ $category->name }}</option>@endforeach</select></td>
|
||||
<td><input name="slug" value="{{ $product->slug }}" placeholder="slug" class="w-140 block mb-6"><input name="sku" value="{{ $product->sku }}" placeholder="SKU" class="w-140"></td>
|
||||
<td><input name="price" value="{{ $product->price }}" class="w-90 block mb-6"><div class="muted">原价:¥{{ number_format((float) $product->original_price, 2) }}</div></td>
|
||||
<td><input name="stock" value="{{ $product->stock }}" class="w-90"></td>
|
||||
<td>{{ $product->created_at?->format('Y-m-d H:i') }}</td>
|
||||
<td>{{ $product->updated_at?->format('Y-m-d H:i') }}</td>
|
||||
<td><select name="status"><option value="draft" @selected($product->status==='draft')>草稿</option><option value="published" @selected($product->status==='published')>已上架</option><option value="offline" @selected($product->status==='offline')>已下架</option></select></td>
|
||||
<td><button type="submit">更新</button></form><form method="post" action="/merchant-admin/products/{{ $product->id }}/delete" class="inline" onsubmit="return confirm('确定删除这个商品?');">@csrf <button type="submit">删除</button></form></td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const master = document.querySelector('[data-check-all="merchant-products"]');
|
||||
const items = document.querySelectorAll('[data-check-item="merchant-products"]');
|
||||
if (!master || !items.length) {
|
||||
return;
|
||||
}
|
||||
master.addEventListener('change', function () {
|
||||
items.forEach(function (item) {
|
||||
item.checked = master.checked;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="pagination-wrap">{{ $products->links() }}</div>
|
||||
@endsection
|
||||
30
resources/views/merchant_admin/users/index.blade.php
Normal file
30
resources/views/merchant_admin/users/index.blade.php
Normal file
@@ -0,0 +1,30 @@
|
||||
@extends('merchant_admin.layouts.app')
|
||||
|
||||
@section('title', '商家用户管理')
|
||||
@section('page_title', '商家用户管理')
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<p class="muted muted-tight">当前用户列表已按登录商家过滤,用于查看商家侧用户资产和注册来源。</p>
|
||||
<p class="muted">当前用户列表已接入缓存:{{ $cacheMeta['store'] }} / TTL {{ $cacheMeta['ttl'] }}。</p>
|
||||
<h3>用户列表</h3>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>姓名</th><th>邮箱</th><th>手机</th><th>状态</th><th>注册来源</th><th>最近登录来源</th></tr></thead>
|
||||
<tbody>
|
||||
@foreach($users as $user)
|
||||
<tr>
|
||||
<td>{{ $user->id }}</td>
|
||||
<td>{{ $user->name }}</td>
|
||||
<td>{{ $user->email }}</td>
|
||||
<td>{{ $user->phone }}</td>
|
||||
<td>{{ $user->status }}</td>
|
||||
<td>{{ $user->register_source }}</td>
|
||||
<td>{{ $user->last_login_source }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">{{ $users->links() }}</div>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user