初始化本地仓库
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller;
|
||||
|
||||
use core\base\BaseController;
|
||||
|
||||
/**
|
||||
* 基类控制器继承的类
|
||||
*
|
||||
* @author Mr.April
|
||||
* @since 1.0
|
||||
*/
|
||||
class Base extends BaseController
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function initialize(): void
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\crontab;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\crontab\CrontabFormRequest;
|
||||
use app\adminapi\schema\request\crontab\CrontabQueryRequest;
|
||||
use app\adminapi\schema\response\crontab\CrontabResponse;
|
||||
use app\adminapi\validate\crontab\CrontabValidate;
|
||||
use app\enum\system\OperationResult;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\crontab\CrontabService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\helper\Arr;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class CrontabController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(CrontabService $service, CrontabValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/crontab/task',
|
||||
summary: '列表',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => CrontabQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:list')]
|
||||
#[PageResponse(CrontabResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/crontab/task/{id}',
|
||||
summary: '详情',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:read')]
|
||||
#[DataResponse(schema: CrontabResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => 400]);
|
||||
}
|
||||
|
||||
$dataArray = $data->toArray();
|
||||
if (!empty($dataArray['cycle_rule'])) {
|
||||
$cycleRule = $dataArray['cycle_rule'];
|
||||
if (is_array($cycleRule)) {
|
||||
$cycleRule = array_map(function ($value) {
|
||||
if (is_string($value) && $value !== '' && is_numeric($value)) {
|
||||
return intval($value);
|
||||
}
|
||||
return $value;
|
||||
}, $cycleRule);
|
||||
$dataArray = array_merge($dataArray, $cycleRule);
|
||||
}
|
||||
unset($dataArray['cycle_rule']);
|
||||
}
|
||||
|
||||
return Json::success('ok', $dataArray);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/crontab/task',
|
||||
summary: '添加',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => CrontabFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:create')]
|
||||
#[DataResponse(schema: CrontabResponse::class, example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->inputFilter($request->all(), ['minute', 'hour', 'day', 'week', 'month', 'second']);
|
||||
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/crontab/task/{id}',
|
||||
summary: '删除',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '任务ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:delete')]
|
||||
#[DataResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $request->input('data', []);
|
||||
$data = !empty($id) && $id !== '0' ? $id : $data;
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$this->service->destroy($data);
|
||||
return Json::success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/crontab/task',
|
||||
summary: '批量删除',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->input('ids', []);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$this->service->destroy($data);
|
||||
return Json::success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/crontab/task/{id}',
|
||||
summary: '更新',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => CrontabFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '任务ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->inputFilter($request->all(), ['minute', 'hour', 'day', 'week', 'month', 'second']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->update($id, $data);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/crontab/task/{id}/resume',
|
||||
summary: '恢复',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '任务ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:resume')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function resume(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$this->service->resumeCrontab(Arr::normalize($id));
|
||||
return Json::success('执行完成');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/crontab/task/{id}/pause',
|
||||
summary: '暂停',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '任务ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:pause')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function pause(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$this->service->pauseCrontab($id);
|
||||
return Json::success('执行完成');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/crontab/task/{id}/execute',
|
||||
summary: '执行',
|
||||
tags: ['定时任务'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:task:execute')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function execute(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$result = $this->service->runOneTask(['id' => $id]);
|
||||
if ($result['code'] == OperationResult::FAILURE->value) {
|
||||
throw new AdminException('执行失败' . $result['log']);
|
||||
}
|
||||
return Json::success('执行完成', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\crontab;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\crontab\CrontabLogQueryRequest;
|
||||
use app\adminapi\schema\response\crontab\CrontabLogResponse;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\crontab\CrontabLogService;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class CrontabLogController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(CrontabLogService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/crontab/log',
|
||||
summary: '列表',
|
||||
tags: ['定时任务.日志'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => CrontabLogQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:log:list')]
|
||||
#[PageResponse(schema: CrontabLogResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/crontab/log/{id}',
|
||||
summary: '详情',
|
||||
tags: ['定时任务.日志'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:log:read')]
|
||||
#[DataResponse(schema: CrontabLogResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/crontab/log/{id}',
|
||||
summary: '删除',
|
||||
tags: ['定时任务.日志'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:log:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/crontab/log',
|
||||
summary: '批量删除',
|
||||
tags: ['定时任务.日志'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'crontab:log:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\dict;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\dict\DictFormRequest;
|
||||
use app\adminapi\schema\request\dict\DictQueryRequest;
|
||||
use app\adminapi\schema\response\system\DictResponse;
|
||||
use app\adminapi\validate\system\DictValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\dict\DictService;
|
||||
use app\service\core\enum\EnumService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class DictController extends Crud
|
||||
{
|
||||
public function __construct(DictService $service, DictValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/dict',
|
||||
summary: '列表',
|
||||
tags: ['字典管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictQueryRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:list')]
|
||||
#[PageResponse(schema: DictResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/dict/dict',
|
||||
summary: '新增',
|
||||
tags: ['字典管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictFormRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/dict/dict/{id}',
|
||||
summary: '更新',
|
||||
tags: ['字典管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictFormRequest::class]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '字典ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer', default: 0),
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
#[OA\Post(
|
||||
path: '/dict/dict/export',
|
||||
summary: '导出',
|
||||
tags: ['字典管理']
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:list', description: '导出')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function export(Request $request): \support\Response
|
||||
{
|
||||
return parent::export($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/dict/dict/{id}',
|
||||
summary: '删除',
|
||||
tags: ['字典管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/dict/dict',
|
||||
summary: '批量删除',
|
||||
tags: ['字典管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/dict/{id}',
|
||||
summary: '详情',
|
||||
tags: ['字典管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:read')]
|
||||
#[SimpleResponse(schema: DictResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/dict/options/by-type',
|
||||
summary: '根据字典类型获取字典项',
|
||||
tags: ['字典管理'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'dict_type',
|
||||
description: '字典类型',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', default: 0),
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:options')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": [{"label": "是","value": 1,"color": "#4CAF50","ext": []},{"label": "否","value": 0,"color": "#FF5252","ext": []}]}')]
|
||||
public function getByDictType(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$dictType = $request->input('dict_type');
|
||||
$service = Container::make(EnumService::class);
|
||||
$data = $service->getEnumByCode($dictType);
|
||||
if (empty($data)) {
|
||||
$data = $this->service->findItemsByCode($dictType);
|
||||
}
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/dict/enum/list',
|
||||
summary: '枚举字典列表',
|
||||
tags: ['字典管理'],
|
||||
)]
|
||||
#[Permission(code: 'dict:dict:enum_list')]
|
||||
#[SimpleResponse(schema: [], example: [
|
||||
'name' => 'CategoryEnum',
|
||||
'namespace' => 'app\\enum\\common\\CategoryEnum',
|
||||
'category' => 'common',
|
||||
'category_label' => '通用枚举',
|
||||
'code' => 'common.categoryenum',
|
||||
'options' => [
|
||||
[
|
||||
'label' => '通用枚举',
|
||||
'value' => 'common',
|
||||
'color' => 'blue',
|
||||
'ext' => [],
|
||||
],
|
||||
[
|
||||
'label' => '系统枚举',
|
||||
'value' => 'system',
|
||||
'color' => 'green',
|
||||
'ext' => [],
|
||||
],
|
||||
[
|
||||
'label' => '开发枚举',
|
||||
'value' => 'dev',
|
||||
'color' => 'orange',
|
||||
'ext' => [],
|
||||
],
|
||||
[
|
||||
'label' => '监控枚举',
|
||||
'value' => 'monitor',
|
||||
'color' => 'red',
|
||||
'ext' => [],
|
||||
],
|
||||
[
|
||||
'label' => '业务枚举',
|
||||
'value' => 'business',
|
||||
'color' => 'purple',
|
||||
'ext' => [],
|
||||
],
|
||||
],
|
||||
'count' => 5,
|
||||
])]
|
||||
public function enumDictList(Request $request): \support\Response
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$limit = $request->input('limit', 10);
|
||||
$search = $request->input('search', '');
|
||||
$category = $request->input('category', '');
|
||||
$service = Container::make(EnumService::class);
|
||||
$result = $service->getEnumsWithPagination($page, $limit, $search, $category);
|
||||
return Json::success('ok', $result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\dict;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\dict\DictItemFormRequest;
|
||||
use app\adminapi\schema\request\dict\DictItemQueryRequest;
|
||||
use app\adminapi\schema\response\system\DictItemResponse;
|
||||
use app\adminapi\validate\system\DictItemValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\dict\DictItemService;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class DictItemController extends Crud
|
||||
{
|
||||
public function __construct(DictItemService $service, DictItemValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/item',
|
||||
summary: '列表',
|
||||
tags: ['字典项管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictItemQueryRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'dict:item:list')]
|
||||
#[PageResponse(schema: DictItemResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/dict/item/{id}',
|
||||
summary: '详情',
|
||||
tags: ['字典项管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'dict:item:read')]
|
||||
#[DataResponse(schema: DictItemResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/dict/item',
|
||||
summary: '新增',
|
||||
tags: ['字典项管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictItemFormRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'dict:item:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/dict/item/{id}',
|
||||
summary: '更新',
|
||||
tags: ['字典项管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DictItemFormRequest::class]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '字典项ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '1')
|
||||
)]
|
||||
#[Permission(code: 'dict:item:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
#[OA\Post(
|
||||
path: '/dict/item/export',
|
||||
summary: '导出',
|
||||
tags: ['字典项管理']
|
||||
)]
|
||||
#[Permission(code: 'dict:item:list', description: '导出')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function export(Request $request): \support\Response
|
||||
{
|
||||
return parent::export($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/dict/item/{id}',
|
||||
summary: '删除',
|
||||
tags: ['字典项管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '字典项ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', default: '0', example: 0)
|
||||
)]
|
||||
#[Permission(code: 'dict:item:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/dict/item',
|
||||
summary: '批量删除',
|
||||
tags: ['字典项管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'dict:item:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\gateway;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\gateway\RateLimiterFormRequest;
|
||||
use app\adminapi\schema\request\gateway\RateLimiterQueryRequest;
|
||||
use app\adminapi\schema\response\gateway\RateLimiterResponse;
|
||||
use app\adminapi\validate\gateway\RateLimiterValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\schema\response\Result;
|
||||
use app\service\admin\gateway\RetaLimiterService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RateLimiterController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(RetaLimiterService $service, RateLimiterValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/gateway/limiter',
|
||||
summary: '列表',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateLimiterQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:list')]
|
||||
#[PageResponse(schema: RateLimiterResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/gateway/limiter/{id}',
|
||||
summary: '详情',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:read')]
|
||||
#[DataResponse(schema: RateLimiterResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/gateway/limiter',
|
||||
summary: '保存',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateLimiterFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
//这里对入库的start_date end_date 转换时间戳 合并到start_time end_time
|
||||
if (isset($data['start_date']) && !empty($data['start_date'])) {
|
||||
$data['start_time'] = strtotime($data['start_date']);
|
||||
unset($data['start_date']);
|
||||
}
|
||||
if (isset($data['end_date']) && !empty($data['end_date'])) {
|
||||
$data['end_time'] = strtotime($data['end_date']);
|
||||
unset($data['end_date']);
|
||||
}
|
||||
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
//添加后移除缓存
|
||||
$this->service->cacheDriver()->delete(RetaLimiterService::CACHE_KEY);
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/gateway/limiter/{id}/change-status',
|
||||
summary: '更新状态',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:status')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function changeStatus(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
$model = $this->service->getModel();
|
||||
$primaryKey = $model->getKeyName();
|
||||
if (!array_key_exists($primaryKey, $data)) {
|
||||
throw new \Exception('参数异常缺少主键');
|
||||
}
|
||||
$targetModel = $model->findOrFail($data[$primaryKey]);
|
||||
if (empty($targetModel)) {
|
||||
throw new \Exception('资源不存在' . $primaryKey . '=', $data[$primaryKey]);
|
||||
}
|
||||
$targetModel->fill($data);
|
||||
if (!$targetModel->save()) {
|
||||
throw new \RuntimeException('数据保存失败');
|
||||
}
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaLimiterService::CACHE_KEY);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/gateway/limiter/{id}',
|
||||
summary: '更新',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateLimiterFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '限访规则ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '247298887944531968')
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
//这里对入库的start_date end_date 转换时间戳 合并到start_time end_time
|
||||
if (isset($data['start_date']) && !empty($data['start_date'])) {
|
||||
$data['start_time'] = strtotime($data['start_date']);
|
||||
unset($data['start_date']);
|
||||
}
|
||||
if (isset($data['end_date']) && !empty($data['end_date'])) {
|
||||
$data['end_time'] = strtotime($data['end_date']);
|
||||
unset($data['end_date']);
|
||||
}
|
||||
$this->service->update($data['id'], $data);
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaLimiterService::CACHE_KEY);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/gateway/limiter/{id}',
|
||||
summary: '删除',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->getDeleteIds($request);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$result = $this->service->transaction(function () use ($data) {
|
||||
$data = is_array($data) ? $data : explode(',', $data);
|
||||
$deletedIds = [];
|
||||
foreach ($data as $id) {
|
||||
$item = $this->service->get($id);
|
||||
if (!$item) {
|
||||
continue; // 如果找不到项,跳过
|
||||
}
|
||||
$item->delete();
|
||||
$primaryKey = $item->getPk();
|
||||
$deletedIds[] = $item->{$primaryKey};
|
||||
}
|
||||
return $deletedIds;
|
||||
});
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaLimiterService::CACHE_KEY);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/gateway/limiter',
|
||||
summary: '批量删除',
|
||||
tags: ['限访规则'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:limiter:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->getDeleteIds($request);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$result = $this->service->transaction(function () use ($data) {
|
||||
$data = is_array($data) ? $data : explode(',', $data);
|
||||
$deletedIds = [];
|
||||
foreach ($data as $id) {
|
||||
$item = $this->service->get($id);
|
||||
if (!$item) {
|
||||
continue; // 如果找不到项,跳过
|
||||
}
|
||||
$item->delete();
|
||||
$primaryKey = $item->getPk();
|
||||
$deletedIds[] = $item->{$primaryKey};
|
||||
}
|
||||
return $deletedIds;
|
||||
});
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaLimiterService::CACHE_KEY);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\gateway;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\gateway\RateRestrictionsFormRequest;
|
||||
use app\adminapi\schema\request\gateway\RateRestrictionsQueryRequest;
|
||||
use app\adminapi\schema\response\gateway\RateRestrictionsResponse;
|
||||
use app\adminapi\validate\gateway\RateRestrictionsValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\ChangeStatusRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\gateway\RetaRestrictionsService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RateRestrictionsController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(RetaRestrictionsService $service, RateRestrictionsValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/gateway/blacklist',
|
||||
summary: '列表',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateRestrictionsQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:list')]
|
||||
#[PageResponse(schema: RateRestrictionsResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/gateway/blacklist/{id}',
|
||||
summary: '详情',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:read')]
|
||||
#[SimpleResponse(schema: RateRestrictionsResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/gateway/blacklist',
|
||||
summary: '保存',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateRestrictionsFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:create')]
|
||||
#[SimpleResponse(schema: RateRestrictionsResponse::class, example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['start_date']) && !empty($data['start_date'])) {
|
||||
$data['start_time'] = strtotime($data['start_date']);
|
||||
unset($data['start_date']);
|
||||
}
|
||||
if (isset($data['end_date']) && !empty($data['end_date'])) {
|
||||
$data['end_time'] = strtotime($data['end_date']);
|
||||
unset($data['end_date']);
|
||||
}
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
//添加后移除缓存
|
||||
$this->service->cacheDriver()->delete(RetaRestrictionsService::CACHE_KEY);
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/gateway/blacklist/{id}/status',
|
||||
summary: '切换状态',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:status')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function changeStatus(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
$model = $this->service->getModel();
|
||||
$primaryKey = $model->getKeyName();
|
||||
if (!array_key_exists($primaryKey, $data)) {
|
||||
throw new \Exception('参数异常缺少主键');
|
||||
}
|
||||
$targetModel = $model->findOrFail($data[$primaryKey]);
|
||||
if (empty($targetModel)) {
|
||||
throw new \Exception('资源不存在' . $primaryKey . '=', $data[$primaryKey]);
|
||||
}
|
||||
$targetModel->fill($data);
|
||||
if (!$targetModel->save()) {
|
||||
throw new \RuntimeException('数据保存失败');
|
||||
}
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaRestrictionsService::CACHE_KEY);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/gateway/blacklist/{id}',
|
||||
summary: '更新',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RateRestrictionsFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string'))]
|
||||
#[Permission(code: 'gateway:blacklist:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->insertInput($request);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->update($data['id'], $data);
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaRestrictionsService::CACHE_KEY);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/gateway/blacklist/{id}',
|
||||
summary: '删除',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id'); // 获取路由地址 id从
|
||||
$data = $request->input('data', []);
|
||||
$data = !empty($id) && $id !== '0' ? $id : $data;
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$result = $this->service->transaction(function () use ($data) {
|
||||
$data = is_array($data) ? $data : explode(',', $data);
|
||||
$deletedIds = [];
|
||||
foreach ($data as $id) {
|
||||
$item = $this->service->get($id);
|
||||
if (!$item) {
|
||||
continue; // 如果找不到项,跳过
|
||||
}
|
||||
$item->delete();
|
||||
$primaryKey = $item->getPk();
|
||||
$deletedIds[] = $item->{$primaryKey};
|
||||
}
|
||||
return $deletedIds;
|
||||
});
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaRestrictionsService::CACHE_KEY);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/gateway/blacklist',
|
||||
summary: '批量删除',
|
||||
tags: ['限访名单'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'gateway:blacklist:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
|
||||
$data = $request->input('ids', []);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$result = $this->service->transaction(function () use ($data) {
|
||||
$data = is_array($data) ? $data : explode(',', $data);
|
||||
$deletedIds = [];
|
||||
foreach ($data as $id) {
|
||||
$item = $this->service->get($id);
|
||||
if (!$item) {
|
||||
continue; // 如果找不到项,跳过
|
||||
}
|
||||
$item->delete();
|
||||
$primaryKey = $item->getPk();
|
||||
$deletedIds[] = $item->{$primaryKey};
|
||||
}
|
||||
return $deletedIds;
|
||||
});
|
||||
//清空缓存
|
||||
$this->service->cacheDriver()->delete(RetaRestrictionsService::CACHE_KEY);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\generator;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\generator\GeneratorValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\generator\GeneratorService;
|
||||
use app\service\admin\generator\GeneratorTableService;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\helper\Arr;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use OpenApi\Attributes as OA;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class GeneratorController extends Crud
|
||||
{
|
||||
public function __construct(GeneratorService $service, GeneratorValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/generator/code',
|
||||
summary: '列表',
|
||||
tags: ['代码生成器']
|
||||
)]
|
||||
#[Permission(code: 'generator:code:list')]
|
||||
#[PageResponse(schema: [], example: [[
|
||||
'id' => '273048217217138688',
|
||||
'table_name' => 'sys_admin_post',
|
||||
'table_content' => '用户与岗位关联表',
|
||||
'module_name' => 'sys_admin_post',
|
||||
'class_name' => 'sys_admin_post',
|
||||
'edit_type' => 1,
|
||||
'plugin_name' => '',
|
||||
'order_type' => 0,
|
||||
'parent_menu' => '',
|
||||
'relations' => null,
|
||||
'push_sync_count' => 0,
|
||||
'created_at' => '2026-01-23T03:16:07.000000Z',
|
||||
'updated_at' => '2026-01-23T03:16:07.000000Z',
|
||||
'created_date' => '2026-01-23 11:16:07',
|
||||
'updated_date' => '2026-01-23 11:16:07',
|
||||
]])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/generator/code/table-list',
|
||||
summary: '数据库表-列表',
|
||||
tags: ['代码生成器']
|
||||
)]
|
||||
#[Permission(code: 'generator:code:list')]
|
||||
#[DataResponse(schema: [], example: [])]
|
||||
public function tableList(Request $request): \support\Response
|
||||
{
|
||||
$data = $request->all();
|
||||
$page = $request->input('page', 1);
|
||||
$limit = $request->input('limit', 10);
|
||||
$result = $this->service->tableList($data, (int)$page, (int)$limit);
|
||||
return Json::success($result);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/generator/code',
|
||||
summary: '生成代码',
|
||||
tags: ['代码生成器']
|
||||
)]
|
||||
#[Permission(code: 'generator:code:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->input('table', []);
|
||||
foreach ($data as $item) {
|
||||
if (!$this->validate->scene('store')->check($item)) {
|
||||
return Json::fail($this->validate->getError());
|
||||
}
|
||||
}
|
||||
foreach ($data as $item) {
|
||||
$this->service->store($item);
|
||||
}
|
||||
return Json::success();
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/generator/code/{id}',
|
||||
summary: '删除',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$this->service->destroy(Arr::normalize($id));
|
||||
return Json::success();
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/generator/code',
|
||||
summary: '批量删除',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function remove(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->input('ids', []);
|
||||
$this->service->destroy(Arr::normalize($data));
|
||||
return Json::success();
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/generator/code/{id}',
|
||||
summary: '详情',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:read')]
|
||||
#[DataResponse(schema: [], example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$service = Container::make(GeneratorTableService::class);
|
||||
$data = $service->getDetail($id);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => 400]);
|
||||
}
|
||||
return Json::success('ok', $data->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/generator/code/{id}',
|
||||
summary: '更新',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:update')]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $request->all();
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
return Json::fail($this->validate->getError());
|
||||
}
|
||||
$this->service->update($id, $data);
|
||||
return Json::success();
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/generator/code/{id}/preview',
|
||||
summary: '预览',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:preview')]
|
||||
public function preview(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$result = $this->service->preview(['id' => $id]);
|
||||
return Json::success($result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/generator/code/{id}/download',
|
||||
summary: '下载',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:download')]
|
||||
public function download(Request $request)
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$result = $this->service->download($id);
|
||||
return response()->download($result['file_path'], $result['file_name']);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/generator/code/{id}/deploy',
|
||||
summary: '部署',
|
||||
tags: ['代码生成器'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'generator:code:deploy')]
|
||||
public function deploy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$result = $this->service->deploy(['id' => $id]);
|
||||
return Json::success($result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\lang;
|
||||
|
||||
use app\adminapi\controller\Base;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\service\core\lang\TranslationService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, OperationMiddleware::class)]
|
||||
final class LangController extends Base
|
||||
{
|
||||
public function __construct(TranslationService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/lang/supported',
|
||||
summary: '获取支持的语言列表',
|
||||
tags: ['语言'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: '成功',
|
||||
content: new OA\JsonContent(
|
||||
type: 'array',
|
||||
items: new OA\Items(type: 'string')
|
||||
)
|
||||
)
|
||||
]
|
||||
)]
|
||||
#[SimpleResponse(example: ['code' => 0,'message' => 'success','data' => []])]
|
||||
public function supported(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$languages = $this->service->getSupportedLanguages();
|
||||
return json(['code' => 200, 'msg' => 'success', 'data' => $languages]);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/lang',
|
||||
summary: '获取语言包列表',
|
||||
tags: ['语言'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'language',
|
||||
description: '语言类型(如en|zh_CN等)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string', example: 'zh_CN')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'file',
|
||||
description: '翻译文件名称',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string', example: 'messages')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'keyword',
|
||||
description: '搜索关键词(支持key和翻译内容)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'page',
|
||||
description: '页码',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 1)
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'limit',
|
||||
description: '每页数量',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 10)
|
||||
)
|
||||
]
|
||||
)]
|
||||
#[PageResponse(schema: [], example: [])]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$language = $request->get('language');
|
||||
$file = $request->get('file');
|
||||
$keyword = $request->get('keyword');
|
||||
$page = (int)$request->get('page', 1);
|
||||
$limit = (int)$request->get('limit', 10);
|
||||
|
||||
$result = $this->service->getList($language, $file, $keyword, $page, $limit);
|
||||
return json(['code' => 200, 'msg' => 'success', 'data' => $result]);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/lang/files',
|
||||
summary: '获取翻译文件列表',
|
||||
tags: ['语言'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: '成功',
|
||||
content: new OA\JsonContent(
|
||||
type: 'array',
|
||||
items: new OA\Items(type: 'string')
|
||||
)
|
||||
)
|
||||
]
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function files(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$files = $this->service->getFileList();
|
||||
return json(['code' => 200, 'msg' => 'success', 'data' => $files]);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/lang/statistics',
|
||||
summary: '获取语言包统计信息',
|
||||
tags: ['语言'],
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function statistics(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$stats = $this->service->getStatistics();
|
||||
return json(['code' => 200, 'msg' => 'success', 'data' => $stats]);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \core\exception\handler\AdminException
|
||||
*/
|
||||
#[OA\Get(
|
||||
path: '/lang/translate',
|
||||
summary: '根据key获取翻译内容',
|
||||
tags: ['语言'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'key',
|
||||
description: '翻译key(格式:文件.键,如:common.operation.success)',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 'common.operation.success')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'language',
|
||||
description: '语言类型(如en|zh_CN等)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string', example: 'zh_CN')
|
||||
)
|
||||
]
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function translate(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$key = $request->get('key');
|
||||
$language = $request->get('language');
|
||||
$parameters = $request->get('parameters', []);
|
||||
if(empty($language)){
|
||||
$language = locale();
|
||||
}
|
||||
|
||||
// 如果parameters是字符串,尝试解析为JSON
|
||||
if (is_string($parameters)) {
|
||||
$parameters = json_decode($parameters, true) ?: [];
|
||||
}
|
||||
|
||||
$translation = $this->service->getTranslationByKey($key, $language, $parameters);
|
||||
|
||||
if ($translation === null) {
|
||||
return json(['code' => 404, 'msg' => 'Translation key not found', 'data' => $key]);
|
||||
}
|
||||
|
||||
return Json::success('common.operation.success',$translation);
|
||||
} catch (\Exception $e) {
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\login;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\schema\request\login\LoginRequest;
|
||||
use app\adminapi\schema\request\ThirdPartyLoginRequest;
|
||||
use app\service\admin\system\AdminService;
|
||||
use core\cache\CacheService;
|
||||
use core\captcha\Captcha;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\jwt\JwtToken;
|
||||
use core\tool\Json;
|
||||
use core\tool\RSAService;
|
||||
use core\uuid\UUIDGenerator;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
|
||||
final class LoginController extends Crud
|
||||
{
|
||||
public function __construct(AdminService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/login/get-captcha-open-flag',
|
||||
summary: '验证码开启状态',
|
||||
tags: ['无需授权'],
|
||||
)]
|
||||
#[SimpleResponse(schema: ['flag' => true], example:[])]
|
||||
public function getCaptchaOpenFlag(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 生成密钥对
|
||||
$cache = Container::make(CacheService::class, []);
|
||||
$keyId = md5(UUIDGenerator::generate());
|
||||
$keys = RSAService::generateKeys();
|
||||
// 存储私钥到缓存,用于解密密码
|
||||
$cache->set("rsa_private_key_$keyId", $keys['private'], 60); // 5分钟过期
|
||||
return Json::success('ok', ['flag' => config('core.captcha.app.enable', false), 'key_id' => $keyId, 'public_key' => $keys['public']]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/login/captcha',
|
||||
summary: '验证码',
|
||||
tags: ['无需授权'],
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example:[])]
|
||||
public function captcha(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$captcha = new Captcha();
|
||||
$type = $request->input('type', 'admin-login');
|
||||
$result = $captcha->captcha($request, $type);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/login/send-sms',
|
||||
summary: '手机验证码',
|
||||
tags: ['无需授权']
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'mobile_phone',
|
||||
description: '手机号码',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer', default: 18888888888)
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: '{"code": 185841,"uid":18888888888}}')]
|
||||
public function sendSms(Request $request): \support\Response
|
||||
{
|
||||
// 1.0生成验证码
|
||||
$captcha = new Captcha();
|
||||
$result = $captcha->generateSmsCaptcha($request);
|
||||
// 2.0发送验证码到手机
|
||||
// 3.0 存储验证码到 Redis,设置过期时间(如 5 分钟)
|
||||
return Json::success('验证码发送成功', $result);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/login/login',
|
||||
summary: '登录',
|
||||
tags: ['无需授权']
|
||||
)]
|
||||
#[RequestBody(
|
||||
description: '请求参数',
|
||||
required: true,
|
||||
content: new OA\JsonContent(ref: LoginRequest::class)
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: '{"token_type": "Bearer","expires_in": 7200,"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWRvbmcudGVjaCIsImF1ZCI6Im1hZG9uZy50ZWNoIiwiaWF0IjoxNzYyNDExMjY5LCJuYmYiOjE3NjI0MTEyNjksImV4cCI6MTc2MjQxODQ2OSwiZXh0ZW5kIjp7ImlkIjoiMiIsInVzZXJfbmFtZSI6ImFkbWluIiwicmVhbF9uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4Iiwibmlja19uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4IiwiaXNfc3VwZXIiOjEsImlzX3RlbmFudF9hZG1pbiI6MSwibW9iaWxlX3Bob25lIjpudWxsLCJlbWFpbCI6bnVsbCwiYXZhdGFyIjoiL3VwbG9hZC80MmY4NmI5YjM2Nzk0ZmI5ZTM4MDkxN2MyNTFmNmQ4MS5wbmciLCJzaWduZWQiOm51bGwsImRhc2hib2FyZCI6bnVsbCwiZGVwdF9pZCI6bnVsbCwiZW5hYmxlZCI6MSwibG9naW5faXAiOiIxMjAuNDEuMjQ2LjIyNSIsImxvZ2luX3RpbWUiOjE3NjI0MTEyNjksInVwZGF0ZWRfYXQiOiIyMDI1LTExLTA2VDA2OjQxOjA5LjAwMDAwMFoiLCJzZXgiOjAsImJpcnRoZGF5IjpudWxsLCJ0ZWwiOm51bGwsImlzX2xvY2tlZCI6MCwiZGVwdHMiOltdLCJwb3N0cyI6W10sInRlbmFudHMiOlt7ImlkIjoiMSIsImRiX25hbWUiOiJtYWRvbmdfYWRtaW5fc2FhcyIsImNvZGUiOiJwbGF0Zm9ybSIsInR5cGUiOjAsImNvbnRhY3RfcGVyc29uIjoiYWRtaW4iLCJjb250YWN0X3Bob25lIjoiMTg4ODg4ODg4ODgiLCJjb21wYW55X25hbWUiOiJ4eHh4IFx1NjcwOVx1OTY1MFx1NTE2Y1x1NTNmOCIsImxpY2Vuc2VfbnVtYmVyIjoiIiwiYWRkcmVzcyI6Ilx1NGUyZFx1NTZmZCIsImRlc2NyaXB0aW9uIjoiXHU1MTg1XHU3ZjZlXHU4ZDI2XHU1M2Y3IiwiZG9tYWluIjoiaHR0cHM6Ly93d3cubWFkb25nLnRlY2giLCJlbmFibGVkIjoxLCJpc29sYXRpb25fbW9kZSI6MiwiaXNfZGVmYXVsdCI6MSwiZXhwaXJlZF9hdCI6bnVsbCwiZGVsZXRlZF9hdCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMjUtMTAtMDNUMDM6MjM6NDcuMDAwMDAwWiIsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOm51bGwsInVwZGF0ZWRfYXQiOm51bGwsImNyZWF0ZWRfZGF0ZSI6IjIwMjUtMTAtMDMgMTE6MjM6NDciLCJ1cGRhdGVkX2RhdGUiOm51bGwsImV4cGlyZWRfZGF0ZSI6bnVsbCwicGl2b3QiOnsiYWRtaW5faWQiOjIsInRlbmFudF9pZCI6MSwiY3JlYXRlZF9kYXRlIjpudWxsLCJ1cGRhdGVkX2RhdGUiOm51bGx9fV0sImNhc2JpbiI6W119fQ.rCaHoiI1gU7xyoJazt3V5JQrS2guV34PH-JjkWnceE4","refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWRvbmcudGVjaCIsImF1ZCI6Im1hZG9uZy50ZWNoIiwiaWF0IjoxNzYyNDExMjY5LCJuYmYiOjE3NjI0MTEyNjksImV4cCI6MTc2MzAxNjA2OSwiZXh0ZW5kIjp7ImlkIjoiMiIsInVzZXJfbmFtZSI6ImFkbWluIiwicmVhbF9uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4Iiwibmlja19uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4IiwiaXNfc3VwZXIiOjEsImlzX3RlbmFudF9hZG1pbiI6MSwibW9iaWxlX3Bob25lIjpudWxsLCJlbWFpbCI6bnVsbCwiYXZhdGFyIjoiL3VwbG9hZC80MmY4NmI5YjM2Nzk0ZmI5ZTM4MDkxN2MyNTFmNmQ4MS5wbmciLCJzaWduZWQiOm51bGwsImRhc2hib2FyZCI6bnVsbCwiZGVwdF9pZCI6bnVsbCwiZW5hYmxlZCI6MSwibG9naW5faXAiOiIxMjAuNDEuMjQ2LjIyNSIsImxvZ2luX3RpbWUiOjE3NjI0MTEyNjksInVwZGF0ZWRfYXQiOiIyMDI1LTExLTA2VDA2OjQxOjA5LjAwMDAwMFoiLCJzZXgiOjAsImJpcnRoZGF5IjpudWxsLCJ0ZWwiOm51bGwsImlzX2xvY2tlZCI6MCwiZGVwdHMiOltdLCJwb3N0cyI6W10sInRlbmFudHMiOlt7ImlkIjoiMSIsImRiX25hbWUiOiJtYWRvbmdfYWRtaW5fc2FhcyIsImNvZGUiOiJwbGF0Zm9ybSIsInR5cGUiOjAsImNvbnRhY3RfcGVyc29uIjoiYWRtaW4iLCJjb250YWN0X3Bob25lIjoiMTg4ODg4ODg4ODgiLCJjb21wYW55X25hbWUiOiJ4eHh4IFx1NjcwOVx1OTY1MFx1NTE2Y1x1NTNmOCIsImxpY2Vuc2VfbnVtYmVyIjoiIiwiYWRkcmVzcyI6Ilx1NGUyZFx1NTZmZCIsImRlc2NyaXB0aW9uIjoiXHU1MTg1XHU3ZjZlXHU4ZDI2XHU1M2Y3IiwiZG9tYWluIjoiaHR0cHM6Ly93d3cubWFkb25nLnRlY2giLCJlbmFibGVkIjoxLCJpc29sYXRpb25fbW9kZSI6MiwiaXNfZGVmYXVsdCI6MSwiZXhwaXJlZF9hdCI6bnVsbCwiZGVsZXRlZF9hdCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMjUtMTAtMDNUMDM6MjM6NDcuMDAwMDAwWiIsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOm51bGwsInVwZGF0ZWRfYXQiOm51bGwsImNyZWF0ZWRfZGF0ZSI6IjIwMjUtMTAtMDMgMTE6MjM6NDciLCJ1cGRhdGVkX2RhdGUiOm51bGwsImV4cGlyZWRfZGF0ZSI6bnVsbCwicGl2b3QiOnsiYWRtaW5faWQiOjIsInRlbmFudF9pZCI6MSwiY3JlYXRlZF9kYXRlIjpudWxsLCJ1cGRhdGVkX2RhdGUiOm51bGx9fV0sImNhc2JpbiI6W119fQ.IgLkKhjjsgjAsjS4qReg51WpzwjiuU27_tbqTpUuD3M","client_id": "127.0.0.1-690c430548ecd5.55813566","expires_time": 1762418469}')]
|
||||
public function login(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$username = $request->input('user_name');
|
||||
$password = $request->input('password', '');
|
||||
$phone = $request->input('mobile_phone', '');
|
||||
$code = $request->input('code', '');
|
||||
$uuid = $request->input('uuid', '');
|
||||
$type = $request->input('type', 'admin');
|
||||
$grantType = $request->input('grant_type', 'deafult');//refresh_token sms default 可以自行定义拓展登录方式
|
||||
$keyId = $request->input('key_id', '');//获取公钥Id
|
||||
|
||||
|
||||
$captcha = new Captcha();
|
||||
|
||||
if (config('core.captcha.app.enable') && $grantType === 'default') {
|
||||
if (!$captcha->check($uuid, $code)) {
|
||||
throw new AdminException('图片验证码错误!');
|
||||
}
|
||||
}
|
||||
|
||||
if ($grantType == 'sms' && !empty($phone)) {
|
||||
if (!$captcha->check($phone, $code)) {
|
||||
throw new AdminException('手机验证码错误!');
|
||||
}
|
||||
$info = $this->service->get(['mobile_phone' => $phone]);
|
||||
if (empty($info)) {
|
||||
throw new AdminException('当前手机未绑定用户!');
|
||||
}
|
||||
$username = $info->getData('user_name');
|
||||
}
|
||||
|
||||
$data = $this->service->login($username, $password, $type, $grantType, ['key_id' => $keyId ?? '']);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/login/logout',
|
||||
summary: '注销',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['无需授权'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'token',
|
||||
description: '令牌(可选,也可通过Authorization头传递)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function logout(Request $request): \support\Response
|
||||
{
|
||||
// 1. 获取token
|
||||
$token = $request->header(config('core.jwt.app.token_name', 'Authorization')) ?: $request->get('token');
|
||||
|
||||
// 2. 快速验证无效token情况
|
||||
if (empty($token) || $token === 'undefined') {
|
||||
return Json::success('ok', []);
|
||||
}
|
||||
|
||||
// 3. 处理Bearer Token格式
|
||||
if (str_starts_with($token, 'Bearer ')) {
|
||||
$token = substr($token, 7); // 移除"Bearer "前缀
|
||||
if (empty($token) || $token === 'undefined') {
|
||||
return Json::success('ok', []);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 退出登录
|
||||
(new JwtToken())->logout($token);
|
||||
|
||||
return Json::success('ok', []);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/login/auth/public-key',
|
||||
summary: '生成RSA密钥对',
|
||||
tags: ['无需授权'],
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function generateRSAKeyPair(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 生成密钥对
|
||||
$cache = Container::make(CacheService::class, []);
|
||||
$keyId = md5(UUIDGenerator::generate());
|
||||
$keys = RSAService::generateKeys();
|
||||
// 存储私钥到缓存,用于解密密码
|
||||
$cache->set("rsa_private_key_$keyId", $keys['private'], 60); // 5分钟过期
|
||||
return Json::success('ok', ['public_key' => $keys['public'], 'key_id' => $keyId]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/login/third-party/login',
|
||||
summary: '第三方测试登录接口(免RSA)',
|
||||
tags: ['无需授权']
|
||||
)]
|
||||
#[RequestBody(
|
||||
description: '请求参数',
|
||||
required: true,
|
||||
content: new OA\JsonContent(ref: ThirdPartyLoginRequest::class)
|
||||
)]
|
||||
#[SimpleResponse(schema:[],example: '{"code": 0,"msg": "ok","data": {"token_type": "Bearer","expires_in": 7200,"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWRvbmcudGVjaCIsImF1ZCI6Im1hZG9uZy50ZWNoIiwiaWF0IjoxNzYyNDExMjY5LCJuYmYiOjE3NjI0MTEyNjksImV4cCI6MTc2MjQxODQ2OSwiZXh0ZW5kIjp7ImlkIjoiMiIsInVzZXJfbmFtZSI6ImFkbWluIiwicmVhbF9uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4Iiwibmlja19uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4IiwiaXNfc3VwZXIiOjEsImlzX3RlbmFudF9hZG1pbiI6MSwibW9iaWxlX3Bob25lIjpudWxsLCJlbWFpbCI6bnVsbCwiYXZhdGFyIjoiL3VwbG9hZC80MmY4NmI5YjM2Nzk0ZmI5ZTM4MDkxN2MyNTFmNmQ4MS5wbmciLCJzaWduZWQiOm51bGwsImRhc2hib2FyZCI6bnVsbCwiZGVwdF9pZCI6bnVsbCwiZW5hYmxlZCI6MSwibG9naW5faXAiOiIxMjAuNDEuMjQ2LjIyNSIsImxvZ2luX3RpbWUiOjE3NjI0MTEyNjksInVwZGF0ZWRfYXQiOiIyMDI1LTExLTA2VDA2OjQxOjA5LjAwMDAwMFoiLCJzZXgiOjAsImJpcnRoZGF5IjpudWxsLCJ0ZWwiOm51bGwsImlzX2xvY2tlZCI6MCwiZGVwdHMiOltdLCJwb3N0cyI6W10sInRlbmFudHMiOlt7ImlkIjoiMSIsImRiX25hbWUiOiJtYWRvbmdfYWRtaW5fc2FhcyIsImNvZGUiOiJwbGF0Zm9ybSIsInR5cGUiOjAsImNvbnRhY3RfcGVyc29uIjoiYWRtaW4iLCJjb250YWN0X3Bob25lIjoiMTg4ODg4ODg4ODgiLCJjb21wYW55X25hbWUiOiJ4eHh4IFx1NjcwOVx1OTY1MFx1NTE2Y1x1NTNmOCIsImxpY2Vuc2VfbnVtYmVyIjoiIiwiYWRkcmVzcyI6Ilx1NGUyZFx1NTZmZCIsImRlc2NyaXB0aW9uIjoiXHU1MTg1XHU3ZjZlXHU4ZDI2XHU1M2Y3IiwiZG9tYWluIjoiaHR0cHM6Ly93d3cubWFkb25nLnRlY2giLCJlbmFibGVkIjoxLCJpc29sYXRpb25fbW9kZSI6MiwiaXNfZGVmYXVsdCI6MSwiZXhwaXJlZF9hdCI6bnVsbCwiZGVsZXRlZF9hdCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMjUtMTAtMDNUMDM6MjM6NDcuMDAwMDAwWiIsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOm51bGwsInVwZGF0ZWRfYXQiOm51bGwsImNyZWF0ZWRfZGF0ZSI6IjIwMjUtMTAtMDMgMTE6MjM6NDciLCJ1cGRhdGVkX2RhdGUiOm51bGwsImV4cGlyZWRfZGF0ZSI6bnVsbCwicGl2b3QiOnsiYWRtaW5faWQiOjIsInRlbmFudF9pZCI6MSwiY3JlYXRlZF9kYXRlIjpudWxsLCJ1cGRhdGVkX2RhdGUiOm51bGx9fV0sImNhc2JpbiI6W119fQ.rCaHoiI1gU7xyoJazt3V5JQrS2guV34PH-JjkWnceE4","refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtYWRvbmcudGVjaCIsImF1ZCI6Im1hZG9uZy50ZWNoIiwiaWF0IjoxNzYyNDExMjY5LCJuYmYiOjE3NjI0MTEyNjksImV4cCI6MTc2MzAxNjA2OSwiZXh0ZW5kIjp7ImlkIjoiMiIsInVzZXJfbmFtZSI6ImFkbWluIiwicmVhbF9uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4Iiwibmlja19uYW1lIjoiXHU4ZDg1XHU3ZWE3XHU3YmExXHU3NDA2XHU1NDU4IiwiaXNfc3VwZXIiOjEsImlzX3RlbmFudF9hZG1pbiI6MSwibW9iaWxlX3Bob25lIjpudWxsLCJlbWFpbCI6bnVsbCwiYXZhdGFyIjoiL3VwbG9hZC80MmY4NmI5YjM2Nzk0ZmI5ZTM4MDkxN2MyNTFmNmQ4MS5wbmciLCJzaWduZWQiOm51bGwsImRhc2hib2FyZCI6bnVsbCwiZGVwdF9pZCI6bnVsbCwiZW5hYmxlZCI6MSwibG9naW5faXAiOiIxMjAuNDEuMjQ2LjIyNSIsImxvZ2luX3RpbWUiOjE3NjI0MTEyNjksInVwZGF0ZWRfYXQiOiIyMDI1LTExLTA2VDA2OjQxOjA5LjAwMDAwMFoiLCJzZXgiOjAsImJpcnRoZGF5IjpudWxsLCJ0ZWwiOm51bGwsImlzX2xvY2tlZCI6MCwiZGVwdHMiOltdLCJwb3N0cyI6W10sInRlbmFudHMiOlt7ImlkIjoiMSIsImRiX25hbWUiOiJtYWRvbmdfYWRtaW5fc2FhcyIsImNvZGUiOiJwbGF0Zm9ybSIsInR5cGUiOjAsImNvbnRhY3RfcGVyc29uIjoiYWRtaW4iLCJjb250YWN0X3Bob25lIjoiMTg4ODg4ODg4ODgiLCJjb21wYW55X25hbWUiOiJ4eHh4IFx1NjcwOVx1OTY1MFx1NTE2Y1x1NTNmOCIsImxpY2Vuc2VfbnVtYmVyIjoiIiwiYWRkcmVzcyI6Ilx1NGUyZFx1NTZmZCIsImRlc2NyaXB0aW9uIjoiXHU1MTg1XHU3ZjZlXHU4ZDI2XHU1M2Y3IiwiZG9tYWluIjoiaHR0cHM6Ly93d3cubWFkb25nLnRlY2giLCJlbmFibGVkIjoxLCJpc29sYXRpb25fbW9kZSI6MiwiaXNfZGVmYXVsdCI6MSwiZXhwaXJlZF9hdCI6bnVsbCwiZGVsZXRlZF9hdCI6bnVsbCwiY3JlYXRlZF9hdCI6IjIwMjUtMTAtMDNUMDM6MjM6NDcuMDAwMDAwWiIsImNyZWF0ZWRfYnkiOjEsInVwZGF0ZWRfYnkiOm51bGwsInVwZGF0ZWRfYXQiOm51bGwsImNyZWF0ZWRfZGF0ZSI6IjIwMjUtMTAtMDMgMTE6MjM6NDciLCJ1cGRhdGVkX2RhdGUiOm51bGwsImV4cGlyZWRfZGF0ZSI6bnVsbCwicGl2b3QiOnsiYWRtaW5faWQiOjIsInRlbmFudF9pZCI6MSwiY3JlYXRlZF9kYXRlIjpudWxsLCJ1cGRhdGVkX2RhdGUiOm51bGx9fV0sImNhc2JpbiI6W119fQ.IgLkKhjjsgjAsjS4qReg51WpzwjiuU27_tbqTpUuD3M","client_id": "127.0.0.1-690c430548ecd5.55813566","expires_time": 1762418469}}')]
|
||||
public function thirdPartyLogin(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$acctId = $request->get('acct_id');
|
||||
$appId = $request->get('app_id');
|
||||
$appSecret = $request->get('app_secret');
|
||||
$userName = $request->get('user_name');
|
||||
$data = $this->service->thirdPartyLogin($acctId, $appId, $appSecret, $userName);
|
||||
return Json::success('登录成功', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\logs;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\logs\LoginLogQueryRequest;
|
||||
use app\adminapi\schema\response\system\LoginLogResponse;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\logs\LoginLogService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class LoginLogController extends Crud
|
||||
{
|
||||
public function __construct(LoginLogService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/logs/login',
|
||||
summary: '列表',
|
||||
tags: ['日志管理.登录'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => LoginLogQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:login:list')]
|
||||
#[PageResponse(schema: LoginLogResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, ['account' => function ($query) {
|
||||
$query->select(['id', 'user_name', 'real_name']);
|
||||
}], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/logs/login/{id}',
|
||||
summary: '详情',
|
||||
tags: ['日志管理.登录'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '日志ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'logs:login:read')]
|
||||
#[SimpleResponse(schema: LoginLogResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id,['*'],['account' => function ($query) {
|
||||
$query->select(['id', 'user_name', 'real_name']);
|
||||
}]);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到');
|
||||
}
|
||||
return Json::success('ok', $data->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/logs/login/{id}',
|
||||
summary: '删除',
|
||||
tags: ['日志管理.登录'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:login:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/logs/login',
|
||||
summary: '批量删除',
|
||||
tags: ['日志管理.登录'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:login:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\logs;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\logs\OperateLogQueryRequest;
|
||||
use app\adminapi\schema\response\system\OperateLogResponse;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\logs\OperateLogService;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class OperateLogController extends Crud
|
||||
{
|
||||
public function __construct(OperateLogService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/logs/operate',
|
||||
summary: '列表',
|
||||
tags: ['日志管理.操作'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => OperateLogQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:operate:list')]
|
||||
#[PageResponse(schema: OperateLogResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/logs/operate/{id}',
|
||||
summary: '详情',
|
||||
tags: ['日志管理.操作'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:operate:read')]
|
||||
#[SimpleResponse(schema: OperateLogResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/logs/operate/{id}',
|
||||
summary: '删除',
|
||||
tags: ['日志管理.操作'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', default: '123456789012345678'),
|
||||
)]
|
||||
#[Permission(code: 'logs:operate:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/logs/operate',
|
||||
summary: '批量删除',
|
||||
tags: ['日志管理.操作'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'logs:operate:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\member;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\member\MemberLevelValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\member\MemberLevelService;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class LevelController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(MemberLevelService $service, MemberLevelValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/level',
|
||||
summary: '列表',
|
||||
tags: ['会员等级'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "name", description: "等级名称", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "status", description: "状态", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:level:list")]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/level',
|
||||
summary: '创建',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "普通会员"),
|
||||
new OA\Property(property: "min_points", type: "integer", example: 0),
|
||||
new OA\Property(property: "max_points", type: "integer", example: 999),
|
||||
new OA\Property(property: "discount", type: "number", example: 1),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "sort", type: "integer", example: 100),
|
||||
])
|
||||
),
|
||||
tags: ['会员等级'],
|
||||
)]
|
||||
#[Permission("member:level:create")]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/level/{id}',
|
||||
summary: '更新',
|
||||
tags: ['会员等级'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:level:update")]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/level/{id}',
|
||||
summary: '删除会员等级',
|
||||
tags: ['会员等级'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:level:delete")]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/level',
|
||||
summary: '批量删除',
|
||||
tags: ['会员等级'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class],
|
||||
)]
|
||||
#[Permission("member:level:delete")]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/level/{id}',
|
||||
summary: '详情',
|
||||
tags: ['会员等级'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:level:show")]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\member;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\CurrentUser;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\member\MemberAuthValidate;
|
||||
use app\service\admin\member\MemberAuthService;
|
||||
use app\service\admin\member\MemberService;
|
||||
use app\service\admin\member\MemberTagPermissionService;
|
||||
use app\service\admin\member\MemberTagRelationService;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class MemberAuthController extends Crud
|
||||
{
|
||||
public function __construct(MemberAuthService $service, MemberAuthValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/permissions',
|
||||
summary: '权限菜单-包含所有',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:permissions')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function getPermissions(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$format = input('format', 'table_tree');
|
||||
$collection = $this->service->getAllMenus(true);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$items = $collection->toArray();
|
||||
return call_user_func([$this, $format_function], $collection, count($items));
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/{id}/tag-permissions',
|
||||
summary: '权限菜单-包含所有',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:tag_permissions')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": []}')]
|
||||
public function getPermissionsByTag(Request $request, $id): \support\Response
|
||||
{
|
||||
try {
|
||||
$format = input('format', 'tree');
|
||||
$collection = $this->service->getMenusByMemberTags($id, true);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$items = $collection->toArray();
|
||||
return call_user_func([$this, $format_function], $items, count($items));
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/perm-code',
|
||||
summary: '获取用户-权限码',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:perm_code')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => ['admin']])]
|
||||
public function getUserCodes(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var CurrentUser $currUser */
|
||||
$currUser = Container::make(CurrentUser::class);
|
||||
$data = $this->service->getCodesByUserRoles($currUser);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/tag-menu-ids',
|
||||
summary: '通过角色ID获取权限ID集合',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:role_menu_ids')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function tagMenuIds(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$tagId = $request->input('tag_id');
|
||||
$result = $this->service->getMenusByTagId($tagId, true);
|
||||
if (empty($result)) {
|
||||
return Json::Success([]);
|
||||
}
|
||||
$data = [];
|
||||
foreach ($result as $item) {
|
||||
$data[] = $item->id;
|
||||
}
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/auth/save-tag-menu',
|
||||
summary: '保存角色菜单关系',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:role_menu')]
|
||||
#[SimpleResponse( example: '{"code": 0,"msg": "ok"}')]
|
||||
public function saveTagMenuRelation(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var MemberTagPermissionService $systemRoleMenuService */
|
||||
$systemRoleMenuService = Container::make(MemberTagPermissionService::class);
|
||||
$systemRoleMenuService->save($data);
|
||||
return Json::success('success');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/user-list-by-tag-id',
|
||||
summary: '获取角色-关联用户列表',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'tag_id',
|
||||
description: '标签ID',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string'),
|
||||
)]
|
||||
#[Permission(code: 'member:auth:tag_user_list')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function getUsersByTagId(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request, [
|
||||
'allowed_fields' => ['username', 'nickname', 'email', 'mobile', 'tag_id'], // 使用 null 表示不限制字段,允许所有模型字段
|
||||
'skip_fields' => [],
|
||||
// 添加自定义参数会自动合并到 where 中
|
||||
'custom_fields' => [],
|
||||
]);
|
||||
/** @var MemberService $systemUserService */
|
||||
$systemUserService = Container::make(MemberService::class);
|
||||
$data = $systemUserService->getUsersListByTagId($where, $field, $page, $limit);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/auth/save-user-tag',
|
||||
summary: '保存用户-关联标签',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:save_user_tag')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "success"}')]
|
||||
public function saveUserTags(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var MemberTagRelationService $memberTagRelationService */
|
||||
$memberTagRelationService = Container::make(MemberTagRelationService::class);
|
||||
$memberTagRelationService->saveUserTags($data);
|
||||
return Json::success('success');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/auth/remove-user-tag',
|
||||
summary: '移除用户-关联角色',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[Permission(code: 'member:auth:remove_user_tag')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok"}')]
|
||||
public function removeUserRole(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var MemberTagRelationService $MemberTagRelationService */
|
||||
$MemberTagRelationService = Container::make(MemberTagRelationService::class);
|
||||
$MemberTagRelationService->removeUserTag($data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/auth/user-list-exclude-tag-id',
|
||||
summary: '获取用户列表-排除指定角色id',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关-会员'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'tag_id',
|
||||
description: '标签ID',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string'),
|
||||
)]
|
||||
#[Permission(code: 'member:auth:user_list_exclude_tag')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function getUsersExcludingTag(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 自定义参数
|
||||
$tagId = $request->input('tag_id');
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request, [
|
||||
'allowed_fields' => null, // 使用 null 表示不限制字段,允许所有模型字段
|
||||
'skip_fields' => ['token', 'deleted_at'],
|
||||
// 添加自定义参数 tag_id,会自动合并到 where 中
|
||||
'custom_fields' => [
|
||||
'tag_id' => $tagId,
|
||||
],
|
||||
]);
|
||||
|
||||
/** @var MemberService $memberUserService */
|
||||
$memberUserService = Container::make(MemberService::class);
|
||||
$data = $memberUserService->getUsersExcludingTag($where, $field, $page, $limit);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\member;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\member\MemberValidate;
|
||||
use app\api\CurrentMember;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\member\MemberService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class MemberController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(MemberService $service, MemberValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/user',
|
||||
summary: '会员用户列表',
|
||||
tags: ['会员用户'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "username", description: "用户名", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "nickname", description: "昵称", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "phone", description: "手机号", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "email", description: "邮箱", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "level_id", description: "等级ID", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "status", description: "状态", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "total", type: "integer", example: 10),
|
||||
new OA\Property(property: "list", type: "array", items: new OA\Items(properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
new OA\Property(property: "username", type: "string", example: "testuser"),
|
||||
new OA\Property(property: "nickname", type: "string", example: "测试用户"),
|
||||
new OA\Property(property: "phone", type: "string", example: "13800138000"),
|
||||
new OA\Property(property: "email", type: "string", example: "test@example.com"),
|
||||
new OA\Property(property: "avatar", type: "string", example: ""),
|
||||
new OA\Property(property: "level_id", type: "integer", example: 1),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "create_time", type: "integer", example: 1640995200),
|
||||
])),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:user:list")]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, ['level', 'tags'], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/user/{id}',
|
||||
summary: '会员用户详情',
|
||||
tags: ['会员用户'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
new OA\Property(property: "username", type: "string", example: "testuser"),
|
||||
new OA\Property(property: "nickname", type: "string", example: "测试用户"),
|
||||
new OA\Property(property: "phone", type: "string", example: "13800138000"),
|
||||
new OA\Property(property: "email", type: "string", example: "test@example.com"),
|
||||
new OA\Property(property: "avatar", type: "string", example: ""),
|
||||
new OA\Property(property: "level_id", type: "integer", example: 1),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "create_time", type: "integer", example: 1640995200),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:user:read")]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/user',
|
||||
summary: '创建',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "username", type: "string", example: "testuser"),
|
||||
new OA\Property(property: "nickname", type: "string", example: "测试用户"),
|
||||
new OA\Property(property: "phone", type: "string", example: "13800138000"),
|
||||
new OA\Property(property: "email", type: "string", example: "test@example.com"),
|
||||
new OA\Property(property: "password", type: "string", example: "123456"),
|
||||
new OA\Property(property: "avatar", type: "string", example: ""),
|
||||
new OA\Property(property: "level_id", type: "integer", example: 1),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
])
|
||||
),
|
||||
tags: ['会员用户'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "创建成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
],
|
||||
)]
|
||||
#[Permission("member:user:create")]
|
||||
#[SimpleResponse( example: '{"code":0,"msg":"created","id":1}')]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/user/{id}',
|
||||
summary: '更新',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "nickname", type: "string", example: "新昵称"),
|
||||
new OA\Property(property: "phone", type: "string", example: "13800138000"),
|
||||
new OA\Property(property: "email", type: "string", example: "test@example.com"),
|
||||
new OA\Property(property: "avatar", type: "string", example: ""),
|
||||
new OA\Property(property: "level_id", type: "integer", example: 2),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
])
|
||||
),
|
||||
tags: ['会员用户'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "用户ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "更新成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:user:update")]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/user/{id}',
|
||||
summary: '删除',
|
||||
tags: ['会员用户'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "用户ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "删除成功"),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:user:delete")]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/user',
|
||||
summary: '批量删除',
|
||||
tags: ['会员用户'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class],
|
||||
)]
|
||||
#[Permission("member:user:delete")]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/user/{id}/reset-password',
|
||||
summary: '重置密码',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "password", type: "string", example: "123456"),
|
||||
])
|
||||
),
|
||||
tags: ['会员用户'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "用户ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "密码重置成功"),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:user:reset_password")]
|
||||
public function resetPassword(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->insertInput($request);
|
||||
if (empty($data['password'])) {
|
||||
return Json::fail('密码不能为空');
|
||||
}
|
||||
$this->service->update($id, ['password' => $data['password']]);
|
||||
return Json::success('密码重置成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/user/{id}/assign-tags',
|
||||
summary: '分配标签',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "tags", type: "array", example: [1, 2, 3]),
|
||||
])
|
||||
),
|
||||
tags: ['会员用户'],
|
||||
)]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
#[Permission("member:user:assign_tags")]
|
||||
public function assignTags(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $request->input('tags', []);
|
||||
if (empty($data)) {
|
||||
return Json::fail('标签不能为空');
|
||||
}
|
||||
$this->service->assignTags($id, $data);
|
||||
return Json::success('标签分配成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/user/{id}/adjust-points',
|
||||
summary: '调整会员积分',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "points", type: "integer", example: 100),
|
||||
])
|
||||
),
|
||||
tags: ['会员用户'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "用户ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
#[Permission("member:user:adjust_points")]
|
||||
public function adjustPoints(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$points = $request->input('points', 0);
|
||||
$this->service->adjustPoints($id, (int)$points);
|
||||
return Json::success('积分调整成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化下拉列表
|
||||
*
|
||||
* @param $items
|
||||
*
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function formatSelect($items): \support\Response
|
||||
{
|
||||
$formatted_items = [];
|
||||
foreach ($items as $item) {
|
||||
$formatted_items[] = [
|
||||
'label' => $item->nickname ?? $item->id,
|
||||
'value' => $item->id,
|
||||
];
|
||||
}
|
||||
return Json::success('ok', $formatted_items);
|
||||
}
|
||||
|
||||
// #[OA\Get(
|
||||
// path: '/member/user/statistics',
|
||||
// summary: '会员统计',
|
||||
// tags: ['会员用户'],
|
||||
// responses: [
|
||||
// new OA\Response(
|
||||
// response: 200,
|
||||
// description: "成功",
|
||||
// content: new OA\JsonContent(properties: [
|
||||
// new OA\Property(property: "code", type: "integer", example: 0),
|
||||
// new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
// new OA\Property(property: "data", properties: [
|
||||
// new OA\Property(property: "total", type: "integer", example: 100),
|
||||
// new OA\Property(property: "active", type: "integer", example: 80),
|
||||
// new OA\Property(property: "inactive", type: "integer", example: 20),
|
||||
// ], type: "object"),
|
||||
// ])
|
||||
// ),
|
||||
// ]
|
||||
// )]
|
||||
// #[Permission("member:user:statistics")]
|
||||
public function statistics(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->getStatistics();
|
||||
return Json::success('获取成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\member;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\member\MemberPointsValidate;
|
||||
use app\service\admin\member\MemberPointsService;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class PointsController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(MemberPointsService $service, MemberPointsValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/points',
|
||||
summary: '列表',
|
||||
tags: ['会员积分'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "member_id", description: "会员ID", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "type", description: "类型", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "start_time", description: "开始时间", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "end_time", description: "结束时间", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:points:list")]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, ['member'], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/points/{id}',
|
||||
summary: '详情',
|
||||
tags: ['会员积分'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:points:read")]
|
||||
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id, ['*'], ['member'], 'created_at', []);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => 400]);
|
||||
}
|
||||
return Json::success('ok', $data->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/points',
|
||||
summary: '新增',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "member_id", type: "integer", example: 1),
|
||||
new OA\Property(property: "points", type: "integer", example: 100),
|
||||
new OA\Property(property: "type", type: "integer", example: 1),
|
||||
new OA\Property(property: "source", type: "string", example: "admin"),
|
||||
new OA\Property(property: "remark", type: "string", example: "管理员操作"),
|
||||
new OA\Property(property: "operator", type: "string", example: "admin"),
|
||||
])
|
||||
),
|
||||
tags: ['会员积分']
|
||||
)]
|
||||
#[Permission("member:points:create")]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->operate($data);
|
||||
return Json::success('操作成功');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\member;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\member\MemberTagValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\member\MemberTagService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class TagController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(MemberTagService $service, MemberTagValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/tag',
|
||||
summary: '列表',
|
||||
tags: ['会员标签'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "name", description: "标签名称", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "status", description: "状态", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:tag:list")]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/tag/{id}',
|
||||
summary: '详情',
|
||||
tags: ['会员标签'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
new OA\Property(property: "name", type: "string", example: "活跃会员"),
|
||||
new OA\Property(property: "color", type: "string", example: "#409EFF"),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "sort", type: "integer", example: 100),
|
||||
new OA\Property(property: "create_time", type: "integer", example: 1640995200),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:tag:read")]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/member/tag',
|
||||
summary: '新增',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "活跃会员"),
|
||||
new OA\Property(property: "color", type: "string", example: "#409EFF"),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "sort", type: "integer", example: 100),
|
||||
])
|
||||
),
|
||||
tags: ['会员标签']
|
||||
)]
|
||||
#[Permission("member:tag:create")]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/tag/{id}',
|
||||
summary: '更新',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "活跃会员"),
|
||||
new OA\Property(property: "color", type: "string", example: "#409EFF"),
|
||||
new OA\Property(property: "status", type: "integer", example: 1),
|
||||
new OA\Property(property: "sort", type: "integer", example: 100),
|
||||
])
|
||||
),
|
||||
tags: ['会员标签'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "标签ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "更新成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("member:tag:update")]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/tag/{id}',
|
||||
summary: '删除',
|
||||
tags: ['会员标签'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "标签ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("member:tag:delete")]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/member/tag',
|
||||
summary: '批量删除',
|
||||
tags: ['会员标签'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class],
|
||||
)]
|
||||
#[Permission("member:tag:delete")]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/member/{id}/permissions',
|
||||
summary: '为标签分配权限',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "permissions", type: "array", items: new OA\Items(type: "string"), example: ["developer", "api_access"]),
|
||||
])
|
||||
),
|
||||
tags: ['会员标签'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "标签ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
)]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
#[Permission("member:tag:assign_permissions")]
|
||||
public function assignPermissions(Request $request, $id): \support\Response
|
||||
{
|
||||
try {
|
||||
$permissions = $request->input('permissions', []);
|
||||
$this->service->assignPermissions($id, $permissions);
|
||||
return Json::success('权限分配成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/{id}/permissions',
|
||||
summary: '获取标签权限',
|
||||
tags: ['会员标签'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "标签ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
)]
|
||||
#[Permission("member:tag:show_permissions")]
|
||||
public function getPermissions(Request $request, $id): \support\Response
|
||||
{
|
||||
try {
|
||||
$tag = $this->service->get($id, ['*'], ['permissions']);
|
||||
if (!$tag) {
|
||||
return Json::fail('标签不存在');
|
||||
}
|
||||
return Json::success('ok', $tag->permissions->toArray());
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/all-with-permissions',
|
||||
summary: '获取所有启用的标签(含权限)',
|
||||
tags: ['会员标签'],
|
||||
)]
|
||||
#[Permission("member:tag:all")]
|
||||
public function getAllWithPermissions(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->getEnabledTagsWithPermissions();
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/member/available-permissions',
|
||||
summary: '获取所有可用的权限码(从菜单表)',
|
||||
tags: ['会员标签'],
|
||||
)]
|
||||
#[Permission("member:tag:all")]
|
||||
public function getAvailablePermissions(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->getAvailablePermissions();
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\message;
|
||||
|
||||
use app\adminapi\CurrentUser;
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\message\MessageFormRequest;
|
||||
use app\adminapi\schema\request\message\MessageQueryRequest;
|
||||
use app\adminapi\schema\response\system\MessageResponse;
|
||||
use app\adminapi\validate\system\MessageValidate;
|
||||
use app\enum\system\MessageStatus;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\message\MessageService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use support\Container;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class MessageController extends Crud
|
||||
{
|
||||
public function __construct(MessageService $service, MessageValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/message',
|
||||
summary: '列表',
|
||||
tags: ['消息管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MessageQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:message:list')]
|
||||
#[PageResponse(MessageResponse::class)]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
$uid = Container::make(CurrentUser::class)->id();
|
||||
$data = $request->get();
|
||||
$data['receiver_id'] = $uid;//消息接收人
|
||||
$request->setGet($data);
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/message/{id}',
|
||||
summary: '详情',
|
||||
tags: ['消息管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:message:read')]
|
||||
#[SimpleResponse(schema: MessageResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/message',
|
||||
summary: '创建',
|
||||
tags: ['消息管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MessageFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:message:create')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/message/{id}',
|
||||
summary: '更新',
|
||||
tags: ['消息管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MessageFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '消息ID(雪花ID)',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(
|
||||
type: 'string',
|
||||
example: '123456789012345678'
|
||||
)
|
||||
)]
|
||||
#[Permission(code: 'network:message:update')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
#[OA\Post(
|
||||
path: '/message/export',
|
||||
summary: '导出',
|
||||
tags: ['消息管理']
|
||||
)]
|
||||
#[Permission(code: 'network:message:list', description: '导出')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function export(Request $request): \support\Response
|
||||
{
|
||||
return parent::export($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/message/{id}',
|
||||
summary: '删除',
|
||||
tags: ['消息管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'id',
|
||||
description: '消息ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(
|
||||
type: 'string',
|
||||
default: 0,
|
||||
example: '123456789012345678',
|
||||
)
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:message:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/message',
|
||||
summary: '批量删除',
|
||||
tags: ['消息管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:message:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/message/{id}/update-read',
|
||||
summary: '消息状态标记',
|
||||
tags: ['消息管理'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '消息ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(
|
||||
type: 'string',
|
||||
default: 0,
|
||||
example: '123456789012345678',
|
||||
)
|
||||
)]
|
||||
#[RequestBody(required: true, content: new OA\JsonContent(
|
||||
required: ['status'],
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'status',
|
||||
description: '消息状态(0=未读,1=已读)',
|
||||
type: 'integer',
|
||||
enum: [0, 1],
|
||||
example: 1
|
||||
),
|
||||
]
|
||||
))]
|
||||
#[Permission(code: 'network:message:update_read')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function updateRead(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
if ($this->validate) {
|
||||
$this->validate->scene('update-read')->check($data);
|
||||
}
|
||||
$actionMap = [
|
||||
MessageStatus::READ->value => 'isRead',
|
||||
MessageStatus::UNREAD->value => 'isUnread',
|
||||
];
|
||||
|
||||
if (!isset($actionMap[$data['status']])) {
|
||||
throw new \InvalidArgumentException('Invalid message status');
|
||||
}
|
||||
|
||||
$this->service->{$actionMap[$data['status']]}(
|
||||
$data['id'] ?? throw new \InvalidArgumentException('Missing message ID')
|
||||
);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
// 统一异常处理(生产环境建议记录日志)
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/message/notify-on-first-login-to-all',
|
||||
summary: '推送广播&消息',
|
||||
tags: ['消息管理'],
|
||||
)]
|
||||
#[Permission(code: 'network:message:push')]
|
||||
#[AllowAnonymous(requireToken: true,requirePermission: false)]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function notifyOnFirstLoginToAll(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = Container::make(CurrentUser::class)->id();
|
||||
$this->service->notifyOnFirstLoginToAll($id);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\monitor;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\admin\monitor\OnlineUserService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class OnlineUserController extends Crud
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/monitor/online-user',
|
||||
summary: '在线用户列表',
|
||||
tags: ['系统监控']
|
||||
)]
|
||||
#[Permission(code: 'monitor:online_user:list')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var OnlineUserService $service */
|
||||
$service = Container::get(OnlineUserService::class);
|
||||
return Json::success('ok', $service->list($request->all()));
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/monitor/online-user/{jti}',
|
||||
summary: '踢下线',
|
||||
tags: ['系统监控']
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'jti',
|
||||
description: '会话JTI',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[Permission(code: 'monitor:online_user:kickout')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$jti = (string)$request->route->param('jti', '');
|
||||
if ($jti === '') {
|
||||
return Json::fail('会话JTI不能为空');
|
||||
}
|
||||
|
||||
/** @var OnlineUserService $service */
|
||||
$service = Container::get(OnlineUserService::class);
|
||||
if (!$service->kickout($jti)) {
|
||||
return Json::fail('会话不存在或已失效');
|
||||
}
|
||||
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/monitor/online-user/{jti}/revoke',
|
||||
summary: '撤销Token',
|
||||
tags: ['系统监控']
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'jti',
|
||||
description: '会话JTI',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[Permission(code: 'monitor:online_user:revoke')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function revoke(Request $request): \support\Response
|
||||
{
|
||||
return $this->destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\monitor;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\response\monitor\RedisMonitorResponse;
|
||||
use core\monitor\ServerMonitor;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RedisController extends Crud
|
||||
{
|
||||
|
||||
#[OA\Get(
|
||||
path: '/monitor/redis',
|
||||
summary: 'Redis监控',
|
||||
tags: ['系统监控']
|
||||
)]
|
||||
#[Permission(code: 'monitor:redis:read')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => RedisMonitorResponse::class])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var ServerMonitor $service */
|
||||
$service = Container::get(ServerMonitor::class);
|
||||
$data = $service->getRedisInfo();
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\monitor;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\response\monitor\ServerMonitorResponse;
|
||||
use core\monitor\ServerMonitor;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ServerController extends Crud
|
||||
{
|
||||
|
||||
#[OA\Get(
|
||||
path: '/monitor/server',
|
||||
summary: '性能监控',
|
||||
tags: ['系统监控']
|
||||
)]
|
||||
#[Permission(code: 'monitor:server:read')]
|
||||
#[SimpleResponse(schema:ServerMonitorResponse::class, example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var ServerMonitor $service */
|
||||
$service = Container::get(ServerMonitor::class);
|
||||
$serverInfo = [
|
||||
'cpu' => $service->getCpuInfo(),
|
||||
'memory' => $service->getMemoryInfo(),
|
||||
'disk' => $service->getDiskInfo(),
|
||||
'php' => $service->getPhpInfo(),
|
||||
];
|
||||
|
||||
return Json::success('ok', $serverInfo);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\notice;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\notice\NoticeFormRequest;
|
||||
use app\adminapi\schema\request\notice\NoticeQueryRequest;
|
||||
use app\adminapi\schema\response\system\NoticeResponse;
|
||||
use app\adminapi\validate\system\NoticeValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\notice\NoticeService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use Webman\RedisQueue\Client;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class NoticeController extends Crud
|
||||
{
|
||||
// 注入服务和验证器
|
||||
public function __construct(NoticeService $service, NoticeValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/notice',
|
||||
summary: '列表',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => NoticeQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:notice:list')]
|
||||
#[PageResponse(schema:NoticeResponse::class,example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request); // 调用父类Crud的列表方法
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/notice/{id}',
|
||||
summary: '详情',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:notice:read')]
|
||||
#[SimpleResponse(schema: NoticeResponse::class, example: ['code' => 0, 'message' => 'success', 'data' => []])] // 详情响应
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request); // 调用父类Crud的详情方法
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/notice',
|
||||
summary: '创建',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => NoticeFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:notice:create')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
// 4. 更新公告
|
||||
#[OA\Put(
|
||||
path: '/notice/{id}',
|
||||
summary: '更新',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => NoticeFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
)]
|
||||
#[Permission(code: 'network:notice:update')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])] // 更新响应
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request); // 调用父类Crud的更新方法
|
||||
}
|
||||
#[OA\Post(
|
||||
path: '/notice/export',
|
||||
summary: '导出',
|
||||
tags: ['公告管理']
|
||||
)]
|
||||
#[Permission(code: 'network:notice:list', description: '导出')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function export(Request $request): \support\Response
|
||||
{
|
||||
return parent::export($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/notice/{id}',
|
||||
summary: '删除',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:notice:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])] // 删除响应
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request); // 调用父类Crud的删除方法
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/notice',
|
||||
summary: '批量删除',
|
||||
tags: ['公告管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'network:notice:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/notice/publish',
|
||||
summary: '发布',
|
||||
tags: ['公告管理'],
|
||||
)]
|
||||
#[Permission(code: 'network:notice:publish')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function publish(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->input('id', null);
|
||||
$model = $this->service->get($id);
|
||||
$queue = 'admin-announcement-push';
|
||||
Client::send($queue, $model->makeVisible('tenant_id')->toArray(), 0);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\org;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\org\DeptFormRequest;
|
||||
use app\adminapi\schema\request\org\DeptQueryRequest;
|
||||
use app\adminapi\schema\response\system\DeptResponse;
|
||||
use app\adminapi\validate\system\DeptValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\org\DeptService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class DeptController extends Crud
|
||||
{
|
||||
public function __construct(DeptService $service, DeptValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/org/dept',
|
||||
summary: '列表',
|
||||
tags: ['部门管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => DeptQueryRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'org:dept:list')]
|
||||
#[PageResponse(DeptResponse::class)]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/org/dept',
|
||||
summary: '创建',
|
||||
tags: ['部门管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => DeptFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:dept:create')]
|
||||
#[SimpleResponse(DeptResponse::class, example: '{"code":0,"msg":"created","id":1}')]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->inputFilter($request->all(), ['leader_id_list']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/org/dept/{id}',
|
||||
summary: '删除',
|
||||
tags: ['部门管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:dept:delete')]
|
||||
#[SimpleResponse( example: '{"code":0,"msg":"success","data":null}')]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/org/dept',
|
||||
summary: '批量删除',
|
||||
tags: ['部门管理'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'org:dept:delete')]
|
||||
#[SimpleResponse(example: '{"code":0,"msg":"success","data":null}')]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/org/dept/{id}',
|
||||
summary: '更新',
|
||||
tags: ['部门管理'],
|
||||
)]
|
||||
#[Permission(code: 'org:dept:update')]
|
||||
#[SimpleResponse( example: '{"code":0,"msg":"success","data":null}')]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->inputFilter($request->all(), ['leader_id_list']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->update($id, $data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/org/dept/{id}',
|
||||
summary: '详情',
|
||||
tags: ['部门管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:dept:read')]
|
||||
#[SimpleResponse(DeptResponse::class, example: '{"code":0,"msg":"success","data":null}')]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\org;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\org\PostFormRequest;
|
||||
use app\adminapi\schema\request\org\PostQueryRequest;
|
||||
use app\adminapi\schema\response\system\PostResponse;
|
||||
use app\adminapi\validate\system\PostValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\org\PostService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class PostController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(PostService $service, PostValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/org/post',
|
||||
summary: '列表',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => PostQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:post:list')]
|
||||
#[PageResponse(PostResponse::class, example: '{"code":0,"msg":"success","data":[]}')] // 分页响应关联岗位Schema
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, ['dept']);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/org/post/{id}',
|
||||
summary: '详情',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:post:read')]
|
||||
#[SimpleResponse(PostResponse::class, example: [])] // 详情响应
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id,['*'],['dept']);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到');
|
||||
}
|
||||
return Json::success('ok', $data->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/org/post',
|
||||
summary: '创建',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => PostFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:post:create')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/org/post/{id}',
|
||||
summary: '更新',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => PostFormRequest::class,
|
||||
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'org:post:update')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/org/post/{id}',
|
||||
summary: '删除',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
)]
|
||||
#[Permission(code: 'org:post:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/org/post',
|
||||
summary: '批量删除',
|
||||
tags: ['岗位管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
)]
|
||||
#[Permission(code: 'org:post:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\plugin;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\plugin\ApplicationAuthFormRequest;
|
||||
use app\adminapi\schema\request\plugin\ApplicationAuthQueryRequest;
|
||||
use app\adminapi\schema\response\plugin\ApplicationAuthResponse;
|
||||
use app\adminapi\validate\plugin\ApplicationAuthValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\plugin\ApplicationAuthService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ApplicationAuthController extends Crud
|
||||
{
|
||||
public function __construct(ApplicationAuthService $service, ApplicationAuthValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/application-auth',
|
||||
summary: '列表',
|
||||
tags: ['应用授权'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthQueryRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:list')]
|
||||
#[PageResponse(schema: ApplicationAuthResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/application-auth/{id}',
|
||||
summary: '详情',
|
||||
tags: ['应用授权'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:read')]
|
||||
#[SimpleResponse(schema: ApplicationAuthResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/plugin/application-auth',
|
||||
summary: '创建',
|
||||
tags: ['应用授权'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthFormRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:create')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/plugin/application-auth/{id}',
|
||||
summary: '更新',
|
||||
tags: ['应用授权'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => ApplicationAuthFormRequest::class]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:update')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
#[OA\Post(
|
||||
path: '/plugin/application-auth/export',
|
||||
summary: '导出',
|
||||
tags: ['应用授权']
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:list', description: '导出')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function export(Request $request): \support\Response
|
||||
{
|
||||
return parent::export($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/plugin/application-auth/{id}',
|
||||
summary: '删除',
|
||||
tags: ['应用授权'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/plugin/application-auth',
|
||||
summary: '批量删除',
|
||||
tags: ['应用授权'],
|
||||
x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/plugin/application-auth/{id}/reset-secret',
|
||||
summary: '重置密钥',
|
||||
tags: ['应用授权'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:application-auth:reset-secret')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => ['id' => '123456789012345678', 'secret_key' => 'SK...']])]
|
||||
public function resetSecret(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
return Json::success('ok', $this->service->resetSecret($id));
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\plugin;
|
||||
|
||||
use app\adminapi\controller\Base;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\core\plugin\PluginDownloadService;
|
||||
use app\service\core\plugin\PluginInstallService;
|
||||
use app\service\core\plugin\PluginRemoteService;
|
||||
use app\service\core\plugin\PluginUninstallService;
|
||||
use app\service\core\plugin\PluginService;
|
||||
use core\tool\Sse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class PluginController extends Base
|
||||
{
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin',
|
||||
summary: '列表',
|
||||
tags: ['模块市场'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'page',
|
||||
description: '页码',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 1)
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'limit',
|
||||
description: '每页数量',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 10)
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'type',
|
||||
description: '模块类型(module: 系统模块, plugin: 插件)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string', enum: ['module', 'plugin'])
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'status',
|
||||
description: '状态(0:禁用,1:启用)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', enum: [0, 1])
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'keyword',
|
||||
description: '搜索关键词',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'installed',
|
||||
description: '是否已安装(0:未安装,1:已安装)',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', enum: [0, 1])
|
||||
),
|
||||
],
|
||||
)]
|
||||
#[PageResponse(schema: [], example: [[
|
||||
'id' => 3,
|
||||
'code' => 'official',
|
||||
'name' => 'official',
|
||||
'type' => 'madong',
|
||||
'version' => '1.0.0',
|
||||
'status' => 1,
|
||||
'description' => '官方应用插件',
|
||||
'detail_description' => '',
|
||||
'author' => 'Madong',
|
||||
'cover' => '',
|
||||
'poster' => '',
|
||||
'price' => 0,
|
||||
'downloads' => 0,
|
||||
'rating' => 0,
|
||||
'created_at' => '2026-03-19 16:26:19',
|
||||
'updated_at' => '2026-03-19 16:26:19',
|
||||
'update_time' => '',
|
||||
'update_logs' => [],
|
||||
'category' => null,
|
||||
'category_name' => '',
|
||||
'tags' => [],
|
||||
'is_new' => 0,
|
||||
'is_hot' => 0,
|
||||
'purchased' => 0,
|
||||
'installed' => 0,
|
||||
'manual_uninstall' => 0,
|
||||
'composer_dependencies' => [],
|
||||
'npm_dependencies' => [],
|
||||
'is_installed' => 1,
|
||||
'installed_version' => '1.0.0',
|
||||
'has_update' => 0,
|
||||
'is_purchased' => 1,
|
||||
'is_downloaded' => 1,
|
||||
'can_uninstall' => 1,
|
||||
'can_download' => 1,
|
||||
'undeletable' => 1,
|
||||
'version_info' => [
|
||||
'remote' => [
|
||||
'version' => '1.0.0',
|
||||
'release_date' => '2026-03-19 16:26:19',
|
||||
],
|
||||
'local' => [
|
||||
'version' => '1.0.0',
|
||||
'install_date' => '2026-03-19 16:26:19',
|
||||
],
|
||||
'comparison' => [
|
||||
'needs_update' => 0,
|
||||
'is_latest' => 1,
|
||||
'version_difference' => null,
|
||||
],
|
||||
],
|
||||
]])]
|
||||
#[Permission(code: 'plugin:module:list')]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$category = $request->input('category', null);
|
||||
$pageInput = $request->input('current', $request->input('page', 1));
|
||||
$limitInput = $request->input('size', $request->input('limit', 15));
|
||||
$page = max(1, (int)$pageInput);
|
||||
$limit = max(1, (int)$limitInput);
|
||||
$type = $request->input('type');
|
||||
$keyword = $request->input('keyword');
|
||||
/** @var PluginService $service */
|
||||
$service = Container::make(PluginService::class);
|
||||
$result = $service->getList($category, $type, $keyword, $page, $limit);
|
||||
return Json::success('common.operation.success', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/{name}/download',
|
||||
summary: '下载模块',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'name',
|
||||
description: '模块标识',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function download(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$pluginCode = $request->route->param('name');
|
||||
|
||||
// 1. 获取下载链接
|
||||
$remoteService = Container::make(PluginRemoteService::class);
|
||||
$authCode = config('madong.auth_code');
|
||||
$secretKey = config('madong.auth_secret');
|
||||
|
||||
$downloadInfo = $remoteService->getRemoteDownloadService($authCode, $secretKey, $pluginCode, 'latest');
|
||||
if (empty($downloadInfo['url'])) {
|
||||
return Json::fail('获取下载链接失败');
|
||||
}
|
||||
|
||||
// 2. 下载并解压插件
|
||||
$downloadService = Container::make(PluginDownloadService::class);
|
||||
$result = $downloadService->downloadAndExtract($pluginCode, $downloadInfo['url']);
|
||||
|
||||
return Json::success('下载成功', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/detail/{name}',
|
||||
summary: '获取模块详情',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'name',
|
||||
description: '模块标识',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function detail(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$moduleName = $request->route->param('name');
|
||||
/** @var PluginService $service */
|
||||
$service = Container::make(PluginService::class);
|
||||
$result = $service->getList(null, null, $moduleName);
|
||||
return Json::success('common.operation.success', $result['items'][0]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/{name}/upgrade-logs',
|
||||
summary: '获取模块升级日志',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'name',
|
||||
description: '模块标识',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function upgradeLogs(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$moduleName = $request->route->param('name');
|
||||
/** @var PluginService $service */
|
||||
$service = Container::make(PluginService::class);
|
||||
$result = $service->getUpgradeLogs($moduleName);
|
||||
|
||||
return Json::success('common.operation.success', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/check-environment',
|
||||
summary: '环境检测',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'name',
|
||||
description: '模块标识',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function checkEnvironment(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$name = $request->input('name');
|
||||
/** @var PluginInstallService $service */
|
||||
$service = Container::make(PluginInstallService::class);
|
||||
$result = $service->installCheck($name);
|
||||
|
||||
// 提取路径列表和状态
|
||||
$paths = [];
|
||||
foreach ($result['checks'] as $check) {
|
||||
if (isset($check['path'])) {
|
||||
// 只展示从madong开始的路径
|
||||
$path = $check['path'];
|
||||
$madongPos = strpos(strtolower($path), 'madong');
|
||||
if ($madongPos !== false) {
|
||||
// 截取从madong开始的路径
|
||||
$path = substr($path, $madongPos);
|
||||
// 确保路径格式正确,madong后面应该有目录分隔符
|
||||
if (substr($path, 6, 1) !== DIRECTORY_SEPARATOR) {
|
||||
$path = 'madong' . DIRECTORY_SEPARATOR . substr($path, 6);
|
||||
}
|
||||
}
|
||||
$paths[] = [
|
||||
'path' => $path,
|
||||
'requirement' => $check['permission_type'] ?? 'readable',
|
||||
'status' => $check['status'] === 'success' ? 'success' : 'error',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return Json::success('common.operation.success', [
|
||||
'paths' => $paths,
|
||||
'overall_status' => $result['overall_status'],
|
||||
'message' => $result['message'],
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/install',
|
||||
summary: '插件安装',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function install(Request $request): void
|
||||
{
|
||||
$connection = $request->connection;
|
||||
$code = $request->input('code');
|
||||
$mode = $request->input('mode', 'local');
|
||||
|
||||
// 验证参数
|
||||
if (empty($code)) {
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
], "\r\n"));
|
||||
$connection->send(\core\tool\Sse::error('参数错误:缺少code参数'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送SSE响应头
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
], "\r\n"));
|
||||
|
||||
try {
|
||||
// 发送开始安装消息
|
||||
$connection->send(Sse::progress('开始安装插件 ' . $code, 0));
|
||||
|
||||
// 调用安装服务
|
||||
$generator = (new PluginInstallService())->install($code, $mode);
|
||||
foreach ($generator as $chunk) {
|
||||
$connection->send($chunk);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// 发送错误消息
|
||||
$connection->send(Sse::error('安装失败:' . $e->getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/uninstall',
|
||||
summary: '插件卸载(SSE流式)',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'code',
|
||||
description: '插件编码',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function uninstall(Request $request): void
|
||||
{
|
||||
$connection = $request->connection;
|
||||
$code = $request->input('code');
|
||||
// 验证参数
|
||||
if (empty($code)) {
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
], "\r\n"));
|
||||
$connection->send(Sse::error('参数错误:缺少code参数'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送SSE响应头
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
], "\r\n"));
|
||||
|
||||
try {
|
||||
// 调用卸载服务(统一入口)
|
||||
$generator = (new PluginUninstallService())->uninstall($code);
|
||||
foreach ($generator as $chunk) {
|
||||
$connection->send($chunk);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// 发送错误消息
|
||||
$connection->send(Sse::error('卸载失败:' . $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/plugin/{name}',
|
||||
summary: '插件删除',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'name',
|
||||
description: '插件名称',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[Permission(code: 'plugin:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$name = $request->route->param('name');
|
||||
if (empty($name)) {
|
||||
return Json::fail('参数错误:缺少name参数', []);
|
||||
}
|
||||
|
||||
/** @var PluginUninstallService $service */
|
||||
$service = Container::get(PluginUninstallService::class);
|
||||
$service->delete($name);
|
||||
return Json::success('common.operation.delete.success', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/select',
|
||||
summary: '获取已安装插件列表(用于下拉框)',
|
||||
tags: ['模块市场'],
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function select(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var PluginService $service */
|
||||
$service = Container::make(PluginService::class);
|
||||
|
||||
// 获取本地插件列表(包括已安装和未安装的)
|
||||
$localModules = $service->getLocalModules();
|
||||
|
||||
// 过滤出已安装的插件
|
||||
$installedPlugins = array_filter($localModules, function ($module) {
|
||||
return $module['is_installed'] === true && $module['status'] == 1;
|
||||
});
|
||||
|
||||
// 构建下拉框格式数据
|
||||
$selectItems = [];
|
||||
foreach ($installedPlugins as $plugin) {
|
||||
$selectItems[] = [
|
||||
'value' => $plugin['name'],
|
||||
'label' => $plugin['name'] . ' - ' . $plugin['description'],
|
||||
'name' => $plugin['name'],
|
||||
'description' => $plugin['description'],
|
||||
'version' => $plugin['version'],
|
||||
'type' => $plugin['type'] ?? 'plugin',
|
||||
];
|
||||
}
|
||||
|
||||
return Json::success('common.operation.success', array_values($selectItems));
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), []);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\plugin;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\plugin\PluginValidate;
|
||||
use app\service\admin\plugin\PluginDevelopService;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class PluginDevelopController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(PluginDevelopService $service, PluginValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件列表
|
||||
* 扫描插件目录,获取type为madong:前缀的插件,同步到数据库并返回列表
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
*/
|
||||
#[OA\Get(
|
||||
path: '/plugin/develop',
|
||||
summary: '插件列表',
|
||||
tags: ['插件开发'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'page',
|
||||
description: '页码',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 1)
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'limit',
|
||||
description: '每页数量',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 15)
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'title',
|
||||
description: '插件标题',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'author',
|
||||
description: '作者',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
),
|
||||
new OA\Parameter(
|
||||
name: 'status',
|
||||
description: '状态',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:develop:list')]
|
||||
#[PageResponse(schema: [], example: [[
|
||||
"id" => "2032735331152958596",
|
||||
"name" => "官网管理",
|
||||
"icon" => null,
|
||||
"code" => "official",
|
||||
"description" => "官网管理插件,用于搭建和管理企业官方网站",
|
||||
"enabled" => 1,
|
||||
"author" => "Mr.April",
|
||||
"version" => "1.0.0",
|
||||
"cover" => null,
|
||||
"type" => "madong:plugin",
|
||||
"support_app" => "admin",
|
||||
"installed_at" => null,
|
||||
"created_at" => 1773476844,
|
||||
"updated_at" => 1773476844,
|
||||
"variables" => null,
|
||||
"created_date" => "2026-03-14 16:27:24",
|
||||
"updated_date" => "2026-03-14 16:27:24",
|
||||
]])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 使用标准模式:通过 selectInput 处理查询参数
|
||||
[$where, , $limit, , , $page] = $this->selectInput($request);
|
||||
|
||||
// 调用服务层获取列表数据
|
||||
$result = $this->service->getList($where, $page, $limit);
|
||||
|
||||
// 使用标准格式返回
|
||||
return Json::success($result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/plugin/develop/{id}',
|
||||
summary: '插件详情',
|
||||
tags: ['插件开发'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'id',
|
||||
description: '插件ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:develop:read')]
|
||||
#[DataResponse(schema: [], example: [
|
||||
"id" => "2032735331152958596",
|
||||
"title" => "官网管理",
|
||||
"icon" => null,
|
||||
"key" => "official",
|
||||
"desc" => "官网管理插件,用于搭建和管理企业官方网站",
|
||||
"status" => 1,
|
||||
"author" => "Mr.April",
|
||||
"version" => "1.0.0",
|
||||
"cover" => null,
|
||||
"type" => "madong:plugin",
|
||||
"support_app" => "admin",
|
||||
"installed_at" => null,
|
||||
"created_at" => 1773476844,
|
||||
"updated_at" => 1773476844,
|
||||
"variables" => null,
|
||||
"created_date" => "2026-03-14 16:27:24",
|
||||
"updated_date" => "2026-03-14 16:27:24",
|
||||
])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$plugin = $this->service->read($id);
|
||||
if (!$plugin) {
|
||||
return Json::fail('插件不存在');
|
||||
}
|
||||
return Json::success($plugin->toArray());
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建插件
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Throwable
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: '/plugin/develop',
|
||||
summary: '创建插件',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['title', 'key'],
|
||||
properties: [
|
||||
new OA\Property(property: 'title', description: '插件标题', type: 'string'),
|
||||
new OA\Property(property: 'key', description: '插件标识(唯一值)', type: 'string'),
|
||||
new OA\Property(property: 'desc', description: '插件描述', type: 'string'),
|
||||
new OA\Property(property: 'author', description: '作者', type: 'string'),
|
||||
new OA\Property(property: 'version', description: '版本', type: 'string', default: '1.0.0'),
|
||||
new OA\Property(property: 'type', description: '类型', type: 'string', default: 'madong:plugin'),
|
||||
new OA\Property(property: 'icon', description: '图标(base64)', type: 'string'),
|
||||
new OA\Property(property: 'cover', description: '封面(base64)', type: 'string'),
|
||||
new OA\Property(property: 'frontend_type', description: '前端类型', type: 'string', default: 'admin'),
|
||||
]
|
||||
)
|
||||
),
|
||||
tags: ['插件开发']
|
||||
)]
|
||||
#[Permission(code: 'plugin:develop:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$this->validate->scene('store')->check($request->all());
|
||||
$this->service->store($request->all());
|
||||
return Json::success();
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包插件
|
||||
* 将后端、后台前端、前台前端复制到后端server/plugin/xxx/resource目录,并打包为zip
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: '/plugin/develop/build',
|
||||
summary: '打包插件',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['plugin_key'],
|
||||
properties: [
|
||||
new OA\Property(property: 'plugin_key', description: '插件标识', type: 'string'),
|
||||
]
|
||||
)
|
||||
),
|
||||
tags: ['插件开发']
|
||||
)]
|
||||
#[Permission(code: 'plugin:develop:build')]
|
||||
#[SimpleResponse(schema: [], example: [
|
||||
"plugin_key" => "test",
|
||||
"zip_path" => "D:\\MyProject\\private\\madong/server/runtime/adminapi/test.zip",
|
||||
"has_frontend" => false,
|
||||
])]
|
||||
public function build(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$pluginKey = $request->input('plugin_key');
|
||||
if (empty($pluginKey)) {
|
||||
return Json::fail('插件标识不能为空');
|
||||
}
|
||||
|
||||
$result = $this->service->buildPlugin($pluginKey);
|
||||
return Json::success('插件打包成功',$result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/plugin/develop/{id}',
|
||||
summary: '编辑插件',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'title', description: '插件标题', type: 'string'),
|
||||
new OA\Property(property: 'desc', description: '插件描述', type: 'string'),
|
||||
new OA\Property(property: 'author', description: '作者', type: 'string'),
|
||||
new OA\Property(property: 'version', description: '版本', type: 'string'),
|
||||
new OA\Property(property: 'icon', description: '图标(base64)', type: 'string'),
|
||||
new OA\Property(property: 'cover', description: '封面(base64)', type: 'string'),
|
||||
]
|
||||
)
|
||||
),
|
||||
tags: ['插件开发'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'id',
|
||||
description: '插件ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'integer')
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'plugin:develop:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$this->service->update($id, $request->all());
|
||||
return Json::success('更新成功');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\plugin;
|
||||
|
||||
use app\adminapi\controller\Base;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\core\plugin\PluginRemoteService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\auth\AllowAnonymous;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class PluginMadongAuthController extends Base
|
||||
{
|
||||
|
||||
public function __construct(PluginRemoteService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/madong/auth-info',
|
||||
summary: '获取插件授权信息',
|
||||
tags: ['应用授权']
|
||||
)]
|
||||
#[Permission('madong:delegation:read')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: true)]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": {"company_name": "-","domain": "-","auth_code": "202601***********888888"}}')]
|
||||
public function read(Request $request): \support\Response
|
||||
{
|
||||
|
||||
$data = [
|
||||
'company_name' => '-',
|
||||
'domain' => '-',
|
||||
'auth_code' => config('madong.auth_code'),
|
||||
];
|
||||
return Json::success($data);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/madong/auth-info',
|
||||
summary: '设置插件授权信息',
|
||||
tags: ['应用授权']
|
||||
)]
|
||||
#[Permission('madong:delegation:setting')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$param = $request->all();
|
||||
if (empty($param['auth_code'])) {
|
||||
throw new \Exception('auth_code 不能为空');
|
||||
}
|
||||
if (empty($param['auth_secret'])) {
|
||||
throw new \Exception('auth_secret 不能为空');
|
||||
}
|
||||
$this->service->verifyRemoteAuthorization($param['auth_code'],$param['auth_secret']);
|
||||
//追加到系统配置
|
||||
$this->updateMadongConfig($param['auth_code'], $param['auth_secret']);
|
||||
|
||||
return Json::success('授权设置成功');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新server/config/madong.php文件中的配置
|
||||
*
|
||||
* @param string $authCode 授权码
|
||||
* @param string $authSecret 授权密钥
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function updateMadongConfig(string $authCode, string $authSecret): void
|
||||
{
|
||||
$configPath = base_path() . '/config/madong.php';
|
||||
if (!file_exists($configPath)) {
|
||||
throw new \Exception('madong.php配置文件不存在');
|
||||
}
|
||||
|
||||
$configContent = file_get_contents($configPath);
|
||||
|
||||
// 定义需要替换的参数映射
|
||||
$replacements = [
|
||||
'auth_code' => $authCode,
|
||||
'auth_secret' => $authSecret,
|
||||
];
|
||||
|
||||
foreach ($replacements as $key => $value) {
|
||||
$pattern = '/\'' . $key . '\'\s*=>\s*env\(\'madong\..*?\'\s*,\s*\'(.*?)\'\)/';
|
||||
$replacement = "'$key' => env('madong." . ($key === 'auth_code' ? 'code' : 'secret') . "', '$value')";
|
||||
$configContent = preg_replace($pattern, $replacement, $configContent);
|
||||
}
|
||||
|
||||
file_put_contents($configPath, $configContent);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\profile;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\CurrentUser;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\profile\ProfileUpdateRequest;
|
||||
use app\adminapi\schema\request\profile\PasswordUpdateRequest;
|
||||
use app\adminapi\schema\request\profile\AvatarUpdateRequest;
|
||||
use app\adminapi\validate\profile\ProfileValidate;
|
||||
use app\dao\logs\LoginLogDao;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\logs\LoginLogService;
|
||||
use app\service\admin\system\AdminService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[OA\Tag(name: '个人中心')]
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ProfileController extends Crud
|
||||
{
|
||||
public function __construct(AdminService $service, ProfileValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/profile',
|
||||
summary: '获取当前用户信息',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[SimpleResponse(example: '{"id": 1, "user_name": "admin", "email": "test@example.com"}')]
|
||||
#[Permission(code: 'admin:profile:info')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$userId = Container::make(CurrentUser::class)->id();
|
||||
$data = $this->service->get($userId);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/profile',
|
||||
summary: '更新个人信息',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(ref: ProfileUpdateRequest::class)
|
||||
)]
|
||||
#[SimpleResponse(example: '{"code": 0, "msg": "success"}')]
|
||||
#[Permission(code: 'admin:profile:update_info')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$userId = Container::make(CurrentUser::class)->id();
|
||||
$data = $this->inputFilter($request->all());
|
||||
|
||||
// 验证数据
|
||||
if (!$this->validate->scene('update-profile')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
|
||||
$this->service->updateUserInfo($userId, $data);
|
||||
return Json::success('个人信息更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/profile/password',
|
||||
summary: '修改密码',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(ref: PasswordUpdateRequest::class)
|
||||
)]
|
||||
#[SimpleResponse(example: '{"code": 0, "msg": "密码修改成功"}')]
|
||||
#[Permission(code: 'admin:profile:password')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function updatePassword(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$userId = Container::make(CurrentUser::class)->id();
|
||||
$data = $this->inputFilter($request->all(), ['old_password', 'new_password', 'confirm_password']);
|
||||
|
||||
// 验证数据
|
||||
if (!$this->validate->scene('update-password')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
|
||||
$this->service->updateUserPwd($userId, $data);
|
||||
return Json::success('密码修改成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/profile/avatar',
|
||||
summary: '更新头像',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
#[Permission(code: 'admin:profile:avatar')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function updateAvatar(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$userId = Container::make(CurrentUser::class)->id();
|
||||
$avatar = $request->input('avatar');
|
||||
|
||||
// 验证数据
|
||||
if (!$this->validate->scene('update-avatar')->check(['avatar' => $avatar])) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
|
||||
$this->service->updateAvatarUser($userId, $avatar);
|
||||
return Json::success('头像更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/profile/sessions',
|
||||
summary: '获取在线设备列表',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'page',
|
||||
description: '页码',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 1)
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'limit',
|
||||
description: '每页数量',
|
||||
in: 'query',
|
||||
required: false,
|
||||
schema: new OA\Schema(type: 'integer', default: 10)
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
#[Permission(code: 'admin:profile:sessions')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function getSessions(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$page = (int) $request->input('page', 1);
|
||||
$limit = (int) $request->input('limit', 10);
|
||||
|
||||
$currUser = Container::make(CurrentUser::class);
|
||||
$jwt = new \core\jwt\JwtToken();
|
||||
|
||||
// 获取当前用户信息(用于兜底)
|
||||
$adminInfo = $currUser->admin(true) ?? [];
|
||||
$defaultUserName = $adminInfo['user_name'] ?? '';
|
||||
$defaultRealName = $adminInfo['real_name'] ?? '';
|
||||
$defaultAvatar = $adminInfo['avatar'] ?? '';
|
||||
|
||||
// 从 JWT 获取真实的会话列表
|
||||
$allSessions = $jwt->getSessions($currUser->id());
|
||||
$total = count($allSessions);
|
||||
|
||||
// 分页处理
|
||||
$offset = ($page - 1) * $limit;
|
||||
$sessions = array_slice($allSessions, $offset, $limit);
|
||||
|
||||
// 格式化数据
|
||||
$items = array_map(function ($session) use ($defaultUserName, $defaultRealName, $defaultAvatar) {
|
||||
$extra = $session['extra'] ?? [];
|
||||
return [
|
||||
'jti' => $session['jti'],
|
||||
'client_type' => $session['client_type'] ?? 'admin',
|
||||
'login_time' => $session['created_at'] ?? time(),
|
||||
'ip' => $extra['ip'] ?? '',
|
||||
'ip_location'=>$extra['ip_location'] ?? '',
|
||||
'os' => $extra['os'] ?? '',
|
||||
'browser' => $extra['browser'] ?? '',
|
||||
'user_name' => $extra['user_name'] ?? $defaultUserName,
|
||||
'real_name' => $extra['real_name'] ?? $defaultRealName,
|
||||
'avatar' => $extra['avatar'] ?? $defaultAvatar,
|
||||
];
|
||||
}, $sessions);
|
||||
|
||||
return Json::success('ok', compact('total', 'items'));
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Throwable
|
||||
*/
|
||||
#[OA\Delete(
|
||||
path: '/profile/sessions/{jti}',
|
||||
summary: '强制下线指定设备',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['个人中心']
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'jti',
|
||||
description: '会话JTI',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string')
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
#[Permission(code: 'admin:profile:kickout')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
public function kickoutSession(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$jti = $request->route->param('jti', null);
|
||||
$jwt = new \core\jwt\JwtToken();
|
||||
$result = $jwt->kickoutByJti($jti);
|
||||
|
||||
if (!$result) {
|
||||
return Json::fail('会话不存在或已失效');
|
||||
}
|
||||
|
||||
return Json::success('ok');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/profile/{id}/update-preferences',
|
||||
summary: '更新用户前端偏好设置',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'preferences',
|
||||
description: '偏好设置',
|
||||
type: 'string',
|
||||
example: '{"theme": "dark"}'
|
||||
),
|
||||
]
|
||||
)
|
||||
)]
|
||||
#[Permission(code: 'system:admin:update_preferences')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function updatePreferences(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$uid = Container::make(CurrentUser::class)->id();
|
||||
$data = $request->all();
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
$data['id'] = $uid;
|
||||
if (!$this->validate->scene('update-preferences')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->updateUserPreferences($uid, $data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\review;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\review\ReviewService;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[OA\Tag(name: '审核管理', description: '通用审核模块')]
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ReviewController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(ReviewService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/review',
|
||||
summary: '审核列表',
|
||||
tags: ['审核管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "status", description: "审核状态:0待审核,1已通过,2已拒绝", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "reviewable_type", description: "审核类型(morph_map别名)", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "LIKE_title", description: "标题模糊搜索", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "LIKE_applicant", description: "申请人模糊搜索", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "LIKE_content", description: "内容模糊搜索", in: "query", schema: new OA\Schema(type: "string")),
|
||||
],
|
||||
)]
|
||||
#[Permission(code: "review:list")]
|
||||
#[PageResponse(schema: [], example: [[
|
||||
'id' => '230104551592014400',
|
||||
'reviewable_type' => 'question',
|
||||
'reviewable_id' => '230104551591014400',
|
||||
'status' => 0,
|
||||
'reason' => '同意',
|
||||
'reviewer_id' => 1,
|
||||
'reviewed_at' => 1758899600,
|
||||
'flow_instance_id' => null,
|
||||
'extra_data' => null,
|
||||
'created_by' => 1,
|
||||
'updated_by' => 1,
|
||||
'created_at' => '2026-03-02T09:12:13.000000Z',
|
||||
'updated_at' => '2026-03-02T09:08:38.000000Z',
|
||||
'title' => '请问Madong框架可以免费商用吗?',
|
||||
'content' => '我想用到项目上可以吗!阿打发斯蒂芬阿斯顿发生大法师',
|
||||
'applicant' => '未知',
|
||||
'reviewer_name' => '超级管理员',
|
||||
'display_name' => 'question',
|
||||
'morph_alias' => null,
|
||||
'status_text' => '待审核',
|
||||
'is_workflow_mode' => false,
|
||||
'reviewer' => [
|
||||
'id' => '1',
|
||||
'user_name' => 'superAdmin',
|
||||
'real_name' => '超级管理员',
|
||||
'nick_name' => '超级管理员',
|
||||
'created_date' => null,
|
||||
'updated_date' => null,
|
||||
],
|
||||
'reviewable' => [
|
||||
'id' => '230104551591014400',
|
||||
'category_id' => '2',
|
||||
'title' => '请问Madong框架可以免费商用吗?',
|
||||
'content' => '我想用到项目上可以吗!阿打发斯蒂芬阿斯顿发生大法师',
|
||||
'deleted_at' => null,
|
||||
'created_at' => '2025-09-26T15:13:20.000000Z',
|
||||
'updated_at' => '2026-03-03T06:39:01.000000Z',
|
||||
'view_count' => 3869,
|
||||
'like_count' => 0,
|
||||
'collect_count' => 0,
|
||||
'comment_count' => 0,
|
||||
'member_id' => '277105476800872448',
|
||||
'is_sticky' => 0,
|
||||
'sticky_order' => 0,
|
||||
'is_excellent' => 0,
|
||||
'is_solved' => 0,
|
||||
'solved_answer_id' => null,
|
||||
'created_date' => '2025-09-26 23:13:20',
|
||||
'updated_date' => '2026-03-03 14:39:01',
|
||||
],
|
||||
]])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
|
||||
// 使用 selectInput 处理参数(现在 title/applicant/content 字段已被跳过)
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
|
||||
// 准备关联预加载
|
||||
$with = [
|
||||
'reviewer' => function ($query) {
|
||||
$query->select(['id', 'user_name', 'real_name', 'nick_name']);
|
||||
},
|
||||
];
|
||||
|
||||
// 获取映射后的审核列表(支持 extra_data 字段搜索)
|
||||
$items = $this->service->getMappedList($where, $field, $page, $limit, $order, $with, false);
|
||||
|
||||
// 使用支持搜索的计数方法
|
||||
$total = $this->service->getCountWithSearch($where);
|
||||
return $this->formatNormal($items, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/review/{id}',
|
||||
summary: '审核详情',
|
||||
tags: ['审核管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("review:read")]
|
||||
#[DataResponse(schema: [], example: [
|
||||
'id' => '230104551592014400',
|
||||
'reviewable_type' => 'question',
|
||||
'reviewable_id' => '230104551591014400',
|
||||
'status' => 0,
|
||||
'reason' => '同意',
|
||||
'reviewer_id' => 1,
|
||||
'reviewed_at' => 1758899600,
|
||||
'flow_instance_id' => null,
|
||||
'extra_data' => null,
|
||||
'created_by' => 1,
|
||||
'updated_by' => 1,
|
||||
'created_at' => '2026-03-02T09:12:13.000000Z',
|
||||
'updated_at' => '2026-03-02T09:08:38.000000Z',
|
||||
'title' => '请问Madong框架可以免费商用吗?',
|
||||
'content' => '我想用到项目上可以吗!阿打发斯蒂芬阿斯顿发生大法师',
|
||||
'applicant' => '未知',
|
||||
'reviewer_name' => '超级管理员',
|
||||
'display_name' => 'question',
|
||||
'morph_alias' => null,
|
||||
'status_text' => '待审核',
|
||||
'is_workflow_mode' => false,
|
||||
'reviewer' => [],
|
||||
'reviewable' => [],
|
||||
])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$detail = $this->service->getMappedReview($id);
|
||||
if (!$detail) {
|
||||
return Json::fail('审核记录不存在');
|
||||
}
|
||||
return Json::success('获取成功', $detail);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/review/{id}/approve',
|
||||
summary: '审核通过',
|
||||
tags: ['审核管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "审核ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
)]
|
||||
#[Permission("review:approve")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function approve(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$this->service->approve($id);
|
||||
return Json::success('审核通过');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/review/{id}/reject',
|
||||
summary: '审核拒绝',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: false,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "reason", type: "string", example: "内容违规"),
|
||||
])
|
||||
),
|
||||
tags: ['审核管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "审核ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
)]
|
||||
#[Permission("review:reject")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function reject(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$reason = $request->input('reason', '');
|
||||
$this->service->reject($id, $reason);
|
||||
return Json::success('审核拒绝');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/review/batch/approve',
|
||||
summary: '批量审核通过',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "ids", type: "array", items: new OA\Items(type: "integer"), example: [1, 2, 3]),
|
||||
])
|
||||
),
|
||||
tags: ['审核管理'],
|
||||
)]
|
||||
#[Permission("review:approve")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchApprove(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$ids = $request->input('ids', []);
|
||||
$reason = $request->input('reason', '');
|
||||
if (empty($ids)) {
|
||||
return Json::fail('请选择要审核的记录');
|
||||
}
|
||||
$count = $this->service->batchApprove($ids, ['reason' => $reason]);
|
||||
return Json::success('批量审核通过成功', ['count' => $count]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/review/batch/reject',
|
||||
summary: '批量审核拒绝',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "ids", type: "array", items: new OA\Items(type: "integer"), example: [1, 2, 3]),
|
||||
new OA\Property(property: "reason", type: "string", example: "内容违规"),
|
||||
])
|
||||
),
|
||||
tags: ['审核管理'],
|
||||
)]
|
||||
#[Permission("review:reject")]
|
||||
#[SimpleResponse(schema: [],example: [])]
|
||||
public function batchReject(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$ids = $request->input('ids', []);
|
||||
$reason = $request->input('reason', '');
|
||||
if (empty($ids)) {
|
||||
return Json::fail('请选择要审核的记录');
|
||||
}
|
||||
$count = $this->service->batchReject($ids, $reason, ['reason' => $reason]);
|
||||
return Json::success('批量审核拒绝成功', ['count' => $count]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/review/review/statistics',
|
||||
summary: '审核统计',
|
||||
tags: ['审核管理'],
|
||||
)]
|
||||
#[Permission("review:list")]
|
||||
#[SimpleResponse(schema: [],example: [])]
|
||||
public function statistics(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->getStatistics();
|
||||
return Json::success('获取成功', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/review/{id}',
|
||||
summary: '删除审核记录',
|
||||
tags: ['审核管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "审核ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
]
|
||||
)]
|
||||
#[Permission("review:delete")]
|
||||
#[SimpleResponse(schema: [],example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\AdminFormRequest;
|
||||
use app\adminapi\schema\request\system\AdminQueryRequest;
|
||||
use app\adminapi\schema\response\system\AdminResponse;
|
||||
use app\adminapi\validate\system\AdminValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\system\AdminRoleService;
|
||||
use app\service\admin\system\AdminService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class AdminController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(AdminService $service, AdminValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/admin',
|
||||
summary: '列表',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => AdminQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:list')]
|
||||
#[PageResponse(schema: AdminResponse::class, example: [
|
||||
'id' => '290809605012324352',
|
||||
'user_name' => 'test11',
|
||||
'real_name' => '123456',
|
||||
'nick_name' => null,
|
||||
'is_super' => 0,
|
||||
'mobile_phone' => '18973598654',
|
||||
'email' => '405784684@qq.com',
|
||||
'avatar' => null,
|
||||
'signed' => null,
|
||||
'dashboard' => null,
|
||||
'dept_id' => null,
|
||||
'enabled' => 1,
|
||||
'login_ip' => null,
|
||||
'login_time' => null,
|
||||
'created_by' => 1,
|
||||
'updated_by' => null,
|
||||
'created_at' => '2026-03-13T03:33:32.000000Z',
|
||||
'updated_at' => '2026-03-13T03:45:28.000000Z',
|
||||
'deleted_at' => null,
|
||||
'sex' => 1,
|
||||
'remark' => 'sadf ',
|
||||
'birthday' => null,
|
||||
'tel' => null,
|
||||
'is_locked' => 0,
|
||||
'created_date' => '2026-03-13 11:33:32',
|
||||
'updated_date' => '2026-03-13 11:45:28',
|
||||
'depts' => [],
|
||||
'posts' => [
|
||||
[
|
||||
'id' => '290793153412726784',
|
||||
'dept_id' => '290786837193555968',
|
||||
'code' => 'tex',
|
||||
'name' => '测试题',
|
||||
'sort' => 1,
|
||||
'enabled' => 1,
|
||||
'created_by' => 1,
|
||||
'updated_by' => null,
|
||||
'created_at' => '2026-03-13T02:28:10.000000Z',
|
||||
'updated_at' => '2026-03-13T02:28:10.000000Z',
|
||||
'deleted_at' => null,
|
||||
'remark' => 'sadv ',
|
||||
'created_date' => '2026-03-13 10:28:10',
|
||||
'updated_date' => '2026-03-13 10:28:10',
|
||||
'pivot' => [
|
||||
'admin_id' => '290809605012324352',
|
||||
'post_id' => '290793153412726784',
|
||||
],
|
||||
],
|
||||
],
|
||||
'roles' => [],
|
||||
])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
[$total, $list] = $this->service->getList($where, $field, $page, $limit, $order, [], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/admin',
|
||||
summary: '插入',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => AdminFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->inputFilter($request->all(), ['post_id_list', 'role_id_list', 'dept_id_list', 'main_dept_id', 'main_post_id']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/admin/{id}',
|
||||
summary: '更新',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => AdminFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->inputFilter($request->all(), ['post_id_list', 'role_id_list', 'dept_id_list', 'main_dept_id', 'main_post_id']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->update($id, $data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/admin/{id}',
|
||||
summary: '详情',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:read')]
|
||||
#[SimpleResponse(schema: AdminResponse::class, example: [
|
||||
'id' => '290809605012324352',
|
||||
'user_name' => 'test11',
|
||||
'real_name' => '123456',
|
||||
'nick_name' => null,
|
||||
'is_super' => 0,
|
||||
'mobile_phone' => '18973598654',
|
||||
'email' => '405784684@qq.com',
|
||||
'avatar' => null,
|
||||
'signed' => null,
|
||||
'dashboard' => null,
|
||||
'dept_id' => null,
|
||||
'enabled' => 1,
|
||||
'login_ip' => null,
|
||||
'login_time' => null,
|
||||
'created_by' => 1,
|
||||
'updated_by' => null,
|
||||
'created_at' => '2026-03-13T03:33:32.000000Z',
|
||||
'updated_at' => '2026-03-13T03:45:28.000000Z',
|
||||
'deleted_at' => null,
|
||||
'sex' => 1,
|
||||
'remark' => 'sadf ',
|
||||
'birthday' => null,
|
||||
'tel' => null,
|
||||
'is_locked' => 0,
|
||||
'created_date' => '2026-03-13 11:33:32',
|
||||
'updated_date' => '2026-03-13 11:45:28',
|
||||
'depts' => [],
|
||||
'posts' => [
|
||||
[
|
||||
'id' => '290793153412726784',
|
||||
'dept_id' => '290786837193555968',
|
||||
'code' => 'tex',
|
||||
'name' => '测试题',
|
||||
'sort' => 1,
|
||||
'enabled' => 1,
|
||||
'created_by' => 1,
|
||||
'updated_by' => null,
|
||||
'created_at' => '2026-03-13T02:28:10.000000Z',
|
||||
'updated_at' => '2026-03-13T02:28:10.000000Z',
|
||||
'deleted_at' => null,
|
||||
'remark' => 'sadv ',
|
||||
'created_date' => '2026-03-13 10:28:10',
|
||||
'updated_date' => '2026-03-13 10:28:10',
|
||||
'pivot' => [
|
||||
'admin_id' => '290809605012324352',
|
||||
'post_id' => '290793153412726784',
|
||||
],
|
||||
],
|
||||
],
|
||||
'roles' => [],
|
||||
])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$result = $this->service->getAdminById($id)->toArray();
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/admin/{id}/locked',
|
||||
summary: '禁用',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:locked')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function locked(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 获取单个 ID 和多个 ID
|
||||
$data = $request->input('data', []);
|
||||
$id = $request->input('id');
|
||||
|
||||
// 如果提供了多个 ID,优先使用多个 ID
|
||||
if (!empty($data)) {
|
||||
$id = $data;
|
||||
} else if (empty($id)) {
|
||||
return Json::fail('Either id or data must be provided.');
|
||||
}
|
||||
$this->service->locked($id);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/admin/{id}/unlocked',
|
||||
summary: '解除',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:unlocked')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function unLocked(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 获取单个 ID 和多个 ID
|
||||
$data = $request->input('data', []);
|
||||
$id = $request->input('id');
|
||||
|
||||
// 如果提供了多个 ID,优先使用多个 ID
|
||||
if (!empty($data)) {
|
||||
$id = $data;
|
||||
} else if (empty($id)) {
|
||||
return Json::fail('Either id or data must be provided.');
|
||||
}
|
||||
$this->service->unLocked($id);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/admin/{id}/change-password',
|
||||
summary: '重置密码',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:change_password')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "success"}')]
|
||||
public function changePassword(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$ids = $request->input('ids');
|
||||
$password = $request->input('password', 123456);
|
||||
$data = ['password' => password_hash($password, PASSWORD_DEFAULT)];
|
||||
$this->service->batchUpdate(['id' => $ids], $data);
|
||||
return Json::success('ok');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/admin/grant-role',
|
||||
summary: '授权角色',
|
||||
tags: ['用户管理'],
|
||||
)]
|
||||
#[Permission(code: 'system:admin:grant_role')]
|
||||
#[SimpleResponse(schema: [], example: '{"code": 0,"msg": "ok"}')]
|
||||
public function grantRole(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->inputFilter($request->all(), ['id', 'role_id_list']);
|
||||
/** @var AdminRoleService $systemUserRoleService */
|
||||
$systemUserRoleService = Container::make(AdminRoleService::class);
|
||||
$systemUserRoleService->save($data);
|
||||
return Json::success('ok');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/admin/{id}',
|
||||
summary: '删除',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
|
||||
try {
|
||||
$data = $this->getDeleteIds($request);
|
||||
$this->service->batchDelete($data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/admin',
|
||||
summary: '批量删除',
|
||||
tags: ['用户管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:admin:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->getDeleteIds($request);
|
||||
$this->service->batchDelete($data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Base;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\attribute\SkipApiEncrypt;
|
||||
use app\service\admin\system\ConfigService;
|
||||
use core\tool\ApiEncryptService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
#[SkipApiEncrypt]
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ApiEncryptController extends Base
|
||||
{
|
||||
protected ApiEncryptService $encryptService;
|
||||
|
||||
protected ConfigService $configService;
|
||||
|
||||
public function __construct(ApiEncryptService $encryptService, ConfigService $configService)
|
||||
{
|
||||
$this->encryptService = $encryptService;
|
||||
$this->configService = $configService;
|
||||
}
|
||||
|
||||
#[OA\Get(path: '/system/api-encrypt', summary: '获取接口加密配置', tags: ['系统配置'])]
|
||||
#[Permission(code: 'system:config:update')]
|
||||
#[DataResponse(description: '获取成功')]
|
||||
public function detail(Request $request): Response
|
||||
{
|
||||
$config = $this->configService->config('api_encrypt_setting', [], ['group_code' => 'system']);
|
||||
$config = is_array($config) ? $config : [];
|
||||
|
||||
return Json::success('获取成功', [
|
||||
'enabled' => (int) ($config['enabled'] ?? ($this->encryptService->isEnabled() ? 1 : 0)),
|
||||
'scope' => (string) ($config['scope'] ?? $this->encryptService->getScope()),
|
||||
'key_version' => (string) ($config['key_version'] ?? $this->encryptService->getKeyVersion()),
|
||||
'timestamp_tolerance' => (int) ($config['timestamp_tolerance'] ?? 300),
|
||||
'exclude_paths' => $config['exclude_paths'] ?? [],
|
||||
'encrypted_paths' => $config['encrypted_paths'] ?? $this->encryptService->getEncryptedPaths(),
|
||||
'public_key_path' => (string) ($config['public_key_path'] ?? ''),
|
||||
'private_key_path' => (string) ($config['private_key_path'] ?? ''),
|
||||
'public_key' => $this->encryptService->getPublicKey(),
|
||||
'private_key' => $this->encryptService->getPrivateKey(),
|
||||
]);
|
||||
}
|
||||
|
||||
#[OA\Post(path: '/system/api-encrypt/generate-keypair', summary: '生成接口加密密钥对', tags: ['系统配置'])]
|
||||
#[Permission(code: 'system:config:update')]
|
||||
#[DataResponse(description: '生成成功')]
|
||||
public function generateKeypair(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$keys = $this->encryptService->generateKeyPair();
|
||||
$this->encryptService->persistKeyPair($keys);
|
||||
|
||||
return Json::success('生成成功', [
|
||||
'public_key' => $this->encryptService->getPublicKey(),
|
||||
'private_key' => $this->encryptService->getPrivateKey(),
|
||||
]);
|
||||
} catch (\Throwable $exception) {
|
||||
return Json::fail($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\CurrentUser;
|
||||
use app\adminapi\event\MenuFormattingEvent;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use support\Container;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\system\AuthValidate;
|
||||
use app\service\admin\system\AdminRoleService;
|
||||
use app\service\admin\system\AdminService;
|
||||
use app\service\admin\system\AuthService;
|
||||
use app\service\admin\system\MenuService;
|
||||
use app\service\admin\system\RoleMenuService;
|
||||
use app\service\admin\system\RoleScopeDeptService;
|
||||
use app\service\admin\system\RoleService;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\exception\handler\UnauthorizedHttpException;
|
||||
use core\jwt\JwtToken;
|
||||
use core\tool\Json;
|
||||
use madong\helper\Dict;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use Webman\Event\Event;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class AuthController extends Crud
|
||||
{
|
||||
public function __construct(AuthService $service, AuthValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/user-info',
|
||||
summary: '获取登录用户',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:user_info')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": {"id": "1","user_name": "admin","real_name": "超级管理员","nick_name": "超级管理员","is_super": 1,"mobile_phone": null,"email": null,"avatar": null,"signed": null,"dashboard": null,"dept_id": "","enabled": 1,"login_ip": "127.0.0.1","login_time": 1762429533,"created_by": null,"updated_by": null,"created_at": "2025-10-30T12:24:09.000000Z","updated_at": "2025-11-06T11:45:34.000000Z","deleted_at": null,"sex": 0,"remark": null,"birthday": null,"tel": null,"is_locked": 0,"role_id_list": [],"post_id_list": [],"created_date": "2025-10-30 20:24:09","updated_date": "2025-11-06 19:45:34","depts": [],"posts": [],"casbin": [],"roles": []}}')]
|
||||
public function getUserInfo(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var CurrentUser $currentUser */
|
||||
$currentUser = Container::make(CurrentUser::class);
|
||||
$data = $currentUser->admin(true);
|
||||
if (empty($data)) {
|
||||
throw new UnauthorizedHttpException('用户凭证失效请重新登录');
|
||||
}
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), null, 401);
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/user-menus',
|
||||
summary: '获取用户-权限菜单',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:user_menus')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function getPermissionsMenu(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$format = input('format', 'default');
|
||||
/** @var CurrentUser $currUser */
|
||||
$currUser = Container::make(CurrentUser::class);
|
||||
$collection = $this->service->getMenusByUserRoles($currUser, true);
|
||||
$event = new MenuFormattingEvent($collection, $format);
|
||||
$data = $event->dispatch();
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/user-permissions',
|
||||
summary: '权限菜单-包含所有 菜单 按钮 接口',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:user_permissions')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": []}')]
|
||||
public function getPermissions(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$format = input('format', 'default');
|
||||
/** @var CurrentUser $currUser */
|
||||
$currUser = Container::make(CurrentUser::class);
|
||||
$collection = $this->service->getMenusByUserRoles($currUser, true);
|
||||
$event = new MenuFormattingEvent($collection, $format);
|
||||
$data = $event->dispatch();
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/perm-code',
|
||||
summary: '获取用户-权限码',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:perm_code')]
|
||||
#[AllowAnonymous(requireToken: true, requirePermission: false)]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok","data": ["admin"]}')]
|
||||
public function getUserCodes(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var CurrentUser $currUser */
|
||||
$currUser = Container::make(CurrentUser::class);
|
||||
$data = $this->service->getCodesByUserRoles($currUser);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/role-menu-ids',
|
||||
summary: '通过角色ID获取权限ID集合',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:role_menu_ids')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function roleMenuIds(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$roleId = $request->input('role_id');
|
||||
/** @var RoleService $systemRoleService */
|
||||
$systemRoleService = Container::make(RoleService::class);
|
||||
$data = $systemRoleService->getPermissionColumns($roleId);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/role-scope-ids',
|
||||
summary: '通过角色ID获取权限范围自定义部门ID集合',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:role_scope_ids')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function roleScopeIds(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$roleId = $request->input('role_id');
|
||||
/** @var RoleScopeDeptService $systemRoleMenuService */
|
||||
$systemRoleMenuService = Container::make(RoleScopeDeptService::class);
|
||||
$data = $systemRoleMenuService->getColumn(['role_id' => $roleId], 'dept_id');
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/auth/save-role-menu',
|
||||
summary: '保存角色菜单关系',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:role_menu')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function saveRoleMenuRelation(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var RoleMenuService $systemRoleMenuService */
|
||||
$systemRoleMenuService = Container::make(RoleMenuService::class);
|
||||
$systemRoleMenuService->save($data);
|
||||
return Json::success('success');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/user-list-by-role-id',
|
||||
summary: '获取角色-关联用户列表',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'role_id',
|
||||
description: '角色ID',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string'),
|
||||
)]
|
||||
#[Permission(code: 'system:auth:role_user_list')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function getUsersByRoleId(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request, [
|
||||
'exclude_filters' => true,
|
||||
'filter_format' => 'simple', // 简洁模式没有操作符
|
||||
'custom_fields' => [
|
||||
'user_name',
|
||||
'real_name',
|
||||
'mobile_phone',
|
||||
'role_id',
|
||||
],
|
||||
]);
|
||||
/** @var AdminService $systemUserService */
|
||||
$systemUserService = Container::make(AdminService::class);
|
||||
$data = $systemUserService->getUsersListByRoleId($where, $field, $page, $limit);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/auth/save-user-role',
|
||||
summary: '保存用户-关联角色',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:save_user_role')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "success"}')]
|
||||
public function saveUserRoles(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var AdminRoleService $systemUserRoleService */
|
||||
$systemUserRoleService = Container::make(AdminRoleService::class);
|
||||
$systemUserRoleService->saveUserRoles($data);
|
||||
return Json::success('success');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/auth/remove-user-role',
|
||||
summary: '移除用户-关联角色',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:remove_user_role')]
|
||||
#[SimpleResponse(example: '{"code": 0,"msg": "ok"}')]
|
||||
public function removeUserRole(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
/** @var AdminRoleService $systemUserRoleService */
|
||||
$systemUserRoleService = Container::make(AdminRoleService::class);
|
||||
$systemUserRoleService->removeUserRole($data);
|
||||
return Json::success('ok');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/auth/user-list-exclude-role-id',
|
||||
summary: '获取用户列表-排除指定角色id',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'role_id',
|
||||
description: '角色ID',
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string'),
|
||||
)]
|
||||
#[Permission(code: 'system:auth:user_list_exclude_role')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function getUsersExcludingRole(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request, [
|
||||
'exclude_filters' => true,
|
||||
'filter_format' => 'simple', // 简洁模式没有操作符
|
||||
'custom_fields' => [
|
||||
'LIKE_user_name',
|
||||
'LIKE_real_name',
|
||||
'LIKE_mobile_phone',
|
||||
'role_id',
|
||||
]]);
|
||||
$systemUserService = Container::make(AdminService::class);
|
||||
$data = $systemUserService->getUsersExcludingRole($where, $field, $page, $limit);
|
||||
return Json::success('ok', $data);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \core\jwt\ex\JwtRefreshTokenExpiredException
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: '/system/auth/refresh-token',
|
||||
summary: '刷新Token',
|
||||
security: [['Bearer' => [], 'ApiKey' => []]],
|
||||
tags: ['权限相关'],
|
||||
)]
|
||||
#[Permission(code: 'system:auth:refresh_token')]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(example: '{"data": "new_access_token"}')]
|
||||
public function refreshToken(Request $request): \support\Response
|
||||
{
|
||||
$token = (new JwtToken())->refresh();
|
||||
return Json::success('ok', [
|
||||
'access_token' => $token->accessToken,
|
||||
'refresh_token' => $token->refreshToken,
|
||||
'expires_in' => $token->expiresIn,
|
||||
'expires_at' => $token->expiresAt->getTimestamp(),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\ConfigGroupQueryRequest;
|
||||
use app\adminapi\schema\request\system\ConfigQueryRequest;
|
||||
use app\adminapi\schema\request\system\ConfigValueRequest;
|
||||
use app\service\admin\system\ConfigService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class ConfigController extends Crud
|
||||
{
|
||||
public function __construct(ConfigService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
|
||||
#[OA\Get(
|
||||
path: "/system/config/group/{group_code}",
|
||||
summary: "按分组获取配置",
|
||||
tags: ["系统配置"],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => ConfigGroupQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: '{"site_open": "1","site_url": "http://127.0.0.1:8001","site_name": "madong-admin","site_logo": "https://madong.tech/assets/images/logo.svg","site_network_security": "2024042441号-2","site_description": "快速开发框架","site_record_no": "2024042442","site_icp_url": "https://beian.miit.gov.cn/","site_network_security_url": ""}')]
|
||||
public function getByGroup(Request $request, string $group_code): \support\Response
|
||||
{
|
||||
try {
|
||||
// 参数验证
|
||||
if (empty($group_code)) {
|
||||
return Json::fail('分组编码不能为空');
|
||||
}
|
||||
|
||||
$options = [
|
||||
'enabled_only' => $request->input('enabled_only', true),
|
||||
'with_metadata' => $request->input('with_metadata', false),
|
||||
];
|
||||
$result = $this->service->getByGroup($group_code, [], $options);
|
||||
return Json::success('操作成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: "/system/config/code/{code}",
|
||||
summary: "按code获取配置",
|
||||
tags: ["系统配置"],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => ConfigQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "code",
|
||||
description: "配置编码",
|
||||
in: "path",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: ' {"site_open": "1","site_url": "http://127.0.0.1:8001"}')]
|
||||
public function getByCode(Request $request, string $code): \support\Response
|
||||
{
|
||||
try {
|
||||
// 参数验证
|
||||
if (empty($code)) {
|
||||
return Json::fail('配置编码不能为空');
|
||||
}
|
||||
|
||||
$groupCode = $request->input('group_code', '');
|
||||
$options = [];
|
||||
if (!empty($groupCode)) {
|
||||
$options['group_code'] = $groupCode;
|
||||
}
|
||||
$result = $this->service->config($code, [], $options);
|
||||
return Json::success('操作成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存单个配置
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: "/system/config",
|
||||
summary: "保存单个配置",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
|
||||
// 参数验证
|
||||
if (empty($data['group_code']) || empty($data['code']) || empty($data['name'])) {
|
||||
return Json::fail('参数不能为空');
|
||||
}
|
||||
|
||||
$options = [
|
||||
'group_code' => $data['group_code'],
|
||||
'name' => $data['name'],
|
||||
];
|
||||
|
||||
if (isset($data['enabled'])) {
|
||||
$options['enabled'] = $data['enabled'];
|
||||
}
|
||||
|
||||
$this->service->update(
|
||||
$data['code'],
|
||||
$data['content'],
|
||||
$options
|
||||
);
|
||||
|
||||
return Json::success('保存成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存单个配置
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Put(
|
||||
path: "/system/config/{code}",
|
||||
summary: "更新配置",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->all();
|
||||
$code = $request->route->param('code');
|
||||
|
||||
$options = [
|
||||
'name' => $data['name'],
|
||||
'group_code' => $data['group_code'] ?? '',
|
||||
'enabled' => $data['enabled'] ?? 0,
|
||||
];
|
||||
$this->service->update(
|
||||
$code,
|
||||
$data['content'],
|
||||
$options
|
||||
);
|
||||
|
||||
return Json::success('更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定配置项的特定键值
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $code
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Get(
|
||||
path: "/system/config/{code}/value",
|
||||
summary: "获取特定配置项的特定键值",
|
||||
tags: ["系统配置"],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => ConfigValueRequest::class,
|
||||
]
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: '{"data": "value"}')]
|
||||
public function getValue(Request $request, string $code): \support\Response
|
||||
{
|
||||
try {
|
||||
// 参数验证
|
||||
if (empty($code)) {
|
||||
return Json::fail('配置项编码不能为空');
|
||||
}
|
||||
|
||||
$groupCode = $request->input('group_code');
|
||||
$key = $request->input('key');
|
||||
|
||||
if (empty($groupCode) || empty($key)) {
|
||||
return Json::fail('分组编码和配置键不能为空');
|
||||
}
|
||||
|
||||
$result = $this->service->getValue($code, $key, null, ['group_code' => $groupCode]);
|
||||
return Json::success('操作成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[OA\Put(
|
||||
path: "/system/config/{code}/value",
|
||||
summary: "更新特定配置项的特定键值",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:update_value')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function setValue(Request $request, string $code): \support\Response
|
||||
{
|
||||
try {
|
||||
// 参数验证
|
||||
if (empty($code)) {
|
||||
return Json::fail('配置项编码不能为空');
|
||||
}
|
||||
|
||||
$groupCode = $request->post('group_code');
|
||||
$key = $request->post('key');
|
||||
$value = $request->post('value');
|
||||
|
||||
if (empty($groupCode) || empty($key)) {
|
||||
return Json::fail('分组编码和配置键不能为空');
|
||||
}
|
||||
|
||||
$result = $this->service->setValue($code, $key, $value, ['group_code' => $groupCode]);
|
||||
if ($result) {
|
||||
return Json::success('更新成功');
|
||||
} else {
|
||||
return Json::fail('更新失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[OA\Get(
|
||||
path: "/system/config/all-grouped",
|
||||
summary: "获取所有配置并按分组整理",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "enabled_only",
|
||||
description: "是否只获取启用的配置项",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "boolean", default: true),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "group_filter",
|
||||
description: "分组过滤,多个分组用逗号分隔",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "with_metadata",
|
||||
description: "是否包含配置项的完整元数据",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "boolean", default: false),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "key_by",
|
||||
description: "按指定字段作为键名('code' 或 'id')",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string", enum: ["code", "id"]),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "sort_groups",
|
||||
description: "是否对分组进行排序",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "boolean", default: false),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "sort_configs",
|
||||
description: "是否对配置项进行排序",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "boolean", default: false),
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: '{"site": {"site_name": "网站名称"}, "oss": {"accessKeyId": "xxx"}}')]
|
||||
public function getAllGrouped(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$options = [
|
||||
'enabled_only' => $request->input('enabled_only', true),
|
||||
'with_metadata' => $request->input('with_metadata', false),
|
||||
'key_by' => $request->input('key_by', null),
|
||||
'sort_groups' => $request->input('sort_groups', false),
|
||||
'sort_configs' => $request->input('sort_configs', false),
|
||||
];
|
||||
|
||||
// 处理分组过滤参数
|
||||
$groupFilter = $request->input('group_filter', '');
|
||||
if (!empty($groupFilter)) {
|
||||
$options['group_filter'] = explode(',', $groupFilter);
|
||||
}
|
||||
|
||||
$result = $this->service->getAllGrouped($options);
|
||||
return Json::success('操作成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[OA\Get(
|
||||
path: "/system/config/items",
|
||||
summary: "获取配置项列表",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "page",
|
||||
description: "页码",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "integer", default: 1),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "pageSize",
|
||||
description: "每页数量",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "integer", default: 20),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "groupCode",
|
||||
description: "分组代码",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "keyword",
|
||||
description: "搜索关键字",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: ['items'=>[],'total'=>0])]
|
||||
public function getItems(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$page = $request->input('page', 1);
|
||||
$pageSize = $request->input('pageSize', 20);
|
||||
$groupCode = $request->input('groupCode', '');
|
||||
$keyword = $request->input('keyword', '');
|
||||
|
||||
if (empty($groupCode)) {
|
||||
return Json::fail('分组代码不能为空');
|
||||
}
|
||||
|
||||
$result = $this->service->getItems((int)$page, (int)$pageSize, $groupCode, $keyword);
|
||||
return Json::success('操作成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单个配置项
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: "/system/config/item",
|
||||
summary: "创建配置项",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function createItem(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
|
||||
// 参数验证
|
||||
if (empty($data['group_code']) || empty($data['code']) || empty($data['name']) || !isset($data['value'])) {
|
||||
return Json::fail('参数不能为空');
|
||||
}
|
||||
|
||||
$type = $data['type'] ?? 'string';
|
||||
|
||||
// 值类型转换
|
||||
$value = $this->convertValue($data['value'], $type);
|
||||
|
||||
$configData = [
|
||||
'group_code' => $data['group_code'],
|
||||
'code' => $data['code'],
|
||||
'name' => $data['name'],
|
||||
'content' => $type === 'json' ? $value : (string)$value,
|
||||
'type' => $type,
|
||||
'description' => $data['description'] ?? '',
|
||||
'enabled' => $data['enabled'] ?? 1,
|
||||
'is_sys' => 0,
|
||||
'remark' => '',
|
||||
];
|
||||
|
||||
$this->service->createItem($configData);
|
||||
|
||||
return Json::success('创建成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单个配置项
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Put(
|
||||
path: "/system/config/item/{id}",
|
||||
summary: "更新配置项",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function updateItem(Request $request, int $id): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
|
||||
$type = $data['type'] ?? 'string';
|
||||
|
||||
// 值类型转换
|
||||
$value = $this->convertValue($data['value'], $type);
|
||||
|
||||
$configData = [
|
||||
'name' => $data['name'],
|
||||
'content' => $type === 'json' ? $value : (string)$value,
|
||||
'type' => $type,
|
||||
'description' => $data['description'] ?? '',
|
||||
'enabled' => $data['enabled'] ?? 1,
|
||||
];
|
||||
|
||||
$this->service->updateItem($id, $configData);
|
||||
|
||||
return Json::success('更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[OA\Put(
|
||||
path: "/system/config/item/{id}/toggle",
|
||||
summary: "切换配置项状态",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[Permission(code: 'system:config:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function toggleItem(Request $request, int $id): \support\Response
|
||||
{
|
||||
try {
|
||||
$enabled = $request->post('enabled', 0);
|
||||
$this->service->toggleItem($id, (bool)$enabled);
|
||||
return Json::success('操作成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 值类型转换
|
||||
*
|
||||
* @param mixed $value 原始值
|
||||
* @param string $type 目标类型
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function convertValue(mixed $value, string $type): mixed
|
||||
{
|
||||
return match ($type) {
|
||||
'string' => (string)$value,
|
||||
'number' => (string)$value,
|
||||
'boolean' => $value ? '1' : '0',
|
||||
'json' => is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE),
|
||||
default => (string)$value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配置项(按code)
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $code 配置编码
|
||||
*
|
||||
* @return \support\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
#[OA\Delete(
|
||||
path: "/system/config/{code}",
|
||||
summary: "删除配置项",
|
||||
tags: ["系统配置"],
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "code",
|
||||
description: "配置编码",
|
||||
in: "path",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "group_code",
|
||||
description: "分组代码",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[Permission(code: 'system:config:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function delete(Request $request, string $code): \support\Response
|
||||
{
|
||||
try {
|
||||
if (empty($code)) {
|
||||
return Json::fail('配置编码不能为空');
|
||||
}
|
||||
|
||||
$options = [];
|
||||
$groupCode = $request->input('group_code');
|
||||
if (!empty($groupCode)) {
|
||||
$options['group_code'] = $groupCode;
|
||||
}
|
||||
|
||||
$result = $this->service->delete($code, $options);
|
||||
if ($result) {
|
||||
return Json::success('删除成功');
|
||||
} else {
|
||||
return Json::fail('配置不存在');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\FeedbackFormRequest;
|
||||
use app\adminapi\schema\request\system\FeedbackQueryRequest;
|
||||
use app\adminapi\schema\response\system\FeedbackResponse;
|
||||
use app\adminapi\validate\system\FeedbackValidate;
|
||||
use app\adminapi\CurrentUser;
|
||||
use core\tool\Json;
|
||||
use support\Container;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\system\FeedbackService;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class FeedbackController extends Crud
|
||||
{
|
||||
public function __construct(FeedbackService $service, FeedbackValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(path: '/feedback', summary: '问题反馈列表', tags: ['问题反馈'], x: [SchemaConstants::X_SCHEMA_REQUEST => FeedbackQueryRequest::class])]
|
||||
#[Permission(code: 'setting:feedback:list')]
|
||||
#[PageResponse(schema: FeedbackResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(path: '/feedback/{id}', summary: '问题反馈详情', tags: ['问题反馈'], x: [SchemaConstants::X_PROPERTY_IN => 'id', SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class])]
|
||||
#[Permission(code: 'setting:feedback:read')]
|
||||
#[SimpleResponse(schema: FeedbackResponse::class, example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(path: '/feedback', summary: '创建问题反馈', tags: ['问题反馈'], x: [SchemaConstants::X_SCHEMA_REQUEST => FeedbackFormRequest::class])]
|
||||
#[Permission(code: 'setting:feedback:create')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(path: '/feedback/{id}', summary: '更新问题反馈', tags: ['问题反馈'], x: [SchemaConstants::X_SCHEMA_REQUEST => FeedbackFormRequest::class])]
|
||||
#[OA\Parameter(name: 'id', description: '反馈ID', in: 'path', required: true, schema: new OA\Schema(type: 'string'))]
|
||||
#[Permission(code: 'setting:feedback:update')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/feedback/{id}/reply',
|
||||
summary: '回复问题反馈',
|
||||
tags: ['问题反馈'],
|
||||
parameters: [new OA\Parameter(name: 'id', description: '反馈ID', in: 'path', required: true, schema: new OA\Schema(type: 'string'))],
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
required: ['reply_content'],
|
||||
properties: [new OA\Property(property: 'reply_content', description: '回复内容', type: 'string', maxLength: 2000)]
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[Permission(code: 'setting:feedback:reply')]
|
||||
#[SimpleResponse(schema: FeedbackResponse::class, example: ['code' => 0, 'message' => '回复成功', 'data' => []])]
|
||||
public function reply(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = [
|
||||
'id' => $request->route->param('id'),
|
||||
'reply_content' => trim((string)$request->input('reply_content')),
|
||||
];
|
||||
$this->validate->scene('reply')->check($data);
|
||||
if ($data['reply_content'] === '') {
|
||||
return Json::fail('请填写回复内容');
|
||||
}
|
||||
|
||||
$feedback = $this->service->get($data['id']);
|
||||
if (!$feedback) {
|
||||
return Json::fail('反馈记录不存在');
|
||||
}
|
||||
|
||||
$adminId = Container::make(CurrentUser::class)->id();
|
||||
if (!$adminId) {
|
||||
return Json::fail('登录状态已失效');
|
||||
}
|
||||
|
||||
$this->service->update($data['id'], [
|
||||
'reply_content' => $data['reply_content'],
|
||||
'reply_by' => $adminId,
|
||||
'reply_at' => time(),
|
||||
]);
|
||||
|
||||
return Json::success('回复成功', $this->service->get($data['id'])?->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(path: '/feedback/{id}', summary: '删除问题反馈', tags: ['问题反馈'], x: [SchemaConstants::X_PROPERTY_IN => 'id', SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class])]
|
||||
#[Permission(code: 'setting:feedback:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(path: '/feedback', summary: '批量删除问题反馈', tags: ['问题反馈'], x: [SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class])]
|
||||
#[Permission(code: 'setting:feedback:delete')]
|
||||
#[SimpleResponse(example: ['code' => 0, 'message' => 'success', 'data' => []])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\MenuFormRequest;
|
||||
use app\adminapi\schema\request\system\MenuQueryRequest;
|
||||
use app\adminapi\schema\response\system\MenuResponse;
|
||||
use app\adminapi\validate\system\MenuValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\scope\global\AccessPermissionScope;
|
||||
use app\service\admin\system\MenuService;
|
||||
use app\service\core\plugin\PluginService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class MenuController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(MenuService $service, MenuValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/menu',
|
||||
summary: '列表',
|
||||
tags: ['菜单管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MenuQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:menu:list')]
|
||||
#[PageResponse(schema: MenuResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/menu/{id}',
|
||||
summary: '详情',
|
||||
tags: ['菜单管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'id',
|
||||
description: '菜单ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
),
|
||||
],
|
||||
)]
|
||||
#[Permission(code: 'system:menu:read')]
|
||||
#[SimpleResponse(schema: MenuResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/menu',
|
||||
summary: '创建',
|
||||
tags: ['菜单管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MenuFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:menu:create')]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_AUTHS_DATA);
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_MENUS_DATA);
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/menu/{id}',
|
||||
summary: '更新',
|
||||
tags: ['菜单管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => MenuFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: '菜单ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'system:menu:update')]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $request->all();
|
||||
$model = $this->service->update($id, $data);
|
||||
return Json::success('更新成功', $model->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/menu',
|
||||
summary: '删除',
|
||||
tags: ['菜单管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:menu:delete')]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->getDeleteIds($request);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('参数错误');
|
||||
}
|
||||
$result = $this->service->batchDelete($data);
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_AUTHS_DATA);
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_MENUS_DATA);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/menu/batch-store',
|
||||
summary: '批量添加菜单',
|
||||
tags: ['菜单管理'],
|
||||
)]
|
||||
#[Permission(code: 'system:menu:batch_store')]
|
||||
#[RequestBody(required: true, content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: MenuFormRequest::class)))]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function batchStore(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$params = $request->input('menus', []);
|
||||
$data = [];
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
foreach ($params as $param) {
|
||||
$data[] = $this->inputFilter($param);
|
||||
if (!$this->validate->scene('batch-store')->check($param)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($data as $item) {
|
||||
$this->service->save($item);
|
||||
}
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_AUTHS_DATA);
|
||||
$this->service->cacheDriver()->delete(MenuService::CACHE_ALL_MENUS_DATA);
|
||||
return Json::success('ok');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/menu/app/list',
|
||||
summary: '获取应用列表',
|
||||
tags: ['菜单管理'],
|
||||
)]
|
||||
#[Permission(code: 'system:menu:app_list')]
|
||||
#[SimpleResponse(schema:[],example: [])]
|
||||
public function appList(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/**@var PluginService $service */
|
||||
$service = Container::make(PluginService::class);
|
||||
$model = $service->selectList([], '*', 0, 0, '', [], false, [AccessPermissionScope::class]);
|
||||
return $this->formatAppSelect($model);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail('获取应用列表失败', []);
|
||||
}
|
||||
}
|
||||
|
||||
private function formatAppSelect($items): \support\Response
|
||||
{
|
||||
$formatted_items = [];
|
||||
$formatted_items[] = ['label' => '系统应用', 'value' => 'admin'];
|
||||
foreach ($items as $item) {
|
||||
$formatted_items[] = [
|
||||
'label' => $item->title ?? $item->name ?? $item->real_name ?? $item->id,
|
||||
'value' => $item->id,
|
||||
];
|
||||
}
|
||||
return Json::success('ok', $formatted_items);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\RecycleBinQueryRequest;
|
||||
use app\adminapi\schema\response\system\RecycleBinResponse;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\system\RecycleBinService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RecycleBinController extends Crud
|
||||
{
|
||||
public function __construct(RecycleBinService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/recycle',
|
||||
summary: '列表',
|
||||
tags: ['数据回收站'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RecycleBinQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:recycle:list')]
|
||||
#[PageResponse(schema: RecycleBinResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/recycle/{id}',
|
||||
summary: '详情',
|
||||
tags: ['数据回收站'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:recycle:read')]
|
||||
#[SimpleResponse(schema: RecycleBinResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/recycle/{id}',
|
||||
summary: '删除',
|
||||
tags: ['数据回收站'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:recycle:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/recycle',
|
||||
summary: '批量删除',
|
||||
tags: ['数据回收站'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:recycle:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/recycle/{id}/restore',
|
||||
summary: '恢复',
|
||||
tags: ['数据回收站'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:recycle:recover')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function restore(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->input('id');
|
||||
$this->service->restoreRecycleBin($id);
|
||||
return Json::success('ok');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\RoleFormRequest;
|
||||
use app\adminapi\schema\request\system\RoleQueryRequest;
|
||||
use app\adminapi\schema\response\system\RoleResponse;
|
||||
use app\adminapi\validate\system\RoleValidate;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\scope\global\AccessPermissionScope;
|
||||
use app\service\admin\org\DeptService;
|
||||
use app\service\admin\system\RoleService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\Container;
|
||||
use support\Request;
|
||||
use support\annotation\Middleware;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RoleController extends Crud
|
||||
{
|
||||
public function __construct(RoleService $service, RoleValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/role',
|
||||
summary: '列表',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RoleQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: ['system:role:list'])]
|
||||
#[PageResponse(schema: RoleResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/role/{id}',
|
||||
summary: '详情',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:role:read')]
|
||||
#[SimpleResponse(schema: RoleResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id, ['*'], ['scopes']);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => 400]);
|
||||
}
|
||||
return Json::success('ok', $data->toArray());
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/role',
|
||||
summary: '新增',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RoleFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:role:create')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$data = $this->inputFilter($request->all(), ['permissions']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('store')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$model = $this->service->save($data);
|
||||
if (empty($model)) {
|
||||
throw new AdminException('插入失败');
|
||||
}
|
||||
$pk = $model->getPk();
|
||||
return Json::success('ok', [$pk => $model->getData($pk)]);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/role/{id}',
|
||||
summary: '更新',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => RoleFormRequest::class,
|
||||
]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: 'id',
|
||||
description: 'ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: 1)
|
||||
)]
|
||||
#[Permission(code: 'system:role:update')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->inputFilter($request->all(), ['permissions', 'scopes']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('update')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->update($id, $data);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/role/{id}',
|
||||
summary: '删除',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:role:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/system/role',
|
||||
summary: '批量删除',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'system:role:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/role/{id}/data-scope',
|
||||
summary: '分配数据权限',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'id', type: 'integer', example: 1),
|
||||
new OA\Property(property: 'data_scope', type: 'integer', example: 1),
|
||||
new OA\Property(property: 'scopes', type: 'array', items: new OA\Items(type: 'string')),
|
||||
]
|
||||
))]
|
||||
#[Permission(code: 'system:role:data_scope')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function dataScope(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->inputFilter($request->all(), ['scopes']);
|
||||
if (isset($this->validate) && $this->validate) {
|
||||
if (!$this->validate->scene('data-scope')->check($data)) {
|
||||
throw new \Exception($this->validate->getError());
|
||||
}
|
||||
}
|
||||
$this->service->updateScope($id, $data);
|
||||
return Json::success('ok', []);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/system/role/{id}/change-status',
|
||||
summary: '切换状态',
|
||||
tags: ['角色管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[RequestBody(required: true, content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(property: 'status', type: 'string', example: 1),
|
||||
]
|
||||
))]
|
||||
#[Permission(code: 'system:role:status')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function changeStatus(Request $request): \support\Response
|
||||
{
|
||||
return parent::changeStatus($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/role/scope/dept',
|
||||
summary: '获取部门权限树',
|
||||
tags: ['角色管理']
|
||||
)]
|
||||
public function getDeptScope(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
/** @var DeptService $service */
|
||||
$service = Container::make(DeptService::class);
|
||||
$iterm = $service->selectList([], ['id', 'pid', 'name'], 0, 0, 'created_at', [], false, [AccessPermissionScope::class]);
|
||||
return $this->formatTree($iterm);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\admin\system\RuleService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class RuleController extends Crud
|
||||
{
|
||||
public function __construct(RuleService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/rule-cate',
|
||||
summary: '获取接口分类(基于tags)',
|
||||
tags: ['接口管理']
|
||||
)]
|
||||
#[Permission(code: 'system:rule:cate')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function cate(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$result = $this->service->getCategories();
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/system/rule',
|
||||
summary: '获取接口列表(支持分类和搜索)',
|
||||
tags: ['接口管理']
|
||||
)]
|
||||
#[Permission(code: 'system:rule:list')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function list(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$cateId = $request->input('cate_id');
|
||||
$keyword = $request->input('keyword');
|
||||
$result = $this->service->getRoutesByCategory($cateId, $keyword);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/system/rule/refresh',
|
||||
summary: '刷新接口扫描缓存',
|
||||
tags: ['接口管理']
|
||||
)]
|
||||
#[Permission(code: 'system:rule:refresh')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function refresh(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$this->service->refresh();
|
||||
return Json::success('刷新成功', []);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\system;
|
||||
|
||||
use app\adminapi\controller\Base;
|
||||
use app\attribute\SkipApiEncrypt;
|
||||
use core\tool\ApiEncryptService;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
#[SkipApiEncrypt]
|
||||
final class SecurityController extends Base
|
||||
{
|
||||
protected ApiEncryptService $encryptService;
|
||||
|
||||
public function __construct(ApiEncryptService $encryptService)
|
||||
{
|
||||
$this->encryptService = $encryptService;
|
||||
}
|
||||
|
||||
#[OA\Get(path: '/system/security/api-encrypt/public-key', summary: '获取接口加密公钥', tags: ['system-security'])]
|
||||
#[DataResponse(description: '获取成功')]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false, description: '公共接口')]
|
||||
public function publicKey(Request $request): Response
|
||||
{
|
||||
$publicKey = $this->encryptService->getPublicKey();
|
||||
if ($publicKey === '') {
|
||||
return Json::fail('接口加密公钥未配置');
|
||||
}
|
||||
|
||||
return Json::success('获取成功', [
|
||||
'enabled' => $this->encryptService->isEnabled(),
|
||||
'scope' => $this->encryptService->getScope(),
|
||||
'algorithm' => $this->encryptService->getAlgorithm(),
|
||||
'key_version' => $this->encryptService->getKeyVersion(),
|
||||
'public_key' => $publicKey,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\terminal;
|
||||
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\service\core\terminal\Terminal;
|
||||
use core\tool\Json;
|
||||
use core\tool\Sse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\annotation\Middleware;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class TerminalController
|
||||
{
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal/config",
|
||||
summary: "获取终端配置",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:read")]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: [
|
||||
'enabled' => true,
|
||||
'npm_package_manager' => 'pnpm',
|
||||
'npm_registry' => 'npm',
|
||||
'composer_registry' => 'composer',
|
||||
'package_managers' => [
|
||||
'npm' => [
|
||||
'name' => 'NPM',
|
||||
'install' => 'npm install',
|
||||
'build' => 'npm run build',
|
||||
'check' => 'npm --version',
|
||||
],
|
||||
'cnpm' => [
|
||||
'name' => 'CNPM',
|
||||
'install' => 'cnpm install',
|
||||
'build' => 'cnpm run build',
|
||||
'check' => 'cnpm --version',
|
||||
],
|
||||
'pnpm' => [
|
||||
'name' => 'PNPM',
|
||||
'install' => 'pnpm install',
|
||||
'build' => 'pnpm run build',
|
||||
'check' => 'pnpm --version',
|
||||
],
|
||||
'yarn' => [
|
||||
'name' => 'YARN',
|
||||
'install' => 'yarn install',
|
||||
'build' => 'yarn build',
|
||||
'check' => 'yarn --version',
|
||||
],
|
||||
],
|
||||
'frontend_programs' => [
|
||||
'admin' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/admin/dist',
|
||||
'target_dir' => '{backend_root}/public/admin',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'web' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/web/.output/public',
|
||||
'target_dir' => '{backend_root}/public',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'h5' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/h5',
|
||||
'target_dir' => '{backend_root}/public/h5',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'app' => [
|
||||
'enabled' => true,
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/app',
|
||||
'target_dir' => '{backend_root}/public/app',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
'uni-app' => [
|
||||
'enabled' => true,
|
||||
'platforms' => [
|
||||
'h5' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/h5',
|
||||
'target_dir' => '{backend_root}/public/uni-app/h5',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
'mp-weixin' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/mp-weixin',
|
||||
'target_dir' => '{backend_root}/public/uni-app/mp-weixin',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
'app-plus' => [
|
||||
'source_dir' => '{project_root}/uni-app/dist/build/app-plus',
|
||||
'target_dir' => '{backend_root}/public/uni-app/app-plus',
|
||||
'copy_mappings' => [
|
||||
'*' => '.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'default_platform' => 'h5',
|
||||
'clean_target' => true,
|
||||
'preserve_files' => [
|
||||
'.gitkeep',
|
||||
],
|
||||
'copy_options' => [
|
||||
'recursive' => true,
|
||||
'overwrite' => true,
|
||||
'preserve_permissions' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
])]
|
||||
public function config(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$config = [
|
||||
'enabled' => config('terminal.enabled', false),
|
||||
'npm_package_manager' => config('terminal.npm_package_manager', 'npm'),
|
||||
'npm_registry' => config('terminal.registries.npm.current', 'npm'),
|
||||
'composer_registry' => config('terminal.registries.composer.current', 'composer'),
|
||||
'package_managers' => config('terminal.package_managers', []),
|
||||
'frontend_programs' => config('terminal.frontend_programs', []),
|
||||
];
|
||||
|
||||
return Json::success('获取配置成功', $config);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: "/terminal/config",
|
||||
summary: "更新终端配置",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:create")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function updateConfig(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$data = $request->post();
|
||||
|
||||
// 读取当前配置
|
||||
$configFile = base_path() . '/config/terminal.php';
|
||||
$config = require $configFile;
|
||||
|
||||
// 更新包管理器配置
|
||||
if (isset($data['npm_package_manager'])) {
|
||||
$config['npm_package_manager'] = $data['npm_package_manager'];
|
||||
}
|
||||
|
||||
// 保存配置到文件
|
||||
$content = "<?php\n\nreturn " . $this->arrayToPhpConfig($config) . ";\n";
|
||||
file_put_contents($configFile, $content);
|
||||
|
||||
return Json::success('配置更新成功');
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal/commands",
|
||||
summary: "获取命令列表(带分组)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[Permission(code: "terminal:config:commands")]
|
||||
#[AllowAnonymous(requireToken: false, requirePermission: false)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function commands(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$webConfig = config('terminal.web.command_groups', []);
|
||||
return Json::success('获取命令列表成功', $webConfig);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: "/terminal",
|
||||
summary: "执行命令(SSE方式)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "command",
|
||||
description: "命令key",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "uuid",
|
||||
description: "会话UUID",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "extend",
|
||||
description: "扩展信息",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[Permission(code: "terminal:exec")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function exec(Request $request): void
|
||||
{
|
||||
$connection = $request->connection;
|
||||
$command = $request->input('command');
|
||||
$uuid = $request->input('uuid', '');
|
||||
$extend = $request->input('extend', '');
|
||||
|
||||
// 发送SSE响应头
|
||||
$connection->send(new Response(200, [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Expose-Headers' => 'Content-Type',
|
||||
'X-Accel-Buffering' => 'no',
|
||||
], "\r\n"));
|
||||
|
||||
// 验证参数
|
||||
if (empty($command) || empty($uuid)) {
|
||||
$connection->send(Sse::error('参数错误:缺少command或uuid参数', null, $uuid));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$terminal = Terminal::create($uuid, $extend);
|
||||
|
||||
foreach ($terminal->exec($command) as $sseMessage) {
|
||||
$connection->send($sseMessage);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$connection->send(Sse::error('执行失败:' . $e->getMessage(), null, $uuid));
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: "/terminal/execute",
|
||||
summary: "执行命令(简单方式)",
|
||||
tags: ["终端管理"]
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "command_key",
|
||||
description: "命令key",
|
||||
in: "query",
|
||||
required: true,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "variables",
|
||||
description: "命令变量",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "object"),
|
||||
)]
|
||||
#[OA\Parameter(
|
||||
name: "session_uuid",
|
||||
description: "会话UUID",
|
||||
in: "query",
|
||||
required: false,
|
||||
schema: new OA\Schema(type: "string"),
|
||||
)]
|
||||
#[Permission(code: "terminal:execute")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function execute(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$commandKey = $request->post('command_key');
|
||||
$variables = $request->post('variables', []);
|
||||
$sessionUuid = $request->post('session_uuid', '');
|
||||
|
||||
if (!$commandKey) {
|
||||
return Json::fail('命令不能为空');
|
||||
}
|
||||
|
||||
$terminal = Terminal::create($sessionUuid, '');
|
||||
$result = $terminal->executeSimple($commandKey, $variables, $sessionUuid);
|
||||
|
||||
return Json::success($result['message'], $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数组转换为PHP配置字符串
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $indent
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function arrayToPhpConfig(array $array, int $indent = 0): string
|
||||
{
|
||||
$spaces = str_repeat(' ', $indent);
|
||||
$result = "[\n";
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$result .= $spaces . " ";
|
||||
|
||||
// 处理键名
|
||||
if (is_string($key)) {
|
||||
$result .= "'" . str_replace("'", "\\'", $key) . "' => ";
|
||||
} else {
|
||||
$result .= $key . " => ";
|
||||
}
|
||||
|
||||
// 处理值
|
||||
if (is_array($value)) {
|
||||
$result .= $this->arrayToPhpConfig($value, $indent + 1);
|
||||
} elseif (is_string($value)) {
|
||||
$result .= "'" . str_replace("'", "\\'", $value) . "'";
|
||||
} elseif (is_bool($value)) {
|
||||
$result .= $value ? 'true' : 'false';
|
||||
} elseif (is_null($value)) {
|
||||
$result .= 'null';
|
||||
} else {
|
||||
$result .= $value;
|
||||
}
|
||||
|
||||
$result .= ",\n";
|
||||
}
|
||||
|
||||
$result .= $spaces . "]";
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,502 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\upload;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\schema\request\system\UploadQueryRequest;
|
||||
use app\adminapi\schema\response\system\UploadResponse;
|
||||
use app\schema\request\BatchDeleteRequest;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\system\UploadService;
|
||||
use core\exception\handler\AdminException;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\PageResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use OpenApi\Attributes as OA;
|
||||
use OpenApi\Attributes\RequestBody;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use Webman\RedisQueue\Client;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class FilesController extends Crud
|
||||
{
|
||||
|
||||
public function __construct(UploadService $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/files',
|
||||
summary: '列表',
|
||||
tags: ['附件管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => UploadQueryRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:list')]
|
||||
#[PageResponse(schema: UploadResponse::class, example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
return parent::index($request);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/files/{id}',
|
||||
summary: '详情',
|
||||
tags: ['附件管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:read')]
|
||||
#[SimpleResponse(schema: UploadResponse::class, example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/files/{id}',
|
||||
summary: '删除',
|
||||
tags: ['附件管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/files',
|
||||
summary: '批量删除',
|
||||
tags: ['附件管理'],
|
||||
x: [
|
||||
SchemaConstants::X_SCHEMA_REQUEST => BatchDeleteRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:delete')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function batchDelete(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/files/fetch-and-save-image',
|
||||
summary: '上传网络图片到服务器',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'url',
|
||||
description: '图片URL',
|
||||
type: 'string',
|
||||
example: 'https://example.com/image.jpg'
|
||||
),
|
||||
]
|
||||
)
|
||||
)]
|
||||
#[Permission(code: 'upload:files:fetch_and_save_image')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function downloadNetworkImage(Request $request): \support\Response
|
||||
{
|
||||
$url = $request->input('url', '');
|
||||
$result = $this->service->saveNetworkImage($url);
|
||||
return Json::success('操作成功', $result);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/files/download-by-id/{id}',
|
||||
summary: '根据ID下载资源',
|
||||
tags: ['附件管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'id',
|
||||
description: '文件ID',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:download_by_id')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function downloadResourceById(Request $request): \support\Response|\Webman\Http\Response
|
||||
{
|
||||
try {
|
||||
$id = $request->route->param('id');
|
||||
$data = $this->service->get($id);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => -1]);
|
||||
}
|
||||
return response()->download($data->path, $data->filename);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/files/download-by-hash/{hash}',
|
||||
summary: '根据hash下载资源',
|
||||
tags: ['附件管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(
|
||||
name: 'hash',
|
||||
description: '文件Hash',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: new OA\Schema(type: 'string', example: '123456789012345678')
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission(code: 'upload:files:download_by_hash')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function downloadResourceByHash(Request $request): \support\Response|\Webman\Http\Response
|
||||
{
|
||||
try {
|
||||
$hash = $request->route->param('hash');
|
||||
$data = $this->service->get(['hash' => $hash]);
|
||||
if (empty($data)) {
|
||||
throw new AdminException('数据未找到', ['errorCode' => -1]);
|
||||
}
|
||||
return response()->download($data->path, $data->filename);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage(), [], $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Throwable
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: '/files/upload-image',
|
||||
summary: '上传图片',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:upload_image')]
|
||||
#[RequestBody(
|
||||
required: true,
|
||||
content: new OA\MediaType(
|
||||
mediaType: 'multipart/form-data',
|
||||
schema: new OA\Schema(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'file',
|
||||
description: '文件',
|
||||
type: 'string',
|
||||
format: 'binary'
|
||||
),
|
||||
new OA\Property(
|
||||
property: 'sub_dir',
|
||||
description: '子目录路径,例如:image/202603',
|
||||
type: 'string',
|
||||
example: 'image/202603'
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[SimpleResponse(schema: UploadResponse::class, example: [])]
|
||||
public function uploadImage(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$subDir = $request->input('sub_dir', 'image');
|
||||
$subDir .= '/' . date('Ym');
|
||||
$result = $this->service->upload($subDir);
|
||||
return Json::success('ok', $result->toArray());
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/files/upload-file',
|
||||
summary: '上传文件',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:upload_file')]
|
||||
#[RequestBody(
|
||||
required: true,
|
||||
content: new OA\MediaType(
|
||||
mediaType: 'multipart/form-data',
|
||||
schema: new OA\Schema(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'file',
|
||||
description: '文件',
|
||||
type: 'string',
|
||||
format: 'binary'
|
||||
),
|
||||
new OA\Property(
|
||||
property: 'sub_dir',
|
||||
description: '子目录路径,例如:file/202603',
|
||||
type: 'string',
|
||||
example: 'file/202603'
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[SimpleResponse(schema: UploadResponse::class, example: [])]
|
||||
public function uploadFile(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$subDir = $request->input('sub_dir', 'file');
|
||||
$subDir .= '/' . date('Ym');
|
||||
$result = $this->service->upload($subDir);
|
||||
return Json::success('ok', $result);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/files/svg-icons',
|
||||
summary: 'SVG图标列表',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:upload_file')]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function svgIcons(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$targetDir = public_path() . '/upload/svg-icons';
|
||||
if (!is_dir($targetDir)) {
|
||||
return Json::success('ok', []);
|
||||
}
|
||||
|
||||
$icons = [];
|
||||
foreach (glob($targetDir . '/*.svg') ?: [] as $file) {
|
||||
$name = pathinfo($file, PATHINFO_FILENAME);
|
||||
$content = file_get_contents($file);
|
||||
if ($content === false) {
|
||||
continue;
|
||||
}
|
||||
$icons[] = [
|
||||
'icon' => 'svg:' . $name,
|
||||
'name' => $name,
|
||||
'filename' => basename($file),
|
||||
'url' => '/upload/svg-icons/' . basename($file),
|
||||
'content' => $content,
|
||||
];
|
||||
}
|
||||
|
||||
return Json::success('ok', $icons);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/files/upload-svg-icon',
|
||||
summary: '上传SVG图标',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:upload_file')]
|
||||
#[RequestBody(
|
||||
required: true,
|
||||
content: new OA\MediaType(
|
||||
mediaType: 'multipart/form-data',
|
||||
schema: new OA\Schema(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'file',
|
||||
description: 'SVG图标文件',
|
||||
type: 'string',
|
||||
format: 'binary'
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
)]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function uploadSvgIcon(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$file = $request->file('file');
|
||||
if (!$file) {
|
||||
return Json::fail('请选择SVG文件');
|
||||
}
|
||||
if ($file->getSize() > 512 * 1024) {
|
||||
return Json::fail('SVG文件大小不能超过512KB');
|
||||
}
|
||||
|
||||
$extension = strtolower($file->getUploadExtension());
|
||||
$mime = $file->getUploadMimeType();
|
||||
$allowedMimeTypes = ['image/svg+xml', 'image/svg', 'text/xml', 'application/xml', 'text/plain', ''];
|
||||
if ($extension !== 'svg' || !in_array($mime, $allowedMimeTypes, true)) {
|
||||
return Json::fail('只支持SVG格式文件');
|
||||
}
|
||||
|
||||
$content = file_get_contents($file->getPathname());
|
||||
if ($content === false || trim($content) === '') {
|
||||
return Json::fail('SVG文件读取失败');
|
||||
}
|
||||
if (!preg_match('/<svg[\s>]/i', $content)) {
|
||||
return Json::fail('请选择有效的SVG文件');
|
||||
}
|
||||
if (preg_match('/<script|<foreignObject|on\w+\s*=|javascript:/i', $content)) {
|
||||
return Json::fail('SVG文件包含不安全内容');
|
||||
}
|
||||
|
||||
$originalName = pathinfo($file->getUploadName(), PATHINFO_FILENAME);
|
||||
$iconName = preg_replace('/[^a-zA-Z0-9_-]/', '-', $originalName) ?: 'icon';
|
||||
$iconName = trim($iconName, '-_') ?: 'icon';
|
||||
$targetDir = public_path() . '/upload/svg-icons';
|
||||
if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true) && !is_dir($targetDir)) {
|
||||
return Json::fail('SVG图标目录创建失败');
|
||||
}
|
||||
|
||||
$targetPath = $targetDir . '/' . $iconName . '.svg';
|
||||
if (is_file($targetPath)) {
|
||||
$iconName .= '-' . date('YmdHis');
|
||||
$targetPath = $targetDir . '/' . $iconName . '.svg';
|
||||
}
|
||||
if (file_put_contents($targetPath, $content, LOCK_EX) === false) {
|
||||
return Json::fail('SVG图标保存失败');
|
||||
}
|
||||
|
||||
return Json::success('上传成功', [
|
||||
'icon' => 'svg:' . $iconName,
|
||||
'name' => $iconName,
|
||||
'filename' => $iconName . '.svg',
|
||||
'url' => '/upload/svg-icons/' . $iconName . '.svg',
|
||||
'path' => str_replace('\\', '/', $targetPath),
|
||||
'content' => $content,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片返回base64
|
||||
* 用于插件开发等需要base64预览的场景
|
||||
*/
|
||||
#[OA\Post(
|
||||
path: '/files/upload-image-base64',
|
||||
summary: '上传图片返回base64',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:upload_image_base64')]
|
||||
#[RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(
|
||||
properties: [
|
||||
new OA\Property(
|
||||
property: 'file',
|
||||
description: '图片文件',
|
||||
type: 'string',
|
||||
format: 'binary'
|
||||
),
|
||||
]
|
||||
)
|
||||
)]
|
||||
public function uploadImageBase64(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$file = $request->file('file');
|
||||
if (!$file) {
|
||||
return Json::fail('请选择图片文件');
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
$allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
||||
if (!in_array($file->getUploadMimeType(), $allowedTypes)) {
|
||||
return Json::fail('只支持PNG、JPEG、JPG、GIF格式的图片');
|
||||
}
|
||||
|
||||
// 验证文件大小(最大2MB)
|
||||
$maxSize = 2 * 1024 * 1024;
|
||||
if ($file->getSize() > $maxSize) {
|
||||
return Json::fail('图片大小不能超过2MB');
|
||||
}
|
||||
|
||||
// 读取文件内容并转换为base64
|
||||
$imageData = file_get_contents($file->getPathname());
|
||||
if ($imageData === false) {
|
||||
return Json::fail('图片读取失败');
|
||||
}
|
||||
|
||||
$base64 = 'data:' . $file->getUploadMimeType() . ';base64,' . base64_encode($imageData);
|
||||
|
||||
return Json::success('上传成功', [
|
||||
'base64' => $base64,
|
||||
'size' => $file->getSize(),
|
||||
'mime' => $file->getUploadMimeType(),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/export/download-excel',
|
||||
summary: '下载导出的excel',//下载导出的excel-后期需要优化实现下载成功后删除原文件
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:download_excel')]
|
||||
public function downloadExcel(Request $request): ?\support\Response
|
||||
{
|
||||
|
||||
$param = $request->all();
|
||||
$file = $param['file_path'];//文件路径
|
||||
$downloadName = $param['file'] ?? date('Y-m-d His', time());//文件下载名称
|
||||
$filePath = runtime_path() . $file;
|
||||
//生成的文件5分钟后超时自动删除
|
||||
$queue = 'remove-excel-file';
|
||||
Client::send($queue, $param, 300);
|
||||
return response()->download($filePath, $downloadName);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/files/common/wangeditor',
|
||||
summary: '适配wangeditor编辑器上传接口',
|
||||
tags: ['附件管理'],
|
||||
)]
|
||||
#[Permission(code: 'upload:files:wangeditor')]
|
||||
public function wangeditor(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$subDir = $request->input('sub_dir', 'image');
|
||||
$subDir .= '/' . date('Ym');
|
||||
$result = $this->service->upload($subDir);
|
||||
$data = $result->toArray();
|
||||
$data['url'] = $data['base_path'] ?? '';
|
||||
return Json(['errno' => 0, 'data' => $data]);
|
||||
} catch (\Exception $e) {
|
||||
return Json([
|
||||
'errno' => 1,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\web;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\web\LinkValidate;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\web\LinkService;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class LinkController extends Crud
|
||||
{
|
||||
public function __construct(LinkService $service, LinkValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/web/link',
|
||||
summary: '友情链接列表',
|
||||
tags: ['友情链接管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "name", description: "链接名称", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "status", description: "状态", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "total", type: "integer", example: 10),
|
||||
new OA\Property(property: "items", type: "array", items: new OA\Items(properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
new OA\Property(property: "name", type: "string", example: "百度"),
|
||||
new OA\Property(property: "url", type: "string", example: "https://www.baidu.com"),
|
||||
new OA\Property(property: "logo", type: "string", example: ""),
|
||||
new OA\Property(property: "logo_type", type: "integer", example: 2, description: "图标类型:1=上传,2=链接"),
|
||||
new OA\Property(property: "sort", type: "integer", example: 1),
|
||||
new OA\Property(property: "enabled", type: "integer", example: 1),
|
||||
])),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("web:link:list")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, [], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/web/link/{id}',
|
||||
summary: '友情链接详情',
|
||||
tags: ['友情链接管理'],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("web:link:read")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/web/link',
|
||||
summary: '创建友情链接',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "百度"),
|
||||
new OA\Property(property: "url", type: "string", example: "https://www.baidu.com"),
|
||||
new OA\Property(property: "logo", type: "string", example: ""),
|
||||
new OA\Property(property: "logo_type", type: "integer", example: 2, description: "图标类型:1=上传,2=链接"),
|
||||
new OA\Property(property: "sort", type: "integer", example: 1),
|
||||
new OA\Property(property: "enabled", type: "integer", example: 1),
|
||||
])
|
||||
),
|
||||
tags: ['友情链接管理'],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "创建成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
],
|
||||
)]
|
||||
#[Permission("web:link:create")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/web/link/{id}',
|
||||
summary: '更新友情链接',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "百度"),
|
||||
new OA\Property(property: "url", type: "string", example: "https://www.baidu.com"),
|
||||
new OA\Property(property: "logo", type: "string", example: ""),
|
||||
new OA\Property(property: "logo_type", description: "图标类型:1=上传,2=链接", type: "integer", example: 2),
|
||||
new OA\Property(property: "sort", type: "integer", example: 1),
|
||||
new OA\Property(property: "enabled", type: "integer", example: 1),
|
||||
])
|
||||
),
|
||||
tags: ['友情链接管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "链接ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "更新成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("web:link:update")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/web/link/{id}',
|
||||
summary: '删除友情链接',
|
||||
tags: ['友情链接管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "链接ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "删除成功"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("web:link:delete")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
return parent::destroy($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
*+------------------
|
||||
* madong
|
||||
*+------------------
|
||||
* Copyright (c) https://gitee.com/motion-code All rights reserved.
|
||||
*+------------------
|
||||
* Author: Mr. April (405784684@qq.com)
|
||||
*+------------------
|
||||
* Official Website: http://www.madong.tech
|
||||
*/
|
||||
|
||||
namespace app\adminapi\controller\web;
|
||||
|
||||
use app\adminapi\controller\Crud;
|
||||
use app\adminapi\middleware\AccessTokenMiddleware;
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use app\adminapi\validate\web\MenuValidate;
|
||||
use app\schema\request\IdRequest;
|
||||
use app\service\admin\web\MenuService;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use WebmanTech\Swagger\DTO\SchemaConstants;
|
||||
|
||||
#[Middleware(AccessTokenMiddleware::class, PermissionMiddleware::class, OperationMiddleware::class)]
|
||||
final class MenuController extends Crud
|
||||
{
|
||||
public function __construct(MenuService $service, MenuValidate $validate)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->validate = $validate;
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/web/menu',
|
||||
summary: '菜单列表',
|
||||
tags: ['菜单管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "name", description: "菜单名称", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "type", description: "菜单类型", in: "query", schema: new OA\Schema(type: "string")),
|
||||
new OA\Parameter(name: "page", description: "页码", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
new OA\Parameter(name: "limit", description: "每页数量", in: "query", schema: new OA\Schema(type: "integer")),
|
||||
]
|
||||
)]
|
||||
#[Permission("web:menu:list")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function index(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
[$where, $format, $limit, $field, $order, $page] = $this->selectInput($request);
|
||||
$methods = [
|
||||
'select' => 'formatSelect',
|
||||
'tree' => 'formatTree',
|
||||
'table_tree' => 'formatTableTree',
|
||||
'normal' => 'formatNormal',
|
||||
];
|
||||
if (empty($order)) {
|
||||
$order = 'sort asc';
|
||||
}
|
||||
$format_function = $methods[$format] ?? 'formatNormal';
|
||||
$total = $this->service->getCount($where);
|
||||
$list = $this->service->selectList($where, $field, $page, $limit, $order, [], false);
|
||||
return call_user_func([$this, $format_function], $list, $total);
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/web/menu/{id}',
|
||||
summary: '菜单详情',
|
||||
tags: ['菜单管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "菜单ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "获取成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
new OA\Property(property: "name", type: "string", example: "首页"),
|
||||
new OA\Property(property: "type", type: "string", example: "page"),
|
||||
new OA\Property(property: "path", type: "string", example: "/home"),
|
||||
new OA\Property(property: "title", type: "string", example: "首页"),
|
||||
new OA\Property(property: "url", type: "string", example: ""),
|
||||
new OA\Property(property: "icon", type: "string", example: "home"),
|
||||
new OA\Property(property: "sort", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("web:menu:read")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function show(Request $request): \support\Response
|
||||
{
|
||||
return parent::show($request);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/web/menu',
|
||||
summary: '创建',
|
||||
tags: ['菜单管理'],
|
||||
)]
|
||||
#[Permission("web:menu:create")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function store(Request $request): \support\Response
|
||||
{
|
||||
return parent::store($request);
|
||||
}
|
||||
|
||||
#[OA\Put(
|
||||
path: '/web/menu/{id}',
|
||||
summary: '更新菜单',
|
||||
requestBody: new OA\RequestBody(
|
||||
required: true,
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "name", type: "string", example: "首页"),
|
||||
new OA\Property(property: "type", type: "string", example: "page"),
|
||||
new OA\Property(property: "path", type: "string", example: "/home"),
|
||||
new OA\Property(property: "title", type: "string", example: "首页"),
|
||||
new OA\Property(property: "url", type: "string", example: ""),
|
||||
new OA\Property(property: "icon", type: "string", example: "home"),
|
||||
new OA\Property(property: "sort", type: "integer", example: 1),
|
||||
])
|
||||
),
|
||||
tags: ['菜单管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "菜单ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "更新成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "id", type: "integer", example: 1),
|
||||
], type: "object"),
|
||||
])
|
||||
),
|
||||
]
|
||||
)]
|
||||
#[Permission("web:menu:update")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function update(Request $request): \support\Response
|
||||
{
|
||||
return parent::update($request);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/web/menu',
|
||||
summary: '删除菜单',
|
||||
tags: ['菜单管理'],
|
||||
parameters: [
|
||||
new OA\Parameter(name: "id", description: "菜单ID", in: "path", required: true, schema: new OA\Schema(type: "integer")),
|
||||
],
|
||||
responses: [
|
||||
new OA\Response(
|
||||
response: 200,
|
||||
description: "成功",
|
||||
content: new OA\JsonContent(properties: [
|
||||
new OA\Property(property: "code", type: "integer", example: 0),
|
||||
new OA\Property(property: "msg", type: "string", example: "删除成功"),
|
||||
new OA\Property(property: "data", properties: [
|
||||
new OA\Property(property: "ids", type: "array", items: new OA\Items(type: "integer")),
|
||||
]),
|
||||
])
|
||||
),
|
||||
],
|
||||
x: [
|
||||
SchemaConstants::X_PROPERTY_IN => 'id',
|
||||
SchemaConstants::X_SCHEMA_REQUEST => IdRequest::class,
|
||||
]
|
||||
)]
|
||||
#[Permission("web:menu:delete")]
|
||||
#[SimpleResponse(schema: [], example: [])]
|
||||
public function destroy(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
$ids = $request->input('ids',[]);
|
||||
$this->service->batchDelete($ids);
|
||||
return Json::success('删除成功');
|
||||
} catch (\Throwable $e) {
|
||||
return Json::fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user