增加后台基础功能,调整前端菜单返回
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\admin\service\CorpFeishuAppService;
|
||||
|
||||
class CorpFeishuAppController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new CorpFeishuAppService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\admin\service\CountryService;
|
||||
|
||||
class CountryController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new CountryService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -22,12 +22,12 @@ class SystemsController extends BaseController
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function indexFormat($data)
|
||||
// {
|
||||
// if (isset($data['created_at']))
|
||||
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
// if (isset($data['updated_at']))
|
||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
// return $data;
|
||||
// }
|
||||
protected function indexFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service;
|
||||
|
||||
use app\common\validate\CorpFeishuAppValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
use support\Request;
|
||||
|
||||
class CorpFeishuAppService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = CorpFeishuApp::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = CorpFeishuAppValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'index'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
|
||||
$config['with']['corpInfo'][] = 'name';
|
||||
$config['with']['systemInfo'][] = 'name';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
|
||||
$config['with']['corpInfo'][] = 'name';
|
||||
$config['with']['systemInfo'][] = 'name';
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\service;
|
||||
|
||||
use app\common\validate\CountryValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
|
||||
class CountryService
|
||||
{
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = CorpFeishuApp::class;
|
||||
|
||||
/**
|
||||
* 验证器
|
||||
*/
|
||||
protected $validator = CountryValidate::class;
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return new $this->validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\controller\BaseController;
|
||||
use app\common\traits\crud\CrudControllerTrait;
|
||||
use app\common\service\ResourceService;
|
||||
use support\Request;
|
||||
|
||||
class ResourceController extends BaseController
|
||||
{
|
||||
use CrudControllerTrait;
|
||||
|
||||
protected $service;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->service = new ResourceService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页数据格式化
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function allFormat($data)
|
||||
{
|
||||
if (isset($data['created_at']))
|
||||
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||
if (isset($data['updated_at']))
|
||||
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源树形结构
|
||||
*/
|
||||
public function listTree(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceListAll($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'allFormat')
|
||||
? [$this, 'allFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单
|
||||
*/
|
||||
public function menuList(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceMenuList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'allFormat')
|
||||
? [$this, 'allFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
|
||||
class CorpFeishuAppLogic
|
||||
{
|
||||
|
||||
use CrudLogicTrait;
|
||||
|
||||
public function getFeishuApp($corpId, $systemId)
|
||||
{
|
||||
return CorpFeishuApp::where('corp_id', $corpId)->where('system_id', $systemId)->first(['id', 'corp_id', 'name', 'app_id', 'r_url', 'state']);
|
||||
}
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = CorpFeishuApp::class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\CorpFeishuApp;
|
||||
|
||||
class CountryLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = CorpFeishuApp::class;
|
||||
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class PermLogic
|
||||
foreach ($user->roles as $role) {
|
||||
$all = $all->merge(
|
||||
$role->resources->filter(function ($resource) use($system) {
|
||||
// var_dump($resource->toArray());
|
||||
// 只保留需要权限认证的资源(或公共资源)
|
||||
return !$resource->no_auth && ($system->id == $resource->system_id || $resource->system_id == 0);
|
||||
})
|
||||
@@ -64,151 +63,6 @@ class PermLogic
|
||||
* @param string $parentPath 父级完整路径(用于递归)
|
||||
* @return array
|
||||
*/
|
||||
public function buildTree_bak($resources, int $parentId = 0, string $parentPath = ''): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
foreach ($resources as $node) {
|
||||
// 只处理目录和菜单,不把 permission 当作菜单节点
|
||||
if ($node->parent_id !== $parentId || $node->type === 'permission') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// —— 拼接当前节点的完整路径 ——
|
||||
$currentPath = rtrim($parentPath, '/');
|
||||
if (!empty($node->url)) {
|
||||
$urlSegment = ltrim($node->url, '/');
|
||||
$currentPath = $currentPath === ''
|
||||
? $urlSegment
|
||||
: "{$currentPath}/{$urlSegment}";
|
||||
}
|
||||
|
||||
// —— 递归构建子节点 ——
|
||||
// 这里只会继续收目录和菜单,permission 永远不会进入此方法
|
||||
$children = $this->buildTree($resources, $node->id, $currentPath);
|
||||
|
||||
// —— 本级权限列表 ——
|
||||
$authList = $resources
|
||||
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
|
||||
->map(fn($r) => [
|
||||
'id' => $r->id,
|
||||
'title' => $r->name,
|
||||
'auth_mark' => $r->code,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
|
||||
// —— 判断是否有子目录或子菜单 ——
|
||||
$hasChildrenMenu = ! empty($children);
|
||||
|
||||
// —— 计算 component 字段 ——
|
||||
if ($hasChildrenMenu) {
|
||||
if ($node->type === 'menu' && !empty($node->url)) {
|
||||
// menu 类型且自身有 url,用自身 url(加前导 slash)
|
||||
$componentValue = '/' . ltrim($node->url, '/');
|
||||
} else {
|
||||
// 其它含子项的节点,固定 Layout 组件
|
||||
$componentValue = '/index/index';
|
||||
}
|
||||
} else {
|
||||
// 叶子节点:拼接路径,确保以 slash 开头
|
||||
$componentValue = $currentPath !== ''
|
||||
? '/' . ltrim($currentPath, '/')
|
||||
: '';
|
||||
}
|
||||
|
||||
$tree[] = [
|
||||
'id' => $node->id,
|
||||
'name' => $node->name,
|
||||
'path' => $node->url,
|
||||
'component' => $componentValue,
|
||||
'meta' => [
|
||||
'title' => $node->name,
|
||||
'icon' => $node->icon,
|
||||
'keepAlive' => true,
|
||||
'authList' => $authList,
|
||||
'openType' => $node->open_type,
|
||||
'isHide' => $node->is_hide == 0 ? false : true,
|
||||
'isHideTab' => $node->is_hide_tab == 0 ? false : true
|
||||
],
|
||||
'children' => $children
|
||||
];
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
public function buildTree_bak2($resources, int $parentId = 0, string $parentPath = ''): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
foreach ($resources as $node) {
|
||||
if ($node->parent_id !== $parentId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// —— 拼接当前节点的完整路径 ——
|
||||
$currentPath = $parentPath;
|
||||
// 去掉末尾多余 slash
|
||||
$currentPath = rtrim($currentPath, '/');
|
||||
|
||||
if (!empty($node->url)) {
|
||||
// 如果当前节点有 url,则拼接
|
||||
$urlSegment = ltrim($node->url, '/');
|
||||
$currentPath = $currentPath === ''
|
||||
? $urlSegment
|
||||
: "{$currentPath}/{$urlSegment}";
|
||||
}
|
||||
|
||||
// —— 递归构建子节点 ——
|
||||
$children = [];
|
||||
if ($node->type === 'directory') {
|
||||
$children = $this->buildTree($resources, $node->id, $currentPath);
|
||||
}
|
||||
|
||||
// —— 收集本级的 permission 权限列表 ——
|
||||
$authList = $resources
|
||||
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
|
||||
->map(fn($r) => [
|
||||
'id' => $r->id,
|
||||
'title' => $r->name,
|
||||
'auth_mark' => $r->code,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
|
||||
// —— 判断是否有子菜单/目录 ——
|
||||
$hasChildrenMenu = $resources
|
||||
->where('parent_id', $node->id)
|
||||
->whereIn('type', ['directory', 'menu'])
|
||||
->isNotEmpty();
|
||||
|
||||
// —— 计算 component 字段 ——
|
||||
if ($hasChildrenMenu) {
|
||||
// 只要有子项,就一律显示顶层 Layout 组件
|
||||
$componentValue = '/index/index';
|
||||
} else {
|
||||
// 叶子节点:如果定义了 url,就使用拼接后的路径;否则用占位符(这里用空串,你可替换)
|
||||
$componentValue = $currentPath !== '' ? $currentPath : '';
|
||||
}
|
||||
|
||||
$tree[] = [
|
||||
'id' => $node->id,
|
||||
'name' => $node->name,
|
||||
'path' => $node->url,
|
||||
'component' => $componentValue,
|
||||
'meta' => [
|
||||
'title' => $node->name,
|
||||
'icon' => $node->icon,
|
||||
'keepAlive' => true,
|
||||
'authList' => $authList,
|
||||
'openType' => $node->open_type,
|
||||
],
|
||||
'children' => $children,
|
||||
];
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array
|
||||
{
|
||||
$tree = [];
|
||||
@@ -258,7 +112,7 @@ class PermLogic
|
||||
'meta' => [
|
||||
'title' => $node->name,
|
||||
'icon' => $node->icon,
|
||||
'keepAlive' => true,
|
||||
'keepAlive' => $node->keep_alive == 1 ? true : false,
|
||||
'authList' => $authList,
|
||||
'openType' => $node->open_type,
|
||||
'isHide' => $node->is_hide == 0 ? false : true,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
use app\common\traits\crud\CrudLogicTrait;
|
||||
use app\common\model\Resource;
|
||||
|
||||
class ResourceLogic
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/**
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
protected string $modelClass = Resource::class;
|
||||
|
||||
}
|
||||
@@ -4,24 +4,6 @@ namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* corp_feishu_app 企业-飞书应用
|
||||
* @property integer $id ID(主键)
|
||||
* @property integer $corp_id 公司ID
|
||||
* @property string $name 名称
|
||||
* @property string $tenant_key 企业标识
|
||||
* @property string $app_id 应用ID
|
||||
* @property string $app_secret 应用秘钥
|
||||
* @property string $base_uri 基础域
|
||||
* @property string $r_url 授权地址
|
||||
* @property string $scopes 授权范围
|
||||
* @property string $state 携带参数
|
||||
* @property string $system_code 绑定系统码
|
||||
* @property integer $sort 排序
|
||||
* @property integer $status 状态
|
||||
* @property integer $created_at 创建时间
|
||||
* @property integer $updated_at 更新时间
|
||||
*/
|
||||
class CorpFeishuApp extends Model
|
||||
{
|
||||
/**
|
||||
@@ -53,4 +35,26 @@ class CorpFeishuApp extends Model
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
}
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'corp_id', 'system_id', 'name', 'tenant_key', 'app_id', 'app_secret', 'base_uri', 'r_url', 'scopes', 'state', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
|
||||
public function corpInfo()
|
||||
{
|
||||
return $this->hasOne(Corp::class, 'id', 'corp_id');
|
||||
}
|
||||
|
||||
public function systemInfo()
|
||||
{
|
||||
return $this->hasOne(Systems::class, 'id', 'system_id');
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class InquiryLog extends Model
|
||||
|
||||
public function recipientInfo()
|
||||
{
|
||||
return $this->hasOne(User::class, 'id', 'recipient');
|
||||
return $this->hasOne(User::class, 'id', 'recipient')->where('status', 1);
|
||||
}
|
||||
|
||||
public function channelInfo()
|
||||
|
||||
@@ -4,20 +4,6 @@ namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
* resources 资源表:目录/菜单/权限
|
||||
* @property integer $id 资源ID(主键)
|
||||
* @property string $name 资源名称
|
||||
* @property string $type 资源类型
|
||||
* @property string $code 资源编码(权限标识)
|
||||
* @property integer $parent_id 父资源ID
|
||||
* @property string $url 路由 path 或 外链 URL
|
||||
* @property string $icon 图标,仅目录/菜单有效
|
||||
* @property string $open_type 菜单打开方式
|
||||
* @property integer $sort 排序
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
*/
|
||||
class Resource extends Model
|
||||
{
|
||||
/**
|
||||
@@ -49,32 +35,15 @@ class Resource extends Model
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
// 所属系统
|
||||
public function system()
|
||||
{
|
||||
return $this->belongsTo(Systems::class, 'system_id', 'id');
|
||||
}
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
// 拥有该资源的角色
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Role::class, 'role_resources', 'resource_id', 'role_id');
|
||||
}
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'system_id', 'name', 'desc', 'type', 'code', 'parent_id', 'url', 'icon', 'open_type', 'is_hide', 'is_hide_tab', 'no_auth', 'is_home', 'instance', 'sort', 'status', 'created_at', 'updated_at'];
|
||||
|
||||
// 拥有该资源的用户(特殊补权)
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'user_resources', 'resource_id', 'user_id');
|
||||
}
|
||||
|
||||
// 递归
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(self::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_id');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -2,82 +2,93 @@
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\model\User;
|
||||
use app\model\Role;
|
||||
use app\model\Resource;
|
||||
use app\common\validate\ResourceValidate;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\common\model\Resource;
|
||||
use app\common\utils\Tree;
|
||||
use support\Request;
|
||||
|
||||
class ResourceService
|
||||
{
|
||||
/**
|
||||
* 获取用户可见菜单树
|
||||
*/
|
||||
public static function getMenuTreeForUser($userId)
|
||||
{
|
||||
$menuList = self::getUserMenus($userId);
|
||||
// 转树
|
||||
return self::buildTree($menuList);
|
||||
}
|
||||
|
||||
use CrudServiceTrait;
|
||||
|
||||
/**
|
||||
* 获取用户所有有权限的菜单资源(type=menu)
|
||||
* 指定当前要操作的模型
|
||||
*/
|
||||
public static function getUserMenus($userId)
|
||||
{
|
||||
$user = User::with('roles.resources')->find($userId);
|
||||
if (!$user) return [];
|
||||
// 合并所有角色下的菜单资源
|
||||
$allMenus = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->resources as $res) {
|
||||
if ($res->type === 'menu') {
|
||||
$allMenus[$res->id] = $res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_values($allMenus); // 去重后返回
|
||||
}
|
||||
protected string $modelClass = Resource::class;
|
||||
|
||||
/**
|
||||
* 获取用户所有有权限的按钮/功能权限 code
|
||||
* 验证器
|
||||
*/
|
||||
public static function getButtonPermissionCodesForUser($userId)
|
||||
{
|
||||
$user = User::with('roles.resources')->find($userId);
|
||||
if (!$user) return [];
|
||||
$codes = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->resources as $res) {
|
||||
if ($res->type === 'button' && $res->code) {
|
||||
$codes[$res->code] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_keys($codes); // 去重后返回权限code数组
|
||||
}
|
||||
protected $validator = ResourceValidate::class;
|
||||
|
||||
/**
|
||||
* 递归构建菜单树
|
||||
* @param Resource[] $list
|
||||
* @param int $parentId
|
||||
* @return array
|
||||
* 获取验证器
|
||||
*/
|
||||
protected static function buildTree($list, $parentId = 0)
|
||||
public function getValidator()
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($list as $item) {
|
||||
if ($item->parent_id == $parentId) {
|
||||
$children = self::buildTree($list, $item->id);
|
||||
$arr = [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'path' => $item->url,
|
||||
'icon' => $item->icon ?? null,
|
||||
'code' => $item->code,
|
||||
'children' => $children,
|
||||
];
|
||||
$tree[] = $arr;
|
||||
}
|
||||
return new $this->validator;
|
||||
}
|
||||
|
||||
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'menuList':
|
||||
$config['where']['status'] = 1;
|
||||
$config['where']['type'] = ['!=', 'permission'];
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'asc';
|
||||
$config['order']['id'] = 'asc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
return $tree;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function serviceMenuList(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'menuList');
|
||||
$result = $this->logicListAll($config);
|
||||
return $this->postProcess('MenuList', $result);
|
||||
}
|
||||
|
||||
|
||||
protected function afterServiceListAll($data)
|
||||
{
|
||||
$data = Tree::buildWithAuthListAndReference($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function afterServiceMenuList($data)
|
||||
{
|
||||
$data = Tree::buildWithReference($data->toArray());
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ trait CrudControllerTrait
|
||||
$res = $this->service->serviceStore($request, $data);
|
||||
return $this->success($res, '创建成功');
|
||||
} catch (\Throwable $e) {
|
||||
dpr($e);
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace app\common\traits\crud;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
/**
|
||||
@@ -48,7 +49,7 @@ trait CrudServiceTrait
|
||||
$config = $this->buildQueryConfig($request, 'default');
|
||||
$result = $this->logicListAll($config);
|
||||
}
|
||||
return $this->postProcess('List', $result);
|
||||
return $this->postProcess('ListAll', $result);
|
||||
}
|
||||
|
||||
/** 查看单条 */
|
||||
@@ -188,6 +189,6 @@ trait CrudServiceTrait
|
||||
*/
|
||||
// protected function complexQuery(array $params): array
|
||||
// {
|
||||
// throw new \LogicException('请在子类实现 complexQuery');
|
||||
// throw new BusinessException('请在子类实现 complexQuery');
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\utils;
|
||||
|
||||
class Tree
|
||||
{
|
||||
/**
|
||||
* 递归构建树形结构
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @param int $level 当前层级
|
||||
* @return array
|
||||
*/
|
||||
public static function build(array $data, int $parentId = 0, string $pidField = 'parent_id', string $idField = 'id', int $level = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
if ($item[$pidField] == $parentId) {
|
||||
$item['level'] = $level;
|
||||
$children = static::build($data, $item[$idField], $pidField, $idField, $level + 1);
|
||||
|
||||
if (!empty($children)) {
|
||||
$item['children'] = $children;
|
||||
}
|
||||
|
||||
$tree[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用引用方式构建树形结构(性能更好)
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @return array
|
||||
*/
|
||||
public static function buildWithReference(array $data, string $pidField = 'parent_id', string $idField = 'id'): array
|
||||
{
|
||||
$items = [];
|
||||
$tree = [];
|
||||
|
||||
// 建立以id为索引的数组
|
||||
foreach ($data as $item) {
|
||||
$item['level'] = 0;
|
||||
$items[$item[$idField]] = $item;
|
||||
}
|
||||
|
||||
// 构建树形结构
|
||||
foreach ($items as $id => $item) {
|
||||
if ($item[$pidField] == 0) {
|
||||
$tree[] = &$items[$id];
|
||||
} else {
|
||||
if (isset($items[$item[$pidField]])) {
|
||||
$items[$id]['level'] = $items[$item[$pidField]]['level'] + 1;
|
||||
|
||||
if (!isset($items[$item[$pidField]]['children'])) {
|
||||
$items[$item[$pidField]]['children'] = [];
|
||||
}
|
||||
|
||||
$items[$item[$pidField]]['children'][] = &$items[$id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将树形结构扁平化为列表(带层级前缀)
|
||||
*
|
||||
* @param array $tree 树形结构数据
|
||||
* @param string $prefix 前缀字符
|
||||
* @param string $field 显示字段名
|
||||
* @param int $level 层级
|
||||
* @return array
|
||||
*/
|
||||
public static function flattenWithPrefix(array $tree, string $prefix = '--', string $field = 'name', int $level = 0): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($tree as $item) {
|
||||
$item[$field . '_with_prefix'] = str_repeat($prefix, $item['level']) . $item[$field];
|
||||
$result[] = $item;
|
||||
|
||||
if (isset($item['children']) && !empty($item['children'])) {
|
||||
$children = static::flattenWithPrefix($item['children'], $prefix, $field, $item['level'] + 1);
|
||||
$result = array_merge($result, $children);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父ID查找所有子节点(包括子孙节点)
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @return array
|
||||
*/
|
||||
public static function findChildren(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array
|
||||
{
|
||||
$children = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
if ($item[$pidField] == $parentId) {
|
||||
$children[] = $item;
|
||||
$grandChildren = static::findChildren($data, $item[$idField], $pidField, $idField);
|
||||
$children = array_merge($children, $grandChildren);
|
||||
}
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定节点的所有父级节点
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $id 当前节点ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @return array
|
||||
*/
|
||||
public static function getParents(array $data, int $id, string $pidField = 'parent_id', string $idField = 'id'): array
|
||||
{
|
||||
$parents = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
if ($item[$idField] == $id) {
|
||||
if ($item[$pidField] != 0) {
|
||||
$parents[] = $item;
|
||||
$parentParents = static::getParents($data, $item[$pidField], $pidField, $idField);
|
||||
$parents = array_merge($parents, $parentParents);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定节点的子孙节点ID列表
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @return array
|
||||
*/
|
||||
public static function getChildrenIds(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array
|
||||
{
|
||||
$ids = [];
|
||||
$children = static::findChildren($data, $parentId, $pidField, $idField);
|
||||
|
||||
foreach ($children as $child) {
|
||||
$ids[] = $child[$idField];
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有子节点
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasChildren(array $data, int $parentId, string $pidField = 'parent_id'): bool
|
||||
{
|
||||
foreach ($data as $item) {
|
||||
if ($item[$pidField] == $parentId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建带有权限列表的资源树(权限不显示在树结构中)
|
||||
*
|
||||
* @param array $data 资源数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @param string $typeField 类型字段名
|
||||
* @param string $permissionType 权限类型标识
|
||||
* @param int $level 当前层级
|
||||
* @return array
|
||||
*/
|
||||
public static function buildWithAuthList(
|
||||
array $data,
|
||||
int $parentId = 0,
|
||||
string $pidField = 'parent_id',
|
||||
string $idField = 'id',
|
||||
string $typeField = 'type',
|
||||
string $permissionType = 'permission',
|
||||
int $level = 0
|
||||
): array {
|
||||
$tree = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
// 只处理指定父级的非权限节点
|
||||
if ($item[$pidField] == $parentId && $item[$typeField] != $permissionType) {
|
||||
$item['level'] = $level;
|
||||
|
||||
// 递归处理子节点(非权限类型)
|
||||
$children = static::buildWithAuthList($data, $item[$idField], $pidField, $idField, $typeField, $permissionType, $level + 1);
|
||||
|
||||
if (!empty($children)) {
|
||||
$item['children'] = $children;
|
||||
}
|
||||
|
||||
// 收集当前节点下的所有权限
|
||||
$item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType);
|
||||
|
||||
$tree[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集指定节点下的直接权限项(只收集直接子节点中的权限)
|
||||
*
|
||||
* @param array $data 数据列表
|
||||
* @param int $parentId 父级ID
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $typeField 类型字段名
|
||||
* @param string $permissionType 权限类型标识
|
||||
* @return array
|
||||
*/
|
||||
public static function collectDirectPermissions(
|
||||
array $data,
|
||||
int $parentId,
|
||||
string $pidField = 'parent_id',
|
||||
string $typeField = 'type',
|
||||
string $permissionType = 'permission'
|
||||
): array {
|
||||
$permissions = [];
|
||||
|
||||
foreach ($data as $item) {
|
||||
// 收集直接子节点中的权限类型
|
||||
if ($item[$pidField] == $parentId && $item[$typeField] == $permissionType) {
|
||||
$permissions[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用引用方式构建带有权限列表的资源树(权限不显示在树结构中)
|
||||
*
|
||||
* @param array $data 资源数据列表
|
||||
* @param string $pidField 父级字段名
|
||||
* @param string $idField ID字段名
|
||||
* @param string $typeField 类型字段名
|
||||
* @param string $permissionType 权限类型标识
|
||||
* @return array
|
||||
*/
|
||||
public static function buildWithAuthListAndReference(
|
||||
array $data,
|
||||
string $pidField = 'parent_id',
|
||||
string $idField = 'id',
|
||||
string $typeField = 'type',
|
||||
string $permissionType = 'permission'
|
||||
): array {
|
||||
$items = [];
|
||||
$tree = [];
|
||||
|
||||
// 建立以id为索引的数组(只包含非权限节点)
|
||||
foreach ($data as $item) {
|
||||
if ($item[$typeField] != $permissionType) {
|
||||
$item['level'] = 0;
|
||||
$items[$item[$idField]] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
// 构建树形结构
|
||||
foreach ($items as $id => $item) {
|
||||
if ($item[$pidField] == 0) {
|
||||
$tree[] = &$items[$id];
|
||||
} else {
|
||||
if (isset($items[$item[$pidField]])) {
|
||||
$items[$id]['level'] = $items[$item[$pidField]]['level'] + 1;
|
||||
|
||||
if (!isset($items[$item[$pidField]]['children'])) {
|
||||
$items[$item[$pidField]]['children'] = [];
|
||||
}
|
||||
|
||||
$items[$item[$pidField]]['children'][] = &$items[$id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 为每个节点添加权限列表
|
||||
foreach ($items as &$item) {
|
||||
$item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class CorpFeishuAppValidate extends Validate
|
||||
{
|
||||
// 规则
|
||||
protected $rule = [
|
||||
|
||||
];
|
||||
|
||||
// 提示
|
||||
protected $message = [
|
||||
|
||||
];
|
||||
|
||||
// 场景
|
||||
protected $scene = [
|
||||
'store' => [
|
||||
|
||||
],
|
||||
|
||||
'update' => [
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class CountryValidate extends Validate
|
||||
{
|
||||
// 规则
|
||||
protected $rule = [
|
||||
|
||||
];
|
||||
|
||||
// 提示
|
||||
protected $message = [
|
||||
|
||||
];
|
||||
|
||||
// 场景
|
||||
protected $scene = [
|
||||
'store' => [
|
||||
|
||||
],
|
||||
|
||||
'update' => [
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class ResourceValidate extends Validate
|
||||
{
|
||||
// 规则
|
||||
protected $rule = [
|
||||
|
||||
];
|
||||
|
||||
// 提示
|
||||
protected $message = [
|
||||
|
||||
];
|
||||
|
||||
// 场景
|
||||
protected $scene = [
|
||||
'store' => [
|
||||
|
||||
],
|
||||
|
||||
'update' => [
|
||||
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -75,27 +75,27 @@ class IndexController
|
||||
public function createResource()
|
||||
{
|
||||
$options = [
|
||||
// 'controller' => [
|
||||
// 'module' => 'inquiry',
|
||||
// 'name' => 'country'
|
||||
// ],
|
||||
'controller' => [
|
||||
'module' => 'common',
|
||||
'name' => 'resources'
|
||||
],
|
||||
'model' => [
|
||||
'module' => 'common',
|
||||
'name' => 'email_parsed_result'
|
||||
'name' => 'resources'
|
||||
],
|
||||
// 'service' => [
|
||||
// 'module' => 'inquiry',
|
||||
// 'name' => 'country'
|
||||
// ],
|
||||
// 'logic' => [
|
||||
// 'module' => 'inquiry',
|
||||
// 'name' => 'country'
|
||||
// ],
|
||||
// 'validate' => [
|
||||
// 'module' => 'inquiry',
|
||||
// 'name' => 'country'
|
||||
// ],
|
||||
'table' => 'email_parsed_result'
|
||||
'service' => [
|
||||
'module' => 'common',
|
||||
'name' => 'resources'
|
||||
],
|
||||
'logic' => [
|
||||
'module' => 'common',
|
||||
'name' => 'resources'
|
||||
],
|
||||
'validate' => [
|
||||
'module' => 'common',
|
||||
'name' => 'resources'
|
||||
],
|
||||
'table' => 'resources'
|
||||
];
|
||||
|
||||
$result = (new Generate($options))->doGenerate();
|
||||
|
||||
@@ -101,7 +101,7 @@ class StatisticsController extends BaseController
|
||||
{
|
||||
$list = InquiryLog::with(["recipientInfo"])
|
||||
->where("recipient", ">", 0)
|
||||
->whereNotIn('recipient', [1,5,10,11,13,15,16,17,19,74,75,78,141,147])
|
||||
->whereNotIn('recipient', [1,5,10,11,13,155,16,17,19,74,75,78,141,147])
|
||||
->select('recipient', Db::raw('COUNT(*) as totals'))
|
||||
->groupBy('recipient')
|
||||
->get();
|
||||
|
||||
+35
-7
@@ -72,13 +72,6 @@ Route::group('/admin', function () {
|
||||
Route::any('/destroy', [app\admin\controller\RoleController::class, 'destroy']);
|
||||
});
|
||||
|
||||
// 用户
|
||||
Route::group('/user', function () {
|
||||
Route::any('/list', [app\admin\controller\UserController::class, 'index']);
|
||||
Route::any('/show', [app\admin\controller\UserController::class, 'show']);
|
||||
Route::any('/update', [app\admin\controller\UserController::class, 'update']);
|
||||
});
|
||||
|
||||
// 公司
|
||||
Route::group('/corp', function () {
|
||||
Route::any('/list', [app\admin\controller\CorpController::class, 'index']);
|
||||
@@ -88,6 +81,41 @@ Route::group('/admin', function () {
|
||||
Route::any('/destroy', [app\admin\controller\CorpController::class, 'destroy']);
|
||||
});
|
||||
|
||||
// 系统
|
||||
Route::group('/systems', function () {
|
||||
Route::any('/list', [app\admin\controller\SystemsController::class, 'index']);
|
||||
Route::any('/show', [app\admin\controller\SystemsController::class, 'show']);
|
||||
Route::any('/store', [app\admin\controller\SystemsController::class, 'store']);
|
||||
Route::any('/update', [app\admin\controller\SystemsController::class, 'update']);
|
||||
Route::any('/destroy', [app\admin\controller\SystemsController::class, 'destroy']);
|
||||
});
|
||||
|
||||
// 飞书应用
|
||||
Route::group('/corp/feishu', function () {
|
||||
Route::any('/list', [app\admin\controller\CorpFeishuAppController::class, 'index']);
|
||||
Route::any('/show', [app\admin\controller\CorpFeishuAppController::class, 'show']);
|
||||
Route::any('/store', [app\admin\controller\CorpFeishuAppController::class, 'store']);
|
||||
Route::any('/update', [app\admin\controller\CorpFeishuAppController::class, 'update']);
|
||||
Route::any('/destroy', [app\admin\controller\CorpFeishuAppController::class, 'destroy']);
|
||||
});
|
||||
|
||||
// 资源
|
||||
Route::group('/resources', function () {
|
||||
Route::any('/list/tree', [app\common\controller\ResourceController::class, 'listTree']);
|
||||
Route::any('/show', [app\common\controller\ResourceController::class, 'show']);
|
||||
Route::any('/store', [app\common\controller\ResourceController::class, 'store']);
|
||||
Route::any('/update', [app\common\controller\ResourceController::class, 'update']);
|
||||
Route::any('/destroy', [app\common\controller\ResourceController::class, 'destroy']);
|
||||
Route::any('/list/menu', [app\common\controller\ResourceController::class, 'menuList']);
|
||||
});
|
||||
|
||||
// 用户
|
||||
Route::group('/user', function () {
|
||||
Route::any('/list', [app\admin\controller\UserController::class, 'index']);
|
||||
Route::any('/show', [app\admin\controller\UserController::class, 'show']);
|
||||
Route::any('/update', [app\admin\controller\UserController::class, 'update']);
|
||||
});
|
||||
|
||||
// 询单
|
||||
Route::group('/inquiry', function () {
|
||||
Route::any('/list', [app\inquiry\controller\InquiryLogController::class, 'index']);
|
||||
|
||||
Reference in New Issue
Block a user