丰富基础代码

This commit is contained in:
技术老胡
2026-03-10 18:39:22 +08:00
parent 9de902231f
commit add2c49272
17 changed files with 931 additions and 14 deletions

View File

@@ -41,6 +41,30 @@ class BaseController
]);
}
/**
* 统一分页返回结构
*
* @param mixed $paginator Laravel/Eloquent paginator
*/
protected function page(mixed $paginator): Response
{
if (!is_object($paginator) || !method_exists($paginator, 'items')) {
return $this->success([
'list' => [],
'total' => 0,
'page' => 1,
'size' => 10,
]);
}
return $this->success([
'list' => $paginator->items(),
'total' => $paginator->total(),
'page' => $paginator->currentPage(),
'size' => $paginator->perPage(),
]);
}
/**
* 获取当前登录用户的 token 载荷
*

View File

@@ -62,11 +62,8 @@ abstract class BaseRepository
{
$query = $this->model->newQuery();
foreach ($where as $field => $value) {
if ($value === null || $value === '') {
continue;
}
$query->where($field, $value);
if (!empty($where)) {
$query->where($where);
}
return $query->paginate($pageSize, $columns, 'page', $page);

View File

@@ -0,0 +1,177 @@
<?php
namespace app\http\admin\controller;
use app\common\base\BaseController;
use app\repositories\MerchantAppRepository;
use app\repositories\MerchantRepository;
use support\Request;
/**
* 商户应用管理
*/
class MerchantAppController extends BaseController
{
public function __construct(
protected MerchantAppRepository $merchantAppRepository,
protected MerchantRepository $merchantRepository,
) {
}
/**
* GET /adminapi/merchant-app/list
*/
public function list(Request $request)
{
$page = (int)$request->get('page', 1);
$pageSize = (int)$request->get('page_size', 10);
$filters = [
'merchant_id' => (int)$request->get('merchant_id', 0),
'status' => $request->get('status', ''),
'app_id' => trim((string)$request->get('app_id', '')),
'app_name' => trim((string)$request->get('app_name', '')),
'api_type' => trim((string)$request->get('api_type', '')),
];
$paginator = $this->merchantAppRepository->searchPaginate($filters, $page, $pageSize);
return $this->page($paginator);
}
/**
* GET /adminapi/merchant-app/detail?id=1
*/
public function detail(Request $request)
{
$id = (int)$request->get('id', 0);
if ($id <= 0) {
return $this->fail('应用ID不能为空', 400);
}
$row = $this->merchantAppRepository->find($id);
if (!$row) {
return $this->fail('应用不存在', 404);
}
return $this->success($row);
}
/**
* POST /adminapi/merchant-app/save
*/
public function save(Request $request)
{
$data = $request->post();
$id = (int)($data['id'] ?? 0);
$merchantId = (int)($data['merchant_id'] ?? 0);
$apiType = trim((string)($data['api_type'] ?? 'epay'));
$appId = trim((string)($data['app_id'] ?? ''));
$appName = trim((string)($data['app_name'] ?? ''));
$status = (int)($data['status'] ?? 1);
if ($merchantId <= 0 || $appId === '' || $appName === '') {
return $this->fail('商户、应用ID、应用名称不能为空', 400);
}
$merchant = $this->merchantRepository->find($merchantId);
if (!$merchant) {
return $this->fail('商户不存在', 404);
}
if (!in_array($apiType, ['openapi', 'epay', 'custom', 'default'], true)) {
return $this->fail('api_type 不合法', 400);
}
if ($id > 0) {
$row = $this->merchantAppRepository->find($id);
if (!$row) {
return $this->fail('应用不存在', 404);
}
// app_id 变更需校验唯一
if ($row->app_id !== $appId) {
$exists = $this->merchantAppRepository->findAnyByAppId($appId);
if ($exists) {
return $this->fail('应用ID已存在', 400);
}
}
$update = [
'merchant_id' => $merchantId,
'api_type' => $apiType,
'app_id' => $appId,
'app_name' => $appName,
'status' => $status,
];
// 可选:前端传入 app_secret 才更新
if (!empty($data['app_secret'])) {
$update['app_secret'] = (string)$data['app_secret'];
}
$this->merchantAppRepository->updateById($id, $update);
} else {
$exists = $this->merchantAppRepository->findAnyByAppId($appId);
if ($exists) {
return $this->fail('应用ID已存在', 400);
}
$secret = !empty($data['app_secret']) ? (string)$data['app_secret'] : $this->generateSecret();
$this->merchantAppRepository->create([
'merchant_id' => $merchantId,
'api_type' => $apiType,
'app_id' => $appId,
'app_secret' => $secret,
'app_name' => $appName,
'status' => $status,
]);
}
return $this->success(null, '保存成功');
}
/**
* POST /adminapi/merchant-app/reset-secret
*/
public function resetSecret(Request $request)
{
$id = (int)$request->post('id', 0);
if ($id <= 0) {
return $this->fail('应用ID不能为空', 400);
}
$row = $this->merchantAppRepository->find($id);
if (!$row) {
return $this->fail('应用不存在', 404);
}
$secret = $this->generateSecret();
$this->merchantAppRepository->updateById($id, ['app_secret' => $secret]);
return $this->success(['app_secret' => $secret], '重置成功');
}
/**
* POST /adminapi/merchant-app/toggle
*/
public function toggle(Request $request)
{
$id = (int)$request->post('id', 0);
$status = $request->post('status', null);
if ($id <= 0 || $status === null) {
return $this->fail('参数错误', 400);
}
$ok = $this->merchantAppRepository->updateById($id, ['status' => (int)$status]);
return $ok ? $this->success(null, '操作成功') : $this->fail('操作失败', 500);
}
private function generateSecret(): string
{
$raw = random_bytes(24);
return rtrim(strtr(base64_encode($raw), '+/', '-_'), '=');
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace app\http\admin\controller;
use app\common\base\BaseController;
use app\repositories\MerchantRepository;
use support\Request;
/**
* 商户管理
*/
class MerchantController extends BaseController
{
public function __construct(
protected MerchantRepository $merchantRepository,
) {
}
/**
* GET /adminapi/merchant/list
*/
public function list(Request $request)
{
$page = (int)$request->get('page', 1);
$pageSize = (int)$request->get('page_size', 10);
$filters = [
'status' => $request->get('status', ''),
'merchant_no' => trim((string)$request->get('merchant_no', '')),
'merchant_name' => trim((string)$request->get('merchant_name', '')),
];
$paginator = $this->merchantRepository->searchPaginate($filters, $page, $pageSize);
return $this->page($paginator);
}
/**
* GET /adminapi/merchant/detail?id=1
*/
public function detail(Request $request)
{
$id = (int)$request->get('id', 0);
if ($id <= 0) {
return $this->fail('商户ID不能为空', 400);
}
$row = $this->merchantRepository->find($id);
if (!$row) {
return $this->fail('商户不存在', 404);
}
return $this->success($row);
}
/**
* POST /adminapi/merchant/save
*/
public function save(Request $request)
{
$data = $request->post();
$id = (int)($data['id'] ?? 0);
$merchantNo = trim((string)($data['merchant_no'] ?? ''));
$merchantName = trim((string)($data['merchant_name'] ?? ''));
$fundsMode = trim((string)($data['funds_mode'] ?? 'direct'));
$status = (int)($data['status'] ?? 1);
if ($merchantNo === '' || $merchantName === '') {
return $this->fail('商户号与商户名称不能为空', 400);
}
if (!in_array($fundsMode, ['direct', 'wallet', 'hybrid'], true)) {
return $this->fail('资金模式不合法', 400);
}
if ($id > 0) {
$this->merchantRepository->updateById($id, [
'merchant_no' => $merchantNo,
'merchant_name' => $merchantName,
'funds_mode' => $fundsMode,
'status' => $status,
]);
} else {
$exists = $this->merchantRepository->findByMerchantNo($merchantNo);
if ($exists) {
return $this->fail('商户号已存在', 400);
}
$this->merchantRepository->create([
'merchant_no' => $merchantNo,
'merchant_name' => $merchantName,
'funds_mode' => $fundsMode,
'status' => $status,
]);
}
return $this->success(null, '保存成功');
}
/**
* POST /adminapi/merchant/toggle
*/
public function toggle(Request $request)
{
$id = (int)$request->post('id', 0);
$status = $request->post('status', null);
if ($id <= 0 || $status === null) {
return $this->fail('参数错误', 400);
}
$ok = $this->merchantRepository->updateById($id, ['status' => (int)$status]);
return $ok ? $this->success(null, '操作成功') : $this->fail('操作失败', 500);
}
}

View File

@@ -0,0 +1,100 @@
<?php
namespace app\http\admin\controller;
use app\common\base\BaseController;
use app\repositories\PaymentMethodRepository;
use app\repositories\PaymentOrderRepository;
use app\services\PayOrderService;
use support\Request;
/**
* 订单管理
*/
class OrderController extends BaseController
{
public function __construct(
protected PaymentOrderRepository $orderRepository,
protected PaymentMethodRepository $methodRepository,
protected PayOrderService $payOrderService,
) {
}
/**
* GET /adminapi/order/list
*/
public function list(Request $request)
{
$page = (int)$request->get('page', 1);
$pageSize = (int)$request->get('page_size', 10);
$methodCode = trim((string)$request->get('method_code', ''));
$methodId = 0;
if ($methodCode !== '') {
$method = $this->methodRepository->findAnyByCode($methodCode);
$methodId = $method ? (int)$method->id : 0;
}
$filters = [
'merchant_id' => (int)$request->get('merchant_id', 0),
'merchant_app_id' => (int)$request->get('merchant_app_id', 0),
'method_id' => $methodId,
'channel_id' => (int)$request->get('channel_id', 0),
'status' => $request->get('status', ''),
'order_id' => trim((string)$request->get('order_id', '')),
'mch_order_no' => trim((string)$request->get('mch_order_no', '')),
'created_from' => trim((string)$request->get('created_from', '')),
'created_to' => trim((string)$request->get('created_to', '')),
];
$paginator = $this->orderRepository->searchPaginate($filters, $page, $pageSize);
return $this->page($paginator);
}
/**
* GET /adminapi/order/detail?id=1 或 order_id=P...
*/
public function detail(Request $request)
{
$id = (int)$request->get('id', 0);
$orderId = trim((string)$request->get('order_id', ''));
if ($id > 0) {
$row = $this->orderRepository->find($id);
} elseif ($orderId !== '') {
$row = $this->orderRepository->findByOrderId($orderId);
} else {
return $this->fail('参数错误', 400);
}
if (!$row) {
return $this->fail('订单不存在', 404);
}
return $this->success($row);
}
/**
* POST /adminapi/order/refund
* - order_id: 系统订单号
* - refund_amount: 退款金额
*/
public function refund(Request $request)
{
$orderId = trim((string)$request->post('order_id', ''));
$refundAmount = (float)$request->post('refund_amount', 0);
$refundReason = trim((string)$request->post('refund_reason', ''));
try {
$result = $this->payOrderService->refundOrder([
'order_id' => $orderId,
'refund_amount' => $refundAmount,
'refund_reason' => $refundReason,
]);
return $this->success($result, '退款发起成功');
} catch (\Throwable $e) {
return $this->fail($e->getMessage(), 400);
}
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace app\http\admin\controller;
use app\common\base\BaseController;
use app\repositories\PaymentMethodRepository;
use support\Request;
/**
* 支付方式管理
*/
class PayMethodController extends BaseController
{
public function __construct(
protected PaymentMethodRepository $methodRepository,
) {
}
/**
* GET /adminapi/pay-method/list
*/
public function list(Request $request)
{
$page = (int)$request->get('page', 1);
$pageSize = (int)$request->get('page_size', 10);
$filters = [
'status' => $request->get('status', ''),
'method_code' => trim((string)$request->get('method_code', '')),
'method_name' => trim((string)$request->get('method_name', '')),
];
$paginator = $this->methodRepository->searchPaginate($filters, $page, $pageSize);
return $this->page($paginator);
}
/**
* POST /adminapi/pay-method/save
*/
public function save(Request $request)
{
$data = $request->post();
$id = (int)($data['id'] ?? 0);
$code = trim((string)($data['method_code'] ?? ''));
$name = trim((string)($data['method_name'] ?? ''));
$icon = trim((string)($data['icon'] ?? ''));
$sort = (int)($data['sort'] ?? 0);
$status = (int)($data['status'] ?? 1);
if ($code === '' || $name === '') {
return $this->fail('支付方式编码与名称不能为空', 400);
}
if ($id > 0) {
$this->methodRepository->updateById($id, [
'method_code' => $code,
'method_name' => $name,
'icon' => $icon,
'sort' => $sort,
'status' => $status,
]);
} else {
$exists = $this->methodRepository->findAnyByCode($code);
if ($exists) {
return $this->fail('支付方式编码已存在', 400);
}
$this->methodRepository->create([
'method_code' => $code,
'method_name' => $name,
'icon' => $icon,
'sort' => $sort,
'status' => $status,
]);
}
return $this->success(null, '保存成功');
}
/**
* POST /adminapi/pay-method/toggle
*/
public function toggle(Request $request)
{
$id = (int)$request->post('id', 0);
$status = $request->post('status', null);
if ($id <= 0 || $status === null) {
return $this->fail('参数错误', 400);
}
$ok = $this->methodRepository->updateById($id, ['status' => (int)$status]);
return $ok ? $this->success(null, '操作成功') : $this->fail('操作失败', 500);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace app\http\admin\controller;
use app\common\base\BaseController;
use app\repositories\PaymentPluginRepository;
use support\Request;
/**
* 插件注册表管理ma_pay_plugin
*
* 注意:与 /channel/plugin/* 的“插件能力读取schema/products”不同这里负责维护插件注册表本身。
*/
class PayPluginController extends BaseController
{
public function __construct(
protected PaymentPluginRepository $pluginRepository,
) {
}
/**
* GET /adminapi/pay-plugin/list
*/
public function list(Request $request)
{
$page = (int)$request->get('page', 1);
$pageSize = (int)$request->get('page_size', 10);
$filters = [
'status' => $request->get('status', ''),
'plugin_code' => trim((string)$request->get('plugin_code', '')),
'plugin_name' => trim((string)$request->get('plugin_name', '')),
];
$paginator = $this->pluginRepository->searchPaginate($filters, $page, $pageSize);
return $this->page($paginator);
}
/**
* POST /adminapi/pay-plugin/save
*/
public function save(Request $request)
{
$data = $request->post();
$pluginCode = trim((string)($data['plugin_code'] ?? ''));
$pluginName = trim((string)($data['plugin_name'] ?? ''));
$className = trim((string)($data['class_name'] ?? ''));
$status = (int)($data['status'] ?? 1);
if ($pluginCode === '' || $pluginName === '') {
return $this->fail('插件编码与名称不能为空', 400);
}
if ($className === '') {
// 默认约定类名
$className = 'app\\common\\payment\\' . ucfirst($pluginCode) . 'Payment';
}
$this->pluginRepository->upsertByCode($pluginCode, [
'plugin_name' => $pluginName,
'class_name' => $className,
'status' => $status,
]);
return $this->success(null, '保存成功');
}
/**
* POST /adminapi/pay-plugin/toggle
*/
public function toggle(Request $request)
{
$pluginCode = trim((string)$request->post('plugin_code', ''));
$status = $request->post('status', null);
if ($pluginCode === '' || $status === null) {
return $this->fail('参数错误', 400);
}
$ok = $this->pluginRepository->updateStatus($pluginCode, (int)$status);
return $ok ? $this->success(null, '操作成功') : $this->fail('操作失败', 500);
}
}

View File

@@ -37,5 +37,43 @@ class MerchantAppRepository extends BaseRepository
->where('status', 1)
->first();
}
/**
* 后台按 app_id 查询(不过滤状态)
*/
public function findAnyByAppId(string $appId): ?MerchantApp
{
return $this->model->newQuery()
->where('app_id', $appId)
->first();
}
/**
* 后台列表:支持筛选与模糊搜索
*/
public function searchPaginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
$query = $this->model->newQuery();
if (!empty($filters['merchant_id'])) {
$query->where('merchant_id', (int)$filters['merchant_id']);
}
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
$query->where('status', (int)$filters['status']);
}
if (!empty($filters['app_id'])) {
$query->where('app_id', 'like', '%' . $filters['app_id'] . '%');
}
if (!empty($filters['app_name'])) {
$query->where('app_name', 'like', '%' . $filters['app_name'] . '%');
}
if (!empty($filters['api_type'])) {
$query->where('api_type', (string)$filters['api_type']);
}
$query->orderByDesc('id');
return $query->paginate($pageSize, ['*'], 'page', $page);
}
}

View File

@@ -24,5 +24,27 @@ class MerchantRepository extends BaseRepository
->where('merchant_no', $merchantNo)
->first();
}
/**
* 后台列表:支持模糊搜索
*/
public function searchPaginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
$query = $this->model->newQuery();
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
$query->where('status', (int)$filters['status']);
}
if (!empty($filters['merchant_no'])) {
$query->where('merchant_no', 'like', '%' . $filters['merchant_no'] . '%');
}
if (!empty($filters['merchant_name'])) {
$query->where('merchant_name', 'like', '%' . $filters['merchant_name'] . '%');
}
$query->orderByDesc('id');
return $query->paginate($pageSize, ['*'], 'page', $page);
}
}

