修复若干bug

This commit is contained in:
2026-03-10 22:24:06 +08:00
parent 7cdb591f69
commit 98156991c1
16 changed files with 1021 additions and 892 deletions
+39 -1
View File
@@ -100,10 +100,13 @@ class MenuController extends BaseController
]);
}
// 获取有权限的菜单及其所有父级菜单
$allMenuIds = $this->getMenuIdsWithParents($menuIds);
// 获取有权限的菜单
$menus = SystemMenu::where('delete_time', null)
->where('status', 1)
->whereIn('id', $menuIds)
->whereIn('id', $allMenuIds)
->field('id,pid,title,path,component_path,icon,sort')
->order('sort', 'asc')
->select();
@@ -489,6 +492,41 @@ class MenuController extends BaseController
}
}
/**
* 获取菜单ID及其所有父级菜单ID
* @param array $menuIds 菜单ID数组
* @return array 包含所有父级菜单的ID数组
*/
private function getMenuIdsWithParents(array $menuIds): array
{
if (empty($menuIds)) {
return [];
}
$allIds = $menuIds;
$toCheck = $menuIds;
while (!empty($toCheck)) {
// 查询这些菜单的父级
$parents = SystemMenu::whereIn('id', $toCheck)
->where('delete_time', null)
->column('pid');
// 过滤掉已经存在的和为0的父ID
$newParents = [];
foreach ($parents as $pid) {
if ($pid > 0 && !in_array($pid, $allIds)) {
$newParents[] = $pid;
$allIds[] = $pid;
}
}
$toCheck = $newParents;
}
return $allIds;
}
/**
* 构建菜单树形结构
* @param array $menus 菜单列表
+69 -5
View File
@@ -8,6 +8,8 @@ use app\admin\BaseController;
use think\response\Json;
use app\model\AdminModules;
use app\model\System\AdminUserGroup;
use app\model\SystemMenu;
use Symfony\Component\VarDumper\VarDumper;
class ModulesController extends BaseController
{
@@ -52,10 +54,9 @@ class ModulesController extends BaseController
{
try {
$userInfo = $this->getAdminUserInfo();
$groupId = $userInfo['group_id'] ?? null;
$menuIds = [];
if ($groupId) {
$userGroup = AdminUserGroup::where('id', $groupId)->find();
if ($userGroup && $userGroup->rights) {
@@ -64,7 +65,7 @@ class ModulesController extends BaseController
$menuIds = is_array($decoded) ? $decoded : [];
}
}
if (empty($menuIds)) {
return json([
'code' => 200,
@@ -75,9 +76,14 @@ class ModulesController extends BaseController
]
]);
}
// 根据子菜单ID查询所有父级模块ID
$moduleIds = $this->getModuleIdsByMenuIds($menuIds);
$modules = AdminModules::where('delete_time', null)
->whereIn('mid', $menuIds)
->whereIn('id', $moduleIds)
->where('status', 1)
->where('is_show', 1)
->order('sort', 'asc')
->order('id', 'asc')
->select()
@@ -386,6 +392,64 @@ class ModulesController extends BaseController
}
}
/**
* 根据菜单ID列表获取对应的模块ID列表(包括父级模块)
* @param array $menuIds 菜单ID列表(子菜单)
* @return array 模块ID列表
*/
private function getModuleIdsByMenuIds(array $menuIds): array
{
if (empty($menuIds)) {
return [];
}
// 1. 获取所有子菜单及其父级菜单ID
$allMenuIds = $this->getMenuIdsWithParents($menuIds);
// 2. 获取所有匹配的模块(mid在allMenuIds中)
$moduleIds = AdminModules::where('delete_time', null)
->whereIn('mid', $allMenuIds)
->column('id');
// 去重并返回
return array_unique($moduleIds);
}
/**
* 获取菜单ID及其所有父级菜单ID
* @param array $menuIds 菜单ID数组
* @return array 包含所有父级菜单的ID数组
*/
private function getMenuIdsWithParents(array $menuIds): array
{
if (empty($menuIds)) {
return [];
}
$allIds = $menuIds;
$toCheck = $menuIds;
while (!empty($toCheck)) {
// 查询这些菜单的父级
$parents = SystemMenu::whereIn('id', $toCheck)
->where('delete_time', null)
->column('pid');
// 过滤掉已经存在的和为0的父ID
$newParents = [];
foreach ($parents as $pid) {
if ($pid > 0 && !in_array($pid, $allIds)) {
$newParents[] = $pid;
$allIds[] = $pid;
}
}
$toCheck = $newParents;
}
return $allIds;
}
/**
* 获取模块选择列表
* @return Json
+22 -11
View File
@@ -43,7 +43,9 @@ class RoleController extends BaseController
public function getRoleById(int $id)
{
$role = AdminUserGroup::where('id', $id)
->where('tid', $this->getTenantId())
->where(function ($query) {
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
})
->where('delete_time', null)
->find();
if (!$role) {
@@ -143,9 +145,11 @@ class RoleController extends BaseController
'rights|权限' => 'array'
]);
// 查找角色(验证tid
// 查找角色(验证tidtid为0的系统角色也可编辑
$role = AdminUserGroup::where('id', $id)
->where('tid', $this->getTenantId())
->where(function ($query) {
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
})
->where('delete_time', null)
->find();
if (!$role) {
@@ -155,10 +159,12 @@ class RoleController extends BaseController
]);
}
// 检查角色名称是否已被其他角色使用
// 检查角色名称是否已被其他角色使用tid为0或当前用户tid的角色)
$exists = AdminUserGroup::where('name', $data['name'])
->where('id', '<>', $id)
->where('tid', $this->getTenantId())
->where(function ($query) {
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
})
->where('delete_time', null)
->find();
if ($exists) {
@@ -169,18 +175,23 @@ class RoleController extends BaseController
}
// 更新数据
$role->name = $data['name'];
$role->status = $data['status'] ?? 1;
$role->rights = !empty($data['rights']) ? json_encode($data['rights']) : null;
$role->update_time = date('Y-m-d H:i:s');
$role->save();
$updateData = [
'name' => $data['name'],
'status' => $data['status'] ?? 1,
'rights' => !empty($data['rights']) ? json_encode($data['rights']) : null,
'update_time' => date('Y-m-d H:i:s')
];
AdminUserGroup::where('id', $id)->update($updateData);
// 重新查询获取最新数据
$updatedRole = AdminUserGroup::where('id', $id)->find();
// 记录操作日志
$this->logSuccess('角色管理', '更新角色', ['id' => $id]);
return json([
'code' => 200,
'msg' => '更新成功',
'data' => $role->toArray()
'data' => $updatedRole->toArray()
]);
} catch (ValidateException $e) {
// 记录失败日志
+2 -1
View File
@@ -5,8 +5,9 @@ return [
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// 跨域支持
\app\common\middleware\AllowCrossDomain::class,
// Session初始化
\think\middleware\SessionInit::class,
];
+4 -30
View File
@@ -15,47 +15,21 @@ class AllowCrossDomain
{
$origin = $request->header('origin', '');
$allowedDomains = [
'http://localhost:3000',
'http://localhost:5000',
'http://localhost:8000',
'http://127.0.0.1:3000',
'http://127.0.0.1:5000',
'http://127.0.0.1:8000',
'http://localhost:5173',
'http://backapi.yunzer.cn',
'http://www.yunzer.cn',
'https://www.yunzer.cn',
'http://yunzer.cn',
'https://yunzer.cn',
'http://back.yunzer.cn',
'https://back.yunzer.cn',
'http://backend.yunzer.cn',
'https://backend.yunzer.cn',
];
if (in_array($origin, $allowedDomains)) {
$header['Access-Control-Allow-Origin'] = $origin;
} else {
if (!empty($origin)) {
$header['Access-Control-Allow-Origin'] = $origin;
} else {
$header['Access-Control-Allow-Origin'] = '*';
}
}
// 允许所有来源(生产环境建议限制具体域名)
$header['Access-Control-Allow-Origin'] = $origin ?: '*';
if ($request->method() === 'OPTIONS') {
$header['Access-Control-Allow-Credentials'] = 'true';
$header['Access-Control-Max-Age'] = 1800;
$header['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS';
$header['Access-Control-Allow-Headers'] = 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With';
$header['Access-Control-Allow-Headers'] = 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, X-Current-Domain';
return response('', 200, $header);
}
$header['Access-Control-Allow-Credentials'] = 'true';
$header['Access-Control-Max-Age'] = 1800;
$header['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS';
$header['Access-Control-Allow-Headers'] = 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With';
$header['Access-Control-Allow-Headers'] = 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, X-Current-Domain';
return $next($request)->header($header);
}
+49 -1
View File
@@ -9,6 +9,7 @@ use think\App;
use think\exception\ValidateException;
use think\Validate;
use think\Request;
use think\facade\Db;
// 在控制器方法中添加
header('Access-Control-Allow-Origin: *');
@@ -44,6 +45,12 @@ abstract class BaseController
*/
protected $middleware = [];
/**
* 当前租户ID
* @var int
*/
protected $tenantId = 0;
/**
* 构造方法
* @access public
@@ -59,7 +66,48 @@ abstract class BaseController
}
// 初始化
protected function initialize() {}
protected function initialize()
{
// 自动检测并设置租户ID
$this->initTenantId();
}
/**
* 初始化租户ID
* 优先从 Referer 获取来源域名,否则使用当前访问域名
* 从 mete_tenant_domain 表查询对应的 tid
*/
protected function initTenantId(): void
{
// 优先从 Referer 获取来源域名(跨域调用场景)
$referer = $this->request->header('Referer');
if ($referer) {
$host = parse_url($referer, PHP_URL_HOST);
} else {
// 否则使用当前访问域名
$host = $this->request->host(true);
}
// 查询域名对应的租户ID
$tenantDomain = Db::name('mete_tenant_domain')
->where('full_domain', $host)
->where('status', 1)
->whereNull('delete_time')
->find();
if ($tenantDomain) {
$this->tenantId = (int)$tenantDomain['tid'];
}
}
/**
* 获取当前租户ID
* @return int
*/
protected function getTenantId(): int
{
return $this->tenantId;
}
/**
* 验证数据
@@ -12,257 +12,46 @@ use think\facade\Session;
use think\response\Json;
use think\db\exception\DbException;
use app\model\Articles;
use app\model\ArticlesCategory;
use app\model\Cms\Articles;
use app\model\Cms\ArticlesCategory;
class NewsCenterController extends BaseController
{
/**
* 根据分类获取文章
* @param string $category 分类名称
* 根据域名获取新闻数据
* @return Json
*/
public function getNewsByCategory(string $category): Json
public function getCenterNews(): Json
{
// 查询分类
$categoryInfo = ArticlesCategory::where('name', $category)
->where('delete_time', null)
->find();
// 从 BaseController 获取当前租户ID
$tid = $this->getTenantId();
if (!$categoryInfo) {
if (empty($tid)) {
return json([
'code' => 200,
'msg' => 'success',
'code' => 400,
'msg' => '无法识别租户信息',
'list' => [],
]);
}
// 查询文章
// 查询该租户下的文章
$articles = Articles::published()
->where('cate', $categoryInfo['id'])
->where('tid', $tid)
->where('delete_time', null)
->order('publish_date', 'desc')
->limit(4)
->limit(8)
->select();
return json([
'code' => 200,
'msg' => 'success',
'list' => $articles,
]);
}
/**
* 获取企业新闻
* @return Json
*/
public function getCompanyNews(): Json
{
// 获取分页参数
$page = Request::param('page', 1);
$limit = Request::param('limit', 10);
$page = max(1, intval($page));
$limit = max(1, min(50, intval($limit))); // 限制每页最多50条
// 查询分类
$categoryInfo = ArticlesCategory::where('name', '企业新闻')
->where('delete_time', null)
->find();
if (!$categoryInfo) {
return json([
'code' => 200,
'msg' => 'success',
'list' => [],
'total' => 0,
'page' => $page,
'limit' => $limit,
]);
}
// 查询总数
$total = Articles::where('cate', $categoryInfo['id'])
->where('delete_time', null)
->where('status', 2)
->count();
// 查询文章
$articles = Articles::where('cate', $categoryInfo['id'])
->where('delete_time', null)
->where('status', 2)
->order('top', 'desc')
->order('recommend', 'desc')
->order('sort', 'desc')
->order('publish_date', 'desc')
->page($page, $limit)
->select();
return json([
'code' => 200,
'msg' => 'success',
'list' => $articles,
'total' => $total,
'page' => $page,
'limit' => $limit,
]);
}
/**
* 获取金蝶新闻
* @return Json
*/
public function getKingdeeNews(): Json
{
// 获取分页参数
$page = Request::param('page', 1);
$limit = Request::param('limit', 10);
$page = max(1, intval($page));
$limit = max(1, min(50, intval($limit))); // 限制每页最多50条
// 查询分类
$categoryInfo = ArticlesCategory::where('name', '金蝶新闻')
->where('delete_time', null)
->find();
if (!$categoryInfo) {
return json([
'code' => 200,
'msg' => 'success',
'list' => [],
'total' => 0,
'page' => $page,
'limit' => $limit,
]);
}
// 查询总数
$total = Articles::where('cate', $categoryInfo['id'])
->where('delete_time', null)
->where('status', 2)
->count();
// 查询文章
$articles = Articles::where('cate', $categoryInfo['id'])
->where('delete_time', null)
->where('status', 2)
->order('top', 'desc')
->order('recommend', 'desc')
->order('sort', 'desc')
->order('publish_date', 'desc')
->page($page, $limit)
->select();
return json([
'code' => 200,
'msg' => 'success',
'list' => $articles,
'total' => $total,
'page' => $page,
'limit' => $limit,
]);
}
/**
* 获取技术中心子分类
* @return Json
*/
public function getTechnologyCategories(): Json
{
// 获取"技术中心"主分类
$parentCategory = ArticlesCategory::where('name', '技术中心')
->where('delete_time', null)
->find();
if (!$parentCategory) {
return json([
'code' => 200,
'msg' => 'success',
'data' => []
]);
}
// 查找所有子分类
$subCategories = ArticlesCategory::where('cid', $parentCategory['id'])
->where('delete_time', null)
->field('id,name,desc,sort,image')
->order('sort', 'desc')
->select();
return json([
'code' => 200,
'msg' => 'success',
'data' => $subCategories
]);
}
/**
* 获取技术中心
* @return Json
*/
public function getTechnologyCenter(): Json
{
// 1. 分页参数规范化
$page = max(1, intval(Request::param('page', 1)));
$limit = max(1, min(50, intval(Request::param('limit', 10))));
// 获取分类ID参数(可选)
$categoryId = Request::param('category_id', null);
// 2. 第一步:获取“技术中心”主分类的 id
$parentCategory = ArticlesCategory::where('name', '技术中心')
->where('delete_time', null)
->find();
// print_r($parentCategory['id']);
if (!$parentCategory) {
return $this->emptyResponse($page, $limit);
}
// 3. 第二步:查找 cid 等于主分类 id 的所有子分类 id
$subCategoryQuery = ArticlesCategory::where('cid', $parentCategory['id'])
->where('delete_time', null);
// print_r($subCategoryQuery->select());
// 如果指定了分类ID,则只查询该分类
if ($categoryId) {
$subCategoryQuery->where('id', $categoryId);
}
$subCategoryIds = $subCategoryQuery->column('id');
// print_r($subCategoryIds);
if (empty($subCategoryIds)) {
return $this->emptyResponse($page, $limit);
}
// 5. 第三步:查询 Articles 表,并限定字段
$articleQuery = Articles::whereIn('cate', $subCategoryIds)
->where('delete_time', null)
->where('status', 2);
// 获取总数
$total = (clone $articleQuery)->count();
// 获取列表:限定返回 id, title, desc, publish_date, image, likes, views
$articles = $articleQuery->field('id,title,desc,publish_date,image,likes,views,cate')
->order([
'top' => 'desc',
'recommend' => 'desc',
'sort' => 'desc',
'publish_date' => 'desc'
])
->page($page, $limit)
->select();
// 如果文章没有image,查询对应分类的image
$categoryImages = ArticlesCategory::whereIn('id', $subCategoryIds)->column('image', 'id');
// 处理图片:如果文章image为空,则取分类的image
foreach ($articles as &$article) {
if (empty($article['image']) && isset($categoryImages[$article['cate']])) {
$article['image'] = $categoryImages[$article['cate']];
if (empty($article['image']) && !empty($article['cate'])) {
$category = ArticlesCategory::where('id', $article['cate'])
->where('delete_time', null)
->find();
if ($category && !empty($category['image'])) {
$article['image'] = $category['image'];
}
}
}
@@ -270,92 +59,9 @@ class NewsCenterController extends BaseController
'code' => 200,
'msg' => 'success',
'list' => $articles,
'total' => $total,
'page' => $page,
'limit' => $limit,
]);
}
/**
* 统一空返回
*/
private function emptyResponse($page, $limit): Json
{
return json([
'code' => 200,
'msg' => 'success',
'list' => [],
'total' => 0,
'page' => $page,
'limit' => $limit,
]);
}
/**
* 获取金蝶新闻详情
*/
public function getKingdeeNewsDetail(int $id): Json
{
$article = Articles::where('id', $id)
->where('delete_time', null)
->where('status', 2)
->field('id,title,cate,image,desc,author,content,publisher,publish_date,views,likes,is_trans,transurl')
->find();
if (!$article) {
return json(['code' => 404, 'msg' => '文章不存在', 'data' => null]);
}
$cate = (int) $article['cate'];
// 转换为数组再处理
$articleData = $article->toArray();
// $articleData['catename'] = $this->getCategoryName($cate);
// 获取相关文章
$articleData['relatedArticles'] = $this->getRelatedArticles($id, $cate);
// 获取上一篇下一篇
$articleData['nextPreviousArticles'] = $this->getNextPreviousArticles($id, $cate);
// 增加浏览量
Articles::where('id', $id)->inc('views')->update();
return json(['code' => 200, 'msg' => 'success', 'data' => $articleData]);
}
/**
* 获取企业新闻详情
*/
public function getCompanyNewsDetail(int $id): Json
{
$article = Articles::where('id', $id)
->where('delete_time', null)
->where('status', 2)
->find();
if (!$article) {
return json(['code' => 404, 'msg' => '文章不存在', 'data' => null]);
}
$cate = (int) $article['cate'];
// 转换为数组再处理
$articleData = $article->toArray();
$articleData['catename'] = $this->getCategoryName($cate);
// 获取相关文章
$articleData['relatedArticles'] = $this->getRelatedArticles($id, $cate);
// 获取上一篇下一篇
$articleData['nextPreviousArticles'] = $this->getNextPreviousArticles($id, $cate);
// 增加浏览量
Articles::where('id', $id)->inc('views')->update();
return json(['code' => 200, 'msg' => 'success', 'data' => $articleData]);
}
/**
* 获取上一篇下一篇
* @param int $id 文章ID
+2 -1
View File
@@ -34,7 +34,8 @@ class Index extends BaseController
// 兼容:从header获取
if ($tid == 0) {
$tid = (int)$request->header('X-Tenant-Id', 0);
$headerTid = $request->header('X-Tenant-Id');
$tid = $headerTid ? (int)$headerTid : 0;
}
// 调试:检查tid
+1 -18
View File
@@ -11,27 +11,10 @@ Route::get('init', 'app\index\controller\Index@init');
// --- 前端底部数据路由 ---
Route::get('footerdata', 'app\index\controller\Index@getFooterData');
// --- 文章详情路由 ---
Route::get('kingdeenews/detail/:id', 'app\index\controller\Article\NewsCenterController@getKingdeeNewsDetail');
Route::get('companynews/detail/:id', 'app\index\controller\Article\NewsCenterController@getCompanyNewsDetail');
// --- 文章列表路由 ---
Route::get('kingdeenews$', 'app\index\controller\Article\NewsCenterController@getKingdeeNews');
Route::get('companynews$', 'app\index\controller\Article\NewsCenterController@getCompanyNews');
Route::get('technologyCenter$', 'app\index\controller\Article\NewsCenterController@getTechnologyCenter');
Route::get('technologyCategories$', 'app\index\controller\Article\NewsCenterController@getTechnologyCategories');
Route::get('newscentertop4', 'app\index\controller\Article\ArticleController@getNewsCenterTop4');
Route::get('newsbycategory/:category', 'app\index\controller\Article\NewsCenterController@getNewsByCategory');
Route::get('getCenterNews', 'app\index\controller\Article\NewsCenterController@getCenterNews');
// --- 文章互动路由 ---
Route::post('articleViews/:id', 'app\index\controller\Article\ArticleController@articleViews');
Route::post('articleLikes/:id', 'app\index\controller\Article\ArticleController@articleLikes');
Route::post('articleUnlikes/:id', 'app\index\controller\Article\ArticleController@articleUnlikes');
// --- 前端导航与单页路由 ---
Route::get('headmenu', 'app\index\controller\Index@getHeadMenu');
Route::rule('onepage/:path', 'app\index\controller\Index@getOnePageByPath', 'GET')->pattern(['path' => '.*']);
// --- 日志相关路由 ---
Route::get('index/getLogs', 'app\index\controller\Index@getLogs');
Route::get('getLogs', 'app\index\controller\Index@getLogs');