M5: Workerman 常驻服务 + AI 审核/润色插件 + 支付插件(支付宝/微信/沙箱)+ 会员插件(套餐/订阅/付费文章)

This commit is contained in:
ak
2026-08-11 18:29:35 +08:00
parent f77c96d3aa
commit 1d1df43cee
52 changed files with 1914 additions and 20 deletions
@@ -0,0 +1,83 @@
<?php
namespace Plugins\Neatstudio\Payment\Filament\Pages;
use App\Models\Setting;
use Filament\Actions\Action;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Schema;
class PaymentSettings extends Page
{
use InteractsWithForms;
protected static \UnitEnum|string|null $navigationGroup = '管理';
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-credit-card';
protected static ?string $navigationLabel = '支付设置';
protected string $view = 'filament.pages.plugin-settings';
public array $data = [];
public function mount(): void
{
$this->form->fill([
'pay_sandbox' => (int) Setting::get('pay_sandbox', 1) === 1,
'pay_alipay_app_id' => Setting::get('pay_alipay_app_id', ''),
'pay_alipay_app_secret' => Setting::get('pay_alipay_app_secret', ''),
'pay_wechat_app_id' => Setting::get('pay_wechat_app_id', ''),
'pay_wechat_mch_id' => Setting::get('pay_wechat_mch_id', ''),
'pay_wechat_mch_secret' => Setting::get('pay_wechat_mch_secret', ''),
]);
}
public function form(Schema $schema): Schema
{
return $schema
->components([
Section::make('通用')
->schema([
Toggle::make('pay_sandbox')->label('沙箱模式(无需真实密钥即可测试支付流程)')->default(true),
]),
Section::make('支付宝')
->columns(2)
->schema([
TextInput::make('pay_alipay_app_id')->label('App ID')->columnSpanFull(),
TextInput::make('pay_alipay_app_secret')->label('应用私钥(app_secret_cert')->password()->columnSpanFull(),
]),
Section::make('微信支付')
->columns(2)
->schema([
TextInput::make('pay_wechat_app_id')->label('App ID'),
TextInput::make('pay_wechat_mch_id')->label('商户号 MCH ID'),
TextInput::make('pay_wechat_mch_secret')->label('API 密钥')->password()->columnSpanFull(),
]),
])
->statePath('data');
}
public function save(): void
{
$data = $this->form->getState();
foreach ($data as $key => $value) {
Setting::set($key, is_bool($value) ? (string) (int) $value : (string) $value);
}
Notification::make()->title('支付设置已保存')->success()->send();
}
protected function getFormActions(): array
{
return [
Action::make('save')->label('保存')->submit('save'),
];
}
}
@@ -0,0 +1,11 @@
<?php
namespace Plugins\Neatstudio\Payment\Filament\Resources\Pages;
use Filament\Resources\Pages\ListRecords;
use Plugins\Neatstudio\Payment\Filament\Resources\PaymentResource;
class ListPayments extends ListRecords
{
protected static string $resource = PaymentResource::class;
}
@@ -0,0 +1,77 @@
<?php
namespace Plugins\Neatstudio\Payment\Filament\Resources;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Plugins\Neatstudio\Payment\Filament\Resources\Pages\ListPayments;
use Plugins\Neatstudio\Payment\Models\Payment;
class PaymentResource extends Resource
{
protected static \UnitEnum|string|null $navigationGroup = '管理';
protected static ?string $model = Payment::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedBanknotes;
protected static ?string $navigationLabel = '订单';
public static function form(Schema $schema): Schema
{
return $schema
->components([
\Filament\Forms\Components\TextInput::make('order_no')->label('订单号')->disabled(),
\Filament\Forms\Components\TextInput::make('subject')->label('商品')->disabled(),
\Filament\Forms\Components\TextInput::make('amount')->label('金额(分)')->numeric()->disabled(),
\Filament\Forms\Components\TextInput::make('channel')->label('渠道')->disabled(),
\Filament\Forms\Components\TextInput::make('status')->label('状态')->disabled(),
\Filament\Forms\Components\DateTimePicker::make('paid_at')->label('支付时间')->disabled(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
\Filament\Tables\Columns\TextColumn::make('order_no')->label('订单号')->searchable(),
\Filament\Tables\Columns\TextColumn::make('user.name')->label('用户'),
\Filament\Tables\Columns\TextColumn::make('subject')->label('商品')->limit(30),
\Filament\Tables\Columns\TextColumn::make('amount')->label('金额')
->formatStateUsing(fn ($state) => '¥'.number_format((float) $state / 100, 2)),
\Filament\Tables\Columns\TextColumn::make('channel')->label('渠道')->badge(),
\Filament\Tables\Columns\TextColumn::make('status')->label('状态')
->badge()
->formatStateUsing(fn ($state) => match ($state) {
'paid' => '已支付',
'pending' => '待支付',
'failed' => '失败',
'closed' => '已关闭',
default => $state,
})
->color(fn ($state) => match ($state) {
'paid' => 'success',
'pending' => 'warning',
default => 'gray',
}),
\Filament\Tables\Columns\TextColumn::make('paid_at')->label('支付时间')->dateTime('Y-m-d H:i'),
\Filament\Tables\Columns\TextColumn::make('created_at')->label('创建时间')->dateTime('Y-m-d H:i'),
])
->filters([
\Filament\Tables\Filters\SelectFilter::make('status')
->options(['paid' => '已支付', 'pending' => '待支付', 'failed' => '失败', 'closed' => '已关闭']),
])
->recordActions([])
->defaultSort('created_at', 'desc');
}
public static function getPages(): array
{
return [
'index' => ListPayments::route('/'),
];
}
}