View File

@@ -31,4 +31,36 @@ class PaymentMethodRepository extends BaseRepository
->where('status', 1)
->first();
}
/**
* 后台按 code 查询(不过滤状态)
*/
public function findAnyByCode(string $methodCode): ?PaymentMethod
{
return $this->model->newQuery()
->where('method_code', $methodCode)
->first();
}
/**
* 后台列表:支持筛选与排序
*/
public function searchPaginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
$query = $this->model->newQuery();
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
$query->where('status', (int)$filters['status']);
}
if (!empty($filters['method_code'])) {
$query->where('method_code', 'like', '%' . $filters['method_code'] . '%');
}
if (!empty($filters['method_name'])) {
$query->where('method_name', 'like', '%' . $filters['method_name'] . '%');
}
$query->orderBy('sort', 'asc')->orderByDesc('id');
return $query->paginate($pageSize, ['*'], 'page', $page);
}
}

View File

@@ -53,4 +53,43 @@ class PaymentOrderRepository extends BaseRepository
}
return $this->updateById($order->id, $data);
}
/**
* 后台订单列表:支持筛选与模糊搜索
*/
public function searchPaginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
$query = $this->model->newQuery();
if (!empty($filters['merchant_id'])) {
$query->where('merchant_id', (int)$filters['merchant_id']);
}
if (!empty($filters['merchant_app_id'])) {
$query->where('merchant_app_id', (int)$filters['merchant_app_id']);
}
if (!empty($filters['method_id'])) {
$query->where('method_id', (int)$filters['method_id']);
}
if (!empty($filters['channel_id'])) {
$query->where('channel_id', (int)$filters['channel_id']);
}
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
$query->where('status', (int)$filters['status']);
}
if (!empty($filters['order_id'])) {
$query->where('order_id', 'like', '%' . $filters['order_id'] . '%');
}
if (!empty($filters['mch_order_no'])) {
$query->where('mch_order_no', 'like', '%' . $filters['mch_order_no'] . '%');
}
if (!empty($filters['created_from'])) {
$query->where('created_at', '>=', $filters['created_from']);
}
if (!empty($filters['created_to'])) {
$query->where('created_at', '<=', $filters['created_to']);
}
$query->orderByDesc('id');
return $query->paginate($pageSize, ['*'], 'page', $page);
}
}

