增加后台基础功能,调整前端菜单返回

This commit is contained in:
mzl@hnxinyouhe.com
2025-08-11 20:09:28 +08:00
parent 7869d6919a
commit 20239dfb6f
23 changed files with 855 additions and 312 deletions
@@ -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;
// }
}
+8 -8
View File
@@ -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;
}
}
+31
View File
@@ -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());
}
}
}
+6 -5
View File
@@ -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;
}
+17
View File
@@ -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;
}
+1 -147
View File
@@ -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,
+17
View File
@@ -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;
}
+23 -19
View File
@@ -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');
}
}
+1 -1
View File
@@ -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()
+10 -41
View File
@@ -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 = [];
}
+74 -63
View File
@@ -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());
}
}
+3 -2
View File
@@ -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');
// }
}
+320
View File
@@ -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' => [
]
];
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace app\common\validate;
use think\Validate;
class CountryValidate extends Validate
{
// 规则
protected $rule = [
];
// 提示
protected $message = [
];
// 场景
protected $scene = [
'store' => [
],
'update' => [
]
];
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace app\common\validate;
use think\Validate;
class ResourceValidate extends Validate
{
// 规则
protected $rule = [
];
// 提示
protected $message = [
];
// 场景
protected $scene = [
'store' => [
],
'update' => [
]
];
}
+18 -18
View File
@@ -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
View File
@@ -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']);