功能:后台新增商店管理页面(站长菜单)
- 路由:GET/POST/PUT/PATCH/DELETE /admin/shop
- 控制器:Admin/ShopItemController(index/store/update/toggle/destroy)
- 视图:admin/shop/index.blade.php
- 表格展示所有商品(名称/类型色标/价格/有效期/排序/状态)
- Alpine.js 弹窗新增/编辑(支持全字段)
- 上下架一键切换(PATCH toggle)
- 删除按键(含二次确认)
- 侧边栏:VIP 下方新增「🛒 商店管理」链接
- 权限:superlevel 可查看/编辑;id=1 可新增/删除
This commit is contained in:
113
app/Http/Controllers/Admin/ShopItemController.php
Normal file
113
app/Http/Controllers/Admin/ShopItemController.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 文件功能:后台商店商品管理控制器(站长功能)
|
||||
*
|
||||
* 提供商店商品的查看、编辑、切换上下架、删除等 CRUD 功能。
|
||||
* 仅 superlevel 及以上可访问,id=1 超级站长才能新增/删除。
|
||||
*
|
||||
* @author ChatRoom Laravel
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ShopItem;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ShopItemController extends Controller
|
||||
{
|
||||
/**
|
||||
* 商品列表页(所有 superlevel 以上可查看)
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
$items = ShopItem::orderBy('sort_order')->orderBy('id')->get();
|
||||
|
||||
return view('admin.shop.index', compact('items'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品(仅 id=1 超级站长)
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
abort_unless(Auth::id() === 1, 403);
|
||||
|
||||
$data = $this->validateItem($request);
|
||||
ShopItem::create($data);
|
||||
|
||||
return redirect()->route('admin.shop.index')->with('success', '商品「'.$data['name'].'」创建成功!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商品信息
|
||||
*
|
||||
* @param ShopItem $shopItem 路由模型自动注入
|
||||
*/
|
||||
public function update(Request $request, ShopItem $shopItem): RedirectResponse
|
||||
{
|
||||
$data = $this->validateItem($request, $shopItem);
|
||||
$shopItem->update($data);
|
||||
|
||||
return redirect()->route('admin.shop.index')->with('success', '商品「'.$shopItem->name.'」更新成功!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换商品上下架状态
|
||||
*
|
||||
* @param ShopItem $shopItem 路由模型自动注入
|
||||
*/
|
||||
public function toggle(ShopItem $shopItem): RedirectResponse
|
||||
{
|
||||
$shopItem->update(['is_active' => ! $shopItem->is_active]);
|
||||
$status = $shopItem->is_active ? '上架' : '下架';
|
||||
|
||||
return redirect()->route('admin.shop.index')->with('success', "「{$shopItem->name}」已{$status}。");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品(仅 id=1 超级站长)
|
||||
*
|
||||
* @param ShopItem $shopItem 路由模型自动注入
|
||||
*/
|
||||
public function destroy(ShopItem $shopItem): RedirectResponse
|
||||
{
|
||||
abort_unless(Auth::id() === 1, 403);
|
||||
|
||||
$name = $shopItem->name;
|
||||
$shopItem->delete();
|
||||
|
||||
return redirect()->route('admin.shop.index')->with('success', "「{$name}」已删除。");
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一验证商品表单(新增/编辑共用)
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function validateItem(Request $request, ?ShopItem $item = null): array
|
||||
{
|
||||
return $request->validate([
|
||||
'name' => 'required|string|max:100',
|
||||
'slug' => ['required', 'string', 'max:100',
|
||||
\Illuminate\Validation\Rule::unique('shop_items', 'slug')->ignore($item?->id),
|
||||
],
|
||||
'icon' => 'required|string|max:20',
|
||||
'description' => 'nullable|string|max:500',
|
||||
'price' => 'required|integer|min:0',
|
||||
'type' => 'required|in:instant,duration,one_time,ring,auto_fishing',
|
||||
'duration_days' => 'nullable|integer|min:0',
|
||||
'duration_minutes' => 'nullable|integer|min:0',
|
||||
'intimacy_bonus' => 'nullable|integer|min:0',
|
||||
'charm_bonus' => 'nullable|integer|min:0',
|
||||
'sort_order' => 'required|integer|min:0',
|
||||
'is_active' => 'boolean',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,10 @@
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.vip.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '👑 VIP 会员等级' . $ro !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.shop.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.shop.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🛒 商店管理' . $ro !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.marriages.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.marriages.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '💒 婚姻管理' . $ro !!}
|
||||
|
||||
351
resources/views/admin/shop/index.blade.php
Normal file
351
resources/views/admin/shop/index.blade.php
Normal file
@@ -0,0 +1,351 @@
|
||||
{{--
|
||||
文件功能:后台商店商品管理页面(站长功能)
|
||||
支持查看、新增、编辑、上下架切换、删除商品。
|
||||
字段:名称、Slug、图标、描述、价格、类型、有效期、排序、状态
|
||||
|
||||
@author ChatRoom Laravel
|
||||
@version 1.0.0
|
||||
--}}
|
||||
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', '🛒 商店商品管理')
|
||||
|
||||
@section('content')
|
||||
|
||||
@php
|
||||
$typeLabels = [
|
||||
'instant' => ['label' => '即时特效', 'color' => 'bg-blue-100 text-blue-700'],
|
||||
'duration' => ['label' => '周卡/时效', 'color' => 'bg-purple-100 text-purple-700'],
|
||||
'one_time' => ['label' => '一次性道具', 'color' => 'bg-yellow-100 text-yellow-700'],
|
||||
'ring' => ['label' => '求婚戒指', 'color' => 'bg-rose-100 text-rose-700'],
|
||||
'auto_fishing' => ['label' => '自动钓鱼卡', 'color' => 'bg-emerald-100 text-emerald-700'],
|
||||
];
|
||||
$isSuperAdmin = Auth::id() === 1;
|
||||
@endphp
|
||||
|
||||
<div x-data="{
|
||||
showForm: false,
|
||||
editing: null,
|
||||
form: {
|
||||
name: '',
|
||||
slug: '',
|
||||
icon: '🎁',
|
||||
description: '',
|
||||
price: 100,
|
||||
type: 'instant',
|
||||
duration_days: 0,
|
||||
duration_minutes: 0,
|
||||
intimacy_bonus: 0,
|
||||
charm_bonus: 0,
|
||||
sort_order: 0,
|
||||
is_active: true,
|
||||
},
|
||||
|
||||
openCreate() {
|
||||
this.editing = null;
|
||||
this.form = {
|
||||
name: '',
|
||||
slug: '',
|
||||
icon: '🎁',
|
||||
description: '',
|
||||
price: 100,
|
||||
type: 'instant',
|
||||
duration_days: 0,
|
||||
duration_minutes: 0,
|
||||
intimacy_bonus: 0,
|
||||
charm_bonus: 0,
|
||||
sort_order: 0,
|
||||
is_active: true,
|
||||
};
|
||||
this.showForm = true;
|
||||
this.$nextTick(() => this.$refs.nameInput?.focus());
|
||||
},
|
||||
|
||||
openEdit(item) {
|
||||
this.editing = item;
|
||||
this.form = {
|
||||
name: item.name,
|
||||
slug: item.slug,
|
||||
icon: item.icon,
|
||||
description: item.description || '',
|
||||
price: item.price,
|
||||
type: item.type,
|
||||
duration_days: item.duration_days || 0,
|
||||
duration_minutes: item.duration_minutes || 0,
|
||||
intimacy_bonus: item.intimacy_bonus || 0,
|
||||
charm_bonus: item.charm_bonus || 0,
|
||||
sort_order: item.sort_order,
|
||||
is_active: item.is_active,
|
||||
};
|
||||
this.showForm = true;
|
||||
this.$nextTick(() => this.$refs.nameInput?.focus());
|
||||
},
|
||||
|
||||
closeForm() {
|
||||
this.showForm = false;
|
||||
this.editing = null;
|
||||
}
|
||||
}">
|
||||
|
||||
{{-- 头部操作栏 --}}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-lg font-bold text-gray-800">商店商品列表</h2>
|
||||
<p class="text-sm text-gray-500">管理聊天室商店内所有可出售商品,支持上下架控制。</p>
|
||||
</div>
|
||||
@if ($isSuperAdmin)
|
||||
<button @click="openCreate()"
|
||||
class="bg-indigo-600 text-white px-5 py-2.5 rounded-lg font-bold hover:bg-indigo-700 transition shadow-sm">
|
||||
+ 新增商品
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- 商品列表表格 --}}
|
||||
<div class="bg-white rounded-xl shadow overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50 text-gray-500 uppercase text-xs tracking-wider">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left">商品</th>
|
||||
<th class="px-4 py-3 text-left">类型</th>
|
||||
<th class="px-4 py-3 text-right">价格</th>
|
||||
<th class="px-4 py-3 text-center">有效期</th>
|
||||
<th class="px-4 py-3 text-center">排序</th>
|
||||
<th class="px-4 py-3 text-center">状态</th>
|
||||
<th class="px-4 py-3 text-center">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
@forelse ($items as $item)
|
||||
@php $tl = $typeLabels[$item->type] ?? ['label' => $item->type, 'color' => 'bg-gray-100 text-gray-600']; @endphp
|
||||
<tr class="hover:bg-gray-50 transition {{ $item->is_active ? '' : 'opacity-50' }}">
|
||||
{{-- 商品信息 --}}
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-2xl leading-none">{{ $item->icon }}</span>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-800">{{ $item->name }}</p>
|
||||
<p class="text-xs text-gray-400 font-mono">{{ $item->slug }}</p>
|
||||
@if ($item->description)
|
||||
<p class="text-xs text-gray-500 mt-0.5 max-w-xs truncate">
|
||||
{{ $item->description }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{{-- 类型 --}}
|
||||
<td class="px-4 py-3">
|
||||
<span class="px-2 py-0.5 rounded-full text-xs font-semibold {{ $tl['color'] }}">
|
||||
{{ $tl['label'] }}
|
||||
</span>
|
||||
</td>
|
||||
{{-- 价格 --}}
|
||||
<td class="px-4 py-3 text-right font-mono font-bold text-amber-600">
|
||||
{{ number_format($item->price) }} 金
|
||||
</td>
|
||||
{{-- 有效期 --}}
|
||||
<td class="px-4 py-3 text-center text-gray-500 text-xs">
|
||||
@if ($item->duration_minutes > 0)
|
||||
{{ $item->duration_minutes >= 60 ? floor($item->duration_minutes / 60) . '小时' : $item->duration_minutes . '分钟' }}
|
||||
@elseif ($item->duration_days > 0)
|
||||
{{ $item->duration_days }} 天
|
||||
@else
|
||||
—
|
||||
@endif
|
||||
</td>
|
||||
{{-- 排序 --}}
|
||||
<td class="px-4 py-3 text-center text-gray-400 font-mono text-xs">{{ $item->sort_order }}</td>
|
||||
{{-- 状态 --}}
|
||||
<td class="px-4 py-3 text-center">
|
||||
<form method="POST" action="{{ route('admin.shop.toggle', $item) }}" class="inline">
|
||||
@csrf @method('PATCH')
|
||||
<button type="submit"
|
||||
class="px-2.5 py-1 rounded-full text-xs font-bold transition
|
||||
{{ $item->is_active
|
||||
? 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200'
|
||||
: 'bg-gray-100 text-gray-500 hover:bg-gray-200' }}">
|
||||
{{ $item->is_active ? '上架中' : '已下架' }}
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
{{-- 操作 --}}
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<button
|
||||
@click="openEdit({{ json_encode([
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'slug' => $item->slug,
|
||||
'icon' => $item->icon,
|
||||
'description' => $item->description,
|
||||
'price' => $item->price,
|
||||
'type' => $item->type,
|
||||
'duration_days' => $item->duration_days,
|
||||
'duration_minutes' => $item->duration_minutes,
|
||||
'intimacy_bonus' => $item->intimacy_bonus,
|
||||
'charm_bonus' => $item->charm_bonus,
|
||||
'sort_order' => $item->sort_order,
|
||||
'is_active' => (bool) $item->is_active,
|
||||
]) }})"
|
||||
class="text-indigo-600 hover:text-indigo-800 text-xs font-semibold px-2 py-1 rounded hover:bg-indigo-50 transition">
|
||||
编辑
|
||||
</button>
|
||||
@if ($isSuperAdmin)
|
||||
<form method="POST" action="{{ route('admin.shop.destroy', $item) }}"
|
||||
onsubmit="return confirm('确定要删除「{{ $item->name }}」吗?此操作不可撤销!')">
|
||||
@csrf @method('DELETE')
|
||||
<button type="submit"
|
||||
class="text-red-500 hover:text-red-700 text-xs font-semibold px-2 py-1 rounded hover:bg-red-50 transition">
|
||||
删除
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="px-4 py-12 text-center text-gray-400">暂无商品数据</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{-- 新增/编辑 抽屉弹窗 --}}
|
||||
<div x-show="showForm" x-cloak class="fixed inset-0 z-50 flex items-center justify-center"
|
||||
style="background: rgba(0,0,0,0.45);">
|
||||
<div @click.stop class="bg-white rounded-2xl shadow-2xl w-full max-w-xl max-h-[90vh] overflow-y-auto"
|
||||
x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-4"
|
||||
x-transition:enter-end="opacity-100 translate-y-0">
|
||||
|
||||
{{-- 弹窗头部 --}}
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b">
|
||||
<h3 class="font-bold text-gray-800 text-lg" x-text="editing ? '编辑商品:' + editing.name : '新增商品'"></h3>
|
||||
<button @click="closeForm()"
|
||||
class="text-gray-400 hover:text-gray-600 text-2xl leading-none">×</button>
|
||||
</div>
|
||||
|
||||
{{-- 表单 --}}
|
||||
<form method="POST"
|
||||
:action="editing
|
||||
?
|
||||
'{{ url('admin/shop') }}/' + editing.id :
|
||||
'{{ route('admin.shop.store') }}'"
|
||||
class="px-6 py-5 space-y-4">
|
||||
@csrf
|
||||
<template x-if="editing"><input type="hidden" name="_method" value="PUT"></template>
|
||||
|
||||
{{-- 基本信息 --}}
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="col-span-2">
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">商品名称 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<input x-ref="nameInput" type="text" name="name" x-model="form.name" required
|
||||
maxlength="100"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Slug(唯一标识)<span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="text" name="slug" x-model="form.slug" required maxlength="100"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">图标(Emoji)<span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="text" name="icon" x-model="form.icon" required maxlength="20"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">商品描述</label>
|
||||
<textarea name="description" x-model="form.description" rows="2" maxlength="500"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none resize-none"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">价格(金币)<span
|
||||
class="text-red-500">*</span></label>
|
||||
<input type="number" name="price" x-model="form.price" required min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">商品类型 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<select name="type" x-model="form.type" required
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none bg-white">
|
||||
<option value="instant">instant — 即时特效</option>
|
||||
<option value="duration">duration — 周卡/时效</option>
|
||||
<option value="one_time">one_time — 一次性道具</option>
|
||||
<option value="ring">ring — 求婚戒指</option>
|
||||
<option value="auto_fishing">auto_fishing — 自动钓鱼卡</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">有效天数</label>
|
||||
<input type="number" name="duration_days" x-model="form.duration_days" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">有效分钟数</label>
|
||||
<input type="number" name="duration_minutes" x-model="form.duration_minutes" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">排序权重</label>
|
||||
<input type="number" name="sort_order" x-model="form.sort_order" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">亲密度加成(戒指)</label>
|
||||
<input type="number" name="intimacy_bonus" x-model="form.intimacy_bonus" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">魅力值加成(戒指)</label>
|
||||
<input type="number" name="charm_bonus" x-model="form.charm_bonus" min="0"
|
||||
class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:border-indigo-400 outline-none">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="hidden" name="is_active" :value="form.is_active ? 1 : 0">
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" x-model="form.is_active" class="sr-only peer">
|
||||
<div
|
||||
class="w-10 h-5 bg-gray-200 peer-checked:bg-indigo-500 rounded-full transition peer-focus:ring-2 peer-focus:ring-indigo-300">
|
||||
</div>
|
||||
<div
|
||||
class="absolute left-0.5 top-0.5 w-4 h-4 bg-white rounded-full shadow transition peer-checked:translate-x-5">
|
||||
</div>
|
||||
</label>
|
||||
<span class="text-sm text-gray-600" x-text="form.is_active ? '🟢 上架显示' : '⚫ 下架隐藏'"></span>
|
||||
</div>
|
||||
|
||||
{{-- 弹窗底部按钮 --}}
|
||||
<div class="flex justify-end gap-3 pt-2 border-t mt-4">
|
||||
<button type="button" @click="closeForm()"
|
||||
class="px-5 py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition text-sm">
|
||||
取消
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="px-6 py-2 bg-indigo-600 text-white rounded-lg font-bold hover:bg-indigo-700 transition text-sm shadow">
|
||||
<span x-text="editing ? '保存修改' : '创建商品'"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
@@ -254,6 +254,13 @@ Route::middleware(['chat.auth', 'chat.has_position'])->prefix('admin')->name('ad
|
||||
Route::put('/vip/{vip}', [\App\Http\Controllers\Admin\VipController::class, 'update'])->name('vip.update');
|
||||
Route::delete('/vip/{vip}', [\App\Http\Controllers\Admin\VipController::class, 'destroy'])->name('vip.destroy');
|
||||
|
||||
// 🛒 商店商品管理(查看/编辑所有 superlevel 可用,新增/删除仅 id=1)
|
||||
Route::get('/shop', [\App\Http\Controllers\Admin\ShopItemController::class, 'index'])->name('shop.index');
|
||||
Route::post('/shop', [\App\Http\Controllers\Admin\ShopItemController::class, 'store'])->name('shop.store');
|
||||
Route::put('/shop/{shopItem}', [\App\Http\Controllers\Admin\ShopItemController::class, 'update'])->name('shop.update');
|
||||
Route::patch('/shop/{shopItem}/toggle', [\App\Http\Controllers\Admin\ShopItemController::class, 'toggle'])->name('shop.toggle');
|
||||
Route::delete('/shop/{shopItem}', [\App\Http\Controllers\Admin\ShopItemController::class, 'destroy'])->name('shop.destroy');
|
||||
|
||||
// 💒 婚姻管理(superlevel 及以上)
|
||||
Route::prefix('marriages')->name('marriages.')->group(function () {
|
||||
// 总览统计
|
||||
|
||||
Reference in New Issue
Block a user