View File

@@ -29,4 +29,61 @@ class PaymentPluginRepository extends BaseRepository
->where('status', 1)
->first();
}
/**
* 后台按编码查询(不过滤状态)
*/
public function findByCode(string $pluginCode): ?PaymentPlugin
{
return $this->model->newQuery()
->where('plugin_code', $pluginCode)
->first();
}
/**
* 后台列表:支持筛选与模糊搜索
*/
public function searchPaginate(array $filters = [], int $page = 1, int $pageSize = 10)
{
$query = $this->model->newQuery();
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
$query->where('status', (int)$filters['status']);
}
if (!empty($filters['plugin_code'])) {
$query->where('plugin_code', 'like', '%' . $filters['plugin_code'] . '%');
}
if (!empty($filters['plugin_name'])) {
$query->where('plugin_name', 'like', '%' . $filters['plugin_name'] . '%');
}
$query->orderByDesc('created_at');
return $query->paginate($pageSize, ['*'], 'page', $page);
}
/**
* 后台保存:存在则更新,不存在则创建
*/
public function upsertByCode(string $pluginCode, array $data): PaymentPlugin
{
$row = $this->findByCode($pluginCode);
if ($row) {
$this->model->newQuery()
->where('plugin_code', $pluginCode)
->update($data);
return $this->findByCode($pluginCode) ?: $row;
}
$data['plugin_code'] = $pluginCode;
/** @var PaymentPlugin $created */
$created = $this->create($data);
return $created;
}
public function updateStatus(string $pluginCode, int $status): bool
{
return (bool)$this->model->newQuery()
->where('plugin_code', $pluginCode)
->update(['status' => $status]);
}
}

