229 lines
9.1 KiB
PHP
229 lines
9.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\SiteAdmin;
|
|
|
|
use App\Http\Controllers\Concerns\ResolvesSiteContext;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Merchant;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\View\View;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class MerchantController extends Controller
|
|
{
|
|
use ResolvesSiteContext;
|
|
|
|
public function index(Request $request): View
|
|
{
|
|
$site = $this->site($request);
|
|
$filters = $this->filters($request);
|
|
|
|
$query = $this->applySorting(
|
|
$this->applyFilters(
|
|
Merchant::query()
|
|
->withCount(['admins', 'users', 'products', 'orders', 'categories'])
|
|
->whereKey($site->id),
|
|
$filters
|
|
),
|
|
$filters
|
|
);
|
|
|
|
$merchants = $query->get();
|
|
$summaryStats = $this->buildSummaryStats($site);
|
|
|
|
return view('site_admin.merchants.index', [
|
|
'site' => $site,
|
|
'merchants' => $merchants,
|
|
'filters' => $filters,
|
|
'activeFilterSummary' => $this->buildActiveFilterSummary($filters),
|
|
'summaryStats' => $summaryStats,
|
|
'statusLabels' => $this->statusLabels(),
|
|
'planLabels' => $this->planLabels(),
|
|
'filterOptions' => [
|
|
'statuses' => array_keys($this->statusLabels()),
|
|
'plans' => array_keys($this->planLabels()),
|
|
'sortOptions' => [
|
|
'latest' => '最近激活优先',
|
|
'name_asc' => '名称 A-Z',
|
|
'name_desc' => '名称 Z-A',
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function export(Request $request): StreamedResponse
|
|
{
|
|
$site = $this->site($request);
|
|
$filters = $this->filters($request);
|
|
|
|
$merchants = $this->applySorting(
|
|
$this->applyFilters(
|
|
Merchant::query()
|
|
->withCount(['admins', 'users', 'products', 'orders', 'categories'])
|
|
->whereKey($site->id),
|
|
$filters
|
|
),
|
|
$filters
|
|
)->get();
|
|
|
|
$summaryStats = $this->buildSummaryStats($site);
|
|
$fileName = 'site_' . $site->id . '_merchants_' . now()->format('Ymd_His') . '.csv';
|
|
|
|
return response()->streamDownload(function () use ($site, $filters, $merchants, $summaryStats) {
|
|
$handle = fopen('php://output', 'w');
|
|
fwrite($handle, "\xEF\xBB\xBF");
|
|
|
|
fputcsv($handle, ['导出信息', '站点商家导出']);
|
|
fputcsv($handle, ['站点ID', $site->id]);
|
|
fputcsv($handle, ['站点名称', $site->name]);
|
|
fputcsv($handle, ['关键词', ($filters['keyword'] ?? '') !== '' ? $filters['keyword'] : '全部']);
|
|
fputcsv($handle, ['状态', $this->statusLabel($filters['status'] ?? '')]);
|
|
fputcsv($handle, ['套餐', $this->planLabel($filters['plan'] ?? '')]);
|
|
fputcsv($handle, ['排序', $this->sortLabel($filters['sort'] ?? 'latest')]);
|
|
fputcsv($handle, ['承接站点数', $summaryStats['site_count'] ?? 0]);
|
|
fputcsv($handle, ['启用中站点', $summaryStats['active_site_count'] ?? 0]);
|
|
fputcsv($handle, ['站点管理员数', $summaryStats['admin_count'] ?? 0]);
|
|
fputcsv($handle, ['站点用户数', $summaryStats['user_count'] ?? 0]);
|
|
fputcsv($handle, ['站点商品数', $summaryStats['product_count'] ?? 0]);
|
|
fputcsv($handle, ['站点订单数', $summaryStats['order_count'] ?? 0]);
|
|
fputcsv($handle, ['商品分类数', $summaryStats['category_count'] ?? 0]);
|
|
fputcsv($handle, []);
|
|
|
|
fputcsv($handle, ['当前站点资料', '']);
|
|
fputcsv($handle, ['站点标识', $site->slug]);
|
|
fputcsv($handle, ['当前状态', $this->statusLabel((string) $site->status)]);
|
|
fputcsv($handle, ['当前套餐', $this->planLabel((string) $site->plan)]);
|
|
fputcsv($handle, ['联系人', $site->contact_name ?: '未设置']);
|
|
fputcsv($handle, ['联系电话', $site->contact_phone ?: '未设置']);
|
|
fputcsv($handle, ['联系邮箱', $site->contact_email ?: '未设置']);
|
|
fputcsv($handle, ['激活时间', $site->activated_at?->format('Y-m-d H:i:s') ?? '未激活']);
|
|
fputcsv($handle, []);
|
|
|
|
fputcsv($handle, ['ID', '名称', 'Slug', '状态', '套餐', '联系人', '联系电话', '联系邮箱', '管理员数', '用户数', '商品数', '订单数', '商品分类数', '激活时间']);
|
|
|
|
foreach ($merchants as $merchant) {
|
|
fputcsv($handle, [
|
|
$merchant->id,
|
|
$merchant->name,
|
|
$merchant->slug,
|
|
$this->statusLabel((string) $merchant->status),
|
|
$this->planLabel((string) $merchant->plan),
|
|
$merchant->contact_name ?: '未设置',
|
|
$merchant->contact_phone ?: '未设置',
|
|
$merchant->contact_email ?: '未设置',
|
|
$merchant->admins_count ?? 0,
|
|
$merchant->users_count ?? 0,
|
|
$merchant->products_count ?? 0,
|
|
$merchant->orders_count ?? 0,
|
|
$merchant->categories_count ?? 0,
|
|
$merchant->activated_at?->format('Y-m-d H:i:s') ?? '未激活',
|
|
]);
|
|
}
|
|
|
|
fclose($handle);
|
|
}, $fileName, [
|
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
]);
|
|
}
|
|
|
|
protected function filters(Request $request): array
|
|
{
|
|
return [
|
|
'keyword' => trim((string) $request->string('keyword')),
|
|
'status' => trim((string) $request->string('status')),
|
|
'plan' => trim((string) $request->string('plan')),
|
|
'sort' => trim((string) $request->string('sort', 'latest')),
|
|
];
|
|
}
|
|
|
|
protected function applyFilters(Builder $query, array $filters): Builder
|
|
{
|
|
return $query
|
|
->when(($filters['status'] ?? '') !== '', fn ($builder) => $builder->where('status', $filters['status']))
|
|
->when(($filters['plan'] ?? '') !== '', fn ($builder) => $builder->where('plan', $filters['plan']))
|
|
->when(($filters['keyword'] ?? '') !== '', function ($builder) use ($filters) {
|
|
$keyword = $filters['keyword'];
|
|
|
|
$builder->where(function ($subQuery) use ($keyword) {
|
|
$subQuery->where('name', 'like', '%' . $keyword . '%')
|
|
->orWhere('slug', 'like', '%' . $keyword . '%')
|
|
->orWhere('contact_name', 'like', '%' . $keyword . '%')
|
|
->orWhere('contact_phone', 'like', '%' . $keyword . '%')
|
|
->orWhere('contact_email', 'like', '%' . $keyword . '%');
|
|
});
|
|
});
|
|
}
|
|
|
|
protected function applySorting(Builder $query, array $filters): Builder
|
|
{
|
|
return match ($filters['sort'] ?? 'latest') {
|
|
'name_asc' => $query->orderBy('name')->orderBy('id'),
|
|
'name_desc' => $query->orderByDesc('name')->orderByDesc('id'),
|
|
default => $query->orderByDesc('activated_at')->orderByDesc('id'),
|
|
};
|
|
}
|
|
|
|
protected function buildSummaryStats(Merchant $site): array
|
|
{
|
|
$site->loadCount(['admins', 'users', 'products', 'orders', 'categories']);
|
|
|
|
return [
|
|
'site_count' => 1,
|
|
'active_site_count' => $site->status === 'active' ? 1 : 0,
|
|
'admin_count' => (int) ($site->admins_count ?? 0),
|
|
'user_count' => (int) ($site->users_count ?? 0),
|
|
'product_count' => (int) ($site->products_count ?? 0),
|
|
'order_count' => (int) ($site->orders_count ?? 0),
|
|
'category_count' => (int) ($site->categories_count ?? 0),
|
|
];
|
|
}
|
|
|
|
protected function buildActiveFilterSummary(array $filters): array
|
|
{
|
|
return [
|
|
'关键词' => ($filters['keyword'] ?? '') !== '' ? $filters['keyword'] : '全部',
|
|
'状态' => $this->statusLabel($filters['status'] ?? ''),
|
|
'套餐' => $this->planLabel($filters['plan'] ?? ''),
|
|
'排序' => $this->sortLabel($filters['sort'] ?? 'latest'),
|
|
];
|
|
}
|
|
|
|
protected function statusLabels(): array
|
|
{
|
|
return [
|
|
'active' => '启用中',
|
|
'inactive' => '未启用',
|
|
'suspended' => '已停用',
|
|
];
|
|
}
|
|
|
|
protected function statusLabel(string $status): string
|
|
{
|
|
return $this->statusLabels()[$status] ?? '全部';
|
|
}
|
|
|
|
protected function planLabels(): array
|
|
{
|
|
return [
|
|
'basic' => '基础版',
|
|
'pro' => '专业版',
|
|
'enterprise' => '企业版',
|
|
];
|
|
}
|
|
|
|
protected function planLabel(string $plan): string
|
|
{
|
|
return $this->planLabels()[$plan] ?? (($plan === '') ? '全部' : $plan);
|
|
}
|
|
|
|
protected function sortLabel(string $sort): string
|
|
{
|
|
return match ($sort) {
|
|
'name_asc' => '名称 A-Z',
|
|
'name_desc' => '名称 Z-A',
|
|
default => '最近激活优先',
|
|
};
|
|
}
|
|
}
|