初始化本地仓库

This commit is contained in:
2026-08-31 11:33:59 +08:00
commit 663f74b633
2390 changed files with 402918 additions and 0 deletions
@@ -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,
]);
}
}