View File

@@ -14,6 +14,11 @@ use app\http\admin\controller\MenuController;
use app\http\admin\controller\SystemController;
use app\http\admin\controller\ChannelController;
use app\http\admin\controller\PluginController;
use app\http\admin\controller\MerchantController;
use app\http\admin\controller\MerchantAppController;
use app\http\admin\controller\PayMethodController;
use app\http\admin\controller\PayPluginController;
use app\http\admin\controller\OrderController;
use app\common\middleware\Cors;
use app\http\admin\middleware\AuthMiddleware;
@@ -47,5 +52,33 @@ Route::group('/adminapi', function () {
Route::get('/channel/plugins', [PluginController::class, 'plugins'])->name('plugins')->setParams(['real_name' => '获取插件列表']);
Route::get('/channel/plugin/config-schema', [PluginController::class, 'configSchema'])->name('configSchema')->setParams(['real_name' => '获取插件配置schema']);
Route::get('/channel/plugin/products', [PluginController::class, 'products'])->name('products')->setParams(['real_name' => '获取插件产品列表']);
// 商户管理
Route::get('/merchant/list', [MerchantController::class, 'list'])->name('merchantList')->setParams(['real_name' => '商户列表']);
Route::get('/merchant/detail', [MerchantController::class, 'detail'])->name('merchantDetail')->setParams(['real_name' => '商户详情']);
Route::post('/merchant/save', [MerchantController::class, 'save'])->name('merchantSave')->setParams(['real_name' => '保存商户']);
Route::post('/merchant/toggle', [MerchantController::class, 'toggle'])->name('merchantToggle')->setParams(['real_name' => '启用禁用商户']);
// 商户应用管理
Route::get('/merchant-app/list', [MerchantAppController::class, 'list'])->name('merchantAppList')->setParams(['real_name' => '商户应用列表']);
Route::get('/merchant-app/detail', [MerchantAppController::class, 'detail'])->name('merchantAppDetail')->setParams(['real_name' => '商户应用详情']);
Route::post('/merchant-app/save', [MerchantAppController::class, 'save'])->name('merchantAppSave')->setParams(['real_name' => '保存商户应用']);
Route::post('/merchant-app/reset-secret', [MerchantAppController::class, 'resetSecret'])->name('merchantAppResetSecret')->setParams(['real_name' => '重置应用密钥']);
Route::post('/merchant-app/toggle', [MerchantAppController::class, 'toggle'])->name('merchantAppToggle')->setParams(['real_name' => '启用禁用商户应用']);
// 支付方式管理
Route::get('/pay-method/list', [PayMethodController::class, 'list'])->name('payMethodList')->setParams(['real_name' => '支付方式列表']);
Route::post('/pay-method/save', [PayMethodController::class, 'save'])->name('payMethodSave')->setParams(['real_name' => '保存支付方式']);
Route::post('/pay-method/toggle', [PayMethodController::class, 'toggle'])->name('payMethodToggle')->setParams(['real_name' => '启用禁用支付方式']);
// 插件注册表管理
Route::get('/pay-plugin/list', [PayPluginController::class, 'list'])->name('payPluginList')->setParams(['real_name' => '支付插件注册表列表']);
Route::post('/pay-plugin/save', [PayPluginController::class, 'save'])->name('payPluginSave')->setParams(['real_name' => '保存支付插件注册表']);
Route::post('/pay-plugin/toggle', [PayPluginController::class, 'toggle'])->name('payPluginToggle')->setParams(['real_name' => '启用禁用支付插件']);
// 订单管理
Route::get('/order/list', [OrderController::class, 'list'])->name('orderList')->setParams(['real_name' => '订单列表']);
Route::get('/order/detail', [OrderController::class, 'detail'])->name('orderDetail')->setParams(['real_name' => '订单详情']);
Route::post('/order/refund', [OrderController::class, 'refund'])->name('orderRefund')->setParams(['real_name' => '订单退款']);
})->middleware([AuthMiddleware::class]);
})->middleware([Cors::class]);

