новый дизайн

This commit is contained in:
2026-07-25 18:36:45 +04:00
parent df7f98fe8b
commit c43a73e148
54 changed files with 4234 additions and 1110 deletions
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\BuildsPortalProps;
use App\Http\Controllers\Controller;
use App\Http\Requests\UpdateAccountAccessRequest;
use App\Services\AzerothCoreAccountService;
@@ -9,16 +10,18 @@ use App\Services\InviteCodeService;
use App\Support\WowData;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Inertia\Inertia;
use Inertia\Response;
class AccountController extends Controller
{
use BuildsPortalProps;
public function index(
Request $request,
AzerothCoreAccountService $accounts,
InviteCodeService $inviteCodes,
): View
{
): Response {
$search = trim((string) $request->query('search', ''));
$searchTerm = $search !== '' ? $search : null;
$activeTab = (string) $request->query('tab', AzerothCoreAccountService::ACCOUNT_TAB_PLAYERS);
@@ -29,8 +32,32 @@ class AccountController extends Controller
$accountStats = $accounts->accountTypeStats($searchTerm);
return view('admin.accounts.index', [
'accounts' => $accounts->listAccounts($searchTerm, $activeTab),
$accountItems = $accounts->listAccounts($searchTerm, $activeTab)
->map(fn (array $account): array => [
...collect($account)->except('characters')->all(),
'email' => $account['email'] !== '' ? $account['email'] : 'email не указан',
'status_label' => $account['locked'] ? 'Заблокирован' : 'Активен',
'characters' => $account['characters']->values()->all(),
'update_access_url' => route('admin.accounts.access.update', $account['id']),
])
->values()
->all();
$invites = $inviteCodes->latest()
->map(fn ($invite): array => [
'id' => $invite->id,
'code' => $invite->code,
'created_by' => $invite->created_by_username ?: '—',
'created_at' => $invite->created_at?->format('d.m.Y H:i'),
'redeemed' => $invite->redeemed_at !== null,
'redeemed_by' => $invite->redeemed_by_username ?: 'ещё не использован',
])
->values()
->all();
return Inertia::render('Admin/Accounts', [
...$this->portalProps($request),
'accounts' => $accountItems,
'accountStats' => $accountStats,
'accountTabs' => [
AzerothCoreAccountService::ACCOUNT_TAB_PLAYERS => [
@@ -43,10 +70,18 @@ class AccountController extends Controller
],
],
'activeTab' => $activeTab,
'inviteCodes' => $inviteCodes->latest(),
'inviteCodes' => $invites,
'inviteStats' => $inviteCodes->stats(),
'inviteStoreUrl' => route('admin.invite-codes.store'),
'registrationRequiresInvite' => (bool) config('moonwell.registration.require_invite_code'),
'search' => $search,
'accessLevels' => WowData::securityLevels(),
'accessLevels' => collect(WowData::securityLevels())
->map(fn (string $label, int $value): array => compact('value', 'label'))
->values()
->all(),
'old' => [
'quantity' => $request->old('quantity', 1),
],
]);
}
@@ -2,24 +2,66 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\BuildsPortalProps;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\AdjustBalanceRequest;
use App\Services\AzerothCoreAccountService;
use App\Services\BalanceService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Inertia\Inertia;
use Inertia\Response;
use InvalidArgumentException;
class BalanceController extends Controller
{
public function index(Request $request, BalanceService $balances): View
use BuildsPortalProps;
public function index(Request $request, BalanceService $balances): Response
{
$search = trim((string) $request->query('search', ''));
return view('admin.balances.index', [
'transactions' => $balances->adminTransactions($search !== '' ? $search : null),
$transactions = $balances->adminTransactions($search !== '' ? $search : null)
->map(function ($transaction): array {
$metadata = $transaction->metadata ?? [];
return [
'id' => $transaction->id,
'username' => $transaction->username ?: 'Аккаунт удалён',
'account_id' => $transaction->account_id,
'created_at' => $transaction->created_at?->format('d.m.Y H:i:s'),
'type_label' => match ($transaction->type) {
'deposit' => 'Пополнение',
'spend' => 'Покупка в игре',
'admin_credit' => 'Начисление администратором',
'admin_debit' => 'Списание администратором',
default => $transaction->type,
},
'description' => $metadata['reason'] ?? $metadata['description'] ?? $transaction->reference,
'admin' => isset($metadata['admin_username']) ? [
'username' => $metadata['admin_username'],
'account_id' => $metadata['admin_account_id'],
] : null,
'amount' => (string) $transaction->amount,
'formatted_amount' => number_format((float) $transaction->amount, 2, ',', ' '),
'is_positive' => (float) $transaction->amount >= 0,
'formatted_balance_after' => number_format((float) $transaction->balance_after, 2, ',', ' '),
];
})
->values()
->all();
return Inertia::render('Admin/Balances', [
...$this->portalProps($request),
'transactions' => $transactions,
'search' => $search,
'adjustUrl' => route('admin.balances.adjust'),
'old' => [
'account' => $request->old('account', ''),
'direction' => $request->old('direction', 'credit'),
'amount' => $request->old('amount', ''),
'reason' => $request->old('reason', ''),
],
]);
}
@@ -2,23 +2,49 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\BuildsPortalProps;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveLoginScreenNewsRequest;
use App\Models\LoginScreenNews;
use App\Services\LoginScreenNewsService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Inertia\Inertia;
use Inertia\Response;
class LoginScreenNewsController extends Controller
{
public function index(LoginScreenNewsService $news): View
use BuildsPortalProps;
public function index(Request $request, LoginScreenNewsService $news): Response
{
return view('admin.login-screen-news.index', [
'newsItems' => $news->listForAdmin(),
return Inertia::render('Admin/LoginScreenNews', [
...$this->portalProps($request),
'newsItems' => $news->listForAdmin()
->map(fn (LoginScreenNews $item): array => [
'id' => $item->id,
'title' => $item->title,
'body' => $item->body,
'sort_order' => $item->sort_order,
'is_published' => $item->is_published,
'updated_by' => $item->updated_by_username,
'updated_at' => $item->updated_at?->format('d.m.Y H:i'),
'update_url' => route('admin.login-screen-news.update', $item),
'destroy_url' => route('admin.login-screen-news.destroy', $item),
])
->values()
->all(),
'newsStats' => $news->stats(),
'feedPreview' => $news->renderFeed(),
'feedUrl' => Str::replaceFirst('https://', 'http://', route('launcher.login-news.show')),
'storeUrl' => route('admin.login-screen-news.store'),
'old' => [
'title' => $request->old('title', ''),
'body' => $request->old('body', ''),
'sort_order' => $request->old('sort_order', 0),
'is_published' => (bool) $request->old('is_published', true),
],
]);
}
+31 -4
View File
@@ -2,20 +2,47 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\BuildsPortalProps;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveNewsRequest;
use App\Models\News;
use App\Services\NewsService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class NewsController extends Controller
{
public function index(NewsService $news): View
use BuildsPortalProps;
public function index(Request $request, NewsService $news): Response
{
return view('admin.news.index', [
'newsItems' => $news->listForAdmin(),
return Inertia::render('Admin/News', [
...$this->portalProps($request),
'newsItems' => $news->listForAdmin()
->map(fn (News $item): array => [
'id' => $item->id,
'title' => $item->title,
'body' => $item->body,
'sort_order' => $item->sort_order,
'is_published' => $item->is_published,
'image_url' => $item->image_url,
'created_by' => $item->created_by_username ?? '—',
'updated_at' => $item->updated_at?->format('d.m.Y H:i'),
'update_url' => route('admin.news.update', $item),
'destroy_url' => route('admin.news.destroy', $item),
])
->values()
->all(),
'newsStats' => $news->stats(),
'storeUrl' => route('admin.news.store'),
'old' => [
'title' => $request->old('title', ''),
'body' => $request->old('body', ''),
'sort_order' => $request->old('sort_order', 0),
'is_published' => (bool) $request->old('is_published', true),
],
]);
}
+64 -5
View File
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Concerns\BuildsPortalProps;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\SaveShopCategoryRequest;
use App\Http\Requests\Admin\SaveShopProductRequest;
@@ -9,15 +10,73 @@ use App\Models\ShopCategory;
use App\Models\ShopProduct;
use App\Services\ShopCatalogService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class ShopController extends Controller
{
public function index(ShopCatalogService $catalog): View
use BuildsPortalProps;
public function index(Request $request, ShopCatalogService $catalog): Response
{
return view('admin.shop.index', [
'categories' => $catalog->categories(),
'products' => $catalog->products(),
$categories = $catalog->categories();
return Inertia::render('Admin/Shop', [
...$this->portalProps($request),
'categories' => $categories
->map(fn (ShopCategory $category): array => [
'id' => $category->id,
'name' => $category->name,
'icon' => $category->icon,
'required_rank' => $category->requiredRank,
'flags' => $category->flags,
'enabled' => $category->enabled,
'products_count' => $category->products_count,
'update_url' => route('admin.shop.categories.update', $category),
'destroy_url' => route('admin.shop.categories.destroy', $category),
])
->values()
->all(),
'products' => $catalog->products()
->map(fn (ShopProduct $product): array => [
'id' => $product->id,
'category_ids' => $product->categories->pluck('id')->values()->all(),
'category_names' => $product->categories->pluck('name')->values()->all(),
'type' => (int) $product->type,
'name' => $product->name,
'tooltip_name' => $product->tooltipName,
'tooltip_type' => $product->tooltipType,
'tooltip_text' => $product->tooltipText,
'icon' => $product->icon,
'price' => (int) $product->price,
'hyperlink_id' => (int) $product->hyperlinkId,
'creature_entry' => (int) $product->creatureEntry,
'discount_amount' => (int) $product->discountAmount,
'flags' => (int) $product->flags,
'rewards' => collect(range(1, 8))->map(fn (int $slot): array => [
'slot' => $slot,
'id' => (int) $product->{'reward_'.$slot},
'count' => (int) $product->{'rewardcount_'.$slot},
])->all(),
'is_new' => (bool) $product->new,
'enabled' => (bool) $product->enabled,
'update_url' => route('admin.shop.products.update', $product),
'destroy_url' => route('admin.shop.products.destroy', $product),
])
->values()
->all(),
'categoryStoreUrl' => route('admin.shop.categories.store'),
'productStoreUrl' => route('admin.shop.products.store'),
'productTypes' => collect([
1 => 'Предмет',
3 => 'Маунт',
4 => 'Питомец',
5 => 'Бафф',
7 => 'Услуга персонажа',
8 => 'Буст',
9 => 'Титул',
])->map(fn (string $label, int $value): array => compact('value', 'label'))->values()->all(),
]);
}