功能:婚姻系统第9步(后台管理页面)

Admin/MarriageManagerController:
- index() 总览统计卡片
- list() 婚姻列表(筛选/强制离婚/取消求婚)
- proposals() 求婚记录
- ceremonies() 婚礼红包记录
- claimDetail() 红包领取明细
- intimacyLogs() 亲密度日志(来源筛选)
- configs/updateConfigs 参数配置(批量保存)
- tiers/updateTier 婚礼档位管理

Views(7个页面):admin/marriages/{index|list|configs|tiers|ceremonies|claim-detail|proposals|intimacy-logs}
侧边栏:superlevel 区块新增「💒 婚姻管理」入口
This commit is contained in:
2026-03-01 15:15:03 +08:00
parent 4f49fb7ce8
commit d2797d5b59
10 changed files with 1108 additions and 1 deletions

View File

@@ -1,10 +1,249 @@
<?php
/**
* 文件功能:后台婚姻系统管理控制器
*
* 提供总览统计、婚姻/求婚明细查询、婚礼档位管理、
* 参数配置、亲密度日志审计、强制离婚等管理操作。
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Marriage;
use App\Models\MarriageIntimacyLog;
use App\Models\WeddingCeremony;
use App\Models\WeddingEnvelopeClaim;
use App\Models\WeddingTier;
use App\Services\MarriageConfigService;
use App\Services\MarriageService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class MarriageManagerController extends Controller
{
//
public function __construct(
private readonly MarriageConfigService $config,
private readonly MarriageService $marriageService,
) {}
/**
* 婚姻管理总览(统计卡片 + 最近记录)。
*/
public function index(): View
{
$stats = [
'total_married' => Marriage::where('status', 'married')->count(),
'total_pending' => Marriage::where('status', 'pending')->count(),
'total_divorced' => Marriage::where('status', 'divorced')->count(),
'total_weddings' => WeddingCeremony::whereIn('status', ['active', 'completed'])->count(),
'total_envelopes' => WeddingEnvelopeClaim::sum('amount'),
'claimed_amount' => WeddingEnvelopeClaim::where('claimed', true)->sum('amount'),
];
$recentMarriages = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
->where('status', 'married')
->orderByDesc('married_at')
->limit(10)
->get();
$recentDivorces = Marriage::with(['user:id,username', 'partner:id,username'])
->where('status', 'divorced')
->orderByDesc('divorced_at')
->limit(8)
->get();
return view('admin.marriages.index', compact('stats', 'recentMarriages', 'recentDivorces'));
}
/**
* 婚姻列表(支持按状态/用户名筛选)。
*/
public function list(Request $request): View
{
$query = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
->orderByDesc('id');
if ($status = $request->get('status')) {
$query->where('status', $status);
}
if ($search = $request->get('search')) {
$query->where(function ($q) use ($search) {
$q->whereHas('user', fn ($u) => $u->where('username', 'like', "%{$search}%"))
->orWhereHas('partner', fn ($u) => $u->where('username', 'like', "%{$search}%"));
});
}
$marriages = $query->paginate(20)->withQueryString();
return view('admin.marriages.list', compact('marriages'));
}
/**
* 求婚记录列表(含 pending/expired/rejected
*/
public function proposals(Request $request): View
{
$proposals = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
->whereIn('status', ['pending', 'expired', 'rejected'])
->orderByDesc('proposed_at')
->paginate(20)
->withQueryString();
return view('admin.marriages.proposals', compact('proposals'));
}
/**
* 婚礼红包记录。
*/
public function ceremonies(Request $request): View
{
$ceremonies = WeddingCeremony::with([
'marriage.user:id,username',
'marriage.partner:id,username',
'tier:id,name,tier,icon',
])
->orderByDesc('id')
->paginate(20)
->withQueryString();
return view('admin.marriages.ceremonies', compact('ceremonies'));
}
/**
* 红包领取明细(某场婚礼)。
*/
public function claimDetail(WeddingCeremony $ceremony): View
{
$ceremony->load(['marriage.user:id,username', 'marriage.partner:id,username', 'tier:id,name,icon']);
$claims = WeddingEnvelopeClaim::with('user:id,username,headface')
->where('ceremony_id', $ceremony->id)
->orderBy('amount', 'desc')
->paginate(30);
return view('admin.marriages.claim-detail', compact('ceremony', 'claims'));
}
/**
* 亲密度日志列表(支持按用户筛选)。
*/
public function intimacyLogs(Request $request): View
{
$query = MarriageIntimacyLog::with(['marriage.user:id,username', 'marriage.partner:id,username'])
->orderByDesc('id');
if ($search = $request->get('search')) {
$query->whereHas('marriage', function ($q) use ($search) {
$q->whereHas('user', fn ($u) => $u->where('username', 'like', "%{$search}%"))
->orWhereHas('partner', fn ($u) => $u->where('username', 'like', "%{$search}%"));
});
}
if ($source = $request->get('source')) {
$query->where('source', $source);
}
$logs = $query->paginate(30)->withQueryString();
return view('admin.marriages.intimacy-logs', compact('logs'));
}
/**
* 参数配置页面(读取所有分组配置)。
*/
public function configs(): View
{
$groups = $this->config->allGrouped();
return view('admin.marriages.configs', compact('groups'));
}
/**
* 批量保存参数配置。
*/
public function updateConfigs(Request $request): RedirectResponse
{
$data = $request->validate([
'configs' => 'required|array',
'configs.*' => 'required|integer',
]);
$this->config->batchSet($data['configs']);
return redirect()->route('admin.marriages.configs')->with('success', '婚姻参数配置已保存!');
}
/**
* 婚礼档位配置页面。
*/
public function tiers(): View
{
$tiers = WeddingTier::orderBy('tier')->get();
return view('admin.marriages.tiers', compact('tiers'));
}
/**
* 更新婚礼档位。
*/
public function updateTier(Request $request, WeddingTier $tier): RedirectResponse
{
$data = $request->validate([
'name' => 'required|string|max:30',
'icon' => 'required|string|max:20',
'amount' => 'required|integer|min:1',
'description' => 'nullable|string|max:100',
'is_active' => 'boolean',
]);
$data['is_active'] = $request->boolean('is_active', true);
$tier->update($data);
return redirect()->route('admin.marriages.tiers')->with('success', "档位【{$tier->name}】已更新!");
}
/**
* 管理员强制离婚。
*/
public function forceDissolve(Request $request, Marriage $marriage): RedirectResponse
{
$data = $request->validate([
'admin_note' => 'required|string|max:200',
]);
if ($marriage->status !== 'married') {
return back()->with('error', '该婚姻不是已婚状态,无法操作。');
}
$admin = $request->user();
$result = $this->marriageService->forceDissolve($marriage, $admin, true);
// 写入管理员备注
$marriage->update(['admin_note' => $data['admin_note']]);
$msg = $result['ok'] ? '强制离婚已完成。' : $result['message'];
$type = $result['ok'] ? 'success' : 'error';
return back()->with($type, $msg);
}
/**
* 管理员取消求婚(释放戒指 退还状态 active
*/
public function cancelProposal(Request $request, Marriage $marriage): RedirectResponse
{
if ($marriage->status !== 'pending') {
return back()->with('error', '该求婚不是进行中状态,无法取消。');
}
$this->marriageService->expireProposal($marriage);
$marriage->update(['admin_note' => '管理员手动取消求婚:'.($request->input('reason', ''))]);
return back()->with('success', '求婚已取消,戒指标记遗失。');
}
}