View File

@@ -39,7 +39,8 @@
"workerman/crontab": "^1.0",
"webman/redis-queue": "^2.1",
"firebase/php-jwt": "^7.0",
"webman/validation": "^2.2"
"webman/validation": "^2.2",
"illuminate/pagination": "^12.53"
},
"suggest": {
"ext-event": "For better performance. "

52
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c9b20b999efb47e639901ded2ade0fdb",
"content-hash": "49b81bfe43345cf72dbd33c88720b5a2",
"packages": [
{
"name": "brick/math",
@@ -1547,6 +1547,56 @@
},
"time": "2024-07-23T16:31:01+00:00"
},
{
"name": "illuminate/pagination",
"version": "v12.53.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/pagination.git",
"reference": "87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/pagination/zipball/87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b",
"reference": "87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b",
"shasum": ""
},
"require": {
"ext-filter": "*",
"illuminate/collections": "^12.0",
"illuminate/contracts": "^12.0",
"illuminate/support": "^12.0",
"php": "^8.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "12.x-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Pagination\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Pagination package.",
"homepage": "https://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-11-16T14:36:17+00:00"
},
{
"name": "illuminate/pipeline",
"version": "v12.49.0",

View File

@@ -17,6 +17,12 @@ use Webman\Route;
use support\Response;
use support\Request;
// 管理后台路由
require_once base_path() . '/app/routes/admin.php';
// API 路由
require_once base_path() . '/app/routes/api.php';
// 匹配所有options路由CORS 预检请求)
Route::options('[{path:.+}]', function (Request $request){
$response = response('', 204);
@@ -27,13 +33,6 @@ Route::options('[{path:.+}]', function (Request $request){
'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'),
]);
});
// 管理后台路由
require_once base_path() . '/app/routes/admin.php';
// API 路由
require_once base_path() . '/app/routes/api.php';
/**
* 关闭默认路由
*/

51
database/dev_seed.sql Normal file
View File

@@ -0,0 +1,51 @@
-- 开发环境初始化数据(可重复执行)
SET NAMES utf8mb4;
-- 1) 管理员(若已有则跳过)
INSERT INTO `ma_admin` (`user_name`, `password`, `nick_name`, `status`, `created_at`)
VALUES ('admin', NULL, '超级管理员', 1, NOW())
ON DUPLICATE KEY UPDATE
`nick_name` = VALUES(`nick_name`),
`status` = VALUES(`status`);
-- 2) 商户
INSERT INTO `ma_merchant` (`merchant_no`, `merchant_name`, `funds_mode`, `status`, `created_at`, `updated_at`)
VALUES ('M001', '测试商户', 'direct', 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
`merchant_name` = VALUES(`merchant_name`),
`funds_mode` = VALUES(`funds_mode`),
`status` = VALUES(`status`),
`updated_at` = NOW();
-- 3) 商户应用pid=app_id 约定:这里 app_id 使用纯数字字符串,方便易支付测试)
INSERT INTO `ma_merchant_app` (`merchant_id`, `api_type`, `app_id`, `app_secret`, `app_name`, `status`, `created_at`, `updated_at`)
SELECT m.id, 'epay', '1001', 'dev_secret_1001', '测试应用-易支付', 1, NOW(), NOW()
FROM `ma_merchant` m
WHERE m.merchant_no = 'M001'
ON DUPLICATE KEY UPDATE
`app_secret` = VALUES(`app_secret`),
`app_name` = VALUES(`app_name`),
`status` = VALUES(`status`),
`updated_at` = NOW();
-- 4) 支付方式
INSERT INTO `ma_pay_method` (`method_code`, `method_name`, `icon`, `sort`, `status`, `created_at`, `updated_at`) VALUES
('alipay', '支付宝', '', 1, 1, NOW(), NOW()),
('wechat', '微信支付', '', 2, 1, NOW(), NOW()),
('unionpay','云闪付', '', 3, 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
`method_name` = VALUES(`method_name`),
`icon` = VALUES(`icon`),
`sort` = VALUES(`sort`),
`status` = VALUES(`status`),
`updated_at` = NOW();
-- 5) 插件注册表按项目约定app\\common\\payment\\{Code}Payment
INSERT INTO `ma_pay_plugin` (`plugin_code`, `plugin_name`, `class_name`, `status`, `created_at`, `updated_at`)
VALUES ('lakala', '拉卡拉(示例)', 'app\\\\common\\\\payment\\\\LakalaPayment', 1, NOW(), NOW())
ON DUPLICATE KEY UPDATE
`plugin_name` = VALUES(`plugin_name`),
`class_name` = VALUES(`class_name`),
`status` = VALUES(`status`),
`updated_at` = NOW();