chore: init saasshop repo + sql migrations runner + gitee go

This commit is contained in:
萝卜
2026-03-10 11:31:02 +00:00
commit 50f15cdea8
210 changed files with 29534 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
<?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 => '最近激活优先',
};
}
}