chore: init saasshop repo + sql migrations runner + gitee go
This commit is contained in:
74
resources/views/admin/plans/form.blade.php
Normal file
74
resources/views/admin/plans/form.blade.php
Normal file
@@ -0,0 +1,74 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', $plan->exists ? '编辑套餐' : '新建套餐')
|
||||
@section('page_title', $plan->exists ? '编辑套餐' : '新建套餐')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p class="muted muted-tight">套餐是平台授权与收费的基础单位,这里维护套餐的基本信息与售卖口径。</p>
|
||||
<p class="muted">当前阶段先提交套餐主数据,后续再补授权项、配额与订阅联动。</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="{{ $formAction }}" class="card form-grid">
|
||||
@csrf
|
||||
|
||||
<label>
|
||||
<span>套餐名称</span>
|
||||
<input name="name" value="{{ old('name', $plan->name) }}" required>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>套餐编码</span>
|
||||
<input name="code" value="{{ old('code', $plan->code) }}" required>
|
||||
<small class="muted">仅限字母、数字、短横线和下划线,用于接口/内部引用。</small>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>计费周期</span>
|
||||
<select name="billing_cycle" required>
|
||||
@foreach($billingCycleLabels as $value => $label)
|
||||
<option value="{{ $value }}" @selected(old('billing_cycle', $plan->billing_cycle) === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>售价</span>
|
||||
<input type="number" step="0.01" min="0" name="price" value="{{ old('price', $plan->price) }}" required>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>划线价</span>
|
||||
<input type="number" step="0.01" min="0" name="list_price" value="{{ old('list_price', $plan->list_price) }}">
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>状态</span>
|
||||
<select name="status" required>
|
||||
@foreach($statusLabels as $value => $label)
|
||||
<option value="{{ $value }}" @selected(old('status', $plan->status) === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>排序</span>
|
||||
<input type="number" min="0" name="sort" value="{{ old('sort', $plan->sort ?? 0) }}">
|
||||
</label>
|
||||
|
||||
<label class="full">
|
||||
<span>发布时间</span>
|
||||
<input type="datetime-local" name="published_at" value="{{ old('published_at', optional($plan->published_at)->format('Y-m-d\TH:i')) }}">
|
||||
</label>
|
||||
|
||||
<label class="full">
|
||||
<span>套餐说明</span>
|
||||
<textarea name="description" rows="4" placeholder="可描述套餐包含的能力与适用场景">{{ old('description', $plan->description) }}</textarea>
|
||||
</label>
|
||||
|
||||
<div class="form-actions">
|
||||
<a href="/admin/plans" class="btn-secondary">返回</a>
|
||||
<button type="submit">保存套餐</button>
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
139
resources/views/admin/plans/index.blade.php
Normal file
139
resources/views/admin/plans/index.blade.php
Normal file
@@ -0,0 +1,139 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('title', '套餐管理')
|
||||
@section('page_title', '套餐管理')
|
||||
|
||||
@section('content')
|
||||
<div class="card mb-20">
|
||||
<p class="muted muted-tight">这里是总台视角的套餐目录页,用于沉淀平台可售卖的标准能力包。</p>
|
||||
<p class="muted">当前阶段先完成套餐主数据可见、可筛与口径收拢,后续再接授权项、售价规则与上下架动作。</p>
|
||||
</div>
|
||||
|
||||
<div class="card mb-20">
|
||||
<h3>工具</h3>
|
||||
<form method="get" action="/admin/plans/export">
|
||||
<input type="hidden" name="status" value="{{ $filters['status'] ?? '' }}">
|
||||
<input type="hidden" name="published" value="{{ $filters['published'] ?? '' }}">
|
||||
<input type="hidden" name="billing_cycle" value="{{ $filters['billing_cycle'] ?? '' }}">
|
||||
<input type="hidden" name="keyword" value="{{ $filters['keyword'] ?? '' }}">
|
||||
<button type="submit">导出当前筛选结果(CSV)</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card mb-20">
|
||||
<h3>筛选条件</h3>
|
||||
<form method="get" action="/admin/plans" class="grid-3">
|
||||
<select name="status">
|
||||
<option value="">全部状态</option>
|
||||
@foreach(($filterOptions['statuses'] ?? []) as $value => $label)
|
||||
<option value="{{ $value }}" @selected(($filters['status'] ?? '') === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<select name="published">
|
||||
<option value="">全部发布状态</option>
|
||||
<option value="published" @selected(($filters['published'] ?? '') === 'published')>已发布</option>
|
||||
<option value="unpublished" @selected(($filters['published'] ?? '') === 'unpublished')>未发布</option>
|
||||
</select>
|
||||
<select name="billing_cycle">
|
||||
<option value="">全部计费周期</option>
|
||||
@foreach(($filterOptions['billingCycles'] ?? []) as $value => $label)
|
||||
<option value="{{ $value }}" @selected(($filters['billing_cycle'] ?? '') === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<input name="keyword" placeholder="搜索套餐名称 / 编码 / 描述" value="{{ $filters['keyword'] ?? '' }}">
|
||||
<div>
|
||||
<button type="submit">应用筛选</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid-4 mb-20">
|
||||
<div class="card">
|
||||
<h3>套餐总数</h3>
|
||||
<div class="num-md">{{ $summaryStats['total_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>启用中套餐</h3>
|
||||
<div class="num-md">{{ $summaryStats['active_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>月付套餐</h3>
|
||||
<div class="num-md">{{ $summaryStats['monthly_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>年付套餐</h3>
|
||||
<div class="num-md">{{ $summaryStats['yearly_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>已发布</h3>
|
||||
<div class="num-md">{{ $summaryStats['published_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>未发布</h3>
|
||||
<div class="num-md">{{ $summaryStats['unpublished_plans'] ?? 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="flex-between">
|
||||
<div>
|
||||
<h3>套餐列表</h3>
|
||||
<p class="muted muted-xs">后续将从这里进入套餐详情、授权项与订阅联动。</p>
|
||||
</div>
|
||||
<a href="/admin/plans/create" class="btn">新建套餐</a>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>套餐名称</th>
|
||||
<th>编码</th>
|
||||
<th>计费周期</th>
|
||||
<th>售价</th>
|
||||
<th>划线价</th>
|
||||
<th>状态</th>
|
||||
<th>排序</th>
|
||||
<th>发布时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($plans as $plan)
|
||||
<tr>
|
||||
<td>{{ $plan->id }}</td>
|
||||
<td>
|
||||
<strong>{{ $plan->name }}</strong>
|
||||
<div class="muted muted-xs">{{ $plan->description ?: '暂无说明' }}</div>
|
||||
</td>
|
||||
<td>{{ $plan->code }}</td>
|
||||
<td>{{ $billingCycleLabels[$plan->billing_cycle] ?? $plan->billing_cycle }}</td>
|
||||
<td>¥{{ number_format((float) $plan->price, 2) }}</td>
|
||||
<td>¥{{ number_format((float) $plan->list_price, 2) }}</td>
|
||||
<td>{{ $statusLabels[$plan->status] ?? $plan->status }}</td>
|
||||
<td>{{ $plan->sort }}</td>
|
||||
<td>{{ optional($plan->published_at)->format('Y-m-d H:i:s') ?: '-' }}</td>
|
||||
<td>
|
||||
<a href="/admin/plans/{{ $plan->id }}/edit" class="link">编辑</a>
|
||||
|
||||
<form method="post" action="/admin/plans/{{ $plan->id }}/set-status" style="margin-top:6px;">
|
||||
@csrf
|
||||
<select name="status" onchange="this.form.submit()" style="width:140px;">
|
||||
@foreach(($filterOptions['statuses'] ?? []) as $value => $label)
|
||||
<option value="{{ $value }}" @selected($plan->status === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<noscript><button type="submit">更新状态</button></noscript>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="10" class="muted">暂无套餐数据,当前阶段先把套餐主表与总台目录立起来,后续可继续接套餐创建、授权项与订阅关联。</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">{{ $plans->links() }}</div>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user