first commit

This commit is contained in:
浪子
2026-03-19 16:44:38 +08:00
commit ff2af385b9
100 changed files with 16826 additions and 0 deletions
@@ -0,0 +1,198 @@
@extends('admin.layout', [
'title' => 'Tstore Admin · 插件 / 主题管理',
'pageTitle' => $filters['type'] === 'plugin' ? '插件列表' : ($filters['type'] === 'theme' ? '主题列表' : '扩展列表'),
'pageSubtitle' => $filters['type'] === 'plugin'
? '查看、筛选、维护和发布插件,统一处理插件版本与状态。'
: ($filters['type'] === 'theme'
? '查看、筛选、维护和发布主题,统一处理主题版本与状态。'
: '查看全部插件与主题,统一管理扩展列表、详情页与发布版本。'),
])
@php
$currentType = $filters['type'] ?? '';
$entityLabel = $currentType === 'plugin' ? '插件' : ($currentType === 'theme' ? '主题' : '扩展');
$entityPluralLabel = $currentType === 'plugin' ? '插件列表' : ($currentType === 'theme' ? '主题列表' : '扩展列表');
$newEntityLabel = $currentType === 'plugin' ? '新建插件' : ($currentType === 'theme' ? '新建主题' : '新建扩展');
$filterHint = $currentType === 'plugin' ? '按类型、状态和关键词快速定位插件。'
: ($currentType === 'theme' ? '按类型、状态和关键词快速定位主题。' : '按类型、状态和关键词快速定位扩展。');
$listHint = $currentType === 'plugin' ? '支持查看插件详情、编辑元数据、上传 zip 发布版本,以及切换插件状态。'
: ($currentType === 'theme' ? '支持查看主题详情、编辑元数据、上传 zip 发布版本,以及切换主题状态。'
: '支持查看详情、编辑元数据、上传 zip 发布版本,以及切换扩展状态。');
$createHint = $currentType === 'plugin' ? '先创建插件 package,再进入详情页补充版本,或直接上传 zip 发布。'
: ($currentType === 'theme' ? '先创建主题 package,再进入详情页补充版本,或直接上传 zip 发布。'
: '先创建 package,再进入详情页补充版本,或直接上传 zip 发布。');
$emptyHint = '当前还没有' . $entityLabel . '。';
@endphp
@section('content')
<div class="grid">
<div class="panel">
<div class="section-title">
<div>
<h2>筛选与查询</h2>
<p>{{ $filterHint }}</p>
</div>
</div>
<form method="get" class="toolbar">
<div class="filters">
<div class="field">
<label>类型</label>
<select name="type" class="select">
<option value="">全部</option>
<option value="plugin" @selected($filters['type']==='plugin')>插件</option>
<option value="theme" @selected($filters['type']==='theme')>主题</option>
</select>
</div>
<div class="field">
<label>状态</label>
<select name="status" class="select">
<option value="">全部</option>
<option value="draft" @selected($filters['status']==='draft')>draft</option>
<option value="published" @selected($filters['status']==='published')>published</option>
<option value="hidden" @selected($filters['status']==='hidden')>hidden</option>
<option value="deprecated" @selected($filters['status']==='deprecated')>deprecated</option>
</select>
</div>
<div class="field" style="min-width:280px">
<label>关键词</label>
<input class="input" type="text" name="keyword" value="{{ $filters['keyword'] }}" placeholder="搜索 name / slug / summary">
</div>
</div>
<div class="form-actions">
<button class="btn" type="submit">筛选</button>
<a class="btn secondary" href="{{ route('webadmin.packages') }}">重置</a>
</div>
</form>
</div>
<div class="split">
<div class="panel">
<div class="section-title">
<div>
<h2>{{ $entityPluralLabel }}</h2>
<p>{{ $listHint }}</p>
</div>
</div>
<div class="table-wrap">
<table class="table">
<thead>
<tr>
<th>{{ $entityLabel }}</th>
<th>类型</th>
<th>状态</th>
<th>最新版本</th>
<th>分类</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@forelse ($packages as $package)
<tr>
<td>
<strong>{{ $package->name }}</strong>
<div class="muted">{{ $package->slug }}</div>
<div class="muted">{{ $package->summary ?: '暂无摘要' }}</div>
</td>
<td>{{ $package->type }}</td>
<td><span class="chip {{ $package->status === 'published' ? 'ok' : ($package->status === 'draft' ? 'muted' : 'warn') }}">{{ $package->status }}</span></td>
<td>{{ $package->latestStableVersion?->version ?: ($package->latest_version ?: '-') }}</td>
<td>
<div class="tags">
@foreach ($package->categories as $category)
<span class="chip">{{ $category->slug }}</span>
@endforeach
</div>
</td>
<td>
<div class="form-actions">
<a class="btn secondary small" href="{{ route('webadmin.packages.show', [$package->type, $package->slug]) }}">详情 / 发布</a>
<form method="post" action="{{ route('webadmin.packages.status', [$package->type, $package->slug]) }}">
@csrf @method('PATCH')
<input type="hidden" name="status" value="{{ $package->status === 'published' ? 'hidden' : 'published' }}">
<button class="btn ghost small" type="submit">{{ $package->status === 'published' ? '隐藏' : '发布' }}</button>
</form>
</div>
</td>
</tr>
@empty
<tr><td colspan="6"><div class="empty">{{ $emptyHint }}</div></td></tr>
@endforelse
</tbody>
</table>
</div>
<div style="margin-top:14px">{{ $packages->links() }}</div>
</div>
<div class="panel">
<div class="section-title">
<div>
<h2>{{ $newEntityLabel }}</h2>
<p>{{ $createHint }}</p>
</div>
</div>
<form method="post" action="{{ route('webadmin.packages.store') }}" class="grid">
@csrf
<div class="form-grid">
<div class="field">
<label>类型</label>
<select class="select" name="type" required>
<option value="plugin" @selected($currentType === 'plugin')>插件</option>
<option value="theme" @selected($currentType === 'theme')>主题</option>
</select>
</div>
<div class="field">
<label>Slug</label>
<input class="input" name="slug" placeholder="HelloStore" required>
</div>
<div class="field">
<label>名称</label>
<input class="input" name="name" placeholder="Hello Store" required>
</div>
<div class="field">
<label>状态</label>
<select class="select" name="status">
<option value="published">published</option>
<option value="draft">draft</option>
<option value="hidden">hidden</option>
<option value="deprecated">deprecated</option>
</select>
</div>
<div class="field">
<label>作者</label>
<input class="input" name="author" placeholder="LT083">
</div>
<div class="field">
<label>License</label>
<input class="input" name="license" placeholder="MIT">
</div>
</div>
<div class="field">
<label>摘要</label>
<input class="input" name="summary" placeholder="一句话说明这个{{ $entityLabel }}是做什么的">
</div>
<div class="field">
<label>描述</label>
<textarea name="description" placeholder="详细描述这个{{ $entityLabel }}的用途与定位"></textarea>
</div>
<div class="form-grid">
<div class="field">
<label>主页</label>
<input class="input" name="homepage" placeholder="https://example.com/package">
</div>
<div class="field">
<label>图标 URL</label>
<input class="input" name="icon_url" placeholder="https://example.com/icon.png">
</div>
</div>
<div class="field">
<label>分类 slug,多个用空格分隔</label>
<input class="input" name="categories_text" placeholder="seo performance">
</div>
<div class="form-actions">
<button class="btn" type="submit">创建{{ $entityLabel }}</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,171 @@
@extends('admin.layout', [
'title' => 'Tstore Admin · ' . $package->name,
'pageTitle' => $package->name,
'pageSubtitle' => ($package->type === 'plugin' ? '插件' : ($package->type === 'theme' ? '主题' : $package->type)) . ' · ' . $package->slug,
])
@php
$entityLabel = $package->type === 'plugin' ? '插件' : ($package->type === 'theme' ? '主题' : '扩展');
@endphp
@section('content')
<div class="grid">
<div class="split">
<div class="panel">
<div class="section-title">
<div>
<h2>{{ $entityLabel }}信息</h2>
<p>编辑基础元数据、分类、图标与发布状态。</p>
</div>
</div>
<form method="post" action="{{ route('webadmin.packages.update', [$package->type, $package->slug]) }}" class="grid">
@csrf @method('PUT')
<div class="form-grid">
<div class="field"><label>类型</label><input class="input" name="type" value="{{ $package->type }}" readonly></div>
<div class="field"><label>Slug</label><input class="input" name="slug" value="{{ $package->slug }}" readonly></div>
<div class="field"><label>名称</label><input class="input" name="name" value="{{ $package->name }}" required></div>
<div class="field"><label>状态</label>
<select class="select" name="status">
@foreach (['draft','published','hidden','deprecated'] as $status)
<option value="{{ $status }}" @selected($package->status === $status)>{{ $status }}</option>
@endforeach
</select>
</div>
<div class="field"><label>作者</label><input class="input" name="author" value="{{ $package->author }}"></div>
<div class="field"><label>License</label><input class="input" name="license" value="{{ $package->license }}"></div>
<div class="field"><label>主页</label><input class="input" name="homepage" value="{{ $package->homepage }}"></div>
<div class="field"><label>图标 URL</label><input class="input" name="icon_url" value="{{ $package->icon_url }}"></div>
</div>
<div class="field"><label>摘要</label><input class="input" name="summary" value="{{ $package->summary }}"></div>
<div class="field"><label>描述</label><textarea name="description">{{ $package->description }}</textarea></div>
<div class="field"><label>分类 slug,多个用逗号或空格分隔</label><input class="input" name="categories_text" value="{{ $package->categories->pluck('slug')->implode(', ') }}"></div>
<div class="form-actions">
<button class="btn" type="submit">保存{{ $entityLabel }}信息</button>
<a class="btn secondary" href="{{ route('webadmin.packages', ['type' => $package->type]) }}">返回{{ $entityLabel }}列表</a>
</div>
</form>
</div>
<div class="panel">
<div class="section-title">
<div>
<h2>当前状态</h2>
<p>快速查看分类、版本、下载与截图信息。</p>
</div>
</div>
<div class="list">
<div class="mini-card"><h3>状态</h3><div class="tags"><span class="chip {{ $package->status === 'published' ? 'ok' : 'warn' }}">{{ $package->status }}</span><span class="chip">下载 {{ $package->download_count }}</span><span class="chip {{ $package->is_featured ? 'ok' : 'muted' }}">{{ $package->is_featured ? '推荐' : '普通' }}</span></div></div>
<div class="mini-card"><h3>分类</h3><div class="tags">@forelse($package->categories as $category)<span class="chip">{{ $category->name }}</span>@empty<span class="muted">尚未关联分类</span>@endforelse</div></div>
<div class="mini-card"><h3>截图</h3><div class="muted">{{ $package->screenshots->count() }} </div></div>
<div class="mini-card"><h3>最新版本</h3><div class="muted">{{ $package->latest_version ?: '尚未发布' }}</div></div>
</div>
</div>
</div>
<div class="split">
<div class="panel">
<div class="section-title">
<div>
<h2>版本记录</h2>
<p>查看版本状态,也可以直接删除历史版本。</p>
</div>
</div>
<div class="table-wrap">
<table class="table">
<thead>
<tr>
<th>版本</th>
<th>稳定版</th>
<th>最新</th>
<th>兼容性</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@forelse ($package->versions as $version)
<tr>
<td>
<strong>{{ $version->version }}</strong>
<div class="muted">{{ $version->package_url ?: '未设置 package_url' }}</div>
</td>
<td><span class="chip {{ $version->is_stable ? 'ok' : 'warn' }}">{{ $version->is_stable ? '是' : '否' }}</span></td>
<td><span class="chip {{ $version->is_latest ? 'ok' : 'muted' }}">{{ $version->is_latest ? '最新' : '历史' }}</span></td>
<td>
<div class="muted">Typecho {{ $version->typecho_min ?: '-' }} ~ {{ $version->typecho_max ?: '-' }}</div>
<div class="muted">PHP {{ $version->php_min ?: '-' }} ~ {{ $version->php_max ?: '-' }}</div>
</td>
<td>{{ optional($version->published_at)->format('Y-m-d H:i') }}</td>
<td>
<form method="post" action="{{ route('webadmin.packages.versions.destroy', [$package->type, $package->slug, $version->id]) }}" onsubmit="return confirm('确认删除这个版本吗?');">
@csrf @method('DELETE')
<button class="btn danger small" type="submit">删除</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="6"><div class="empty">当前还没有版本记录。</div></td></tr>
@endforelse
</tbody>
</table>
</div>
</div>
<div class="panel">
<div class="section-title">
<div>
<h2>zip 上传发布</h2>
<p>直接调用 publishFromZip,按 manifest 自动生成版本。</p>
</div>
</div>
<form method="post" action="{{ route('webadmin.packages.publish', [$package->type, $package->slug]) }}" class="grid" enctype="multipart/form-data">
@csrf
<div class="field"><label>zip 文件</label><input class="input" type="file" name="package_file" accept=".zip" required></div>
<div class="field"><label>发布说明(可选)</label><textarea name="changelog" placeholder="补充这次发布说明"></textarea></div>
<div class="form-grid">
<div class="field"><label>发布时间(可选)</label><input class="input" type="datetime-local" name="published_at"></div>
<div class="field"><label>发布选项</label>
<div class="tags">
<label><input type="checkbox" name="is_stable" value="1" checked> 设为稳定版</label>
<label><input type="checkbox" name="mark_as_latest" value="1" checked> 设为最新</label>
</div>
</div>
</div>
<div class="form-actions"><button class="btn" type="submit">上传并发布</button></div>
</form>
</div>
</div>
<div class="panel">
<div class="section-title">
<div>
<h2>手动添加版本</h2>
<p>调试阶段可以快速手动录入版本元数据。</p>
</div>
</div>
<form method="post" action="{{ route('webadmin.packages.versions.store', [$package->type, $package->slug]) }}" class="grid">
@csrf
<div class="form-grid">
<div class="field"><label>版本号</label><input class="input" name="version" placeholder="1.0.0" required></div>
<div class="field"><label>发布时间</label><input class="input" type="datetime-local" name="published_at"></div>
<div class="field"><label>Typecho Min</label><input class="input" name="typecho_min" placeholder="1.2.0"></div>
<div class="field"><label>Typecho Max</label><input class="input" name="typecho_max" placeholder="1.3.*"></div>
<div class="field"><label>PHP Min</label><input class="input" name="php_min" placeholder="7.4"></div>
<div class="field"><label>PHP Max</label><input class="input" name="php_max" placeholder="8.3"></div>
<div class="field"><label>Package URL</label><input class="input" name="package_url" placeholder="https://..."></div>
<div class="field"><label>Size</label><input class="input" name="package_size" type="number" placeholder="238000"></div>
<div class="field"><label>SHA256</label><input class="input" name="sha256" placeholder="可选,默认会补 64 位 0"></div>
<div class="field"><label>PHP Extensions</label><input class="input" name="php_extensions" placeholder="curl,json"></div>
</div>
<div class="field"><label>发布说明</label><textarea name="changelog" placeholder="输入更新内容"></textarea></div>
<div class="form-grid">
<label><input type="checkbox" name="is_stable" value="1"> 设为稳定版</label>
<label><input type="checkbox" name="is_latest" value="1"> 设为最新版本</label>
</div>
<div class="form-actions">
<button class="btn" type="submit">添加版本</button>
</div>
</form>
</div>
</div>
@endsection