Compare commits
26
Commits
c389fec971
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4eab9ad89 | ||
|
|
2a6b14f698 | ||
|
|
9281c1dc35 | ||
|
|
d30a2531a7 | ||
|
|
b3a25ceb82 | ||
|
|
14c305f518 | ||
|
|
a7908e0677 | ||
|
|
bf21006d4e | ||
|
|
1f8d876cef | ||
|
|
e46a4100c7 | ||
|
|
f134b0e759 | ||
|
|
5dffe62adc | ||
|
|
98156991c1 | ||
|
|
7cdb591f69 | ||
|
|
c00229f2ee | ||
|
|
e27cc8f457 | ||
|
|
e09b4c639c | ||
|
|
bf0daf987b | ||
|
|
4cbc52c51b | ||
|
|
99fc99f8ad | ||
|
|
21480f43b1 | ||
|
|
050d1adc0b | ||
|
|
f80e1f71d4 | ||
|
|
bfa5292962 | ||
|
|
1e8b6fe77d | ||
|
|
67244496f1 |
+4
-1
@@ -1,5 +1,6 @@
|
|||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
runtime
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
@@ -25,4 +26,6 @@ dist-ssr
|
|||||||
|
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.example.env
|
!.example.env
|
||||||
|
|
||||||
|
public\storage
|
||||||
@@ -187,4 +187,15 @@ abstract class BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户的 tid
|
||||||
|
*
|
||||||
|
* @return int 租户ID
|
||||||
|
*/
|
||||||
|
protected function getTenantId(): int
|
||||||
|
{
|
||||||
|
$userInfo = $this->getAdminUserInfo();
|
||||||
|
return isset($userInfo['tid']) ? intval($userInfo['tid']) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-5
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\Cms\Analytics;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\Articles;
|
use app\model\Cms\Articles;
|
||||||
use app\model\ArticlesCategory;
|
use app\model\Cms\ArticlesCategory;
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class AnalyticsController extends BaseController
|
class AnalyticsController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -29,11 +29,13 @@ class AnalyticsController extends BaseController
|
|||||||
|
|
||||||
// 总发布量
|
// 总发布量
|
||||||
$totalArticles = Articles::where('delete_time', null)
|
$totalArticles = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->count();
|
->count();
|
||||||
|
|
||||||
// 昨日新增发布
|
// 昨日新增发布
|
||||||
$yesterdayArticles = Articles::where('delete_time', null)
|
$yesterdayArticles = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->where('publish_date', '>=', $yesterday . ' 00:00:00')
|
->where('publish_date', '>=', $yesterday . ' 00:00:00')
|
||||||
->where('publish_date', '<=', $yesterday . ' 23:59:59')
|
->where('publish_date', '<=', $yesterday . ' 23:59:59')
|
||||||
@@ -41,6 +43,7 @@ class AnalyticsController extends BaseController
|
|||||||
|
|
||||||
// 本月新增发布
|
// 本月新增发布
|
||||||
$monthNewArticles = Articles::where('delete_time', null)
|
$monthNewArticles = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->where('publish_date', '>=', $monthStart . ' 00:00:00')
|
->where('publish_date', '>=', $monthStart . ' 00:00:00')
|
||||||
->where('publish_date', '<=', $monthEnd)
|
->where('publish_date', '<=', $monthEnd)
|
||||||
@@ -48,16 +51,19 @@ class AnalyticsController extends BaseController
|
|||||||
|
|
||||||
// 总点赞量
|
// 总点赞量
|
||||||
$totalLikes = Articles::where('delete_time', null)
|
$totalLikes = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->sum('likes');
|
->sum('likes');
|
||||||
|
|
||||||
// 总访问量
|
// 总访问量
|
||||||
$totalViews = Articles::where('delete_time', null)
|
$totalViews = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->sum('views');
|
->sum('views');
|
||||||
|
|
||||||
// 热门内容TOP5
|
// 热门内容TOP5
|
||||||
$hotArticles = Articles::where('delete_time', null)
|
$hotArticles = Articles::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 2)
|
->where('status', 2)
|
||||||
->order('views', 'desc')
|
->order('views', 'desc')
|
||||||
->limit(5)
|
->limit(5)
|
||||||
@@ -100,7 +106,9 @@ class AnalyticsController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$stats = [
|
$stats = [
|
||||||
'total_users' => AdminUser::where('delete_time', null)->count(),
|
'total_users' => AdminUser::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->count(),
|
||||||
];
|
];
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('用户统计', '获取用户统计', ['data' => $stats]);
|
$this->logSuccess('用户统计', '获取用户统计', ['data' => $stats]);
|
||||||
+12
-10
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
declare (strict_types = 1);
|
declare (strict_types = 1);
|
||||||
|
|
||||||
namespace app\admin\controller\Article;
|
namespace app\admin\controller\Cms\Article;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -9,6 +9,7 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
|
use app\model\Cms\ArticlesCategory;
|
||||||
|
|
||||||
class ArticleCategoryController extends BaseController
|
class ArticleCategoryController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -24,8 +25,8 @@ class ArticleCategoryController extends BaseController
|
|||||||
$keyword = $keyword ?? '';
|
$keyword = $keyword ?? '';
|
||||||
|
|
||||||
// 获取文章分类列表
|
// 获取文章分类列表
|
||||||
$categories = Db::name('mete_articles_category')
|
$categories = ArticlesCategory::where('delete_time', null)
|
||||||
->where('delete_time', null)
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 1)
|
->where('status', 1)
|
||||||
->where('name', 'like', '%' . $keyword . '%')
|
->where('name', 'like', '%' . $keyword . '%')
|
||||||
->order('sort', 'desc')
|
->order('sort', 'desc')
|
||||||
@@ -55,8 +56,8 @@ class ArticleCategoryController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 获取文章分类列表
|
// 获取文章分类列表
|
||||||
$categories = Db::name('mete_articles_category')
|
$categories = ArticlesCategory::where('delete_time', null)
|
||||||
->where('delete_time', null)
|
->where('tid', $this->getTenantId())
|
||||||
->where('status', 1)
|
->where('status', 1)
|
||||||
->field('id,cid,name,image,sort')
|
->field('id,cid,name,image,sort')
|
||||||
->order('sort', 'desc')
|
->order('sort', 'desc')
|
||||||
@@ -93,10 +94,11 @@ class ArticleCategoryController extends BaseController
|
|||||||
$data['cid'] = isset($data['cid']) ? (int)$data['cid'] : 0;
|
$data['cid'] = isset($data['cid']) ? (int)$data['cid'] : 0;
|
||||||
$data['sort'] = isset($data['sort']) ? (int)$data['sort'] : 0;
|
$data['sort'] = isset($data['sort']) ? (int)$data['sort'] : 0;
|
||||||
$data['status']= isset($data['status']) ? (int)$data['status'] : 1;
|
$data['status']= isset($data['status']) ? (int)$data['status'] : 1;
|
||||||
|
$data['tid'] = $this->getTenantId();
|
||||||
$data['create_time'] = date('Y-m-d H:i:s');
|
$data['create_time'] = date('Y-m-d H:i:s');
|
||||||
$data['update_time'] = $data['create_time'];
|
$data['update_time'] = $data['create_time'];
|
||||||
|
|
||||||
$id = Db::name('mete_articles_category')->insertGetId($data);
|
$id = ArticlesCategory::insertGetId($data);
|
||||||
return json(['code'=>200,'msg'=>'success','data'=>['id'=>$id]]);
|
return json(['code'=>200,'msg'=>'success','data'=>['id'=>$id]]);
|
||||||
} catch (ValidateException $ve) {
|
} catch (ValidateException $ve) {
|
||||||
// 记录失败日志
|
// 记录失败日志
|
||||||
@@ -122,7 +124,7 @@ class ArticleCategoryController extends BaseController
|
|||||||
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
||||||
}
|
}
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
$affected = Db::name('mete_articles_category')->where('id',$id)->update($data);
|
$affected = ArticlesCategory::where('id',$id)->where('tid', $this->getTenantId())->update($data);
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
// 记录成功日志
|
// 记录成功日志
|
||||||
$this->logSuccess('文章分类管理', '更新文章分类', ['id' => $id]);
|
$this->logSuccess('文章分类管理', '更新文章分类', ['id' => $id]);
|
||||||
@@ -144,8 +146,8 @@ class ArticleCategoryController extends BaseController
|
|||||||
public function deleteCategory(int $id): Json
|
public function deleteCategory(int $id): Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$affected = Db::name('mete_articles_category')
|
$affected = ArticlesCategory::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -179,7 +181,7 @@ class ArticleCategoryController extends BaseController
|
|||||||
}
|
}
|
||||||
$data['status'] = isset($data['status']) ? (int)$data['status'] : 1;
|
$data['status'] = isset($data['status']) ? (int)$data['status'] : 1;
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
$affected = Db::name('mete_articles_category')->where('id',$id)->update($data);
|
$affected = ArticlesCategory::where('id',$id)->where('tid', $this->getTenantId())->update($data);
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
// 记录成功日志
|
// 记录成功日志
|
||||||
$this->logSuccess('文章分类管理', '更新分类状态', ['id' => $id]);
|
$this->logSuccess('文章分类管理', '更新分类状态', ['id' => $id]);
|
||||||
+56
-40
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
declare (strict_types = 1);
|
declare (strict_types = 1);
|
||||||
|
|
||||||
namespace app\admin\controller\Article;
|
namespace app\admin\controller\Cms\Article;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -10,6 +10,8 @@ use think\facade\Request;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
|
use app\model\Cms\Articles;
|
||||||
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class ArticleController extends BaseController
|
class ArticleController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -21,18 +23,20 @@ class ArticleController extends BaseController
|
|||||||
* @param int $pageSize 每页条数(默认10)
|
* @param int $pageSize 每页条数(默认10)
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getArticlesList(string $keyword = '', string $cate = '', int $page = 1, int $pageSize = 10): Json
|
public function getArticlesList(string $author = '', string $keyword = '', string $cate = '', int $page = 1, int $pageSize = 10): Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 安全处理参数(防止非法参数)
|
// 安全处理参数(防止非法参数)
|
||||||
$page = max(1, $page); // 页码最小为1
|
$page = max(1, $page); // 页码最小为1
|
||||||
$pageSize = max(1, min(100, $pageSize)); // 每页条数限制1-100条
|
$pageSize = max(1, min(100, $pageSize)); // 每页条数限制1-100条
|
||||||
|
$author = trim($author);
|
||||||
$keyword = trim($keyword);
|
$keyword = trim($keyword);
|
||||||
$cate = trim($cate);
|
$cate = trim($cate);
|
||||||
|
|
||||||
// 输出参数值
|
// 输出参数值
|
||||||
trace('查询参数:', 'debug');
|
trace('查询参数:', 'debug');
|
||||||
trace([
|
trace([
|
||||||
|
'author' => $author,
|
||||||
'keyword' => $keyword,
|
'keyword' => $keyword,
|
||||||
'cate' => $cate,
|
'cate' => $cate,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
@@ -40,8 +44,9 @@ class ArticleController extends BaseController
|
|||||||
], 'debug');
|
], 'debug');
|
||||||
|
|
||||||
// 构建查询条件,合并表连接
|
// 构建查询条件,合并表连接
|
||||||
$query = Db::name('mete_articles')->alias('a')
|
$query = Articles::alias('a')
|
||||||
->where('a.delete_time', null)
|
->where('a.delete_time', null)
|
||||||
|
->where('a.tid', $this->getTenantId())
|
||||||
->leftJoin('mete_admin_user u', 'a.publisher = u.id')
|
->leftJoin('mete_admin_user u', 'a.publisher = u.id')
|
||||||
->leftJoin('mete_articles_category c', 'a.cate = c.id');
|
->leftJoin('mete_articles_category c', 'a.cate = c.id');
|
||||||
|
|
||||||
@@ -49,6 +54,11 @@ class ArticleController extends BaseController
|
|||||||
if ($keyword) {
|
if ($keyword) {
|
||||||
$query->where('a.title', 'like', '%' . $keyword . '%');
|
$query->where('a.title', 'like', '%' . $keyword . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 作者筛选
|
||||||
|
if ($author) {
|
||||||
|
$query->where('a.publisher', 'like', '%' . $author . '%');
|
||||||
|
}
|
||||||
|
|
||||||
// 分类筛选
|
// 分类筛选
|
||||||
if ($cate) {
|
if ($cate) {
|
||||||
@@ -98,8 +108,7 @@ class ArticleController extends BaseController
|
|||||||
$newTitleLength = strlen($newTitleLower);
|
$newTitleLength = strlen($newTitleLower);
|
||||||
|
|
||||||
// 获取所有文章标题
|
// 获取所有文章标题
|
||||||
$allTitles = Db::name('mete_articles')
|
$allTitles = Articles::field('id, title')
|
||||||
->field('id, title')
|
|
||||||
->select();
|
->select();
|
||||||
|
|
||||||
$similarArticles = [];
|
$similarArticles = [];
|
||||||
@@ -180,10 +189,11 @@ class ArticleController extends BaseController
|
|||||||
'is_trans' => $data['is_trans'] ?? 0,
|
'is_trans' => $data['is_trans'] ?? 0,
|
||||||
'transurl' => $data['is_trans'] == 1 ? ($data['transurl'] ?? '') : '',
|
'transurl' => $data['is_trans'] == 1 ? ($data['transurl'] ?? '') : '',
|
||||||
'publisher' => $userId,
|
'publisher' => $userId,
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'create_time' => date('Y-m-d H:i:s'),
|
'create_time' => date('Y-m-d H:i:s'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$id = Db::name('mete_articles')->insertGetId($insertData);
|
$id = Articles::insertGetId($insertData);
|
||||||
|
|
||||||
// 记录成功日志
|
// 记录成功日志
|
||||||
$this->logSuccess('文章管理', '创建文章', ['id' => $id]);
|
$this->logSuccess('文章管理', '创建文章', ['id' => $id]);
|
||||||
@@ -206,10 +216,17 @@ class ArticleController extends BaseController
|
|||||||
public function getArticle(int $id): Json
|
public function getArticle(int $id): Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$article = Db::name('mete_articles')
|
$article = Articles::alias('a')
|
||||||
->where('id', $id)
|
->where('a.id', $id)
|
||||||
->field('id,title,cate,image,desc,author,content,is_trans,transurl,views,likes,publisher,create_time,publish_date,update_time')
|
->where('a.tid', $this->getTenantId())
|
||||||
->find();
|
->leftJoin('mete_admin_user u', 'a.publisher = u.id')
|
||||||
|
->field('a.id,a.title,a.cate,a.image,a.desc,a.author,a.content,a.is_trans,a.transurl,a.views,a.likes,u.name as publisher_name,a.create_time,a.publish_date,a.update_time')
|
||||||
|
->find()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 将 publisher_name 赋值给 publisher
|
||||||
|
$article['publisher'] = $article['publisher_name'] ?? '';
|
||||||
|
unset($article['publisher_name']);
|
||||||
|
|
||||||
if (!$article) {
|
if (!$article) {
|
||||||
return json(['code' => 404, 'msg' => '文章不存在', 'data' => null]);
|
return json(['code' => 404, 'msg' => '文章不存在', 'data' => null]);
|
||||||
@@ -234,12 +251,17 @@ class ArticleController extends BaseController
|
|||||||
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
||||||
}
|
}
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
$affected = Db::name('mete_articles')->where('id',$id)->update($data);
|
$article = Articles::where('id', $id)->where('tid', $this->getTenantId())->find();
|
||||||
|
if (!$article) {
|
||||||
|
return json(['code'=>404,'msg'=>'文章不存在','data'=>null]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$affected = Articles::where('id',$id)->where('tid', $this->getTenantId())->update($data);
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
|
// 记录成功日志
|
||||||
|
$this->logSuccess('文章管理', '编辑文章', ['id' => $id]);
|
||||||
return json(['code'=>200,'msg'=>'success','data'=>null]);
|
return json(['code'=>200,'msg'=>'success','data'=>null]);
|
||||||
}
|
}
|
||||||
// 记录成功日志
|
|
||||||
$this->logSuccess('文章管理', '编辑文章', ['id' => $id]);
|
|
||||||
return json(['code'=>404,'msg'=>'not found','data'=>null]);
|
return json(['code'=>404,'msg'=>'not found','data'=>null]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// 记录失败日志
|
// 记录失败日志
|
||||||
@@ -256,24 +278,18 @@ class ArticleController extends BaseController
|
|||||||
public function deleteArticle(int $id): Json
|
public function deleteArticle(int $id): Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
// 记录成功日志
|
$this->logSuccess('文章管理', '删除文章', ['id' => $id]);
|
||||||
$this->logSuccess('文章管理', '删除文章', ['id' => $id]);
|
|
||||||
return json(['code' => 200, 'msg' => 'success', 'data' => null]);
|
return json(['code' => 200, 'msg' => 'success', 'data' => null]);
|
||||||
}
|
}
|
||||||
return json(['code' => 404, 'msg' => 'not found', 'data' => null]);
|
return json(['code' => 404, 'msg' => 'not found', 'data' => null]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// 记录失败日志
|
$this->logFail('文章管理', '删除文章', $e->getMessage());
|
||||||
$this->logFail('文章管理', '删除文章', $e->getMessage());
|
return json(['code' => 500, 'msg' => 'fail:' . $e->getMessage(), 'data' => null]);
|
||||||
return json([
|
|
||||||
'code' => 500,
|
|
||||||
'msg' => 'fail:' . $e->getMessage(),
|
|
||||||
'data' => $e->getTraceAsString()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +306,7 @@ class ArticleController extends BaseController
|
|||||||
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
return json(['code'=>400,'msg'=>'无更新数据','data'=>null]);
|
||||||
}
|
}
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
$affected = Db::name('mete_articles')->where('id',$id)->update($data);
|
$affected = Articles::where('id',$id)->where('tid', $this->getTenantId())->update($data);
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
// 记录成功日志
|
// 记录成功日志
|
||||||
$this->logSuccess('文章管理', '更新文章分类状态', ['id' => $id]);
|
$this->logSuccess('文章管理', '更新文章分类状态', ['id' => $id]);
|
||||||
@@ -329,8 +345,8 @@ class ArticleController extends BaseController
|
|||||||
'publisher' => $user_id,
|
'publisher' => $user_id,
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -366,8 +382,8 @@ class ArticleController extends BaseController
|
|||||||
'update_time' => $currentTime
|
'update_time' => $currentTime
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -400,8 +416,8 @@ class ArticleController extends BaseController
|
|||||||
'recommend' => 1, // 推荐状态
|
'recommend' => 1, // 推荐状态
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -434,8 +450,8 @@ class ArticleController extends BaseController
|
|||||||
'recommend' => 0, // 取消推荐状态
|
'recommend' => 0, // 取消推荐状态
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -464,8 +480,8 @@ class ArticleController extends BaseController
|
|||||||
'top' => 1, // 置顶状态
|
'top' => 1, // 置顶状态
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -494,8 +510,8 @@ class ArticleController extends BaseController
|
|||||||
'top' => 0, // 取消置顶状态
|
'top' => 0, // 取消置顶状态
|
||||||
];
|
];
|
||||||
|
|
||||||
$affected = Db::name('mete_articles')
|
$affected = Articles::where('id', $id)
|
||||||
->where('id', $id)
|
->where('tid', $this->getTenantId())
|
||||||
->update($data);
|
->update($data);
|
||||||
|
|
||||||
if ($affected) {
|
if ($affected) {
|
||||||
@@ -539,9 +555,9 @@ class ArticleController extends BaseController
|
|||||||
], 'debug');
|
], 'debug');
|
||||||
|
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
$query = Db::name('mete_articles')
|
$query = Articles::alias('a')
|
||||||
->alias('a')
|
->where('a.delete_time', null)
|
||||||
->where('a.delete_time', null);
|
->where('a.tid', $this->getTenantId());
|
||||||
|
|
||||||
// 关键词筛选(标题模糊匹配)
|
// 关键词筛选(标题模糊匹配)
|
||||||
if (!empty($keyword)) {
|
if (!empty($keyword)) {
|
||||||
+16
-7
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\Cms\Banner;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -10,7 +10,7 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\Banner;
|
use app\model\Cms\Banner;
|
||||||
|
|
||||||
class BannerController extends BaseController
|
class BannerController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -22,7 +22,8 @@ class BannerController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$banners = Banner::where('delete_time', null)
|
$banners = Banner::where('delete_time', null)
|
||||||
->order('sort', 'asc')
|
->where('tid', $this->getTenantId())
|
||||||
|
->order('sort desc, id desc')
|
||||||
->field('id, title, desc, url, image, sort, create_time, update_time')
|
->field('id, title, desc, url, image, sort, create_time, update_time')
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
@@ -66,6 +67,7 @@ class BannerController extends BaseController
|
|||||||
// 准备Banner数据
|
// 准备Banner数据
|
||||||
$bannerData = [
|
$bannerData = [
|
||||||
'title' => $data['title'],
|
'title' => $data['title'],
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'desc' => $data['desc'] ?? '',
|
'desc' => $data['desc'] ?? '',
|
||||||
'url' => $data['url'] ?? '',
|
'url' => $data['url'] ?? '',
|
||||||
'image' => $data['image'] ?? '',
|
'image' => $data['image'] ?? '',
|
||||||
@@ -127,8 +129,9 @@ class BannerController extends BaseController
|
|||||||
'sort|排序号' => 'integer',
|
'sort|排序号' => 'integer',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 检查Banner是否存在
|
// 检查Banner是否存在(验证tid)
|
||||||
$banner = Banner::where('id', $id)
|
$banner = Banner::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -150,10 +153,14 @@ class BannerController extends BaseController
|
|||||||
];
|
];
|
||||||
|
|
||||||
// 执行更新
|
// 执行更新
|
||||||
Banner::where('id', $id)->update($updateData);
|
Banner::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update($updateData);
|
||||||
|
|
||||||
// 获取更新后的Banner信息
|
// 获取更新后的Banner信息
|
||||||
$updatedBanner = Banner::where('id', $id)->find();
|
$updatedBanner = Banner::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('Banner管理', '更新Banner', ['id' => $id]);
|
$this->logSuccess('Banner管理', '更新Banner', ['id' => $id]);
|
||||||
@@ -187,8 +194,9 @@ class BannerController extends BaseController
|
|||||||
public function deleteBanner(int $id)
|
public function deleteBanner(int $id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 检查Banner是否存在
|
// 检查Banner是否存在(验证tid)
|
||||||
$banner = Banner::where('id', $id)
|
$banner = Banner::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -201,6 +209,7 @@ class BannerController extends BaseController
|
|||||||
|
|
||||||
// 逻辑删除Banner
|
// 逻辑删除Banner
|
||||||
$result = Banner::where('id', $id)
|
$result = Banner::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->update([
|
->update([
|
||||||
'delete_time' => time(),
|
'delete_time' => time(),
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Demand;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use Symfony\Component\VarDumper\VarDumper;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
use think\facade\Request;
|
||||||
|
use think\facade\Session;
|
||||||
|
use think\response\Json;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
|
||||||
|
use app\model\Cms\Demand;
|
||||||
|
use app\model\Cms\DemandCategory;
|
||||||
|
|
||||||
|
|
||||||
|
class DemandController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取需求列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getDemandList(): Json
|
||||||
|
{
|
||||||
|
// 查询分类
|
||||||
|
$demandList = Demand::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->order('id', 'desc')
|
||||||
|
->select();
|
||||||
|
|
||||||
|
if (!$demandList) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => $demandList,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加需求
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function addDemand(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = Request::only(['title', 'desc', 'applicant', 'status']);
|
||||||
|
|
||||||
|
// 验证数据
|
||||||
|
if (empty($data['title']) || empty($data['desc'])) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '标题和描述不能为空',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建需求
|
||||||
|
$demand = Demand::create([
|
||||||
|
'title' => $data['title'],
|
||||||
|
'desc' => $data['desc'],
|
||||||
|
'applicant' => $data['applicant'] ?? '',
|
||||||
|
'status' => $data['status'] ?? 'pending',
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '添加成功',
|
||||||
|
'data' => $demand,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '添加失败:' . $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑需求
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function editDemand(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$id = Request::param('id');
|
||||||
|
$data = Request::only(['title', 'desc', 'applicant', 'status']);
|
||||||
|
|
||||||
|
// 验证数据
|
||||||
|
if (empty($id)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '需求ID不能为空',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data['title']) || empty($data['desc'])) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '标题和描述不能为空',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找需求(验证tid)
|
||||||
|
$demand = Demand::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if (!$demand) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '需求不存在',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新需求
|
||||||
|
$demand->save([
|
||||||
|
'title' => $data['title'],
|
||||||
|
'desc' => $data['desc'],
|
||||||
|
'applicant' => $data['applicant'] ?? '',
|
||||||
|
'status' => $data['status'] ?? 'pending',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '编辑成功',
|
||||||
|
'data' => $demand,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '编辑失败:' . $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除需求
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function deleteDemand(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$id = Request::param('id');
|
||||||
|
|
||||||
|
// 验证数据
|
||||||
|
if (empty($id)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '需求ID不能为空',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找需求(验证tid)
|
||||||
|
$demand = Demand::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if (!$demand) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '需求不存在',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 软删除
|
||||||
|
$demand->delete();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功',
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败:' . $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Domain;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\Request;
|
||||||
|
use app\model\System\SystemDomainPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主域名池管理控制器
|
||||||
|
*/
|
||||||
|
class DomainPoolController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取域名池列表
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$page = $request->param('page', 1, 'int');
|
||||||
|
$pageSize = $request->param('pageSize', 10, 'int');
|
||||||
|
$mainDomain = $request->param('main_domain', '');
|
||||||
|
$status = $request->param('status', '');
|
||||||
|
|
||||||
|
$where = [['delete_time', '=', null]];
|
||||||
|
|
||||||
|
if ($mainDomain) {
|
||||||
|
$where[] = ['main_domain', 'like', "%$mainDomain%"];
|
||||||
|
}
|
||||||
|
if ($status !== '' && $status !== null) {
|
||||||
|
$where[] = ['status', '=', $status];
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = SystemDomainPool::where($where)
|
||||||
|
->page($page, $pageSize)
|
||||||
|
->order('id', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$total = SystemDomainPool::where($where)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取启用状态的主域名列表(供租户选择)
|
||||||
|
*/
|
||||||
|
public function getEnabledDomains()
|
||||||
|
{
|
||||||
|
$list = SystemDomainPool::where('status', 1)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建主域名
|
||||||
|
*/
|
||||||
|
public function create(Request $request)
|
||||||
|
{
|
||||||
|
$mainDomain = $request->param('main_domain', '');
|
||||||
|
|
||||||
|
if (empty($mainDomain)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '主域名不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查域名是否已存在
|
||||||
|
$exists = SystemDomainPool::where('main_domain', $mainDomain)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if ($exists) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该域名已存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$id = SystemDomainPool::insertGetId([
|
||||||
|
'main_domain' => $mainDomain,
|
||||||
|
'status' => 1,
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '创建成功',
|
||||||
|
'data' => ['id' => $id]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑主域名
|
||||||
|
*/
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$id = $request->param('id', 0, 'int');
|
||||||
|
$mainDomain = $request->param('main_domain', '');
|
||||||
|
$status = $request->param('status', null);
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($mainDomain)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '主域名不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查域名是否与其他记录重复
|
||||||
|
$exists = SystemDomainPool::where('main_domain', $mainDomain)
|
||||||
|
->where('id', '<>', $id)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if ($exists) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该域名已存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'main_domain' => $mainDomain,
|
||||||
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($status !== null) {
|
||||||
|
$data['status'] = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemDomainPool::where('id', $id)->update($data);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除主域名(软删除)
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemDomainPool::where('id', $id)
|
||||||
|
->update([
|
||||||
|
'delete_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换主域名状态
|
||||||
|
*/
|
||||||
|
public function toggleStatus(Request $request)
|
||||||
|
{
|
||||||
|
$id = $request->param('id', 0, 'int');
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = SystemDomainPool::where('id', $id)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$domain) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '域名不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newStatus = $domain['status'] == 1 ? 0 : 1;
|
||||||
|
|
||||||
|
SystemDomainPool::where('id', $id)
|
||||||
|
->update([
|
||||||
|
'status' => $newStatus,
|
||||||
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '状态更新成功',
|
||||||
|
'data' => ['status' => $newStatus]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Domain;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\Request;
|
||||||
|
use think\facade\Session;
|
||||||
|
use app\model\Tenant\TenantDomain;
|
||||||
|
use app\model\Tenant\Tenant;
|
||||||
|
use app\model\System\SystemDomainPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户域名绑定控制器
|
||||||
|
*/
|
||||||
|
class TenantDomainController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取租户域名列表(管理员查看所有)
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$page = $request->param('page', 1, 'int');
|
||||||
|
$pageSize = $request->param('pageSize', 10, 'int');
|
||||||
|
$tenantId = $request->param('tid', 0, 'int');
|
||||||
|
$status = $request->param('status', '');
|
||||||
|
$subDomain = $request->param('sub_domain', '');
|
||||||
|
|
||||||
|
$where = [['delete_time', '=', null]];
|
||||||
|
|
||||||
|
if ($tenantId > 0) {
|
||||||
|
$where[] = ['tid', '=', $tenantId];
|
||||||
|
}
|
||||||
|
if ($status !== '' && $status !== null) {
|
||||||
|
$where[] = ['status', '=', $status];
|
||||||
|
}
|
||||||
|
if ($subDomain) {
|
||||||
|
$where[] = ['sub_domain', 'like', "%$subDomain%"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = TenantDomain::where($where)
|
||||||
|
->page($page, $pageSize)
|
||||||
|
->order('id', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$total = TenantDomain::where($where)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// 获取租户名称
|
||||||
|
$tenantIds = array_column($list, 'tid');
|
||||||
|
$tenants = [];
|
||||||
|
if ($tenantIds) {
|
||||||
|
$tenantList = Tenant::whereIn('id', $tenantIds)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
$tenants = array_column($tenantList, null, 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 附加租户名称
|
||||||
|
foreach ($list as &$item) {
|
||||||
|
$item['tenant_name'] = $tenants[$item['tid']]['tenant_name'] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前租户的域名列表(租户端)
|
||||||
|
*/
|
||||||
|
public function myDomains(Request $request)
|
||||||
|
{
|
||||||
|
$tid = $request->param('tid', 0, 'int');
|
||||||
|
|
||||||
|
if ($tid <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '租户ID不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = TenantDomain::where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('id', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户申请二级域名
|
||||||
|
*/
|
||||||
|
public function apply(Request $request)
|
||||||
|
{
|
||||||
|
$tid = $request->param('tid', 0, 'int');
|
||||||
|
$subDomain = $request->param('sub_domain', '');
|
||||||
|
$mainDomain = $request->param('main_domain', '');
|
||||||
|
|
||||||
|
if ($tid <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '租户ID不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查该租户是否已有域名数据
|
||||||
|
$hasDomain = TenantDomain::where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if ($hasDomain) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该租户已有域名,请删除后再次申请'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($subDomain)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '二级域名前缀不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($mainDomain)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '请选择主域名'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证域名格式(只能包含字母、数字、连字符)
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$/', $subDomain)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '二级域名前缀格式不正确'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查主域名是否存在且启用
|
||||||
|
$mainDomainInfo = SystemDomainPool::where('main_domain', $mainDomain)
|
||||||
|
->where('status', 1)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$mainDomainInfo) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '主域名不存在或已禁用'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查二级域名是否已被使用
|
||||||
|
$exists = TenantDomain::where('sub_domain', $subDomain)
|
||||||
|
->where('main_domain', $mainDomain)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if ($exists) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该二级域名已被使用'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullDomain = $subDomain . '.' . $mainDomain;
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$id = TenantDomain::insertGetId([
|
||||||
|
'tid' => $tid,
|
||||||
|
'sub_domain' => $subDomain,
|
||||||
|
'main_domain' => $mainDomain,
|
||||||
|
'full_domain' => $fullDomain,
|
||||||
|
'status' => 0, // 审核中
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '申请提交成功,等待审核',
|
||||||
|
'data' => ['id' => $id]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核租户域名(通过/拒绝)
|
||||||
|
*/
|
||||||
|
public function audit(Request $request)
|
||||||
|
{
|
||||||
|
$id = $request->param('id', 0, 'int');
|
||||||
|
$action = $request->param('action', ''); // 'approve' 或 'reject'
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = TenantDomain::where('id', $id)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$domain) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '域名不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($domain['status'] != 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该域名已审核过了'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newStatus = $action === 'approve' ? 1 : 2; // 1-已生效 2-已拒绝
|
||||||
|
|
||||||
|
TenantDomain::where('id', $id)
|
||||||
|
->update([
|
||||||
|
'status' => $newStatus,
|
||||||
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
$msg = $action === 'approve' ? '审核通过' : '已拒绝';
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => $msg
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用/启用租户域名
|
||||||
|
*/
|
||||||
|
public function toggleStatus(Request $request)
|
||||||
|
{
|
||||||
|
$id = $request->param('id', 0, 'int');
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = TenantDomain::where('id', $id)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$domain) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '域名不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有已生效的域名才能被禁用
|
||||||
|
if ($domain['status'] != 1) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '只有已生效的域名才能被禁用'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换为禁用状态
|
||||||
|
TenantDomain::where('id', $id)
|
||||||
|
->update([
|
||||||
|
'status' => 2,
|
||||||
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '已禁用'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除租户域名(软删除)
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
if ($id <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数错误'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TenantDomain::where('id', $id)
|
||||||
|
->update([
|
||||||
|
'delete_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Friendlink;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\response\Json;
|
||||||
|
use app\model\Cms\Friendlink;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 友情链接管理控制器
|
||||||
|
*/
|
||||||
|
class FriendlinkController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取友情链接列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getList(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$page = (int)$this->request->param('page', 1);
|
||||||
|
$limit = (int)$this->request->param('limit', 10);
|
||||||
|
$keyword = $this->request->param('keyword', '');
|
||||||
|
$status = $this->request->param('status', '');
|
||||||
|
|
||||||
|
$query = Friendlink::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
|
// 关键词搜索
|
||||||
|
if (!empty($keyword)) {
|
||||||
|
$query->where('link_name', 'like', '%' . $keyword . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态筛选
|
||||||
|
if ($status !== '') {
|
||||||
|
$query->where('status', (int)$status);
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $query->count();
|
||||||
|
$list = $query->order('sort', 'asc')
|
||||||
|
->order('id', 'desc')
|
||||||
|
->page($page, $limit)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有友情链接(用于下拉选择)
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getAll(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$list = Friendlink::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('status', 1)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->field('id,link_name')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加友情链接
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function add(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
// 验证参数
|
||||||
|
$this->validate($data, [
|
||||||
|
'link_name|链接名称' => 'require|max:100',
|
||||||
|
'link_url|链接地址' => 'require|url|max:255',
|
||||||
|
'sort|排序' => 'integer',
|
||||||
|
'status|状态' => 'in:0,1'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$friendlink = new Friendlink();
|
||||||
|
$friendlink->tid = $this->getTenantId();
|
||||||
|
$friendlink->link_name = $data['link_name'];
|
||||||
|
$friendlink->link_url = $data['link_url'];
|
||||||
|
$friendlink->link_logo = $data['link_logo'] ?? '';
|
||||||
|
$friendlink->description = $data['description'] ?? '';
|
||||||
|
$friendlink->sort = $data['sort'] ?? 0;
|
||||||
|
$friendlink->status = $data['status'] ?? 1;
|
||||||
|
$friendlink->create_time = date('Y-m-d H:i:s');
|
||||||
|
$friendlink->save();
|
||||||
|
|
||||||
|
$this->logSuccess('友情链接', '添加链接', ['id' => $friendlink->id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '添加成功',
|
||||||
|
'data' => $friendlink->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('友情链接', '添加链接', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '添加失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新友情链接
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function update(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$friendlink = Friendlink::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$friendlink) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '链接不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证参数
|
||||||
|
if (isset($data['link_name'])) {
|
||||||
|
$this->validate($data, [
|
||||||
|
'link_name|链接名称' => 'require|max:100'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (isset($data['link_url'])) {
|
||||||
|
$this->validate($data, [
|
||||||
|
'link_url|链接地址' => 'require|url|max:255'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['link_name'])) $friendlink->link_name = $data['link_name'];
|
||||||
|
if (isset($data['link_url'])) $friendlink->link_url = $data['link_url'];
|
||||||
|
if (isset($data['link_logo'])) $friendlink->link_logo = $data['link_logo'];
|
||||||
|
if (isset($data['description'])) $friendlink->description = $data['description'];
|
||||||
|
if (isset($data['sort'])) $friendlink->sort = $data['sort'];
|
||||||
|
if (isset($data['status'])) $friendlink->status = $data['status'];
|
||||||
|
$friendlink->update_time = date('Y-m-d H:i:s');
|
||||||
|
$friendlink->save();
|
||||||
|
|
||||||
|
$this->logSuccess('友情链接', '更新链接', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功',
|
||||||
|
'data' => $friendlink->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('友情链接', '更新链接', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '更新失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除友情链接
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function delete(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$friendlink = Friendlink::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$friendlink) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '链接不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$friendlink->delete();
|
||||||
|
|
||||||
|
$this->logSuccess('友情链接', '删除链接', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('友情链接', '删除链接', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除友情链接
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function batchDelete(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$ids = $this->request->param('ids', []);
|
||||||
|
|
||||||
|
if (empty($ids)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '请选择要删除的链接'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Friendlink::whereIn('id', $ids)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
|
$this->logSuccess('友情链接', '批量删除链接', ['ids' => $ids]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '批量删除成功'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('友情链接', '批量删除链接', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '批量删除失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\Cms\FrontMenu;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -10,7 +10,7 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\FrontMenu;
|
use app\model\Cms\FrontMenu;
|
||||||
|
|
||||||
class FrontMenuController extends BaseController
|
class FrontMenuController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -23,6 +23,7 @@ class FrontMenuController extends BaseController
|
|||||||
try {
|
try {
|
||||||
// 获取所有未删除的菜单
|
// 获取所有未删除的菜单
|
||||||
$frontMenus = FrontMenu::where('delete_time', null)
|
$frontMenus = FrontMenu::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->field('id,pid,title,type,image,path,component_path,sort,desc')
|
->field('id,pid,title,type,image,path,component_path,sort,desc')
|
||||||
->order('sort', 'desc')
|
->order('sort', 'desc')
|
||||||
->select()
|
->select()
|
||||||
@@ -69,6 +70,7 @@ class FrontMenuController extends BaseController
|
|||||||
// 准备菜单数据
|
// 准备菜单数据
|
||||||
$menuData = [
|
$menuData = [
|
||||||
'pid' => $data['pid'] ?? 0,
|
'pid' => $data['pid'] ?? 0,
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'title' => $data['title'],
|
'title' => $data['title'],
|
||||||
'type' => $data['type'],
|
'type' => $data['type'],
|
||||||
'sort' => $data['sort'] ?? 0,
|
'sort' => $data['sort'] ?? 0,
|
||||||
@@ -130,6 +132,7 @@ class FrontMenuController extends BaseController
|
|||||||
// 准备更新数据
|
// 准备更新数据
|
||||||
$updateData = [
|
$updateData = [
|
||||||
'title' => $data['title'],
|
'title' => $data['title'],
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'pid' => $data['pid'] ?? null,
|
'pid' => $data['pid'] ?? null,
|
||||||
'type' => $data['type'],
|
'type' => $data['type'],
|
||||||
'path' => $data['path'] ?? null,
|
'path' => $data['path'] ?? null,
|
||||||
@@ -177,6 +180,7 @@ class FrontMenuController extends BaseController
|
|||||||
try {
|
try {
|
||||||
// 检查是否有子前端导航
|
// 检查是否有子前端导航
|
||||||
$hasChildren = FrontMenu::where('pid', $id)
|
$hasChildren = FrontMenu::where('pid', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('pid', $id)
|
->where('pid', $id)
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->count() > 0;
|
->count() > 0;
|
||||||
@@ -192,6 +196,7 @@ class FrontMenuController extends BaseController
|
|||||||
$result = FrontMenu::where('id', $id)
|
$result = FrontMenu::where('id', $id)
|
||||||
->where('id', $id)
|
->where('id', $id)
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->update([
|
->update([
|
||||||
'delete_time' => date('Y-m-d H:i:s'),
|
'delete_time' => date('Y-m-d H:i:s'),
|
||||||
'update_time' => date('Y-m-d H:i:s')
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
+11
-4
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\Cms\OnePage;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -10,7 +10,7 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\OnePage;
|
use app\model\Cms\OnePage;
|
||||||
|
|
||||||
class OnePageController extends BaseController
|
class OnePageController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -22,6 +22,7 @@ class OnePageController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$onePages = OnePage::where('delete_time', null)
|
$onePages = OnePage::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->order('sort', 'asc')
|
->order('sort', 'asc')
|
||||||
->field('id, title, content, path, sort, status, create_time, update_time')
|
->field('id, title, content, path, sort, status, create_time, update_time')
|
||||||
->select()
|
->select()
|
||||||
@@ -69,6 +70,7 @@ class OnePageController extends BaseController
|
|||||||
|
|
||||||
// 检查路由是否已存在
|
// 检查路由是否已存在
|
||||||
$exists = OnePage::where('path', $data['path'])
|
$exists = OnePage::where('path', $data['path'])
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if ($exists) {
|
if ($exists) {
|
||||||
@@ -85,6 +87,7 @@ class OnePageController extends BaseController
|
|||||||
'path' => $data['path'],
|
'path' => $data['path'],
|
||||||
'sort' => $data['sort'] ?? 0,
|
'sort' => $data['sort'] ?? 0,
|
||||||
'status' => $data['status'] ?? 1,
|
'status' => $data['status'] ?? 1,
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'create_time' => date('Y-m-d H:i:s'),
|
'create_time' => date('Y-m-d H:i:s'),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -150,8 +153,9 @@ class OnePageController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查单页是否存在
|
// 检查单页是否存在(验证tid)
|
||||||
$onePage = OnePage::where('id', $id)
|
$onePage = OnePage::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -165,6 +169,7 @@ class OnePageController extends BaseController
|
|||||||
// 检查路由是否被其他单页使用
|
// 检查路由是否被其他单页使用
|
||||||
$exists = OnePage::where('path', $data['path'])
|
$exists = OnePage::where('path', $data['path'])
|
||||||
->where('id', '<>', $id)
|
->where('id', '<>', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if ($exists) {
|
if ($exists) {
|
||||||
@@ -222,8 +227,9 @@ class OnePageController extends BaseController
|
|||||||
public function deleteOnePage(int $id)
|
public function deleteOnePage(int $id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// 检查单页是否存在
|
// 检查单页是否存在(验证tid)
|
||||||
$onePage = OnePage::where('id', $id)
|
$onePage = OnePage::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -236,6 +242,7 @@ class OnePageController extends BaseController
|
|||||||
|
|
||||||
// 逻辑删除单页
|
// 逻辑删除单页
|
||||||
$result = OnePage::where('id', $id)
|
$result = OnePage::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->update([
|
->update([
|
||||||
'delete_time' => date('Y-m-d H:i:s'),
|
'delete_time' => date('Y-m-d H:i:s'),
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Products;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\response\Json;
|
||||||
|
use app\model\Cms\Products;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特色产品管理控制器
|
||||||
|
*/
|
||||||
|
class ProductsController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取特色产品列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function productsList(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$page = (int)$this->request->param('page', 1);
|
||||||
|
$limit = (int)$this->request->param('limit', 10);
|
||||||
|
$keyword = $this->request->param('keyword', '');
|
||||||
|
|
||||||
|
$query = Products::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
|
// 关键词搜索
|
||||||
|
if (!empty($keyword)) {
|
||||||
|
$query->where('title', 'like', '%' . $keyword . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $query->count();
|
||||||
|
$list = $query->order('sort', 'asc')
|
||||||
|
->order('id', 'desc')
|
||||||
|
->page($page, $limit)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加特色产品
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function addProducts(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$product = new Products();
|
||||||
|
$product->tid = $this->getTenantId();
|
||||||
|
$product->title = $data['title'];
|
||||||
|
$product->url = $data['url'];
|
||||||
|
$product->thumb = $data['thumb'] ?? '';
|
||||||
|
$product->desc = $data['desc'] ?? '';
|
||||||
|
$product->content = $data['content'] ?? '';
|
||||||
|
$product->sort = $data['sort'] ?? 0;
|
||||||
|
$product->create_time = date('Y-m-d H:i:s');
|
||||||
|
$product->save();
|
||||||
|
|
||||||
|
$this->logSuccess('特色产品', '添加产品', ['id' => $product->id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '添加成功',
|
||||||
|
'data' => $product->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色产品', '添加产品', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '添加失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新特色产品
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function editProducts(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$product = Products::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '产品不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['title'])) $product->title = $data['title'];
|
||||||
|
if (isset($data['url'])) $product->url = $data['url'];
|
||||||
|
if (isset($data['thumb'])) $product->thumb = $data['thumb'];
|
||||||
|
if (isset($data['desc'])) $product->desc = $data['desc'];
|
||||||
|
if (isset($data['sort'])) $product->sort = $data['sort'];
|
||||||
|
$product->update_time = date('Y-m-d H:i:s');
|
||||||
|
$product->save();
|
||||||
|
|
||||||
|
$this->logSuccess('特色产品', '更新产品', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功',
|
||||||
|
'data' => $product->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色产品', '更新产品', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '更新失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除特色产品
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function deleteProducts(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$product = Products::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '产品不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$product->delete();
|
||||||
|
|
||||||
|
$this->logSuccess('特色产品', '删除产品', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色产品', '删除产品', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Products;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use app\model\Cms\ProductsTypes;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
use think\response\Json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品分类管理控制器
|
||||||
|
*/
|
||||||
|
class ProductsTypesController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取产品分类列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function productsTypesList(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$page = (int)$this->request->param('page', 1);
|
||||||
|
$limit = (int)$this->request->param('limit', 10);
|
||||||
|
$keyword = (string)$this->request->param('keyword', '');
|
||||||
|
|
||||||
|
$query = ProductsTypes::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
|
if ($keyword !== '') {
|
||||||
|
$query->where('title', 'like', '%' . $keyword . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $query->count();
|
||||||
|
|
||||||
|
$list = $query->order('sort', 'asc')
|
||||||
|
->order('id', 'desc')
|
||||||
|
->page($page, $limit)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => [
|
||||||
|
'list' => [],
|
||||||
|
'total' => 0
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加产品分类
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function addProductsTypes(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$title = (string)($data['title'] ?? '');
|
||||||
|
if ($title === '') {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '分类名称不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = new ProductsTypes();
|
||||||
|
$type->tid = $this->getTenantId();
|
||||||
|
$type->pid = isset($data['pid']) ? (int)$data['pid'] : 0;
|
||||||
|
$type->title = $title;
|
||||||
|
$type->desc = (string)($data['desc'] ?? '');
|
||||||
|
$type->sort = isset($data['sort']) ? (int)$data['sort'] : 0;
|
||||||
|
$type->create_time = date('Y-m-d H:i:s');
|
||||||
|
$type->update_time = date('Y-m-d H:i:s');
|
||||||
|
$type->save();
|
||||||
|
|
||||||
|
$this->logSuccess('产品分类管理', '添加分类', ['id' => $type->id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '添加成功',
|
||||||
|
'data' => $type->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('产品分类管理', '添加分类', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '添加失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新产品分类
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function editProductsTypes(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$type = ProductsTypes::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$type) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '分类不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['title'])) $type->title = (string)$data['title'];
|
||||||
|
if (isset($data['pid'])) $type->pid = (int)$data['pid'];
|
||||||
|
if (isset($data['desc'])) $type->desc = (string)$data['desc'];
|
||||||
|
if (isset($data['sort'])) $type->sort = (int)$data['sort'];
|
||||||
|
|
||||||
|
if ((string)$type->title === '') {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '分类名称不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type->update_time = date('Y-m-d H:i:s');
|
||||||
|
$type->save();
|
||||||
|
|
||||||
|
$this->logSuccess('产品分类管理', '更新分类', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功',
|
||||||
|
'data' => $type->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('产品分类管理', '更新分类', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '更新失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除产品分类(软删除)
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function deleteProductsTypes(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$type = ProductsTypes::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$type) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '分类不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type->delete();
|
||||||
|
|
||||||
|
$this->logSuccess('产品分类管理', '删除分类', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('产品分类管理', '删除分类', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Services;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\response\Json;
|
||||||
|
use app\model\Cms\Services;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特色服务管理控制器
|
||||||
|
*/
|
||||||
|
class ServicesController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取特色服务列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function servicesList(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$page = (int)$this->request->param('page', 1);
|
||||||
|
$limit = (int)$this->request->param('limit', 10);
|
||||||
|
$keyword = $this->request->param('keyword', '');
|
||||||
|
|
||||||
|
$query = Services::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
|
// 关键词搜索
|
||||||
|
if (!empty($keyword)) {
|
||||||
|
$query->where('name', 'like', '%' . $keyword . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $query->count();
|
||||||
|
$list = $query->order('sort', 'asc')
|
||||||
|
->order('id', 'desc')
|
||||||
|
->page($page, $limit)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $list,
|
||||||
|
'total' => $total
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加特色服务
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function addServices(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$service = new Services();
|
||||||
|
$service->tid = $this->getTenantId();
|
||||||
|
$service->title = $data['title'];
|
||||||
|
$service->url = $data['url'];
|
||||||
|
$service->thumb = $data['thumb'] ?? '';
|
||||||
|
$service->desc = $data['desc'] ?? '';
|
||||||
|
$service->sort = $data['sort'] ?? 0;
|
||||||
|
$service->create_time = date('Y-m-d H:i:s');
|
||||||
|
$service->save();
|
||||||
|
|
||||||
|
$this->logSuccess('特色服务', '添加服务', ['id' => $service->id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '添加成功',
|
||||||
|
'data' => $service->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色服务', '添加服务', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '添加失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新特色服务
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function editServices(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->param();
|
||||||
|
|
||||||
|
$service = Services::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$service) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '服务不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['title'])) $service->title = $data['title'];
|
||||||
|
if (isset($data['url'])) $service->url = $data['url'];
|
||||||
|
if (isset($data['thumb'])) $service->thumb = $data['thumb'];
|
||||||
|
if (isset($data['desc'])) $service->desc = $data['desc'];
|
||||||
|
if (isset($data['sort'])) $service->sort = $data['sort'];
|
||||||
|
$service->update_time = date('Y-m-d H:i:s');
|
||||||
|
$service->save();
|
||||||
|
|
||||||
|
$this->logSuccess('特色服务', '更新服务', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功',
|
||||||
|
'data' => $service->toArray()
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色服务', '更新服务', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '更新失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除特色服务
|
||||||
|
* @param int $id
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function deleteServices(int $id): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$service = Services::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$service) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '服务不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$service->delete();
|
||||||
|
|
||||||
|
$this->logSuccess('特色服务', '删除服务', ['id' => $id]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('特色服务', '删除服务', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Cms\Theme;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use app\service\ThemeService;
|
||||||
|
use think\facade\Request;
|
||||||
|
use app\model\Cms\TemplateSiteConfig;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板管理控制器
|
||||||
|
*/
|
||||||
|
class ThemeController extends BaseController
|
||||||
|
{
|
||||||
|
private ThemeService $themeService;
|
||||||
|
|
||||||
|
public function __construct(\think\App $app)
|
||||||
|
{
|
||||||
|
parent::__construct($app);
|
||||||
|
$this->themeService = new ThemeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板列表(后台管理)
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
$themes = $this->themeService->getThemeList();
|
||||||
|
$currentTheme = $this->themeService->getCurrentTheme($tid);
|
||||||
|
|
||||||
|
$theme_useing = TemplateSiteConfig::where('tid', $tid)
|
||||||
|
->where('key', 'current_theme')
|
||||||
|
->value('value');
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'list' => $themes,
|
||||||
|
'currentTheme' => $currentTheme
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换模板
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function switch()
|
||||||
|
{
|
||||||
|
$tid = Request::post('tid', 0, 'int');
|
||||||
|
$themeKey = Request::post('theme_key', '');
|
||||||
|
|
||||||
|
if (empty($tid) || $tid == 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '未获取到租户ID,请先选择租户'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($themeKey)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '模板标识不能为空'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->themeService->switchTheme($tid, $themeKey);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '切换成功'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '切换失败,模板不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板字段数据
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
$tid = Request::get('tid', 0, 'int');
|
||||||
|
$themeKey = Request::get('theme_key', '');
|
||||||
|
|
||||||
|
$themeData = $this->themeService->getThemeData($tid, $themeKey ?: null);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => $themeData
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存模板字段数据
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function saveData()
|
||||||
|
{
|
||||||
|
$tid = Request::post('tid', 0, 'int');
|
||||||
|
$themeKey = Request::post('theme_key', '');
|
||||||
|
$fieldKey = Request::post('field_key', '');
|
||||||
|
$fieldValue = Request::post('field_value', '');
|
||||||
|
|
||||||
|
if (empty($themeKey) || empty($fieldKey)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '参数不完整'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->themeService->saveThemeField($tid, $themeKey, $fieldKey, $fieldValue);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '保存成功'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '保存失败'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Erp;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Session;
|
||||||
|
use think\response\Json;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use app\model\Erp\Employee;
|
||||||
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
|
class EmployeeController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取员工列表
|
||||||
|
*/
|
||||||
|
public function getEmployee()
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = Employee::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取员工详情
|
||||||
|
*/
|
||||||
|
public function getEmployeeDetail($id)
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$detail = Employee::where('id', $id)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->find()
|
||||||
|
->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $detail
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建员工
|
||||||
|
*/
|
||||||
|
public function createEmployee()
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->request->post();
|
||||||
|
$data['tid'] = $tid;
|
||||||
|
|
||||||
|
$employee = Employee::create($data);
|
||||||
|
if ($employee) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '创建成功',
|
||||||
|
'data' => $employee
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '创建失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑员工
|
||||||
|
*/
|
||||||
|
public function editEmployee($id)
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->request->post();
|
||||||
|
unset($data['tid']); // 不允许修改租户ID
|
||||||
|
|
||||||
|
$employee = Employee::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->update($data);
|
||||||
|
if ($employee !== false) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '编辑成功',
|
||||||
|
'data' => $employee
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '编辑失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除员工
|
||||||
|
*/
|
||||||
|
public function deleteEmployee($id)
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = Employee::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
if ($employee) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ use think\facade\Session;
|
|||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\Erp\Organization;
|
use app\model\Erp\Organization;
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class OrganizationController extends BaseController
|
class OrganizationController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -20,7 +20,15 @@ class OrganizationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getOrganization()
|
public function getOrganization()
|
||||||
{
|
{
|
||||||
$list = Organization::where('delete_time', null)->select()->toArray();
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = Organization::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '获取成功',
|
'msg' => '获取成功',
|
||||||
@@ -33,8 +41,18 @@ class OrganizationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getOrganizationDetail($id)
|
public function getOrganizationDetail($id)
|
||||||
{
|
{
|
||||||
$detail = Organization::where('id', $id)->where('delete_time', null)->find()->toArray();
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$detail = Organization::where('id', $id)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->find()
|
||||||
|
->toArray();
|
||||||
$detail['leader_name'] = AdminUser::where('id', $detail['leader_id'])->value('name');
|
$detail['leader_name'] = AdminUser::where('id', $detail['leader_id'])->value('name');
|
||||||
|
$detail['parent_name'] = Organization::where('id', $detail['parent_id'])->value('org_name');
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '获取成功',
|
'msg' => '获取成功',
|
||||||
@@ -47,7 +65,14 @@ class OrganizationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function createOrganization()
|
public function createOrganization()
|
||||||
{
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->request->post();
|
$data = $this->request->post();
|
||||||
|
$data['tid'] = $tid;
|
||||||
|
|
||||||
$organization = Organization::create($data);
|
$organization = Organization::create($data);
|
||||||
if ($organization) {
|
if ($organization) {
|
||||||
return json([
|
return json([
|
||||||
@@ -68,9 +93,18 @@ class OrganizationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function editOrganization($id)
|
public function editOrganization($id)
|
||||||
{
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->request->post();
|
$data = $this->request->post();
|
||||||
$organization = Organization::where('id', $id)->update($data);
|
unset($data['tid']); // 不允许修改租户ID
|
||||||
if ($organization) {
|
|
||||||
|
$organization = Organization::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->update($data);
|
||||||
|
if ($organization !== false) {
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '编辑成功',
|
'msg' => '编辑成功',
|
||||||
@@ -89,7 +123,14 @@ class OrganizationController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function deleteOrganization($id)
|
public function deleteOrganization($id)
|
||||||
{
|
{
|
||||||
$organization = Organization::where('id', $id)->update(['delete_time' => date('Y-m-d H:i:s')]);
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$organization = Organization::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
if ($organization) {
|
if ($organization) {
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
@@ -102,4 +143,50 @@ class OrganizationController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取企业单位
|
||||||
|
*/
|
||||||
|
public function getCompanys()
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$where = [['delete_time', '=', null], ['is_company', '=', 1], ['tid', '=', $tid]];
|
||||||
|
|
||||||
|
$list = Organization::where($where)->select()->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取部门
|
||||||
|
*/
|
||||||
|
public function getDepartments()
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if (!$tid) {
|
||||||
|
return json(['code' => 403, 'msg' => '无法获取租户信息']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentId = input('parent_id/d', 0);
|
||||||
|
|
||||||
|
$where = [['delete_time', '=', null], ['is_company', '=', 0], ['tid', '=', $tid]];
|
||||||
|
|
||||||
|
if ($parentId > 0) {
|
||||||
|
$where[] = ['parent_id', '=', $parentId];
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = Organization::where($where)->select()->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,17 @@ use think\facade\Cache;
|
|||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use app\service\JwtService;
|
use app\service\JwtService;
|
||||||
|
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
use app\model\System\AdminUserGroup;
|
||||||
use app\model\System\SystemSiteSettings;
|
use app\model\System\SystemSiteSettings;
|
||||||
use app\model\Tenant\Tenant;
|
use app\model\Tenant\Tenant;
|
||||||
|
use app\model\System\OperationLog;
|
||||||
|
|
||||||
class LoginController extends BaseController
|
class LoginController extends BaseController
|
||||||
{
|
{
|
||||||
|
private const SMS_CODE_TTL_SECONDS = 300; // 5分钟
|
||||||
|
private const SMS_CODE_RESEND_SECONDS = 60; // 60秒可重发
|
||||||
|
|
||||||
private function generateToken($userInfo): string
|
private function generateToken($userInfo): string
|
||||||
{
|
{
|
||||||
return JwtService::generateToken($userInfo);
|
return JwtService::generateToken($userInfo);
|
||||||
@@ -27,6 +32,186 @@ class LoginController extends BaseController
|
|||||||
return JwtService::verifyToken($token);
|
return JwtService::verifyToken($token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getSiteSettingValue(string $label): string
|
||||||
|
{
|
||||||
|
$row = SystemSiteSettings::where('label', $label)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('id', 'asc')
|
||||||
|
->find();
|
||||||
|
return $row ? (string)$row['value'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function smsCodeCacheKey(string $scene, string $tenantName, string $account, string $phone): string
|
||||||
|
{
|
||||||
|
return 'sms_code:' . md5($scene . '|' . $tenantName . '|' . $account . '|' . $phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function smsCodeThrottleKey(string $scene, string $tenantName, string $account, string $phone): string
|
||||||
|
{
|
||||||
|
return 'sms_code_throttle:' . md5($scene . '|' . $tenantName . '|' . $account . '|' . $phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function postJson(string $url, array $payload, array $headers): array
|
||||||
|
{
|
||||||
|
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
|
if ($body === false) {
|
||||||
|
return ['ok' => false, 'error' => 'json_encode failed'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$context = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => implode("\r\n", $headers),
|
||||||
|
'content' => $body,
|
||||||
|
'timeout' => 10,
|
||||||
|
'ignore_errors' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$respBody = @file_get_contents($url, false, $context);
|
||||||
|
$status = 0;
|
||||||
|
if (!empty($http_response_header) && is_array($http_response_header)) {
|
||||||
|
foreach ($http_response_header as $line) {
|
||||||
|
if (preg_match('#^HTTP/\\S+\\s+(\\d+)#', $line, $m)) {
|
||||||
|
$status = (int)$m[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($respBody === false) {
|
||||||
|
$last = error_get_last();
|
||||||
|
return ['ok' => false, 'status' => $status, 'error' => (string)($last['message'] ?? 'http request failed')];
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode((string)$respBody, true);
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
$decoded = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'ok' => $status >= 200 && $status < 300,
|
||||||
|
'status' => $status,
|
||||||
|
'body' => (string)$respBody,
|
||||||
|
'json' => $decoded,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendSmsCodeInternal(string $scene, string $tenantName, string $account, string $phone): Json
|
||||||
|
{
|
||||||
|
$throttleKey = $this->smsCodeThrottleKey($scene, $tenantName, $account, $phone);
|
||||||
|
if (Cache::has($throttleKey)) {
|
||||||
|
return json(['code' => 429, 'msg' => '验证码发送过于频繁,请稍后再试']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$backendUrl = $this->getSiteSettingValue('backendUrl');
|
||||||
|
$apiKey = $this->getSiteSettingValue('apiKey');
|
||||||
|
if ($backendUrl === '' || $apiKey === '') {
|
||||||
|
return json(['code' => 500, 'msg' => '短信网关配置缺失,请联系管理员']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = (string)random_int(100000, 999999);
|
||||||
|
$sceneTextMap = [
|
||||||
|
'register' => '注册',
|
||||||
|
'reset' => '找回密码',
|
||||||
|
'login' => '登录',
|
||||||
|
];
|
||||||
|
$sceneText = $sceneTextMap[$scene] ?? '验证';
|
||||||
|
$content = "【云泽网】{$sceneText}验证码:{$code},5分钟内有效。";
|
||||||
|
|
||||||
|
$enqueueUrl = rtrim($backendUrl, '/') . '/api/v1/business/outbound-tasks';
|
||||||
|
$resp = $this->postJson($enqueueUrl, [
|
||||||
|
'phone' => $phone,
|
||||||
|
'content' => $content,
|
||||||
|
], [
|
||||||
|
'X-Api-Key: ' . $apiKey,
|
||||||
|
'Content-Type: application/json; charset=utf-8',
|
||||||
|
'Accept: application/json',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (empty($resp['ok'])) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '验证码短信发送失败',
|
||||||
|
'detail' => [
|
||||||
|
'http_status' => $resp['status'] ?? null,
|
||||||
|
'body_preview' => isset($resp['body']) ? substr((string)$resp['body'], 0, 200) : '',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$codeKey = $this->smsCodeCacheKey($scene, $tenantName, $account, $phone);
|
||||||
|
Cache::set($codeKey, $code, self::SMS_CODE_TTL_SECONDS);
|
||||||
|
Cache::set($throttleKey, 1, self::SMS_CODE_RESEND_SECONDS);
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '验证码已发送']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildLoginSuccessResponse($user, $tenant): Json
|
||||||
|
{
|
||||||
|
$tid = (int)$tenant->id;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$loginCount = isset($user['login_count']) && $user['login_count'] !== null ? (int)$user['login_count'] : 0;
|
||||||
|
AdminUser::where('id', $user['id'])->update([
|
||||||
|
'login_count' => $loginCount + 1,
|
||||||
|
'last_login_ip' => $this->request->ip(),
|
||||||
|
'last_login_time' => date('Y-m-d H:i:s')
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('更新登录信息失败: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$userInfo = [
|
||||||
|
'id' => $user['id'],
|
||||||
|
'account' => $user['account'],
|
||||||
|
'name' => $user['name'],
|
||||||
|
'group_id' => $user['group_id'],
|
||||||
|
'tid' => $tid,
|
||||||
|
'tenant' => $tenant
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($user['group_id']) {
|
||||||
|
$userGroup = AdminUserGroup::where('id', $user['group_id'])->find();
|
||||||
|
if ($userGroup && $userGroup->rights) {
|
||||||
|
$userInfo['rights'] = json_decode($userGroup->rights, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$token = $this->generateToken($userInfo);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('登录管理', '登录', 'Token生成失败: ' . $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '登录失败,请稍后重试']);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$cacheKey = 'admin_user_' . $user['id'] . '_' . $tid;
|
||||||
|
\think\facade\Cache::set($cacheKey, $userInfo, 86400 * 7);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('用户缓存写入失败: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->logSuccess('登录管理', '登录', [
|
||||||
|
'id' => $user['id'],
|
||||||
|
'tid' => $tid,
|
||||||
|
'tenant' => $tenant
|
||||||
|
], $userInfo);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log('登录日志记录失败: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '登录成功',
|
||||||
|
'data' => [
|
||||||
|
'token' => $token,
|
||||||
|
'user' => $userInfo
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录接口
|
* 登录接口
|
||||||
* @return Json
|
* @return Json
|
||||||
@@ -75,12 +260,12 @@ class LoginController extends BaseController
|
|||||||
'msg' => '租户不存在或已禁用'
|
'msg' => '租户不存在或已禁用'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$tenant_id = $tenant->id;
|
$tid = $tenant->id;
|
||||||
$tenant_name = $tenant->tenant_name;
|
$tenant_name = $tenant->tenant_name;
|
||||||
|
|
||||||
// 5. 查询用户(新增:关联租户ID,确保用户属于该租户)
|
// 5. 查询用户(新增:关联租户ID,确保用户属于该租户)
|
||||||
$user = AdminUser::where('account', $data['account'])
|
$user = AdminUser::where('account', $data['account'])
|
||||||
->where('tenant_id', $tenant_id) // 核心:验证用户所属租户
|
->where('tid', $tid) // 核心:验证用户所属租户
|
||||||
->where('status', 1)
|
->where('status', 1)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -114,15 +299,23 @@ class LoginController extends BaseController
|
|||||||
error_log('更新登录信息失败: ' . $e->getMessage());
|
error_log('更新登录信息失败: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. 组装用户信息(新增:加入租户ID和租户名称)
|
// 9. 组装用户信息(新增:加入租户ID和租户名称和角色权限)
|
||||||
$userInfo = [
|
$userInfo = [
|
||||||
'id' => $user['id'],
|
'id' => $user['id'],
|
||||||
'account' => $user['account'],
|
'account' => $user['account'],
|
||||||
'name' => $user['name'],
|
'name' => $user['name'],
|
||||||
'group_id' => $user['group_id'],
|
'group_id' => $user['group_id'],
|
||||||
'tenant_id' => $tenant_id, // 新增:租户ID
|
'tid' => $tid, // 新增:租户ID
|
||||||
'tenant' => $tenant // 新增:租户名称
|
'tenant' => $tenant // 新增:租户名称
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 获取角色权限
|
||||||
|
if ($user['group_id']) {
|
||||||
|
$userGroup = AdminUserGroup::where('id', $user['group_id'])->find();
|
||||||
|
if ($userGroup && $userGroup->rights) {
|
||||||
|
$userInfo['rights'] = json_decode($userGroup->rights, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 10. 生成Token(Token中已包含租户信息,后续可通过Token解析获取)
|
// 10. 生成Token(Token中已包含租户信息,后续可通过Token解析获取)
|
||||||
try {
|
try {
|
||||||
@@ -137,7 +330,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
// 11. 写入用户数据缓存(核心:缓存包含租户信息,示例用Redis,可根据你的缓存工具调整)
|
// 11. 写入用户数据缓存(核心:缓存包含租户信息,示例用Redis,可根据你的缓存工具调整)
|
||||||
try {
|
try {
|
||||||
$cacheKey = 'admin_user_' . $user['id'] . '_' . $tenant_id; // 缓存键加入租户ID,避免多租户冲突
|
$cacheKey = 'admin_user_' . $user['id'] . '_' . $tid; // 缓存键加入租户ID,避免多租户冲突
|
||||||
$cacheExpire = 86400 * 7; // 缓存7天,可根据需求调整
|
$cacheExpire = 86400 * 7; // 缓存7天,可根据需求调整
|
||||||
// 写入缓存(这里假设你使用thinkphp的Cache类,若用其他工具可替换)
|
// 写入缓存(这里假设你使用thinkphp的Cache类,若用其他工具可替换)
|
||||||
\think\facade\Cache::set($cacheKey, $userInfo, $cacheExpire);
|
\think\facade\Cache::set($cacheKey, $userInfo, $cacheExpire);
|
||||||
@@ -150,7 +343,7 @@ class LoginController extends BaseController
|
|||||||
try {
|
try {
|
||||||
$this->logSuccess('登录管理', '登录', [
|
$this->logSuccess('登录管理', '登录', [
|
||||||
'id' => $user['id'],
|
'id' => $user['id'],
|
||||||
'tenant_id' => $tenant_id,
|
'tid' => $tid,
|
||||||
'tenant' => $tenant
|
'tenant' => $tenant
|
||||||
], $userInfo);
|
], $userInfo);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -181,6 +374,87 @@ class LoginController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送手机号登录验证码
|
||||||
|
*/
|
||||||
|
public function sendLoginCode(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||||||
|
->where('status', 1)
|
||||||
|
->find();
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||||||
|
->where('phone', (string)$data['phone'])
|
||||||
|
->where('status', 1)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if (!$user) {
|
||||||
|
return json(['code' => 404, 'msg' => '手机号未绑定可用账号']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sendSmsCodeInternal('login', (string)$data['tenant_name'], (string)$data['phone'], (string)$data['phone']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号验证码登录
|
||||||
|
*/
|
||||||
|
public function loginBySms(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
'sms_code|短信验证码' => 'require|length:4,8',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$codeKey = $this->smsCodeCacheKey('login', (string)$data['tenant_name'], (string)$data['phone'], (string)$data['phone']);
|
||||||
|
$cachedCode = (string)Cache::get($codeKey, '');
|
||||||
|
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||||||
|
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||||||
|
->where('status', 1)
|
||||||
|
->field(['id', 'tenant_name'])
|
||||||
|
->find();
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 401, 'msg' => '租户不存在或已禁用']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||||||
|
->where('phone', (string)$data['phone'])
|
||||||
|
->where('status', 1)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if (!$user) {
|
||||||
|
return json(['code' => 401, 'msg' => '手机号未绑定可用账号']);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cache::delete($codeKey);
|
||||||
|
return $this->buildLoginSuccessResponse($user, $tenant);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '登录失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出登录
|
* 退出登录
|
||||||
* @return Json
|
* @return Json
|
||||||
@@ -200,7 +474,7 @@ class LoginController extends BaseController
|
|||||||
if ($userInfo && isset($userInfo['id'])) {
|
if ($userInfo && isset($userInfo['id'])) {
|
||||||
$this->logSuccess('登录管理', '退出登录', ['result' => 'success'], $userInfo);
|
$this->logSuccess('登录管理', '退出登录', ['result' => 'success'], $userInfo);
|
||||||
} else {
|
} else {
|
||||||
\app\model\OperationLog::create([
|
OperationLog::create([
|
||||||
'user_id' => 0,
|
'user_id' => 0,
|
||||||
'user_account' => '',
|
'user_account' => '',
|
||||||
'user_name' => '未知用户',
|
'user_name' => '未知用户',
|
||||||
@@ -287,4 +561,268 @@ class LoginController extends BaseController
|
|||||||
'data' => $loginInfo
|
'data' => $loginInfo
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册账号(按租户维度)
|
||||||
|
*/
|
||||||
|
public function sendRegisterCode(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'account|账号' => 'require|length:3,32',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
]);
|
||||||
|
return $this->sendSmsCodeInternal('register', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'account|账号' => 'require|length:3,32',
|
||||||
|
'name|姓名' => 'require|length:2,32',
|
||||||
|
'password|密码' => 'require|length:6,32',
|
||||||
|
'confirm_password|确认密码' => 'require',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
'sms_code|短信验证码' => 'require|length:4,8',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ((string)$data['password'] !== (string)$data['confirm_password']) {
|
||||||
|
return json(['code' => 400, 'msg' => '两次输入的密码不一致']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$codeKey = $this->smsCodeCacheKey('register', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||||||
|
$cachedCode = (string)Cache::get($codeKey, '');
|
||||||
|
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||||||
|
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||||||
|
->where('status', 1)
|
||||||
|
->find();
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$exists = AdminUser::where('tid', (int)$tenant['id'])
|
||||||
|
->where('account', (string)$data['account'])
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if ($exists) {
|
||||||
|
return json(['code' => 400, 'msg' => '账号已存在']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$user = new AdminUser();
|
||||||
|
$user->save([
|
||||||
|
'tid' => (int)$tenant['id'],
|
||||||
|
'account' => (string)$data['account'],
|
||||||
|
'name' => (string)$data['name'],
|
||||||
|
'phone' => (string)$data['phone'],
|
||||||
|
'email' => (string)($data['email'] ?? ''),
|
||||||
|
'password' => md5((string)$data['password']),
|
||||||
|
'status' => 1,
|
||||||
|
'group_id' => 0,
|
||||||
|
'login_count' => 0,
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Cache::delete($codeKey);
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '注册成功']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '注册失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忘记密码:通过租户 + 账号 + 手机号重置密码
|
||||||
|
*/
|
||||||
|
public function sendResetCode(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'account|账号' => 'require|length:3,32',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||||||
|
->where('status', 1)
|
||||||
|
->find();
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||||||
|
->where('account', (string)$data['account'])
|
||||||
|
->where('phone', (string)$data['phone'])
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if (!$user) {
|
||||||
|
return json(['code' => 404, 'msg' => '账号不存在或手机号不匹配']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sendSmsCodeInternal('reset', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetPassword(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->request->post();
|
||||||
|
$this->validate($data, [
|
||||||
|
'tenant_name|租户名称' => 'require|length:1,128',
|
||||||
|
'account|账号' => 'require|length:3,32',
|
||||||
|
'phone|手机号' => 'require|mobile',
|
||||||
|
'new_password|新密码' => 'require|length:6,32',
|
||||||
|
'confirm_password|确认密码' => 'require',
|
||||||
|
'sms_code|短信验证码' => 'require|length:4,8',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ((string)$data['new_password'] !== (string)$data['confirm_password']) {
|
||||||
|
return json(['code' => 400, 'msg' => '两次输入的密码不一致']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$codeKey = $this->smsCodeCacheKey('reset', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||||||
|
$cachedCode = (string)Cache::get($codeKey, '');
|
||||||
|
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||||||
|
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||||||
|
->where('status', 1)
|
||||||
|
->find();
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||||||
|
->where('account', (string)$data['account'])
|
||||||
|
->where('phone', (string)$data['phone'])
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if (!$user) {
|
||||||
|
return json(['code' => 404, 'msg' => '账号不存在或手机号不匹配']);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdminUser::where('id', (int)$user['id'])->update([
|
||||||
|
'password' => md5((string)$data['new_password']),
|
||||||
|
'update_time' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Cache::delete($codeKey);
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '密码重置成功']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '重置失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取极验3.0的id和key
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getGeetest3Infos()
|
||||||
|
{
|
||||||
|
// 定义你需要的 label 列表
|
||||||
|
$targetLabels = [
|
||||||
|
'geetest3ID',
|
||||||
|
'geetest3KEY'
|
||||||
|
];
|
||||||
|
|
||||||
|
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||||||
|
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||||||
|
->field('label, value')
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看极验3.0的id和key', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $legalInfos->toArray()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取极验4.0的id和key
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getGeetest4Infos()
|
||||||
|
{
|
||||||
|
// 定义你需要的 label 列表
|
||||||
|
$targetLabels = [
|
||||||
|
'geetest4ID',
|
||||||
|
'geetest4KEY'
|
||||||
|
];
|
||||||
|
|
||||||
|
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||||||
|
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||||||
|
->field('label, value')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 转换为前端需要的格式
|
||||||
|
$data = [];
|
||||||
|
foreach ($legalInfos as $item) {
|
||||||
|
if ($item['label'] === 'geetest4ID') {
|
||||||
|
$data['captcha_id'] = $item['value'];
|
||||||
|
}
|
||||||
|
if ($item['label'] === 'geetest4KEY') {
|
||||||
|
$data['captcha_key'] = $item['value'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看极验4.0的id和key', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $data
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否开启验证
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getOpenVerify()
|
||||||
|
{
|
||||||
|
// 定义你需要的 label 列表
|
||||||
|
$targetLabels = [
|
||||||
|
'openVerify',
|
||||||
|
'verifyModel'
|
||||||
|
];
|
||||||
|
|
||||||
|
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||||||
|
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||||||
|
->field('label, value')
|
||||||
|
->select();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $legalInfos->toArray()
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use think\facade\Session;
|
|||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use app\model\SystemMenu;
|
use app\model\SystemMenu;
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
use app\model\AdminUserGroup;
|
use app\model\System\AdminUserGroup;
|
||||||
|
|
||||||
class MenuController extends BaseController
|
class MenuController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -69,6 +69,10 @@ class MenuController extends BaseController
|
|||||||
$userGroup = AdminUserGroup::where('id', $user['group_id'])
|
$userGroup = AdminUserGroup::where('id', $user['group_id'])
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
|
// 调试日志
|
||||||
|
error_log('getMenus - user group_id: ' . $user['group_id']);
|
||||||
|
error_log('getMenus - userGroup: ' . json_encode($userGroup));
|
||||||
|
|
||||||
// var_dump($userGroup);
|
// var_dump($userGroup);
|
||||||
|
|
||||||
if (!$userGroup) {
|
if (!$userGroup) {
|
||||||
@@ -81,8 +85,9 @@ class MenuController extends BaseController
|
|||||||
|
|
||||||
// 解析权限数组
|
// 解析权限数组
|
||||||
$menuIds = [];
|
$menuIds = [];
|
||||||
if (!empty($userGroup['rights'])) {
|
if ($userGroup->rights) {
|
||||||
$menuIds = is_array($userGroup['rights']) ? $userGroup['rights'] : json_decode($userGroup['rights'], true);
|
$decoded = json_decode($userGroup->rights, true);
|
||||||
|
$menuIds = is_array($decoded) ? $decoded : [];
|
||||||
}
|
}
|
||||||
// var_dump($menuIds);
|
// var_dump($menuIds);
|
||||||
|
|
||||||
@@ -95,11 +100,14 @@ class MenuController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取有权限的菜单及其所有父级菜单
|
||||||
|
$allMenuIds = $this->getMenuIdsWithParents($menuIds);
|
||||||
|
|
||||||
// 获取有权限的菜单
|
// 获取有权限的菜单
|
||||||
$menus = SystemMenu::where('delete_time', null)
|
$menus = SystemMenu::where('delete_time', null)
|
||||||
->where('status', 1)
|
->where('status', 1)
|
||||||
->whereIn('id', $menuIds)
|
->whereIn('id', $allMenuIds)
|
||||||
->field('id,pid,title,path,component_path,icon,sort')
|
->field('id,pid,title,path,component_path,icon,sort,is_visible')
|
||||||
->order('sort', 'asc')
|
->order('sort', 'asc')
|
||||||
->select();
|
->select();
|
||||||
|
|
||||||
@@ -253,6 +261,7 @@ class MenuController extends BaseController
|
|||||||
'title|菜单名称' => 'require|max:50',
|
'title|菜单名称' => 'require|max:50',
|
||||||
'type|菜单类型' => 'require|in:1,2,3',
|
'type|菜单类型' => 'require|in:1,2,3',
|
||||||
'status|菜单状态' => 'require|in:0,1',
|
'status|菜单状态' => 'require|in:0,1',
|
||||||
|
'is_visible|是否显示' => 'require|in:0,1',
|
||||||
'sort|排序号' => 'integer',
|
'sort|排序号' => 'integer',
|
||||||
'path|路由路径' => 'max:200',
|
'path|路由路径' => 'max:200',
|
||||||
'icon|菜单图标' => 'max:100',
|
'icon|菜单图标' => 'max:100',
|
||||||
@@ -266,6 +275,7 @@ class MenuController extends BaseController
|
|||||||
'title' => $data['title'],
|
'title' => $data['title'],
|
||||||
'type' => $data['type'],
|
'type' => $data['type'],
|
||||||
'status' => $data['status'] ?? 1,
|
'status' => $data['status'] ?? 1,
|
||||||
|
'is_visible' => $data['is_visible'] ?? 1,
|
||||||
'sort' => $data['sort'] ?? 0,
|
'sort' => $data['sort'] ?? 0,
|
||||||
'path' => $data['path'] ?? '',
|
'path' => $data['path'] ?? '',
|
||||||
'component_path' => $data['component_path'] ?? '',
|
'component_path' => $data['component_path'] ?? '',
|
||||||
@@ -321,6 +331,7 @@ class MenuController extends BaseController
|
|||||||
'pid|上级菜单ID' => 'integer',
|
'pid|上级菜单ID' => 'integer',
|
||||||
'type|菜单类型' => 'require|in:1,2,3',
|
'type|菜单类型' => 'require|in:1,2,3',
|
||||||
'status|菜单状态' => 'require|in:0,1',
|
'status|菜单状态' => 'require|in:0,1',
|
||||||
|
'is_visible|是否显示' => 'require|in:0,1',
|
||||||
'sort|排序号' => 'integer',
|
'sort|排序号' => 'integer',
|
||||||
'path|路由路径' => 'max:200',
|
'path|路由路径' => 'max:200',
|
||||||
'icon|菜单图标' => 'max:100',
|
'icon|菜单图标' => 'max:100',
|
||||||
@@ -338,6 +349,7 @@ class MenuController extends BaseController
|
|||||||
'icon' => $data['icon'] ?? null,
|
'icon' => $data['icon'] ?? null,
|
||||||
'sort' => $data['sort'] ?? 0,
|
'sort' => $data['sort'] ?? 0,
|
||||||
'status' => $data['status'],
|
'status' => $data['status'],
|
||||||
|
'is_visible' => $data['is_visible'],
|
||||||
'permission' => $data['permission'] ?? null,
|
'permission' => $data['permission'] ?? null,
|
||||||
'remark' => $data['remark'] ?? null,
|
'remark' => $data['remark'] ?? null,
|
||||||
'update_time' => date('Y-m-d H:i:s')
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
@@ -484,6 +496,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 菜单列表
|
* @param array $menus 菜单列表
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use think\response\Json;
|
|||||||
|
|
||||||
use app\model\SystemModuleCenter;
|
use app\model\SystemModuleCenter;
|
||||||
use app\model\SystemModuleCategory;
|
use app\model\SystemModuleCategory;
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class ModuleCenterController extends BaseController
|
class ModuleCenterController extends BaseController
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace app\admin\controller;
|
|||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use app\model\AdminModules;
|
use app\model\AdminModules;
|
||||||
|
use app\model\System\AdminUserGroup;
|
||||||
|
use app\model\SystemMenu;
|
||||||
|
use Symfony\Component\VarDumper\VarDumper;
|
||||||
|
|
||||||
class ModulesController extends BaseController
|
class ModulesController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -43,13 +46,77 @@ class ModulesController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取租户模块列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getTenantList()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$userInfo = $this->getAdminUserInfo();
|
||||||
|
$groupId = $userInfo['group_id'] ?? null;
|
||||||
|
$menuIds = [];
|
||||||
|
|
||||||
|
if ($groupId) {
|
||||||
|
$userGroup = AdminUserGroup::where('id', $groupId)->find();
|
||||||
|
if ($userGroup && $userGroup->rights) {
|
||||||
|
$rights = $userGroup->rights;
|
||||||
|
$decoded = json_decode($rights, true);
|
||||||
|
$menuIds = is_array($decoded) ? $decoded : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($menuIds)) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => [
|
||||||
|
'list' => [],
|
||||||
|
'total' => 0
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据子菜单ID查询所有父级模块ID
|
||||||
|
$moduleIds = $this->getModuleIdsByMenuIds($menuIds);
|
||||||
|
|
||||||
|
$modules = AdminModules::where('delete_time', null)
|
||||||
|
->whereIn('id', $moduleIds)
|
||||||
|
->where('status', 1)
|
||||||
|
->where('is_show', 1)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->order('id', 'asc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$this->logSuccess('模块管理', '获取模块列表', ['count' => count($modules)]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => [
|
||||||
|
'list' => $modules,
|
||||||
|
'total' => count($modules)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('模块管理', '获取模块列表', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取模块详情
|
* 获取模块详情
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getDetail(int $id)
|
public function getDetail($id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$id = (int) $id;
|
||||||
$module = AdminModules::where('id', $id)
|
$module = AdminModules::where('id', $id)
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
@@ -325,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
|
* @return Json
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ namespace app\admin\controller\OperationLog;
|
|||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\facade\Request;
|
use think\facade\Request;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use app\model\OperationLog;
|
use app\model\System\OperationLog;
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class OperationLogController extends BaseController
|
class OperationLogController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,8 @@ class OperationLogController extends BaseController
|
|||||||
$startTime = Request::param('startTime/s', '');
|
$startTime = Request::param('startTime/s', '');
|
||||||
$endTime = Request::param('endTime/s', '');
|
$endTime = Request::param('endTime/s', '');
|
||||||
|
|
||||||
$query = OperationLog::where('delete_time', null);
|
$query = OperationLog::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
// 关键词搜索(用户姓名、URL)
|
// 关键词搜索(用户姓名、URL)
|
||||||
if ($keyword) {
|
if ($keyword) {
|
||||||
@@ -129,6 +130,7 @@ class OperationLogController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$log = OperationLog::where('id', $id)
|
$log = OperationLog::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -164,6 +166,7 @@ class OperationLogController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$log = OperationLog::where('id', $id)
|
$log = OperationLog::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
|
|
||||||
@@ -206,6 +209,7 @@ class OperationLogController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
OperationLog::whereIn('id', $ids)
|
OperationLog::whereIn('id', $ids)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->delete();
|
->delete();
|
||||||
|
|
||||||
@@ -230,11 +234,13 @@ class OperationLogController extends BaseController
|
|||||||
try {
|
try {
|
||||||
// 获取模块列表
|
// 获取模块列表
|
||||||
$modules = OperationLog::where('delete_time', null)
|
$modules = OperationLog::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->group('module')
|
->group('module')
|
||||||
->column('module');
|
->column('module');
|
||||||
|
|
||||||
// 获取动作列表
|
// 获取动作列表
|
||||||
$actions = OperationLog::where('delete_time', null)
|
$actions = OperationLog::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->group('action')
|
->group('action')
|
||||||
->column('action');
|
->column('action');
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace app\admin\controller\OperationLog;
|
namespace app\admin\controller\OperationLog;
|
||||||
|
|
||||||
use app\model\OperationLog;
|
use app\model\System\OperationLog;
|
||||||
use think\facade\Request;
|
use think\facade\Request;
|
||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
|
|
||||||
@@ -37,6 +37,7 @@ class OperationLogHelper
|
|||||||
$userId = $userInfo['id'] ?? 0;
|
$userId = $userInfo['id'] ?? 0;
|
||||||
$userAccount = $userInfo['account'] ?? '';
|
$userAccount = $userInfo['account'] ?? '';
|
||||||
$userName = $userInfo['name'] ?? '';
|
$userName = $userInfo['name'] ?? '';
|
||||||
|
$tid = $userInfo['tid'] ?? ($userInfo['tid'] ?? 0);
|
||||||
|
|
||||||
// 获取请求信息
|
// 获取请求信息
|
||||||
$method = Request::method();
|
$method = Request::method();
|
||||||
@@ -52,6 +53,7 @@ class OperationLogHelper
|
|||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'user_account' => $userAccount,
|
'user_account' => $userAccount,
|
||||||
'user_name' => $userName,
|
'user_name' => $userName,
|
||||||
|
'tid' => $tid,
|
||||||
'module' => $module,
|
'module' => $module,
|
||||||
'action' => $action,
|
'action' => $action,
|
||||||
'method' => $method,
|
'method' => $method,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace app\admin\controller\OperationLog;
|
namespace app\admin\controller\OperationLog;
|
||||||
|
|
||||||
use think\facade\Request;
|
use think\facade\Request;
|
||||||
use app\model\OperationLog;
|
use app\model\System\OperationLog;
|
||||||
use app\service\JwtService;
|
use app\service\JwtService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,6 +33,7 @@ class OperationLogger
|
|||||||
$userId = $userInfo['id'] ?? 0;
|
$userId = $userInfo['id'] ?? 0;
|
||||||
$userAccount = $userInfo['account'] ?? '';
|
$userAccount = $userInfo['account'] ?? '';
|
||||||
$userName = $userInfo['name'] ?? '';
|
$userName = $userInfo['name'] ?? '';
|
||||||
|
$tid = $userInfo['tid'] ?? ($userInfo['tid'] ?? 0);
|
||||||
|
|
||||||
if (empty($requestData)) {
|
if (empty($requestData)) {
|
||||||
$requestData = Request::param();
|
$requestData = Request::param();
|
||||||
@@ -49,6 +50,7 @@ class OperationLogger
|
|||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'user_account' => $userAccount,
|
'user_account' => $userAccount,
|
||||||
'user_name' => $userName,
|
'user_name' => $userName,
|
||||||
|
'tid' => $tid,
|
||||||
'module' => $module,
|
'module' => $module,
|
||||||
'action' => $action,
|
'action' => $action,
|
||||||
'method' => $method,
|
'method' => $method,
|
||||||
|
|||||||
@@ -8,24 +8,59 @@ use app\admin\BaseController;
|
|||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
use app\model\System\SystemSiteSetting;
|
||||||
use app\model\System\SystemSiteSettings;
|
use app\model\System\SystemSiteSettings;
|
||||||
|
use app\model\Tenant\Tenant;
|
||||||
|
|
||||||
class SiteSettingsController extends BaseController
|
class SiteSettingsController extends BaseController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 获取所有站点设置列表
|
* 获取指定站点设置列表
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getNormalInfos()
|
public function getNormalInfos()
|
||||||
{
|
{
|
||||||
$siteSettings = SystemSiteSettings::where('delete_time', null)
|
// 获取当前租户ID
|
||||||
->field('id, label, value, sort')
|
$tid = $this->request->param('tid', 0, 'int');
|
||||||
->order('id', 'asc')
|
|
||||||
->select();
|
// 查询站点设置
|
||||||
|
$siteSetting = SystemSiteSetting::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// 如果没有数据,返回空值结构
|
||||||
|
if (!$siteSetting) {
|
||||||
|
$data = [
|
||||||
|
'sitename' => '',
|
||||||
|
'logo' => '',
|
||||||
|
'logow' => '',
|
||||||
|
'ico' => '',
|
||||||
|
'companyintroduction' => '',
|
||||||
|
'description' => '',
|
||||||
|
'copyright' => '',
|
||||||
|
'companyname' => '',
|
||||||
|
'icp' => ''
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$data = [
|
||||||
|
'sitename' => $siteSetting->sitename ?? '',
|
||||||
|
'logo' => $siteSetting->logo ?? '',
|
||||||
|
'logow' => $siteSetting->logow ?? '',
|
||||||
|
'ico' => $siteSetting->ico ?? '',
|
||||||
|
'companyintroduction' => $siteSetting->companyintroduction ?? '',
|
||||||
|
'description' => $siteSetting->description ?? '',
|
||||||
|
'copyright' => $siteSetting->copyright ?? '',
|
||||||
|
'companyname' => $siteSetting->companyname ?? '',
|
||||||
|
'icp' => $siteSetting->icp ?? ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看基本信息配置', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '获取成功',
|
'msg' => '获取成功',
|
||||||
'data' => $siteSettings->toArray()
|
'data' => $data
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,65 +71,137 @@ class SiteSettingsController extends BaseController
|
|||||||
public function saveNormalInfos()
|
public function saveNormalInfos()
|
||||||
{
|
{
|
||||||
$params = $this->request->param();
|
$params = $this->request->param();
|
||||||
|
$rawData = isset($params['data']) ? json_decode($params['data'], true) : $params;
|
||||||
|
$tid = $params['tid'] ?? 0;
|
||||||
|
|
||||||
if (!isset($params['data']) || empty($params['data'])) {
|
// 查找或创建记录
|
||||||
return json(['code' => 400, 'msg' => '数据不能为空', 'data' => null]);
|
$siteSetting = SystemSiteSetting::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$siteSetting) {
|
||||||
|
$siteSetting = new SystemSiteSetting();
|
||||||
|
$siteSetting->tid = $tid;
|
||||||
|
$siteSetting->create_time = date('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode($params['data'], true);
|
// 更新字段
|
||||||
if (!is_array($data)) {
|
if (isset($rawData['sitename'])) {
|
||||||
return json(['code' => 400, 'msg' => '数据格式错误', 'data' => null]);
|
$siteSetting->sitename = (string)$rawData['sitename'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['companyintroduction'])) {
|
||||||
|
$siteSetting->companyintroduction = (string)$rawData['companyintroduction'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['logo'])) {
|
||||||
|
$siteSetting->logo = (string)$rawData['logo'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['logow'])) {
|
||||||
|
$siteSetting->logow = (string)$rawData['logow'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['ico'])) {
|
||||||
|
$siteSetting->ico = (string)$rawData['ico'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['description'])) {
|
||||||
|
$siteSetting->description = (string)$rawData['description'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['copyright'])) {
|
||||||
|
$siteSetting->copyright = (string)$rawData['copyright'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['companyname'])) {
|
||||||
|
$siteSetting->companyname = (string)$rawData['companyname'];
|
||||||
|
}
|
||||||
|
if (isset($rawData['icp'])) {
|
||||||
|
$siteSetting->icp = (string)$rawData['icp'];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($data as $item) {
|
$siteSetting->update_time = date('Y-m-d H:i:s');
|
||||||
if (!isset($item['label']) || !isset($item['value'])) {
|
$siteSetting->save();
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$label = $item['label'];
|
$this->logSuccess('站点设置管理', '保存基本信息', ['tid' => $tid], $this->getAdminUserInfo());
|
||||||
$value = $item['value'] ?? '';
|
|
||||||
|
|
||||||
$setting = SystemSiteSettings::where('label', $label)->find();
|
return json(['code' => 200, 'msg' => '基本信息保存成功']);
|
||||||
if ($setting) {
|
}
|
||||||
$setting->value = $value;
|
|
||||||
$setting->save();
|
|
||||||
} else {
|
|
||||||
SystemSiteSettings::create([
|
|
||||||
'label' => $label,
|
|
||||||
'value' => $value,
|
|
||||||
'create_time' => date('Y-m-d H:i:s')
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$allSettings = SystemSiteSettings::column('value', 'label');
|
/**
|
||||||
$allSettings['type'] = 'normal';
|
* 获取登录验证数据
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getVerifyInfos()
|
||||||
|
{
|
||||||
|
// 定义你需要的 label 列表
|
||||||
|
$targetLabels = [
|
||||||
|
'openVerify',
|
||||||
|
'verifyModel',
|
||||||
|
'geetest3ID',
|
||||||
|
'geetest3KEY',
|
||||||
|
'geetest4ID',
|
||||||
|
'geetest4KEY'
|
||||||
|
];
|
||||||
|
|
||||||
$labels = array_column($data, 'label');
|
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||||||
$userInfo = $this->getAdminUserInfo();
|
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||||||
$this->logSuccess('站点设置管理', '保存基本信息', ['labels' => $labels], $userInfo);
|
->field('label, value')
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看登录验证数据', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '保存成功',
|
'msg' => '获取成功',
|
||||||
'data' => $allSettings
|
'data' => $legalInfos->toArray()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有站点设置列表
|
* 保存登录验证数据
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function saveVerifyInfos()
|
||||||
|
{
|
||||||
|
$params = $this->request->param();
|
||||||
|
$allowedLabels = ['openVerify', 'verifyModel', 'geetest3ID', 'geetest3KEY', 'geetest4ID', 'geetest4KEY'];
|
||||||
|
|
||||||
|
foreach ($allowedLabels as $label) {
|
||||||
|
if (isset($params[$label])) {
|
||||||
|
$val = $params[$label];
|
||||||
|
if (is_bool($val)) {
|
||||||
|
$val = $val ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemSiteSettings::where('label', $label)->update([
|
||||||
|
'value' => (string)$val
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '保存登录验证配置', $params, $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '保存成功']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取法律声明和隐私条款
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getLegalInfos()
|
public function getLegalInfos()
|
||||||
{
|
{
|
||||||
$siteSettings = SystemSiteSettings::where('delete_time', null)
|
// 定义你需要的 label 列表
|
||||||
->field('id, label, value, sort')
|
$targetLabels = [
|
||||||
->order('id', 'asc')
|
'legalNotice',
|
||||||
|
'privacyTerms'
|
||||||
|
];
|
||||||
|
|
||||||
|
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||||||
|
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||||||
|
->field('label, value')
|
||||||
->select();
|
->select();
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看法律声明和隐私条款', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '获取成功',
|
'msg' => '获取成功',
|
||||||
'data' => $siteSettings->toArray()
|
'data' => $legalInfos->toArray()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,58 +212,175 @@ class SiteSettingsController extends BaseController
|
|||||||
public function saveLegalInfos()
|
public function saveLegalInfos()
|
||||||
{
|
{
|
||||||
$params = $this->request->param();
|
$params = $this->request->param();
|
||||||
|
$rawData = isset($params['data']) ? json_decode($params['data'], true) : $params;
|
||||||
|
$allowedLabels = ['legalNotice', 'privacyTerms'];
|
||||||
|
|
||||||
if (!isset($params['data']) || empty($params['data'])) {
|
foreach ($allowedLabels as $label) {
|
||||||
return json(['code' => 400, 'msg' => '数据不能为空', 'data' => null]);
|
if (isset($rawData[$label])) {
|
||||||
}
|
SystemSiteSettings::update(
|
||||||
|
['value' => (string)$rawData[$label]],
|
||||||
$data = json_decode($params['data'], true);
|
['label' => $label]
|
||||||
if (!is_array($data)) {
|
);
|
||||||
return json(['code' => 400, 'msg' => '数据格式错误', 'data' => null]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($data as $item) {
|
|
||||||
if (!isset($item['label']) || !isset($item['value'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$label = $item['label'];
|
|
||||||
$value = $item['value'] ?? '';
|
|
||||||
|
|
||||||
$setting = SystemSiteSettings::where('label', $label)->find();
|
|
||||||
if ($setting) {
|
|
||||||
$setting->value = $value;
|
|
||||||
$setting->save();
|
|
||||||
} else {
|
|
||||||
SystemSiteSettings::create([
|
|
||||||
'label' => $label,
|
|
||||||
'value' => $value,
|
|
||||||
'create_time' => date('Y-m-d H:i:s')
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '保存法律声明和隐私条款', ['labels' => $allowedLabels], $this->getAdminUserInfo());
|
||||||
|
|
||||||
$allSettings = SystemSiteSettings::column('value', 'label');
|
return json(['code' => 200, 'msg' => '法律声明和隐私条款保存成功']);
|
||||||
$allSettings['type'] = 'legal_notice';
|
}
|
||||||
|
|
||||||
$labels = array_column($data, 'label');
|
/**
|
||||||
|
* 获取企业信息
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getCompanyInfos()
|
||||||
|
{
|
||||||
|
// 获取当前租户ID
|
||||||
|
$tid = $this->request->param('tid', 0, 'int');
|
||||||
|
|
||||||
$userId = Session::get('user_id', 0);
|
// 查询租户信息
|
||||||
$userFromSession = Session::get('user', []);
|
$tenant = Tenant::where('delete_time', null)
|
||||||
$userFromCache = Cache::get('userInfo_' . $userId, []);
|
->where('id', $tid)
|
||||||
$account = Session::get('account', '');
|
->find();
|
||||||
$name = Session::get('name', '');
|
|
||||||
|
|
||||||
\think\facade\Log::record('SiteSettings Debug - user_id: ' . $userId . ', userFromSession: ' . json_encode($userFromSession) . ', userFromCache: ' . json_encode($userFromCache) . ', account: ' . $account . ', name: ' . $name);
|
// 如果没有数据,返回空值结构
|
||||||
|
if (!$tenant) {
|
||||||
|
$data = [
|
||||||
|
'contact_phone' => '',
|
||||||
|
'contact_email' => '',
|
||||||
|
'address' => '',
|
||||||
|
'worktime' => ''
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$data = [
|
||||||
|
'contact_phone' => $tenant->contact_phone ?? '',
|
||||||
|
'contact_email' => $tenant->contact_email ?? '',
|
||||||
|
'address' => $tenant->address ?? '',
|
||||||
|
'worktime' => $tenant->worktime ?? ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$this->logSuccess('站点设置管理', '保存法律声明和隐私条款', ['labels' => $labels]);
|
$this->logSuccess('站点设置管理', '查看企业信息', [], $this->getAdminUserInfo());
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '保存成功',
|
'msg' => '获取成功',
|
||||||
'data' => $allSettings
|
'data' => $data
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存企业信息
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function saveCompanyInfos()
|
||||||
|
{
|
||||||
|
$params = $this->request->param();
|
||||||
|
$tid = $params['tid'] ?? 0;
|
||||||
|
|
||||||
|
// 查找租户记录
|
||||||
|
$tenant = Tenant::where('delete_time', null)
|
||||||
|
->where('id', $tid)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$tenant) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '租户不存在'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新字段
|
||||||
|
if (isset($params['contact_phone'])) {
|
||||||
|
$tenant->contact_phone = (string)$params['contact_phone'];
|
||||||
|
}
|
||||||
|
if (isset($params['contact_email'])) {
|
||||||
|
$tenant->contact_email = (string)$params['contact_email'];
|
||||||
|
}
|
||||||
|
if (isset($params['address'])) {
|
||||||
|
$tenant->address = (string)$params['address'];
|
||||||
|
}
|
||||||
|
if (isset($params['worktime'])) {
|
||||||
|
$tenant->worktime = (string)$params['worktime'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant->save();
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '保存企业信息', ['tid' => $tid], $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '企业信息保存成功']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取企业SEO
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getCompanySeo()
|
||||||
|
{
|
||||||
|
// 获取当前租户ID
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
// 直接根据 ID 查询租户记录
|
||||||
|
$tenant = Tenant::where('delete_time', null)
|
||||||
|
->where('id', $tid)
|
||||||
|
->field('seoTitle, seoKeywords, seoDescription')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// 如果没有数据,返回默认空值
|
||||||
|
if (!$tenant) {
|
||||||
|
$data = [
|
||||||
|
'seoTitle' => '',
|
||||||
|
'seoKeywords' => '',
|
||||||
|
'seoDescription' => ''
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// 直接读取模型对象的属性
|
||||||
|
$data = [
|
||||||
|
'seoTitle' => $tenant->seoTitle ?? '',
|
||||||
|
'seoKeywords' => $tenant->seoKeywords ?? '',
|
||||||
|
'seoDescription' => $tenant->seoDescription ?? ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '查看企业SEO', ['tid' => $tid], $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $data
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存企业SEO
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function saveCompanySeo()
|
||||||
|
{
|
||||||
|
$params = $this->request->param();
|
||||||
|
|
||||||
|
$id = $this->getTenantId();
|
||||||
|
|
||||||
|
$tenant = Tenant::where('delete_time', null)
|
||||||
|
->where('id', $id)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$tenant) {
|
||||||
|
return json(['code' => 404, 'msg' => '租户不存在']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建更新数据
|
||||||
|
$updateData = [];
|
||||||
|
if (isset($params['seoTitle'])) $updateData['seoTitle'] = (string)$params['seoTitle'];
|
||||||
|
if (isset($params['seoKeywords'])) $updateData['seoKeywords'] = (string)$params['seoKeywords'];
|
||||||
|
if (isset($params['seoDescription'])) $updateData['seoDescription'] = (string)$params['seoDescription'];
|
||||||
|
|
||||||
|
if (!empty($updateData)) {
|
||||||
|
$tenant->save($updateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logSuccess('站点设置管理', '保存企业SEO', ['tid' => $id], $this->getAdminUserInfo());
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '企业SEO保存成功']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+202
-121
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\System;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\facade\Filesystem;
|
use think\facade\Filesystem;
|
||||||
@@ -8,8 +8,8 @@ use think\facade\Request;
|
|||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\Response;
|
use think\Response;
|
||||||
|
|
||||||
use app\model\FilesCategory;
|
use app\model\System\FilesCategory;
|
||||||
use app\model\Files;
|
use app\model\System\Files;
|
||||||
|
|
||||||
class FileController extends BaseController
|
class FileController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -38,7 +38,8 @@ class FileController extends BaseController
|
|||||||
$cate = Request::param('cate/d', 0);
|
$cate = Request::param('cate/d', 0);
|
||||||
$keyword = Request::param('keyword/s', '');
|
$keyword = Request::param('keyword/s', '');
|
||||||
|
|
||||||
$query = Files::where('delete_time', null);
|
$query = Files::where('delete_time', null)
|
||||||
|
->where('tid', $this->getTenantId());
|
||||||
|
|
||||||
if ($cate) {
|
if ($cate) {
|
||||||
$query->where('cate', $cate);
|
$query->where('cate', $cate);
|
||||||
@@ -75,11 +76,20 @@ class FileController extends BaseController
|
|||||||
public function getUserCate()
|
public function getUserCate()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$cate = FilesCategory::where('delete_time', null)->field('id,name')->select();
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
// 只根据 tid 筛选分类
|
||||||
|
$cate = FilesCategory::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->field('id,name')
|
||||||
|
->select();
|
||||||
|
|
||||||
// 获取每个分类下的文件数量
|
// 获取每个分类下的文件数量
|
||||||
foreach ($cate as &$c) {
|
foreach ($cate as &$c) {
|
||||||
$c['total'] = Files::where('cate', $c['id'])->where('delete_time', null)->count();
|
$c['total'] = Files::where('cate', $c['id'])
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
@@ -101,6 +111,7 @@ class FileController extends BaseController
|
|||||||
try {
|
try {
|
||||||
$data = Request::param();
|
$data = Request::param();
|
||||||
$data['create_time'] = date('Y-m-d H:i:s');
|
$data['create_time'] = date('Y-m-d H:i:s');
|
||||||
|
$data['tid'] = $this->getTenantId();
|
||||||
$id = FilesCategory::insertGetId($data);
|
$id = FilesCategory::insertGetId($data);
|
||||||
|
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
@@ -129,7 +140,9 @@ class FileController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$data = Request::param();
|
$data = Request::param();
|
||||||
$result = FilesCategory::where('id', $id)->update(['name' => $data['name']]);
|
$result = FilesCategory::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['name' => $data['name']]);
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('文件管理', '重命名文件分组', ['id' => $id]);
|
$this->logSuccess('文件管理', '重命名文件分组', ['id' => $id]);
|
||||||
return json([
|
return json([
|
||||||
@@ -150,7 +163,21 @@ class FileController extends BaseController
|
|||||||
public function deleteFileCate($id)
|
public function deleteFileCate($id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$result = FilesCategory::where('id', $id)->update(['delete_time' => date('Y-m-d H:i:s')]);
|
// 检查分组里是否有关联文件
|
||||||
|
$fileCount = Files::where('cate', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->count();
|
||||||
|
if ($fileCount > 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '该分组下还有 ' . $fileCount . ' 个文件,请先删除分组内文件!'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = FilesCategory::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('文件管理', '删除文件分组', ['id' => $id]);
|
$this->logSuccess('文件管理', '删除文件分组', ['id' => $id]);
|
||||||
return json([
|
return json([
|
||||||
@@ -175,12 +202,16 @@ class FileController extends BaseController
|
|||||||
$pageSize = Request::param('pageSize/d', 10);
|
$pageSize = Request::param('pageSize/d', 10);
|
||||||
$keyword = Request::param('keyword/s', '');
|
$keyword = Request::param('keyword/s', '');
|
||||||
|
|
||||||
$query = Files::where('cate', $id)->where('delete_time', null);
|
$query = Files::where('cate', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null);
|
||||||
|
|
||||||
if ($keyword) {
|
if ($keyword) {
|
||||||
$query->whereLike('name', "%{$keyword}%");
|
$query->whereLike('name', "%{$keyword}%");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取总条数
|
||||||
|
$total = $query->count();
|
||||||
$list = $query->page($page, $pageSize)
|
$list = $query->page($page, $pageSize)
|
||||||
->order('create_time', 'desc')
|
->order('create_time', 'desc')
|
||||||
->select();
|
->select();
|
||||||
@@ -196,6 +227,7 @@ class FileController extends BaseController
|
|||||||
'msg' => 'success',
|
'msg' => 'success',
|
||||||
'data' => [
|
'data' => [
|
||||||
'list' => $list,
|
'list' => $list,
|
||||||
|
'total' => $total,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'pageSize' => $pageSize,
|
'pageSize' => $pageSize,
|
||||||
'categoryId' => $id
|
'categoryId' => $id
|
||||||
@@ -209,7 +241,7 @@ class FileController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传文件
|
// 文件上传
|
||||||
public function uploadFile()
|
public function uploadFile()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -230,7 +262,10 @@ class FileController extends BaseController
|
|||||||
$fileMd5 = md5_file($file->getRealPath());
|
$fileMd5 = md5_file($file->getRealPath());
|
||||||
|
|
||||||
// 检查是否已存在相同文件
|
// 检查是否已存在相同文件
|
||||||
$existFile = Files::where('md5', $fileMd5)->where('delete_time', null)->find();
|
$existFile = Files::where('md5', $fileMd5)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
if ($existFile) {
|
if ($existFile) {
|
||||||
return json([
|
return json([
|
||||||
@@ -272,6 +307,7 @@ class FileController extends BaseController
|
|||||||
'src' => $fileUrl,
|
'src' => $fileUrl,
|
||||||
'md5' => $fileMd5,
|
'md5' => $fileMd5,
|
||||||
'uploader' => $userId,
|
'uploader' => $userId,
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'create_time' => date('Y-m-d H:i:s'),
|
'create_time' => date('Y-m-d H:i:s'),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -309,7 +345,10 @@ class FileController extends BaseController
|
|||||||
|
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
$result = Files::where('id', $id)->where('delete_time', null)->update($data);
|
$result = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->update($data);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
@@ -329,7 +368,17 @@ class FileController extends BaseController
|
|||||||
public function deleteFile($id)
|
public function deleteFile($id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$result = Files::where('id', $id)->update(['delete_time' => date('Y-m-d H:i:s')]);
|
// 先获取文件信息
|
||||||
|
$file = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if (!$file) {
|
||||||
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
@@ -345,11 +394,49 @@ class FileController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//永久删除文件
|
||||||
|
public function deleteFilePermanently($id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 先获取文件信息
|
||||||
|
$file = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if (!$file) {
|
||||||
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除服务器上的文件
|
||||||
|
if ($file['src']) {
|
||||||
|
$this->deleteFileFromServer($file['src']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
// 记录操作日志
|
||||||
|
$this->logSuccess('文件管理', '永久删除文件', ['id' => $id]);
|
||||||
|
return json(['code' => 200, 'msg' => '永久删除成功']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// 记录失败日志
|
||||||
|
$this->logFail('文件管理', '永久删除文件', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '永久删除失败: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 下载文件
|
// 下载文件
|
||||||
public function download($id)
|
public function download($id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$file = Files::where('id', $id)->where('delete_time', null)->find();
|
$file = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
if (!$file) {
|
if (!$file) {
|
||||||
return json(['code' => 404, 'msg' => '文件不存在']);
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
@@ -374,7 +461,9 @@ class FileController extends BaseController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$cate = Request::param('cate/d', 0);
|
$cate = Request::param('cate/d', 0);
|
||||||
$result = Files::where('id', $id)->update(['cate' => $cate]);
|
$result = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['cate' => $cate]);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('文件管理', '移动文件', ['id' => $id]);
|
$this->logSuccess('文件管理', '移动文件', ['id' => $id]);
|
||||||
@@ -389,128 +478,120 @@ class FileController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//删除服务器上文件
|
||||||
|
private function deleteFileFromServer($fileUrl)
|
||||||
// 上传头像
|
|
||||||
public function uploadAvatar()
|
|
||||||
{
|
{
|
||||||
try {
|
// 去掉开头的 /storage/,得到相对路径
|
||||||
$file = Request::file('file');
|
$relativePath = ltrim($fileUrl, '/');
|
||||||
if (!$file) {
|
if (strpos($relativePath, 'storage/') === 0) {
|
||||||
return json(['code' => 400, 'msg' => '请选择要上传的文件']);
|
$relativePath = substr($relativePath, 8); // 去掉 'storage/' 部分
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证文件大小和类型
|
// 获取实际服务器路径
|
||||||
$maxSize = 50 * 1024 * 1024; // 50MB
|
$fullPath = root_path() . 'public/storage/' . $relativePath;
|
||||||
$fileExt = strtolower($file->getOriginalExtension());
|
|
||||||
|
|
||||||
if ($file->getSize() > $maxSize) {
|
if (file_exists($fullPath)) {
|
||||||
return json(['code' => 400, 'msg' => '文件大小不能超过50MB']);
|
unlink($fullPath);
|
||||||
}
|
|
||||||
|
|
||||||
// 计算文件MD5
|
|
||||||
$fileMd5 = md5_file($file->getRealPath());
|
|
||||||
|
|
||||||
// 检查是否已存在相同文件
|
|
||||||
$existFile = Files::where('md5', $fileMd5)->where('delete_time', null)->find();
|
|
||||||
|
|
||||||
if ($existFile) {
|
|
||||||
// 检查物理文件是否存在
|
|
||||||
$existFilePath = public_path() . $existFile['src'];
|
|
||||||
if (!file_exists($existFilePath)) {
|
|
||||||
// 物理文件不存在,删除数据库记录,继续上传
|
|
||||||
Files::where('id', $existFile['id'])->delete();
|
|
||||||
} else {
|
|
||||||
return json([
|
|
||||||
'code' => 201,
|
|
||||||
'msg' => '文件已存在',
|
|
||||||
'data' => [
|
|
||||||
'url' => $existFile['src'],
|
|
||||||
'id' => $existFile['id'],
|
|
||||||
'name' => $existFile['name']
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确定文件类型
|
|
||||||
$fileType = 1; // 默认为文件
|
|
||||||
foreach ($this->allowedExtensions as $type => $extensions) {
|
|
||||||
if (in_array($fileExt, $extensions)) {
|
|
||||||
$fileType = $this->fileTypes[$type];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$cate = Request::param('cate/d', 0);
|
|
||||||
// 生成按日期分类的目录结构
|
|
||||||
$datePath = date('Y/m/d');
|
|
||||||
$saveName = $datePath . '/' . uniqid() . '.' . $fileExt;
|
|
||||||
$fullPath = Filesystem::disk('public')->putFileAs('avatar', $file, $saveName);
|
|
||||||
$fileUrl = '/storage/' . str_replace('\\', '/', $fullPath);
|
|
||||||
|
|
||||||
// 获取当前登录用户ID
|
|
||||||
$userId = Request::middleware('user_id', '');
|
|
||||||
|
|
||||||
// 保存文件信息到数据库
|
|
||||||
$fileData = [
|
|
||||||
'name' => $file->getOriginalName(),
|
|
||||||
'type' => $fileType,
|
|
||||||
'cate' => $cate,
|
|
||||||
'size' => $file->getSize(),
|
|
||||||
'src' => $fileUrl,
|
|
||||||
'md5' => $fileMd5,
|
|
||||||
'uploader' => $userId,
|
|
||||||
'create_time' => date('Y-m-d H:i:s'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$fileId = Files::insertGetId($fileData);
|
|
||||||
|
|
||||||
// 记录操作日志
|
|
||||||
$this->logSuccess('文件管理', '上传图片', ['id' => $fileId]);
|
|
||||||
return json([
|
|
||||||
'code' => 200,
|
|
||||||
'msg' => '上传成功',
|
|
||||||
'data' => [
|
|
||||||
'url' => $fileUrl,
|
|
||||||
'id' => $fileId,
|
|
||||||
'name' => $fileData['name']
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
// 记录失败日志
|
|
||||||
$this->logFail('文件管理', '上传图片', $e->getMessage());
|
|
||||||
return json([
|
|
||||||
'code' => 500,
|
|
||||||
'msg' => '上传失败: ' . $e->getMessage()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新头像
|
// 批量删除文件
|
||||||
public function updateAvatar($id)
|
public function batchDeleteFiles()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$data = Request::only(['name', 'cate']);
|
$ids = Request::param('ids/a', []);
|
||||||
if (empty($data)) {
|
|
||||||
return json(['code' => 400, 'msg' => '无更新数据']);
|
if (empty($ids)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请选择要删除的文件']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
foreach ($ids as $id) {
|
||||||
|
$file = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if ($file && $file['src']) {
|
||||||
|
$this->deleteFileFromServer($file['src']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$result = Files::where('id', $id)->where('delete_time', null)->update($data);
|
$result = Files::where('id', 'in', $ids)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
// 记录操作日志
|
$this->logSuccess('文件管理', '批量删除文件', ['ids' => $ids]);
|
||||||
$this->logSuccess('文件管理', '更新头像', ['id' => $id]);
|
return json(['code' => 200, 'msg' => '批量删除成功']);
|
||||||
return json(['code' => 200, 'msg' => '更新成功']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json(['code' => 404, 'msg' => '头像不存在']);
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// 记录失败日志
|
$this->logFail('文件管理', '批量删除文件', $e->getMessage());
|
||||||
$this->logFail('文件管理', '更新头像', $e->getMessage());
|
return json(['code' => 500, 'msg' => '批量删除失败: ' . $e->getMessage()]);
|
||||||
return json(['code' => 500, 'msg' => '更新失败: ' . $e->getMessage()]);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量彻底删除文件
|
||||||
|
public function batchDeleteFilesPermanently()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$ids = Request::param('ids/a', []);
|
||||||
|
|
||||||
|
if (empty($ids)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请选择要彻底删除的文件']);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$file = Files::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->find();
|
||||||
|
if ($file && $file['src']) {
|
||||||
|
$this->deleteFileFromServer($file['src']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Files::where('id', 'in', $ids)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->force(true)
|
||||||
|
->update(['delete_time' => date('Y-m-d H:i:s')])
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$this->logSuccess('文件管理', '批量彻底删除文件', ['ids' => $ids]);
|
||||||
|
return json(['code' => 200, 'msg' => '批量彻底删除成功']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('文件管理', '批量彻底删除文件', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '批量彻底删除失败: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量移动文件
|
||||||
|
public function batchMoveFiles()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$ids = Request::param('ids/a', []);
|
||||||
|
$cate = Request::param('cate/d', 0);
|
||||||
|
|
||||||
|
if (empty($ids)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请选择要移动的文件']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Files::where('id', 'in', $ids)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
|
->update(['cate' => $cate]);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$this->logSuccess('文件管理', '批量移动文件', ['ids' => $ids, 'cate' => $cate]);
|
||||||
|
return json(['code' => 200, 'msg' => '批量移动成功']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json(['code' => 404, 'msg' => '文件不存在']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logFail('文件管理', '批量移动文件', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '批量移动失败: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+34
-12
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller\System;
|
||||||
|
|
||||||
use app\admin\BaseController;
|
use app\admin\BaseController;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
@@ -10,8 +10,8 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
use app\model\AdminUserGroup;
|
use app\model\System\AdminUserGroup;
|
||||||
|
|
||||||
class RoleController extends BaseController
|
class RoleController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,11 @@ class RoleController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getAllRoles()
|
public function getAllRoles()
|
||||||
{
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
$roles = AdminUserGroup::where('delete_time', null)
|
$roles = AdminUserGroup::where('delete_time', null)
|
||||||
|
->where(function ($query) use ($tid) {
|
||||||
|
$query->where('tid', $tid)->whereOr('tid', 0);
|
||||||
|
})
|
||||||
->order('id', 'asc')
|
->order('id', 'asc')
|
||||||
->select();
|
->select();
|
||||||
return json([
|
return json([
|
||||||
@@ -39,6 +43,9 @@ class RoleController extends BaseController
|
|||||||
public function getRoleById(int $id)
|
public function getRoleById(int $id)
|
||||||
{
|
{
|
||||||
$role = AdminUserGroup::where('id', $id)
|
$role = AdminUserGroup::where('id', $id)
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
|
||||||
|
})
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if (!$role) {
|
if (!$role) {
|
||||||
@@ -73,6 +80,7 @@ class RoleController extends BaseController
|
|||||||
|
|
||||||
// 检查角色名称是否已存在
|
// 检查角色名称是否已存在
|
||||||
$exists = AdminUserGroup::where('name', $data['name'])
|
$exists = AdminUserGroup::where('name', $data['name'])
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if ($exists) {
|
if ($exists) {
|
||||||
@@ -85,6 +93,7 @@ class RoleController extends BaseController
|
|||||||
// 准备数据
|
// 准备数据
|
||||||
$roleData = [
|
$roleData = [
|
||||||
'name' => $data['name'],
|
'name' => $data['name'],
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
'status' => $data['status'] ?? 1,
|
'status' => $data['status'] ?? 1,
|
||||||
'rights' => !empty($data['rights']) ? json_encode($data['rights']) : null,
|
'rights' => !empty($data['rights']) ? json_encode($data['rights']) : null,
|
||||||
'create_time' => date('Y-m-d H:i:s'),
|
'create_time' => date('Y-m-d H:i:s'),
|
||||||
@@ -136,8 +145,11 @@ class RoleController extends BaseController
|
|||||||
'rights|权限' => 'array'
|
'rights|权限' => 'array'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 查找角色
|
// 查找角色(验证tid,tid为0的系统角色也可编辑)
|
||||||
$role = AdminUserGroup::where('id', $id)
|
$role = AdminUserGroup::where('id', $id)
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
|
||||||
|
})
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if (!$role) {
|
if (!$role) {
|
||||||
@@ -147,9 +159,12 @@ class RoleController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查角色名称是否已被其他角色使用
|
// 检查角色名称是否已被其他角色使用(tid为0或当前用户tid的角色)
|
||||||
$exists = AdminUserGroup::where('name', $data['name'])
|
$exists = AdminUserGroup::where('name', $data['name'])
|
||||||
->where('id', '<>', $id)
|
->where('id', '<>', $id)
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('tid', $this->getTenantId())->whereOr('tid', 0);
|
||||||
|
})
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if ($exists) {
|
if ($exists) {
|
||||||
@@ -160,18 +175,23 @@ class RoleController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新数据
|
// 更新数据
|
||||||
$role->name = $data['name'];
|
$updateData = [
|
||||||
$role->status = $data['status'] ?? 1;
|
'name' => $data['name'],
|
||||||
$role->rights = !empty($data['rights']) ? json_encode($data['rights']) : null;
|
'status' => $data['status'] ?? 1,
|
||||||
$role->update_time = date('Y-m-d H:i:s');
|
'rights' => !empty($data['rights']) ? json_encode($data['rights']) : null,
|
||||||
$role->save();
|
'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]);
|
$this->logSuccess('角色管理', '更新角色', ['id' => $id]);
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => '更新成功',
|
'msg' => '更新成功',
|
||||||
'data' => $role->toArray()
|
'data' => $updatedRole->toArray()
|
||||||
]);
|
]);
|
||||||
} catch (ValidateException $e) {
|
} catch (ValidateException $e) {
|
||||||
// 记录失败日志
|
// 记录失败日志
|
||||||
@@ -206,8 +226,9 @@ class RoleController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找角色
|
// 查找角色(验证tid)
|
||||||
$role = AdminUserGroup::where('id', $id)
|
$role = AdminUserGroup::where('id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->find();
|
->find();
|
||||||
if (!$role) {
|
if (!$role) {
|
||||||
@@ -219,6 +240,7 @@ class RoleController extends BaseController
|
|||||||
|
|
||||||
// 检查是否有用户正在使用该角色
|
// 检查是否有用户正在使用该角色
|
||||||
$userCount = AdminUser::where('group_id', $id)
|
$userCount = AdminUser::where('group_id', $id)
|
||||||
|
->where('tid', $this->getTenantId())
|
||||||
->where('delete_time', null)
|
->where('delete_time', null)
|
||||||
->count();
|
->count();
|
||||||
if ($userCount > 0) {
|
if ($userCount > 0) {
|
||||||
@@ -0,0 +1,676 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\System;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use app\model\System\SystemSiteSettings;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Log;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
use think\facade\Request;
|
||||||
|
|
||||||
|
class SmsController extends BaseController
|
||||||
|
{
|
||||||
|
private function getSiteSettingValue(string $label): string
|
||||||
|
{
|
||||||
|
$row = SystemSiteSettings::where('label', $label)->order('id', 'asc')->find();
|
||||||
|
if (!$row) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return (string)$row['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function upsertSiteSetting(string $label, string $value): void
|
||||||
|
{
|
||||||
|
$row = SystemSiteSettings::where('label', $label)->order('id', 'asc')->find();
|
||||||
|
if ($row) {
|
||||||
|
SystemSiteSettings::update(['value' => $value], ['id' => $row['id']]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$model = new SystemSiteSettings();
|
||||||
|
$model->label = $label;
|
||||||
|
$model->value = $value;
|
||||||
|
$model->sort = 0;
|
||||||
|
$model->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取短信网关配置
|
||||||
|
*/
|
||||||
|
public function getSmsInfo()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$backendUrl = $this->getSiteSettingValue('backendUrl');
|
||||||
|
$apiKey = $this->getSiteSettingValue('apiKey');
|
||||||
|
|
||||||
|
// 前端约定返回 data[0],字段名兼容 backend_url/api_key 与 backendUrl/apiKey
|
||||||
|
$data = [[
|
||||||
|
'backend_url' => $backendUrl,
|
||||||
|
'api_key' => $apiKey,
|
||||||
|
'backendUrl' => $backendUrl,
|
||||||
|
'apiKey' => $apiKey,
|
||||||
|
]];
|
||||||
|
|
||||||
|
$this->logSuccess('短信管理', '获取短信网关配置', ['data' => $data]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
|
} catch (DbException $e) {
|
||||||
|
$this->logFail('短信管理', '获取短信网关配置', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取失败:' . $e->getMessage(),
|
||||||
|
'data' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑短信网关配置(本表设计为单条配置)
|
||||||
|
*/
|
||||||
|
public function editSmsInfo()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$raw = $this->request->post();
|
||||||
|
$data = [
|
||||||
|
'backend_url' => $raw['backendUrl'] ?? $raw['backend_url'] ?? '',
|
||||||
|
'api_key' => $raw['apiKey'] ?? $raw['api_key'] ?? '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->validate($data, [
|
||||||
|
'backend_url|短信网关地址' => 'require|max:255',
|
||||||
|
'api_key|短信网关 API KEY' => 'require|max:255',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->upsertSiteSetting('backendUrl', (string)$data['backend_url']);
|
||||||
|
$this->upsertSiteSetting('apiKey', (string)$data['api_key']);
|
||||||
|
|
||||||
|
$updated = [[
|
||||||
|
'backend_url' => $this->getSiteSettingValue('backendUrl'),
|
||||||
|
'api_key' => $this->getSiteSettingValue('apiKey'),
|
||||||
|
]];
|
||||||
|
|
||||||
|
$this->logSuccess('短信管理', '更新短信网关配置', ['data' => $updated]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '更新成功',
|
||||||
|
'data' => $updated,
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
$this->logFail('短信管理', '更新短信网关配置', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => $e->getError(),
|
||||||
|
]);
|
||||||
|
} catch (DbException $e) {
|
||||||
|
$this->logFail('短信管理', '更新短信网关配置', $e->getMessage());
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '更新失败:' . $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台发起“短信测试”:入队一条任务,等待 Android 网关轮询取走并发送
|
||||||
|
*/
|
||||||
|
public function sendTestSms()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$raw = $this->request->post();
|
||||||
|
$phone = trim((string)($raw['phone'] ?? $raw['testPhone'] ?? ''));
|
||||||
|
$content = trim((string)($raw['content'] ?? ''));
|
||||||
|
|
||||||
|
if (empty($phone)) {
|
||||||
|
return json(['code' => 400, 'msg' => '缺少测试手机号']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android 网关文档:国际格式 +8613712345678
|
||||||
|
if (!preg_match('/^\+\d{6,15}$/', $phone)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请使用国际格式手机号(以 + 开头,后为数字)']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前网关配置(来自 mete_system_site_settings label/value)
|
||||||
|
$apiKey = $this->getSiteSettingValue('apiKey');
|
||||||
|
$backendUrl = $this->getSiteSettingValue('backendUrl');
|
||||||
|
if (empty($apiKey)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请先配置短信网关 API KEY']);
|
||||||
|
}
|
||||||
|
if (empty($backendUrl)) {
|
||||||
|
return json(['code' => 400, 'msg' => '请先配置短信网关地址 backendUrl']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = (string)random_int(100000, 999999);
|
||||||
|
if ($content === '') {
|
||||||
|
$content = '短信测试验证码:' . $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容:调用 Uniapp/sms 后端入队发送任务
|
||||||
|
$enqueueUrl = rtrim($backendUrl, '/') . '/api/v1/business/outbound-tasks';
|
||||||
|
$enqueuePayload = [
|
||||||
|
'phone' => $phone,
|
||||||
|
'content' => $content,
|
||||||
|
];
|
||||||
|
$enqueueHeaders = [
|
||||||
|
'X-Api-Key: ' . (string)$apiKey,
|
||||||
|
'Content-Type: application/json; charset=utf-8',
|
||||||
|
'Accept: application/json',
|
||||||
|
];
|
||||||
|
|
||||||
|
Log::write('[sms_enqueue] url=' . $enqueueUrl . ' phone=' . $phone);
|
||||||
|
$enqueueResp = $this->postJson($enqueueUrl, $enqueuePayload, $enqueueHeaders);
|
||||||
|
if (empty($enqueueResp['ok'])) {
|
||||||
|
Log::write('[sms_enqueue] failed http_status=' . ($enqueueResp['status'] ?? '') . ' body=' . ($enqueueResp['body'] ?? ''));
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '短信网关入队失败:' . ($enqueueResp['error'] ?? 'unknown'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$smsGatewayTaskId = (string)($enqueueResp['json']['taskId'] ?? '');
|
||||||
|
Log::write('[sms_enqueue] success taskId=' . $smsGatewayTaskId);
|
||||||
|
|
||||||
|
$enqueueDebug = [
|
||||||
|
'enqueueOk' => (bool)($enqueueResp['ok'] ?? false),
|
||||||
|
'enqueueStatus' => $enqueueResp['status'] ?? null,
|
||||||
|
'enqueueJsonKeys' => array_keys((array)($enqueueResp['json'] ?? [])),
|
||||||
|
'gatewayTaskId' => $smsGatewayTaskId,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 同步一条本地记录(用于前端列表展示/对账)
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
$taskId = Db::name('mete_system_sms_tasks')->insertGetId([
|
||||||
|
'api_key' => (string)$apiKey,
|
||||||
|
'tid' => $this->getTenantId(),
|
||||||
|
'phone' => $phone,
|
||||||
|
'content' => $content,
|
||||||
|
'status' => 0, // pending(本地不自动同步网关状态)
|
||||||
|
'code' => $code, // 预期验证码(用于对账/展示)
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->logSuccess('短信管理', '发送测试短信(调用网关入队)', [
|
||||||
|
'to' => $phone,
|
||||||
|
'local_task_id' => $taskId ?? null,
|
||||||
|
'gateway_task_id' => $smsGatewayTaskId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '测试短信任务已入队,等待网关发送',
|
||||||
|
'data' => [
|
||||||
|
'taskId' => $smsGatewayTaskId ?: ($taskId ?? null),
|
||||||
|
'code' => $code,
|
||||||
|
],
|
||||||
|
'debug' => empty($smsGatewayTaskId) ? $enqueueDebug : null,
|
||||||
|
]);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
$this->logFail('短信管理', '发送测试短信', $e->getMessage());
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->logFail('短信管理', '发送测试短信', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简单 JSON POST(无 curl 扩展时使用)
|
||||||
|
* @return array{ok:bool,status?:int,body?:string,error?:string,json?:array}
|
||||||
|
*/
|
||||||
|
private function postJson(string $url, array $payload, array $headers): array
|
||||||
|
{
|
||||||
|
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||||
|
if ($body === false) {
|
||||||
|
return ['ok' => false, 'error' => 'json_encode failed'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$headerStr = implode("\r\n", $headers);
|
||||||
|
$context = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => $headerStr,
|
||||||
|
'content' => $body,
|
||||||
|
'timeout' => 10,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$respBody = @file_get_contents($url, false, $context);
|
||||||
|
$status = 0;
|
||||||
|
if (!empty($http_response_header) && is_array($http_response_header)) {
|
||||||
|
foreach ($http_response_header as $line) {
|
||||||
|
if (preg_match('#^HTTP/\\S+\\s+(\\d+)#', $line, $m)) {
|
||||||
|
$status = (int)$m[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($respBody === false) {
|
||||||
|
$last = error_get_last();
|
||||||
|
$errMsg = $last['message'] ?? 'http request failed';
|
||||||
|
return ['ok' => false, 'status' => $status, 'error' => (string)$errMsg];
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = null;
|
||||||
|
$decoded = json_decode((string)$respBody, true);
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
$decoded = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ok = $status >= 200 && $status < 300;
|
||||||
|
return [
|
||||||
|
'ok' => $ok,
|
||||||
|
'status' => $status,
|
||||||
|
'body' => (string)$respBody,
|
||||||
|
'json' => $decoded,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简单 JSON GET(无 curl 扩展时使用)
|
||||||
|
* @return array{ok:bool,status?:int,body?:string,error?:string,json?:array}
|
||||||
|
*/
|
||||||
|
private function httpGetJson(string $url, array $headers): array
|
||||||
|
{
|
||||||
|
$headerStr = implode("\r\n", $headers);
|
||||||
|
$context = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'method' => 'GET',
|
||||||
|
'header' => $headerStr,
|
||||||
|
'timeout' => 10,
|
||||||
|
// 对 4xx/5xx 也返回响应体,便于排障
|
||||||
|
'ignore_errors' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$respBody = @file_get_contents($url, false, $context);
|
||||||
|
$status = 0;
|
||||||
|
if (!empty($http_response_header) && is_array($http_response_header)) {
|
||||||
|
foreach ($http_response_header as $line) {
|
||||||
|
if (preg_match('#^HTTP/\\S+\\s+(\\d+)#', $line, $m)) {
|
||||||
|
$status = (int)$m[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($respBody === false) {
|
||||||
|
$last = error_get_last();
|
||||||
|
$errMsg = $last['message'] ?? 'http request failed';
|
||||||
|
return ['ok' => false, 'status' => $status, 'error' => (string)$errMsg];
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode((string)$respBody, true);
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
$decoded = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ok = $status >= 200 && $status < 300;
|
||||||
|
return [
|
||||||
|
'ok' => $ok,
|
||||||
|
'status' => $status,
|
||||||
|
'body' => (string)$respBody,
|
||||||
|
'json' => $decoded,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android 网关轮询:获取待发送任务
|
||||||
|
*
|
||||||
|
* 约定:
|
||||||
|
* - apiKey 通过 header `X-API-KEY` / `X-SMS-GATEWAY-API-KEY` 或 body/query `apiKey`
|
||||||
|
*/
|
||||||
|
public function gatewayPoll()
|
||||||
|
{
|
||||||
|
$apiKey = $this->getApiKeyFromRequest();
|
||||||
|
if (empty($apiKey)) {
|
||||||
|
Log::write('[sms_gateway_poll] missing apiKey');
|
||||||
|
return json(['code' => 401, 'msg' => '缺少 apiKey']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不强制要求 mete_system_site_settings(apiKey) 与网关入参完全一致;
|
||||||
|
// 直接按任务表的 api_key 匹配,提高兼容性与排障速度。
|
||||||
|
$apiKeySetting = $this->getSiteSettingValue('apiKey');
|
||||||
|
if (empty($apiKeySetting) || (string)$apiKeySetting !== (string)$apiKey) {
|
||||||
|
Log::write('[sms_gateway_poll] apiKey differs from setting; setting=' . $this->maskKey($apiKeySetting) . ' req=' . $this->maskKey($apiKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
$task = Db::name('mete_system_sms_tasks')
|
||||||
|
->where('api_key', (string)$apiKey)
|
||||||
|
->where('status', 0)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->order('id', 'asc')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// 没有任务
|
||||||
|
if (!$task) {
|
||||||
|
Log::write('[sms_gateway_poll] no task for apiKey=' . $this->maskKey($apiKey));
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'no task',
|
||||||
|
'data' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记为处理中,避免被重复领取
|
||||||
|
Db::name('mete_system_sms_tasks')->where('id', (int)$task['id'])->update([
|
||||||
|
'status' => 1,
|
||||||
|
'update_time' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Log::write('[sms_gateway_poll] send task id=' . (int)$task['id'] . ' phone=' . (string)$task['phone']);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'taskId' => $task['id'],
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'phone' => $task['phone'],
|
||||||
|
'content' => $task['content'],
|
||||||
|
'smsContent' => $task['content'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android 网关上报:上传实际收到的短信内容并解析验证码
|
||||||
|
*/
|
||||||
|
public function gatewayReport()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$raw = $this->request->post();
|
||||||
|
$apiKey = $this->getApiKeyFromRequest();
|
||||||
|
$taskId = $raw['taskId'] ?? $raw['task_id'] ?? $raw['id'] ?? null;
|
||||||
|
$smsContent = trim((string)($raw['smsContent'] ?? $raw['sms_content'] ?? $raw['content'] ?? $raw['message'] ?? $raw['sms'] ?? ''));
|
||||||
|
$status = $raw['status'] ?? $raw['result'] ?? $raw['state'] ?? null; // success/failed/int
|
||||||
|
|
||||||
|
if (empty($apiKey)) {
|
||||||
|
return json(['code' => 401, 'msg' => '缺少 apiKey']);
|
||||||
|
}
|
||||||
|
if (empty($taskId)) {
|
||||||
|
return json(['code' => 400, 'msg' => '缺少 taskId']);
|
||||||
|
}
|
||||||
|
if ($smsContent === '') {
|
||||||
|
return json(['code' => 400, 'msg' => '缺少 smsContent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$task = Db::name('mete_system_sms_tasks')
|
||||||
|
->where('id', (int)$taskId)
|
||||||
|
->where('api_key', (string)$apiKey)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$task) {
|
||||||
|
Log::write('[sms_gateway_report] task not found; taskId=' . (int)$taskId . ' apiKey=' . $this->maskKey($apiKey));
|
||||||
|
return json(['code' => 404, 'msg' => '任务不存在或 apiKey 不匹配']);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::write('[sms_gateway_report] received taskId=' . (int)$taskId . ' status=' . (string)($status ?? ''));
|
||||||
|
|
||||||
|
// 从短信内容里抓取验证码(通用策略:4-6 位数字)
|
||||||
|
$parsedCode = '';
|
||||||
|
if (preg_match('/(\d{4,6})/', $smsContent, $m)) {
|
||||||
|
$parsedCode = (string)$m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$update = [
|
||||||
|
'report_raw' => $smsContent,
|
||||||
|
'code' => $parsedCode !== '' ? $parsedCode : (string)$task['code'],
|
||||||
|
'update_time' => date('Y-m-d H:i:s'),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($status === 'failed' || $status === 'error' || $status === 2) {
|
||||||
|
$update['status'] = 2;
|
||||||
|
} elseif ($status === 'success' || $status === 'reported' || $status === 3 || $status === 1) {
|
||||||
|
// success => reported/done
|
||||||
|
$update['status'] = 3;
|
||||||
|
} else {
|
||||||
|
// 默认当做已上报
|
||||||
|
$update['status'] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::name('mete_system_sms_tasks')->where('id', (int)$task['id'])->update($update);
|
||||||
|
|
||||||
|
$this->logSuccess('短信管理', '网关上报短信(解析验证码)', [
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'parsed_code' => $update['code'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '上报成功']);
|
||||||
|
} catch (DbException $e) {
|
||||||
|
$this->logFail('短信管理', '网关上报短信', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '服务器错误:' . $e->getMessage()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->logFail('短信管理', '网关上报短信', $e->getMessage());
|
||||||
|
return json(['code' => 500, 'msg' => '服务器错误:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员:获取短信任务列表(租户隔离)
|
||||||
|
*
|
||||||
|
* 支持参数(可选):
|
||||||
|
* - status: 任务状态
|
||||||
|
* - phone: 手机号关键词
|
||||||
|
*/
|
||||||
|
public function getSmsTaskList()
|
||||||
|
{
|
||||||
|
$backendUrl = $this->getSiteSettingValue('backendUrl');
|
||||||
|
$apiKey = $this->getSiteSettingValue('apiKey');
|
||||||
|
|
||||||
|
if (empty($backendUrl) || empty($apiKey)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '短信网关配置未完成(backendUrl/apiKey 缺失)',
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = (string)Request::param('status', '');
|
||||||
|
$phoneKeyword = trim((string)Request::param('phone', ''));
|
||||||
|
$limit = (int)Request::param('limit', 50, 'int');
|
||||||
|
$limit = $limit > 0 ? min($limit, 200) : 50;
|
||||||
|
|
||||||
|
// 前端 status: 0/1/2/3 -> uniapp backend status: pending/sending/failed/success
|
||||||
|
$statusMap = [
|
||||||
|
'0' => 'pending',
|
||||||
|
'1' => 'sending',
|
||||||
|
'2' => 'failed',
|
||||||
|
'3' => 'success',
|
||||||
|
];
|
||||||
|
$uniStatus = $status !== '' && isset($statusMap[$status]) ? $statusMap[$status] : '';
|
||||||
|
|
||||||
|
$url = rtrim($backendUrl, '/') . '/api/v1/business/outbound-tasks?limit=' . $limit;
|
||||||
|
if ($uniStatus !== '') {
|
||||||
|
$url .= '&status=' . urlencode($uniStatus);
|
||||||
|
}
|
||||||
|
if ($phoneKeyword !== '') {
|
||||||
|
$url .= '&phone=' . urlencode($phoneKeyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'X-Api-Key: ' . (string)$apiKey,
|
||||||
|
'Accept: application/json',
|
||||||
|
];
|
||||||
|
|
||||||
|
$resp = $this->httpGetJson($url, $headers);
|
||||||
|
if (empty($resp['ok'])) {
|
||||||
|
// 兼容:如果 uniapp 后端还未部署新增查询接口,则 fallback 到本地队列表(只能看到“已入队”,无法看到发送成功/失败)
|
||||||
|
$fallback = [];
|
||||||
|
try {
|
||||||
|
$fWhere = [
|
||||||
|
['api_key', '=', (string)$apiKey],
|
||||||
|
['delete_time', '=', null],
|
||||||
|
];
|
||||||
|
if ($phoneKeyword !== '') {
|
||||||
|
$fWhere[] = ['phone', 'like', '%' . $phoneKeyword . '%'];
|
||||||
|
}
|
||||||
|
// 前端 status=0/1/2/3,局部队列表字段同样使用数字状态
|
||||||
|
if ($status !== '') {
|
||||||
|
$fWhere[] = ['status', '=', (int)$status];
|
||||||
|
}
|
||||||
|
|
||||||
|
$fallback = Db::name('mete_system_sms_tasks')
|
||||||
|
->where($fWhere)
|
||||||
|
->order('id', 'desc')
|
||||||
|
->limit($limit)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$fallback = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'uniapp 查询任务接口不可用,已使用本地队列表(仅展示入队状态)',
|
||||||
|
'detail' => [
|
||||||
|
'http_status' => $resp['status'] ?? null,
|
||||||
|
'body_preview' => isset($resp['body']) ? substr((string)$resp['body'], 0, 300) : '',
|
||||||
|
],
|
||||||
|
'list' => $fallback,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tasks = (array)($resp['json']['tasks'] ?? []);
|
||||||
|
|
||||||
|
$statusNumMap = [
|
||||||
|
'pending' => 0,
|
||||||
|
'sending' => 1,
|
||||||
|
'failed' => 2,
|
||||||
|
'success' => 3,
|
||||||
|
];
|
||||||
|
|
||||||
|
$list = array_map(function ($t) use ($statusNumMap) {
|
||||||
|
$content = (string)($t['content'] ?? '');
|
||||||
|
$parsedCode = '';
|
||||||
|
if (preg_match('/(\d{4,6})/', $content, $m)) {
|
||||||
|
$parsedCode = (string)$m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusStr = (string)($t['status'] ?? '');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $t['taskId'] ?? '',
|
||||||
|
'phone' => $t['phone'] ?? '',
|
||||||
|
'content' => $content,
|
||||||
|
'code' => $parsedCode,
|
||||||
|
'status' => $statusNumMap[$statusStr] ?? 0,
|
||||||
|
'create_time' => isset($t['createdAt']) ? date('Y-m-d H:i:s', (int)($t['createdAt'] / 1000)) : '',
|
||||||
|
'update_time' => isset($t['updatedAt']) ? date('Y-m-d H:i:s', (int)($t['updatedAt'] / 1000)) : '',
|
||||||
|
];
|
||||||
|
}, $tasks);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => $list,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员:编辑短信任务(租户隔离)
|
||||||
|
*
|
||||||
|
* body:
|
||||||
|
* - status
|
||||||
|
* - code
|
||||||
|
* - report_raw
|
||||||
|
*/
|
||||||
|
public function editSmsTask($id = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
$id = $this->request->param('id', $id);
|
||||||
|
|
||||||
|
$data = Request::only(['status', 'code', 'report_raw']);
|
||||||
|
|
||||||
|
if (empty($id)) {
|
||||||
|
return json(['code' => 400, 'msg' => '任务ID不能为空']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($data['status'])) {
|
||||||
|
return json(['code' => 400, 'msg' => '状态不能为空']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validate($data, [
|
||||||
|
'status|状态' => 'integer',
|
||||||
|
'code|验证码' => 'max:20',
|
||||||
|
'report_raw|上报内容' => 'max:100000',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$task = Db::name('mete_system_sms_tasks')
|
||||||
|
->where('id', (int)$id)
|
||||||
|
->where('tid', (int)$tid)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$task) {
|
||||||
|
return json(['code' => 404, 'msg' => '任务不存在或无权限']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$update = [
|
||||||
|
'status' => (int)$data['status'],
|
||||||
|
'code' => (string)($data['code'] ?? ''),
|
||||||
|
'report_raw' => (string)($data['report_raw'] ?? ''),
|
||||||
|
'update_time' => date('Y-m-d H:i:s'),
|
||||||
|
];
|
||||||
|
|
||||||
|
Db::name('mete_system_sms_tasks')
|
||||||
|
->where('id', (int)$id)
|
||||||
|
->where('tid', (int)$tid)
|
||||||
|
->update($update);
|
||||||
|
|
||||||
|
return json(['code' => 200, 'msg' => '编辑成功']);
|
||||||
|
} catch (ValidateException $e) {
|
||||||
|
return json(['code' => 400, 'msg' => $e->getError()]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json(['code' => 500, 'msg' => '编辑失败:' . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getApiKeyFromRequest(): string
|
||||||
|
{
|
||||||
|
$req = Request::instance();
|
||||||
|
|
||||||
|
$apiKey = (string)$req->header('X-SMS-GATEWAY-API-KEY', '');
|
||||||
|
if ($apiKey !== '') {
|
||||||
|
return $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiKey = (string)$req->header('X-API-KEY', '');
|
||||||
|
if ($apiKey !== '') {
|
||||||
|
return $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiKey = (string)$req->header('X-SMS-API-KEY', '');
|
||||||
|
if ($apiKey !== '') {
|
||||||
|
return $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiKey = (string)$req->header('Authorization', '');
|
||||||
|
if ($apiKey !== '' && preg_match('/Bearer\\s+(.+)/i', $apiKey, $m)) {
|
||||||
|
return (string)$m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// body/query
|
||||||
|
$apiKey = (string)($req->post('apiKey') ?? $req->post('api_key') ?? $req->param('apiKey', '') ?? $req->param('api_key', ''));
|
||||||
|
return $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function maskKey(string $key): string
|
||||||
|
{
|
||||||
|
$key = (string)$key;
|
||||||
|
if ($key === '') return '';
|
||||||
|
if (strlen($key) <= 6) return '***';
|
||||||
|
return substr($key, 0, 3) . '***' . substr($key, -3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller\Tenant;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Session;
|
||||||
|
use think\response\Json;
|
||||||
|
use think\db\exception\DbException;
|
||||||
|
use think\Request;
|
||||||
|
use app\model\Tenant\Tenant;
|
||||||
|
use app\model\System\AdminUser;
|
||||||
|
use app\model\Template\TemplateSiteConfig;
|
||||||
|
|
||||||
|
class TenantController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取租户列表
|
||||||
|
*/
|
||||||
|
public function getTenant(Request $request)
|
||||||
|
{
|
||||||
|
// 获取参数
|
||||||
|
$page = $request->param('page', 1, 'int');
|
||||||
|
$pageSize = $request->param('pageSize', 10, 'int');
|
||||||
|
$tenantName = $request->param('tenant_name', '');
|
||||||
|
$tenantCode = $request->param('tenant_code', '');
|
||||||
|
$contactPerson = $request->param('contact_person', '');
|
||||||
|
$contactPhone = $request->param('contact_phone', '');
|
||||||
|
|
||||||
|
$where = [['delete_time', '=', null]];
|
||||||
|
|
||||||
|
// 动态增加模糊搜索条件
|
||||||
|
if ($tenantName) $where[] = ['tenant_name', 'like', "%$tenantName%"];
|
||||||
|
if ($tenantCode) $where[] = ['tenant_code', 'like', "%$tenantCode%"];
|
||||||
|
if ($contactPerson) $where[] = ['contact_person', 'like', "%$contactPerson%"];
|
||||||
|
if ($contactPhone) $where[] = ['contact_phone', 'like', "%$contactPhone%"];
|
||||||
|
|
||||||
|
$list = Tenant::where($where)->page($page, $pageSize)->select()->toArray();
|
||||||
|
$total = Tenant::where($where)->count();
|
||||||
|
|
||||||
|
return json(['code' => 200, 'data' => ['list' => $list, 'total' => $total]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取租户详情
|
||||||
|
*/
|
||||||
|
public function getTenantDetail($id)
|
||||||
|
{
|
||||||
|
$detail = Tenant::where('id', $id)->where('delete_time', null)->find()->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => $detail
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建租户
|
||||||
|
*/
|
||||||
|
public function createTenant()
|
||||||
|
{
|
||||||
|
$data = $this->request->post();
|
||||||
|
$tenant = Tenant::create($data);
|
||||||
|
if ($tenant) {
|
||||||
|
// 创建租户默认数据
|
||||||
|
$this->createTenantDefaultData($tenant->id);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '创建成功',
|
||||||
|
'data' => $tenant
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '创建失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建租户默认数据
|
||||||
|
* @param int $tenantId 租户ID
|
||||||
|
*/
|
||||||
|
private function createTenantDefaultData(int $tenantId)
|
||||||
|
{
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
// 创建租户默认模板配置
|
||||||
|
TemplateSiteConfig::create([
|
||||||
|
'tid' => $tenantId,
|
||||||
|
'key' => 'current_theme',
|
||||||
|
'value' => 'default',
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑租户
|
||||||
|
*/
|
||||||
|
public function editTenant($id)
|
||||||
|
{
|
||||||
|
$data = $this->request->post();
|
||||||
|
$tenant = Tenant::where('id', $id)->update($data);
|
||||||
|
if ($tenant) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '编辑成功',
|
||||||
|
'data' => $tenant
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '编辑失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除租户
|
||||||
|
*/
|
||||||
|
public function deleteTenant($id)
|
||||||
|
{
|
||||||
|
$tenant = Tenant::where('id', $id)->update(['delete_time' => date('Y-m-d H:i:s')]);
|
||||||
|
if ($tenant) {
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '删除成功',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '删除失败',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询租户编码重复(不筛选删除数据)
|
||||||
|
*/
|
||||||
|
public function findTenantCode(Request $request)
|
||||||
|
{
|
||||||
|
$tenantCode = $request->param('tenant_code', '');
|
||||||
|
|
||||||
|
if (!$tenantCode) {
|
||||||
|
return json(['code' => 400, 'msg' => '缺少编码参数']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接去表里查,只要有一条一样的就返回重复
|
||||||
|
$hasOne = Tenant::where('tenant_code', $tenantCode)->find();
|
||||||
|
|
||||||
|
if ($hasOne) {
|
||||||
|
return json([
|
||||||
|
'code' => 201,
|
||||||
|
'msg' => '编码已存在',
|
||||||
|
'data' => $hasOne
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '编码可用'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,25 +10,50 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class UserController extends BaseController
|
class UserController extends BaseController
|
||||||
{
|
{
|
||||||
|
private function getCurrentTenantIdOrFail(): int
|
||||||
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if ($tid <= 0) {
|
||||||
|
throw new \RuntimeException('未获取到有效租户信息');
|
||||||
|
}
|
||||||
|
return $tid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有用户信息
|
* 获取所有用户信息
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getAllUsers()
|
public function getAllUsers()
|
||||||
{
|
{
|
||||||
$users = AdminUser::where('delete_time', null)->field('id, account, name, phone, birth, email, qq, sex, group_id, status, last_login_ip, login_count, create_time, update_time')->select()->toArray();
|
try {
|
||||||
return json([
|
$tid = $this->getCurrentTenantIdOrFail();
|
||||||
'code' => 200,
|
$users = AdminUser::where('delete_time', null)
|
||||||
'msg' => '获取成功',
|
->where('tid', $tid)
|
||||||
'data' => [
|
->field('id, tid, account, name, phone, birth, email, qq, sex, group_id, status, last_login_ip, login_count, create_time, update_time')
|
||||||
'list' => $users,
|
->select()
|
||||||
'total' => count($users)
|
->toArray();
|
||||||
]
|
return json([
|
||||||
]);
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => [
|
||||||
|
'list' => $users,
|
||||||
|
'total' => count($users)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '获取用户失败:' . $e->getMessage(),
|
||||||
|
'data' => [
|
||||||
|
'list' => [],
|
||||||
|
'total' => 0
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,15 +62,33 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getTenantUsers(int $tenantId)
|
public function getTenantUsers(int $tenantId)
|
||||||
{
|
{
|
||||||
$users = AdminUser::where('delete_time', null)->where('tenant_id', $tenantId)->field('id, account, name, phone, birth, email, qq, sex, group_id, status, last_login_ip, login_count, create_time, update_time')->select()->toArray();
|
try {
|
||||||
return json([
|
$tid = $this->getCurrentTenantIdOrFail();
|
||||||
'code' => 200,
|
if ($tenantId !== $tid) {
|
||||||
'msg' => '获取成功',
|
return json([
|
||||||
'data' => [
|
'code' => 403,
|
||||||
'list' => $users,
|
'msg' => '禁止跨租户查看用户'
|
||||||
'total' => count($users)
|
]);
|
||||||
]
|
}
|
||||||
]);
|
$users = AdminUser::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->field('id, tid, account, name, phone, birth, email, qq, sex, group_id, status, last_login_ip, login_count, create_time, update_time')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => '获取成功',
|
||||||
|
'data' => [
|
||||||
|
'list' => $users,
|
||||||
|
'total' => count($users)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '获取用户失败:' . $e->getMessage()
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,9 +97,18 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function getUserInfo(int $id)
|
public function getUserInfo(int $id)
|
||||||
{
|
{
|
||||||
|
$tid = $this->getTenantId();
|
||||||
$user = AdminUser::where('id', $id)
|
$user = AdminUser::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
->field('id, account, name, phone, email, birth, qq, sex, group_id, status, create_time, last_login_ip')
|
->field('id, account, name, phone, email, birth, qq, sex, group_id, status, create_time, last_login_ip')
|
||||||
->find();
|
->find();
|
||||||
|
if (!$user) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '用户不存在或无权限访问'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('用户管理', '获取用户信息', ['id' => $id]);
|
$this->logSuccess('用户管理', '获取用户信息', ['id' => $id]);
|
||||||
@@ -75,10 +127,20 @@ class UserController extends BaseController
|
|||||||
public function changePassword(int $id, string $password)
|
public function changePassword(int $id, string $password)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
AdminUser::where('id', $id)->update([
|
$tid = $this->getCurrentTenantIdOrFail();
|
||||||
|
$affected = AdminUser::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->update([
|
||||||
'password' => md5($password),
|
'password' => md5($password),
|
||||||
'update_time' => date('Y-m-d H:i:s')
|
'update_time' => date('Y-m-d H:i:s')
|
||||||
]);
|
]);
|
||||||
|
if (!$affected) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '用户不存在或无权限修改'
|
||||||
|
]);
|
||||||
|
}
|
||||||
// 记录操作日志
|
// 记录操作日志
|
||||||
$this->logSuccess('用户管理', '修改密码', ['id' => $id]);
|
$this->logSuccess('用户管理', '修改密码', ['id' => $id]);
|
||||||
return json([
|
return json([
|
||||||
@@ -102,12 +164,21 @@ class UserController extends BaseController
|
|||||||
public function addUser()
|
public function addUser()
|
||||||
{
|
{
|
||||||
$data = request()->param();
|
$data = request()->param();
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if ($tid <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '未获取到有效租户信息'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$data['password'] = md5($data['password']);
|
$data['password'] = md5($data['password']);
|
||||||
$data['create_time'] = date('Y-m-d H:i:s');
|
$data['create_time'] = date('Y-m-d H:i:s');
|
||||||
$data['update_time'] = $data['create_time'];
|
$data['update_time'] = $data['create_time'];
|
||||||
$data['group_id'] = 2;
|
$data['group_id'] = 2;
|
||||||
|
$data['tid'] = $tid;
|
||||||
|
|
||||||
$id = AdminUser::insertGetId($data);
|
$id = AdminUser::insertGetId($data);
|
||||||
// 记录操作日志
|
|
||||||
$this->logSuccess('用户管理', '添加用户', ['data' => $data]);
|
$this->logSuccess('用户管理', '添加用户', ['data' => $data]);
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
@@ -124,8 +195,25 @@ class UserController extends BaseController
|
|||||||
{
|
{
|
||||||
$data = request()->param();
|
$data = request()->param();
|
||||||
unset($data['_t'], $data['id']);
|
unset($data['_t'], $data['id']);
|
||||||
|
unset($data['tid']);
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
if ($tid <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '未获取到有效租户信息'
|
||||||
|
]);
|
||||||
|
}
|
||||||
$data['update_time'] = date('Y-m-d H:i:s');
|
$data['update_time'] = date('Y-m-d H:i:s');
|
||||||
AdminUser::where('id', $id)->update($data);
|
$affected = AdminUser::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->update($data);
|
||||||
|
if (!$affected) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '用户不存在或无权限编辑'
|
||||||
|
]);
|
||||||
|
}
|
||||||
$this->logSuccess('用户管理', '编辑用户', ['id' => $id]);
|
$this->logSuccess('用户管理', '编辑用户', ['id' => $id]);
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
@@ -139,16 +227,29 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function deleteUser(int $id)
|
public function deleteUser(int $id)
|
||||||
{
|
{
|
||||||
$user = AdminUser::where('id', $id)->where('delete_time', null)->find();
|
$tid = $this->getTenantId();
|
||||||
|
if ($tid <= 0) {
|
||||||
|
return json([
|
||||||
|
'code' => 401,
|
||||||
|
'msg' => '未获取到有效租户信息'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = AdminUser::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return json([
|
return json([
|
||||||
'code' => 404,
|
'code' => 404,
|
||||||
'msg' => '用户不存在或已删除'
|
'msg' => '用户不存在、已删除或无权限操作'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdminUser::where('id', $id)->update([
|
AdminUser::where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->update([
|
||||||
'delete_time' => date('Y-m-d H:i:s')
|
'delete_time' => date('Y-m-d H:i:s')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ return [
|
|||||||
// \think\middleware\CheckRequestCache::class,
|
// \think\middleware\CheckRequestCache::class,
|
||||||
// 多语言加载
|
// 多语言加载
|
||||||
// \think\middleware\LoadLangPack::class,
|
// \think\middleware\LoadLangPack::class,
|
||||||
// Session初始化
|
// 跨域支持
|
||||||
\app\common\middleware\AllowCrossDomain::class,
|
\app\common\middleware\AllowCrossDomain::class,
|
||||||
|
// Session初始化
|
||||||
\think\middleware\SessionInit::class,
|
\think\middleware\SessionInit::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 数据统计路由
|
// 数据统计路由
|
||||||
Route::get('contentstats', 'app\\admin\\controller\\AnalyticsController@getContentStats');
|
Route::get('contentstats', 'app\\admin\\controller\\Cms\\Analytics\\AnalyticsController@getContentStats');
|
||||||
Route::get('usersstats', 'app\\admin\\controller\\AnalyticsController@getUserStats');
|
Route::get('usersstats', 'app\\admin\\controller\\Cms\\Analytics\\AnalyticsController@getUserStats');
|
||||||
|
|||||||
@@ -2,22 +2,22 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 文章路由
|
// 文章路由
|
||||||
Route::get('articlesList', 'app\\admin\\controller\\Article\\ArticleController@getArticlesList');
|
Route::get('articlesList', 'app\\admin\\controller\\Cms\\Article\\ArticleController@getArticlesList');
|
||||||
Route::get('allarticles', 'app\\admin\\controller\\Article\\ArticleController@getAllArticles');
|
Route::get('allarticles', 'app\\admin\\controller\\Cms\\Article\\ArticleController@getAllArticles');
|
||||||
Route::get('articles/:id', 'app\\admin\\controller\\Article\\ArticleController@getArticle');
|
Route::get('articles/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@getArticle');
|
||||||
Route::post('createarticle', 'app\\admin\\controller\\Article\\ArticleController@createArticle');
|
Route::post('createarticle', 'app\\admin\\controller\\Cms\\Article\\ArticleController@createArticle');
|
||||||
Route::post('editarticle/:id', 'app\\admin\\controller\\Article\\ArticleController@editArticle');
|
Route::post('editarticle/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@editArticle');
|
||||||
Route::delete('deletearticle/:id', 'app\\admin\\controller\\Article\\ArticleController@deleteArticle');
|
Route::delete('deletearticle/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@deleteArticle');
|
||||||
Route::post('publisharticle/:id', 'app\\admin\\controller\\Article\\ArticleController@publishArticle');
|
Route::post('publisharticle/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@publishArticle');
|
||||||
Route::post('unPublisharticle/:id', 'app\\admin\\controller\\Article\\ArticleController@unPublishArticle');
|
Route::post('unPublisharticle/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@unPublishArticle');
|
||||||
Route::post('articleRecommend/:id', 'app\\admin\\controller\\Article\\ArticleController@articleRecommend');
|
Route::post('articleRecommend/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@articleRecommend');
|
||||||
Route::post('unArticleRecommend/:id', 'app\\admin\\controller\\Article\\ArticleController@unArticleRecommend');
|
Route::post('unArticleRecommend/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@unArticleRecommend');
|
||||||
Route::post('articleTop/:id', 'app\\admin\\controller\\Article\\ArticleController@articleTop');
|
Route::post('articleTop/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@articleTop');
|
||||||
Route::post('unArticleTop/:id', 'app\\admin\\controller\\Article\\ArticleController@unArticleTop');
|
Route::post('unArticleTop/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleController@unArticleTop');
|
||||||
|
|
||||||
// 文章分类路由
|
// 文章分类路由
|
||||||
Route::get('allcategories', 'app\\admin\\controller\\Article\\ArticleCategoryController@getAllArticleCategories');
|
Route::get('allcategories', 'app\\admin\\controller\\Cms\\Article\\ArticleCategoryController@getAllArticleCategories');
|
||||||
Route::get('categories', 'app\\admin\\controller\\Article\\ArticleCategoryController@getArticleCategories');
|
Route::get('categories', 'app\\admin\\controller\\Cms\\Article\\ArticleCategoryController@getArticleCategories');
|
||||||
Route::delete('categories/:id', 'app\\admin\\controller\\Article\\ArticleCategoryController@deleteCategory');
|
Route::delete('categories/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleCategoryController@deleteCategory');
|
||||||
Route::post('createCategory', 'app\\admin\\controller\\Article\\ArticleCategoryController@createCategory');
|
Route::post('createCategory', 'app\\admin\\controller\\Cms\\Article\\ArticleCategoryController@createCategory');
|
||||||
Route::post('editCategory/:id', 'app\\admin\\controller\\Article\\ArticleCategoryController@editCategory');
|
Route::post('editCategory/:id', 'app\\admin\\controller\\Cms\\Article\\ArticleCategoryController@editCategory');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// Banner路由
|
// Banner路由
|
||||||
Route::get('allbanners', 'app\\admin\\controller\\BannerController@getAllBanners');
|
Route::get('allbanners', 'app\\admin\\controller\\Cms\\Banner\\BannerController@getAllBanners');
|
||||||
Route::post('createbanner', 'app\\admin\\controller\\BannerController@createBanner');
|
Route::post('createbanner', 'app\\admin\\controller\\Cms\\Banner\\BannerController@createBanner');
|
||||||
Route::post('editbanner/:id', 'app\\admin\\controller\\BannerController@editBanner');
|
Route::post('editbanner/:id', 'app\\admin\\controller\\Cms\\Banner\\BannerController@editBanner');
|
||||||
Route::delete('deletebanner/:id', 'app\\admin\\controller\\BannerController@deleteBanner');
|
Route::delete('deletebanner/:id', 'app\\admin\\controller\\Cms\\Banner\\BannerController@deleteBanner');
|
||||||
|
|||||||
@@ -11,5 +11,17 @@ Route::get('storage/:path', 'app\\admin\\controller\\StorageController@index')->
|
|||||||
// 登录路由
|
// 登录路由
|
||||||
Route::post('loginInfo', 'app\\admin\\controller\\LoginController@loginInfo');
|
Route::post('loginInfo', 'app\\admin\\controller\\LoginController@loginInfo');
|
||||||
Route::post('login', 'app\\admin\\controller\\LoginController@login');
|
Route::post('login', 'app\\admin\\controller\\LoginController@login');
|
||||||
|
Route::post('sendLoginCode', 'app\\admin\\controller\\LoginController@sendLoginCode');
|
||||||
|
Route::post('loginBySms', 'app\\admin\\controller\\LoginController@loginBySms');
|
||||||
|
Route::post('sendRegisterCode', 'app\\admin\\controller\\LoginController@sendRegisterCode');
|
||||||
|
Route::post('sendResetCode', 'app\\admin\\controller\\LoginController@sendResetCode');
|
||||||
|
Route::post('register', 'app\\admin\\controller\\LoginController@register');
|
||||||
|
Route::post('resetPassword', 'app\\admin\\controller\\LoginController@resetPassword');
|
||||||
Route::post('logout', 'app\\admin\\controller\\LoginController@logout');
|
Route::post('logout', 'app\\admin\\controller\\LoginController@logout');
|
||||||
Route::get('user/info', 'app\\admin\\controller\\LoginController@userInfo');
|
Route::get('user/info', 'app\\admin\\controller\\LoginController@userInfo');
|
||||||
|
|
||||||
|
// 极验路由
|
||||||
|
Route::get('login/getGeetest3Infos', 'app\\admin\\controller\\LoginController@getGeetest3Infos');
|
||||||
|
Route::get('login/getGeetest4Infos', 'app\\admin\\controller\\LoginController@getGeetest4Infos');
|
||||||
|
Route::get('login/getOpenVerify', 'app\\admin\\controller\\LoginController@getOpenVerify');
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 需求路由
|
||||||
|
Route::get('demandList', 'app\\admin\\controller\\Cms\\Demand\\DemandController@getDemandList');
|
||||||
|
Route::post('addDemand', 'app\\admin\\controller\\Cms\\Demand\\DemandController@addDemand');
|
||||||
|
Route::post('editDemand/:id', 'app\\admin\\controller\\Cms\\Demand\\DemandController@editDemand');
|
||||||
|
Route::post('deleteDemand/:id', 'app\\admin\\controller\\Cms\\Demand\\DemandController@deleteDemand');
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 主域名池管理路由
|
||||||
|
Route::group('domain/pool', function () {
|
||||||
|
Route::get('index', 'app\admin\controller\Cms\Domain\DomainPoolController/index');
|
||||||
|
Route::get('getEnabledDomains', 'app\admin\controller\Cms\Domain\DomainPoolController/getEnabledDomains');
|
||||||
|
Route::post('create', 'app\admin\controller\Cms\Domain\DomainPoolController/create');
|
||||||
|
Route::post('update', 'app\admin\controller\Cms\Domain\DomainPoolController/update');
|
||||||
|
Route::delete('delete/:id', 'app\admin\controller\Cms\Domain\DomainPoolController/delete');
|
||||||
|
Route::post('toggleStatus', 'app\admin\controller\Cms\Domain\DomainPoolController/toggleStatus');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 租户域名绑定路由
|
||||||
|
Route::group('domain/tenant', function () {
|
||||||
|
Route::get('index', 'app\admin\controller\Cms\Domain\TenantDomainController/index');
|
||||||
|
Route::get('myDomains', 'app\admin\controller\Cms\Domain\TenantDomainController/myDomains');
|
||||||
|
Route::post('apply', 'app\admin\controller\Cms\Domain\TenantDomainController/apply');
|
||||||
|
Route::post('audit', 'app\admin\controller\Cms\Domain\TenantDomainController/audit');
|
||||||
|
Route::post('toggleStatus', 'app\admin\controller\Cms\Domain\TenantDomainController/toggleStatus');
|
||||||
|
Route::delete('delete/:id', 'app\admin\controller\Cms\Domain\TenantDomainController/delete');
|
||||||
|
});
|
||||||
@@ -3,9 +3,20 @@ use think\facade\Route;
|
|||||||
|
|
||||||
// 组织机构管理路由
|
// 组织机构管理路由
|
||||||
Route::group('erp', function() {
|
Route::group('erp', function() {
|
||||||
Route::get('organization', 'app\admin\controller\Erp\OrganizationController/getOrganization');
|
Route::get('getOrganization', 'app\admin\controller\Erp\OrganizationController/getOrganization');
|
||||||
Route::get('getOrganizationDetail/:id', 'app\admin\controller\Erp\OrganizationController/getOrganizationDetail');
|
Route::get('getOrganizationDetail/:id', 'app\admin\controller\Erp\OrganizationController/getOrganizationDetail');
|
||||||
Route::post('organization', 'app\admin\controller\Erp\OrganizationController/createOrganization');
|
Route::post('createOrganization', 'app\admin\controller\Erp\OrganizationController/createOrganization');
|
||||||
Route::post('organization/:id', 'app\admin\controller\Erp\OrganizationController/editOrganization');
|
Route::post('editOrganization/:id', 'app\admin\controller\Erp\OrganizationController/editOrganization');
|
||||||
Route::delete('organization/:id', 'app\admin\controller\Erp\OrganizationController/deleteOrganization');
|
Route::delete('deleteOrganization/:id', 'app\admin\controller\Erp\OrganizationController/deleteOrganization');
|
||||||
|
Route::get('getCompanys', 'app\admin\controller\Erp\OrganizationController/getCompanys');
|
||||||
|
Route::get('getDepartments', 'app\admin\controller\Erp\OrganizationController/getDepartments');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
// 员工管理路由
|
||||||
|
Route::group('erp', function() {
|
||||||
|
Route::get('getEmployee', 'app\admin\controller\Erp\EmployeeController/getEmployee');
|
||||||
|
Route::get('getEmployeeDetail/:id', 'app\admin\controller\Erp\EmployeeController/getEmployeeDetail');
|
||||||
|
Route::post('createEmployee', 'app\admin\controller\Erp\EmployeeController/createEmployee');
|
||||||
|
Route::post('editEmployee/:id', 'app\admin\controller\Erp\EmployeeController/editEmployee');
|
||||||
|
Route::delete('deleteEmployee/:id', 'app\admin\controller\Erp\EmployeeController/deleteEmployee');
|
||||||
|
});
|
||||||
@@ -2,16 +2,21 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 文件路由
|
// 文件路由
|
||||||
Route::get('usercate', 'app\\admin\\controller\\FileController@getUserCate');
|
Route::get('usercate', 'app\\admin\\controller\\System\\FileController@getUserCate');
|
||||||
Route::get('allfiles', 'app\\admin\\controller\\FileController@getAllFiles');
|
Route::get('allfiles', 'app\\admin\\controller\\System\\FileController@getAllFiles');
|
||||||
Route::get('catefiles/:id', 'app\\admin\\controller\\FileController@getCateFiles');
|
Route::get('catefiles/:id', 'app\\admin\\controller\\System\\FileController@getCateFiles');
|
||||||
Route::post('uploadfile', 'app\\admin\\controller\\FileController@uploadFile');
|
Route::post('uploadfile', 'app\\admin\\controller\\System\\FileController@uploadFile');
|
||||||
Route::post('updatefile/:id', 'app\\admin\\controller\\FileController@updateFile');
|
Route::post('uploadfiles', 'app\\admin\\controller\\System\\FileController@uploadFile');
|
||||||
Route::delete('deletefile/:id', 'app\\admin\\controller\\FileController@deleteFile');
|
Route::post('updatefile/:id', 'app\\admin\\controller\\System\\FileController@updateFile');
|
||||||
Route::get('movefile/:id', 'app\\admin\\controller\\FileController@moveFile');
|
Route::delete('deletefile/:id', 'app\\admin\\controller\\System\\FileController@deleteFile');
|
||||||
Route::post('createfilecate', 'app\\admin\\controller\\FileController@createFileCate');
|
Route::get('movefile/:id', 'app\\admin\\controller\\System\\FileController@moveFile');
|
||||||
Route::post('renamefilecate/:id', 'app\\admin\\controller\\FileController@renameFileCate');
|
Route::post('createfilecate', 'app\\admin\\controller\\System\\FileController@createFileCate');
|
||||||
Route::delete('deletefilecate/:id', 'app\\admin\\controller\\FileController@deleteFileCate');
|
Route::post('renamefilecate/:id', 'app\\admin\\controller\\System\\FileController@renameFileCate');
|
||||||
|
Route::delete('deletefilecate/:id', 'app\\admin\\controller\\System\\FileController@deleteFileCate');
|
||||||
|
|
||||||
Route::post('uploadavatar', 'app\\admin\\controller\\FileController@uploadAvatar');
|
Route::post('uploadavatar', 'app\\admin\\controller\\System\\FileController@uploadAvatar');
|
||||||
Route::post('uploadavatar/:id', 'app\\admin\\controller\\FileController@updateAvatar');
|
Route::post('uploadavatar/:id', 'app\\admin\\controller\\System\\FileController@updateAvatar');
|
||||||
|
Route::post('batchdeletefiles', 'app\\admin\\controller\\System\\FileController@batchDeleteFiles');
|
||||||
|
|
||||||
|
Route::post('batchDeleteFilesPermanently', 'app\\admin\\controller\\System\\FileController@batchDeleteFilesPermanently');
|
||||||
|
Route::post('batchMoveFiles', 'app\\admin\\controller\\System\\FileController@batchMoveFiles');
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 友情链接路由
|
||||||
|
Route::get('friendlinks', 'app\admin\controller\Cms\Friendlink\FriendlinkController@getList');
|
||||||
|
Route::get('friendlinks/all', 'app\admin\controller\Cms\Friendlink\FriendlinkController@getAll');
|
||||||
|
Route::post('friendlinks', 'app\admin\controller\Cms\Friendlink\FriendlinkController@add');
|
||||||
|
Route::put('friendlinks/:id', 'app\admin\controller\Cms\Friendlink\FriendlinkController@update');
|
||||||
|
Route::delete('friendlinks/:id', 'app\admin\controller\Cms\Friendlink\FriendlinkController@delete');
|
||||||
|
Route::post('friendlinks/batchdelete', 'app\admin\controller\Cms\Friendlink\FriendlinkController@batchDelete');
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 前端导航路由
|
// 前端导航路由
|
||||||
Route::get('frontmenus', 'app\\admin\\controller\\FrontMenuController@getFrontMenus');
|
Route::get('frontmenus', 'app\\admin\\controller\\Cms\\FrontMenu\\FrontMenuController@getFrontMenus');
|
||||||
Route::post('createfrontmenu', 'app\\admin\\controller\\FrontMenuController@createFrontMenu');
|
Route::post('createfrontmenu', 'app\\admin\\controller\\Cms\\FrontMenu\\FrontMenuController@createFrontMenu');
|
||||||
Route::post('editfrontmenu/:id', 'app\\admin\\controller\\FrontMenuController@editFrontMenu');
|
Route::post('editfrontmenu/:id', 'app\\admin\\controller\\Cms\\FrontMenu\\FrontMenuController@editFrontMenu');
|
||||||
Route::delete('deletefrontmenu/:id', 'app\\admin\\controller\\FrontMenuController@deleteFrontMenu');
|
Route::delete('deletefrontmenu/:id', 'app\\admin\\controller\\Cms\\FrontMenu\\FrontMenuController@deleteFrontMenu');
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use think\facade\Route;
|
|||||||
|
|
||||||
// 模块管理路由
|
// 模块管理路由
|
||||||
Route::get('modules/list', 'app\\admin\\controller\\ModulesController@getList');
|
Route::get('modules/list', 'app\\admin\\controller\\ModulesController@getList');
|
||||||
|
Route::get('modules/getTenantList', 'app\\admin\\controller\\ModulesController@getTenantList');
|
||||||
Route::get('modules/:id', 'app\\admin\\controller\\ModulesController@getDetail');
|
Route::get('modules/:id', 'app\\admin\\controller\\ModulesController@getDetail');
|
||||||
Route::post('modules', 'app\\admin\\controller\\ModulesController@add');
|
Route::post('modules', 'app\\admin\\controller\\ModulesController@add');
|
||||||
Route::put('modules/:id', 'app\\admin\\controller\\ModulesController@edit');
|
Route::put('modules/:id', 'app\\admin\\controller\\ModulesController@edit');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 单页路由
|
// 单页路由
|
||||||
Route::get('allonepages', 'app\\admin\\controller\\OnePageController@getAllOnePages');
|
Route::get('allonepages', 'app\\admin\\controller\\Cms\\OnePage\\OnePageController@getAllOnePages');
|
||||||
Route::post('createonepage', 'app\\admin\\controller\\OnePageController@createOnePage');
|
Route::post('createonepage', 'app\\admin\\controller\\Cms\\OnePage\\OnePageController@createOnePage');
|
||||||
Route::post('editonepage/:id', 'app\\admin\\controller\\OnePageController@editOnePage');
|
Route::post('editonepage/:id', 'app\\admin\\controller\\Cms\\OnePage\\OnePageController@editOnePage');
|
||||||
Route::delete('deleteonepage/:id', 'app\\admin\\controller\\OnePageController@deleteOnePage');
|
Route::delete('deleteonepage/:id', 'app\\admin\\controller\\Cms\\OnePage\\OnePageController@deleteOnePage');
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 特色产品路由
|
||||||
|
Route::get('productsList', 'app\admin\controller\Cms\Products\ProductsController@productsList');
|
||||||
|
Route::post('addProducts', 'app\admin\controller\Cms\Products\ProductsController@addProducts');
|
||||||
|
Route::put('editProducts/:id', 'app\admin\controller\Cms\Products\ProductsController@editProducts');
|
||||||
|
Route::delete('deleteProducts/:id', 'app\admin\controller\Cms\Products\ProductsController@deleteProducts');
|
||||||
|
|
||||||
|
// 产品分类
|
||||||
|
Route::get('productsTypesList', 'app\admin\controller\Cms\Products\ProductsTypesController@productsTypesList');
|
||||||
|
Route::post('addProductsTypes', 'app\admin\controller\Cms\Products\ProductsTypesController@addProductsTypes');
|
||||||
|
Route::put('editProductsTypes/:id', 'app\admin\controller\Cms\Products\ProductsTypesController@editProductsTypes');
|
||||||
|
Route::delete('deleteProductsTypes/:id', 'app\admin\controller\Cms\Products\ProductsTypesController@deleteProductsTypes');
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
use think\facade\Route;
|
use think\facade\Route;
|
||||||
|
|
||||||
// 角色路由
|
// 角色路由
|
||||||
Route::get('allRoles', 'app\\admin\\controller\\RoleController@getAllRoles');
|
Route::get('allRoles', 'app\\admin\\controller\\System\\RoleController@getAllRoles');
|
||||||
Route::get('roles/:id', 'app\\admin\\controller\\RoleController@getRoleById');
|
Route::get('roles/:id', 'app\\admin\\controller\\System\\RoleController@getRoleById');
|
||||||
Route::post('roles', 'app\\admin\\controller\\RoleController@createRole');
|
Route::post('roles', 'app\\admin\\controller\\System\\RoleController@createRole');
|
||||||
Route::put('roles/:id', 'app\\admin\\controller\\RoleController@updateRole');
|
Route::put('roles/:id', 'app\\admin\\controller\\System\\RoleController@updateRole');
|
||||||
Route::delete('roles/:id', 'app\\admin\\controller\\RoleController@deleteRole');
|
Route::delete('roles/:id', 'app\\admin\\controller\\System\\RoleController@deleteRole');
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 特色服务路由
|
||||||
|
Route::get('servicesList', 'app\admin\controller\Cms\Services\ServicesController@servicesList');
|
||||||
|
Route::post('addServices', 'app\admin\controller\Cms\Services\ServicesController@addServices');
|
||||||
|
Route::put('editServices/:id', 'app\admin\controller\Cms\Services\ServicesController@editServices');
|
||||||
|
Route::delete('deleteServices/:id', 'app\admin\controller\Cms\Services\ServicesController@deleteServices');
|
||||||
@@ -4,5 +4,11 @@ use think\facade\Route;
|
|||||||
// 站点设置路由
|
// 站点设置路由
|
||||||
Route::get('normalInfos', 'app\\admin\\controller\\SiteSettingsController@getNormalInfos');
|
Route::get('normalInfos', 'app\\admin\\controller\\SiteSettingsController@getNormalInfos');
|
||||||
Route::post('saveNormalInfos', 'app\\admin\\controller\\SiteSettingsController@saveNormalInfos');
|
Route::post('saveNormalInfos', 'app\\admin\\controller\\SiteSettingsController@saveNormalInfos');
|
||||||
|
Route::get('loginVerifyInfos', 'app\\admin\\controller\\SiteSettingsController@getVerifyInfos');
|
||||||
|
Route::post('saveloginVerifyInfos', 'app\\admin\\controller\\SiteSettingsController@saveVerifyInfos');
|
||||||
Route::get('legalInfos', 'app\\admin\\controller\\SiteSettingsController@getLegalInfos');
|
Route::get('legalInfos', 'app\\admin\\controller\\SiteSettingsController@getLegalInfos');
|
||||||
Route::post('saveLegalInfos', 'app\\admin\\controller\\SiteSettingsController@saveLegalInfos');
|
Route::post('saveLegalInfos', 'app\\admin\\controller\\SiteSettingsController@saveLegalInfos');
|
||||||
|
Route::get('companyInfos', 'app\\admin\\controller\\SiteSettingsController@getCompanyInfos');
|
||||||
|
Route::post('saveCompanyInfos', 'app\\admin\\controller\\SiteSettingsController@saveCompanyInfos');
|
||||||
|
Route::get('companySeo', 'app\\admin\\controller\\SiteSettingsController@getCompanySeo');
|
||||||
|
Route::post('saveCompanySeo', 'app\\admin\\controller\\SiteSettingsController@saveCompanySeo');
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 短信管理路由
|
||||||
|
Route::group('sms', function () {
|
||||||
|
// 获取短信网关配置
|
||||||
|
Route::get('info', 'app\\admin\\controller\\System\\SmsController@getSmsInfo');
|
||||||
|
|
||||||
|
// 编辑短信网关配置
|
||||||
|
Route::post('editinfo', 'app\\admin\\controller\\System\\SmsController@editSmsInfo');
|
||||||
|
|
||||||
|
// 发送测试短信(入队任务)
|
||||||
|
Route::post('sendtest', 'app\\admin\\controller\\System\\SmsController@sendTestSms');
|
||||||
|
|
||||||
|
// Android 网关轮询待发送任务
|
||||||
|
Route::post('gateway/poll', 'app\\admin\\controller\\System\\SmsController@gatewayPoll');
|
||||||
|
// 兼容:如果网关端只请求 poll(不带 gateway)
|
||||||
|
Route::post('poll', 'app\\admin\\controller\\System\\SmsController@gatewayPoll');
|
||||||
|
Route::get('poll', 'app\\admin\\controller\\System\\SmsController@gatewayPoll');
|
||||||
|
|
||||||
|
// Android 网关上报短信内容(解析验证码)
|
||||||
|
Route::post('gateway/report', 'app\\admin\\controller\\System\\SmsController@gatewayReport');
|
||||||
|
// 兼容:如果网关端只请求 report(不带 gateway)
|
||||||
|
Route::post('report', 'app\\admin\\controller\\System\\SmsController@gatewayReport');
|
||||||
|
|
||||||
|
// 管理员:短信任务列表(租户隔离)
|
||||||
|
Route::get('taskList', 'app\\admin\\controller\\System\\SmsController@getSmsTaskList');
|
||||||
|
|
||||||
|
// 管理员:编辑短信任务(租户隔离)
|
||||||
|
Route::post('taskEdit/:id', 'app\\admin\\controller\\System\\SmsController@editSmsTask');
|
||||||
|
});
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 租户管理路由
|
||||||
|
Route::group('tenant', function() {
|
||||||
|
Route::get('getTenant', 'app\admin\controller\Tenant\TenantController/getTenant');
|
||||||
|
Route::get('getTenantDetail/:id', 'app\admin\controller\Tenant\TenantController/getTenantDetail');
|
||||||
|
Route::post('createTenant', 'app\admin\controller\Tenant\TenantController/createTenant');
|
||||||
|
Route::post('editTenant/:id', 'app\admin\controller\Tenant\TenantController/editTenant');
|
||||||
|
Route::delete('deleteTenant/:id', 'app\admin\controller\Tenant\TenantController/deleteTenant');
|
||||||
|
Route::get('findTenantCode', 'app\admin\controller\Tenant\TenantController/findTenantCode');
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 模板管理路由
|
||||||
|
Route::get('theme', 'app\admin\controller\Cms\Theme\ThemeController@index');
|
||||||
|
Route::post('theme/switch', 'app\admin\controller\Cms\Theme\ThemeController@switch');
|
||||||
|
Route::get('theme/data', 'app\admin\controller\Cms\Theme\ThemeController@getData');
|
||||||
|
Route::post('theme/data', 'app\admin\controller\Cms\Theme\ThemeController@saveData');
|
||||||
@@ -11,7 +11,7 @@ use think\facade\Cache;
|
|||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use app\service\JwtService;
|
use app\service\JwtService;
|
||||||
|
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
use app\model\System\SystemSiteSettings;
|
use app\model\System\SystemSiteSettings;
|
||||||
|
|
||||||
class LoginController extends BaseController
|
class LoginController extends BaseController
|
||||||
@@ -80,7 +80,7 @@ class LoginController extends BaseController
|
|||||||
'id' => $user['id'],
|
'id' => $user['id'],
|
||||||
'account' => $user['account'],
|
'account' => $user['account'],
|
||||||
'name' => $user['name'],
|
'name' => $user['name'],
|
||||||
'tenant_id' => $user['tenant_id'],
|
'tid' => $user['tid'],
|
||||||
'group_id' => $user['group_id']
|
'group_id' => $user['group_id']
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use think\facade\Db;
|
|||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
use app\model\AdminUser;
|
use app\model\System\AdminUser;
|
||||||
|
|
||||||
class UserController extends BaseController
|
class UserController extends BaseController
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
use think\facade\Route;
|
||||||
|
|
||||||
|
// 模板相关路由
|
||||||
|
Route::get('theme', 'app\admin\controller\ThemeController@index');
|
||||||
|
Route::post('theme/switch', 'app\admin\controller\ThemeController@switch');
|
||||||
|
Route::get('theme/data', 'app\admin\controller\ThemeController@getData');
|
||||||
|
Route::post('theme/data', 'app\admin\controller\ThemeController@saveData');
|
||||||
@@ -15,47 +15,21 @@ class AllowCrossDomain
|
|||||||
{
|
{
|
||||||
$origin = $request->header('origin', '');
|
$origin = $request->header('origin', '');
|
||||||
|
|
||||||
$allowedDomains = [
|
// 允许所有来源(生产环境建议限制具体域名)
|
||||||
'http://localhost:3000',
|
$header['Access-Control-Allow-Origin'] = $origin ?: '*';
|
||||||
'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'] = '*';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->method() === 'OPTIONS') {
|
if ($request->method() === 'OPTIONS') {
|
||||||
$header['Access-Control-Allow-Credentials'] = 'true';
|
$header['Access-Control-Allow-Credentials'] = 'true';
|
||||||
$header['Access-Control-Max-Age'] = 1800;
|
$header['Access-Control-Max-Age'] = 1800;
|
||||||
$header['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS';
|
$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);
|
return response('', 200, $header);
|
||||||
}
|
}
|
||||||
|
|
||||||
$header['Access-Control-Allow-Credentials'] = 'true';
|
$header['Access-Control-Allow-Credentials'] = 'true';
|
||||||
$header['Access-Control-Max-Age'] = 1800;
|
$header['Access-Control-Max-Age'] = 1800;
|
||||||
$header['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS';
|
$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);
|
return $next($request)->header($header);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\common\middleware;
|
||||||
|
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 域名解析中间件
|
||||||
|
* 通过访问域名自动识别租户
|
||||||
|
*/
|
||||||
|
class DomainParse
|
||||||
|
{
|
||||||
|
public function handle(Request $request, \Closure $next)
|
||||||
|
{
|
||||||
|
$host = $request->host(true); // 获取完整域名,不带端口
|
||||||
|
|
||||||
|
// 你的后台/平台域名(排除,不走租户逻辑)
|
||||||
|
$adminDomains = ['back.yunzer.cn', 'api.yunzer.cn'];
|
||||||
|
$platformDomains = ['www.yunzer.cn', 'yunzer.cn'];
|
||||||
|
|
||||||
|
// 后台/平台/API域名,直接放行
|
||||||
|
if (in_array($host, $adminDomains) || in_array($host, $platformDomains)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析域名(兼容 yunzer.com.cn/dh2.fun)
|
||||||
|
$domainParts = explode('.', $host);
|
||||||
|
$allowMainDomains = ['yunzer.com.cn', 'dh2.fun'];
|
||||||
|
$mainDomain = '';
|
||||||
|
|
||||||
|
foreach ($allowMainDomains as $domain) {
|
||||||
|
$domainLen = count(explode('.', $domain));
|
||||||
|
$currentLen = count($domainParts);
|
||||||
|
if ($currentLen > $domainLen) {
|
||||||
|
$matchMain = implode('.', array_slice($domainParts, -$domainLen));
|
||||||
|
if ($matchMain === $domain) {
|
||||||
|
$mainDomain = $matchMain;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非租户主域名,放行(走API默认界面,可改为跳转到平台)
|
||||||
|
if (empty($mainDomain)) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询租户域名绑定记录
|
||||||
|
$tenantDomain = Db::name('mete_tenant_domain')
|
||||||
|
->where('full_domain', $host)
|
||||||
|
->where('status', 1)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if ($tenantDomain) {
|
||||||
|
// 1. 写入租户ID到请求(核心,后续所有逻辑都能获取)
|
||||||
|
$request->tenantId = $tenantDomain['tid'];
|
||||||
|
$request->header('X-Tenant-Id', (string)$tenantDomain['tid']);
|
||||||
|
|
||||||
|
// 2. 额外:写入租户域名信息,方便模板使用
|
||||||
|
$request->tenantDomain = $host;
|
||||||
|
$request->tenantMainDomain = $mainDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use think\App;
|
|||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
use think\Validate;
|
use think\Validate;
|
||||||
use think\Request;
|
use think\Request;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
// 在控制器方法中添加
|
// 在控制器方法中添加
|
||||||
header('Access-Control-Allow-Origin: *');
|
header('Access-Control-Allow-Origin: *');
|
||||||
@@ -44,6 +45,12 @@ abstract class BaseController
|
|||||||
*/
|
*/
|
||||||
protected $middleware = [];
|
protected $middleware = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前租户ID
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $tenantId = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造方法
|
* 构造方法
|
||||||
* @access public
|
* @access public
|
||||||
@@ -59,7 +66,65 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据域名获取租户ID(静态方法,方便全局调用)
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function getTenantIdByDomain(string $baseUrl): int
|
||||||
|
{
|
||||||
|
|
||||||
|
// 查询域名对应的租户ID
|
||||||
|
$tenantDomain = Db::name('mete_tenant_domain')
|
||||||
|
->where('full_domain', $baseUrl)
|
||||||
|
->where('status', 1)
|
||||||
|
->whereNull('delete_time')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
return $tenantDomain ? (int)$tenantDomain['tid'] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证数据
|
* 验证数据
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ declare(strict_types=1);
|
|||||||
namespace app\index\controller\Article;
|
namespace app\index\controller\Article;
|
||||||
|
|
||||||
use app\index\BaseController;
|
use app\index\BaseController;
|
||||||
use app\model\Articles;
|
|
||||||
use app\model\ArticlesCategory;
|
|
||||||
use Symfony\Component\VarDumper\VarDumper;
|
use Symfony\Component\VarDumper\VarDumper;
|
||||||
use think\exception\ValidateException;
|
use think\exception\ValidateException;
|
||||||
use think\facade\Request;
|
use think\facade\Request;
|
||||||
use think\facade\Session;
|
use think\facade\Session;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
|
use app\model\Cms\Articles;
|
||||||
|
use app\model\Cms\ArticlesCategory;
|
||||||
|
|
||||||
class ArticleController extends BaseController
|
class ArticleController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -102,6 +102,44 @@ class ArticleController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文章分类列表(mete_articles_category:当前租户 tid、启用状态)
|
||||||
|
* 支持 baseUrl=租户前台域名,与 getCenterNews 一致,便于 api 域名跨域调用时解析 tid
|
||||||
|
*
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getArticleCategories(): Json
|
||||||
|
{
|
||||||
|
$baseUrl = $this->request->get('baseUrl', '');
|
||||||
|
if (!empty($baseUrl)) {
|
||||||
|
$this->tenantId = BaseController::getTenantIdByDomain($baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
if (empty($tid)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '无法识别租户信息',
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$articleCategories = ArticlesCategory::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('status', 1)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->order('id', 'asc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => $articleCategories,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游客文章阅读量函数
|
* 游客文章阅读量函数
|
||||||
* @return Json
|
* @return Json
|
||||||
|
|||||||
@@ -12,348 +12,196 @@ use think\facade\Session;
|
|||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
|
|
||||||
use app\model\Articles;
|
use app\model\Cms\Articles;
|
||||||
use app\model\ArticlesCategory;
|
use app\model\Cms\ArticlesCategory;
|
||||||
|
use tidy;
|
||||||
|
|
||||||
class NewsCenterController extends BaseController
|
class NewsCenterController extends BaseController
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 根据分类获取文章
|
* 根据域名获取新闻数据
|
||||||
* @param string $category 分类名称
|
*
|
||||||
|
* 返回字段:list 列表;total 当前租户下已发布新闻总数;count 当前筛选(全部或 cate)下的条数,翻页按 count 与 page_size。
|
||||||
|
*
|
||||||
* @return Json
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getNewsByCategory(string $category): Json
|
public function getCenterNews(): Json
|
||||||
{
|
{
|
||||||
// 查询分类
|
$baseUrl = (string) $this->request->param('baseUrl', '');
|
||||||
$categoryInfo = ArticlesCategory::where('name', $category)
|
|
||||||
->where('delete_time', null)
|
|
||||||
->find();
|
|
||||||
|
|
||||||
if (!$categoryInfo) {
|
if ($baseUrl !== '') {
|
||||||
|
$this->tenantId = BaseController::getTenantIdByDomain($baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
if (empty($tid)) {
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 400,
|
||||||
'msg' => 'success',
|
'msg' => '无法识别租户信息',
|
||||||
'list' => [],
|
'list' => [],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询文章
|
// param 合并 GET,避免个别环境下仅 get 取不到查询串
|
||||||
$articles = Articles::published()
|
$cateId = (int) $this->request->param('cate', 0);
|
||||||
->where('cate', $categoryInfo['id'])
|
$listPage = (int) $this->request->param('page', 0);
|
||||||
->order('publish_date', 'desc')
|
$pageSizeReq = (int) $this->request->param('page_size', 0);
|
||||||
->limit(4)
|
|
||||||
->select();
|
|
||||||
|
|
||||||
return json([
|
// 点击左侧分类:文章 cate 可能挂在子分类上,需包含「该分类 + 其下所有子分类」id
|
||||||
'code' => 200,
|
$categoryIdsForFilter = [];
|
||||||
'msg' => 'success',
|
if ($cateId > 0) {
|
||||||
'list' => $articles,
|
$categoryIdsForFilter = $this->resolveCategoryBranchIds($cateId, $tid);
|
||||||
]);
|
if ($categoryIdsForFilter === []) {
|
||||||
}
|
$categoryIdsForFilter = [$cateId];
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取企业新闻
|
|
||||||
* @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');
|
|
||||||
|
|
||||||
foreach ($articles as &$article) {
|
|
||||||
if (empty($article['image']) && isset($categoryImages[$article['cate']])) {
|
|
||||||
$article['image'] = $categoryImages[$article['cate']];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$baseQuery = static function () use ($tid, $cateId, $categoryIdsForFilter) {
|
||||||
|
$q = Articles::published()
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null);
|
||||||
|
if ($cateId > 0 && $categoryIdsForFilter !== []) {
|
||||||
|
$q->whereIn('cate', $categoryIdsForFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $q;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当前租户下「全部」已发布新闻数(不受 cate 筛选影响)
|
||||||
|
$totalTenantNews = (int) Articles::published()
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
// 当前列表条件下的总数:tid +(可选)cate,用于翻页总页数 = ceil(count / page_size)
|
||||||
|
$countFiltered = (int) $baseQuery()->count();
|
||||||
|
|
||||||
|
$useListPagination = $listPage > 0 && $pageSizeReq > 0;
|
||||||
|
|
||||||
|
if ($useListPagination) {
|
||||||
|
// 新闻中心列表页:服务端分页;不要用查询参数名 page,避免与路由占位符冲突
|
||||||
|
$pageSizeReq = max(1, min($pageSizeReq, 50));
|
||||||
|
$listPage = max(1, $listPage);
|
||||||
|
$articles = $baseQuery()
|
||||||
|
->order('publish_date', 'desc')
|
||||||
|
->page($listPage, $pageSizeReq)
|
||||||
|
->select();
|
||||||
|
} else {
|
||||||
|
// 首页等:按 limit 取前 N 条(默认 8)
|
||||||
|
$limit = (int) $this->request->param('limit', 8);
|
||||||
|
if ($limit < 1) {
|
||||||
|
$limit = 8;
|
||||||
|
}
|
||||||
|
if ($limit > 200) {
|
||||||
|
$limit = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
$articles = $baseQuery()
|
||||||
|
->order('publish_date', 'desc')
|
||||||
|
->limit($limit)
|
||||||
|
->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片:如果文章 image 为空,则取分类的 image
|
||||||
|
foreach ($articles as &$article) {
|
||||||
|
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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($article);
|
||||||
|
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => 'success',
|
'msg' => 'success',
|
||||||
'list' => $articles,
|
'list' => $articles,
|
||||||
'total' => $total,
|
// 当前租户下新闻总条数(全部状态为已发布)
|
||||||
'page' => $page,
|
'total' => $totalTenantNews,
|
||||||
'limit' => $limit,
|
// 当前筛选(全部或某分类)下的条数,列表翻页按 count 与 page_size 计算
|
||||||
|
'count' => $countFiltered,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一空返回
|
* 解析分类筛选用的 id 列表:自身 + mete_articles_category 中 cid=该 id 的所有子孙(同 tid、未删除)
|
||||||
*/
|
*/
|
||||||
private function emptyResponse($page, $limit): Json
|
private function resolveCategoryBranchIds(int $rootId, int $tid): array
|
||||||
{
|
{
|
||||||
return json([
|
if ($rootId <= 0 || $tid <= 0) {
|
||||||
'code' => 200,
|
return [];
|
||||||
'msg' => 'success',
|
}
|
||||||
'list' => [],
|
|
||||||
'total' => 0,
|
$root = ArticlesCategory::where('id', $rootId)
|
||||||
'page' => $page,
|
->where('tid', $tid)
|
||||||
'limit' => $limit,
|
->where('delete_time', null)
|
||||||
]);
|
->find();
|
||||||
|
if (!$root) {
|
||||||
|
return [$rootId];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [$rootId];
|
||||||
|
$queue = [$rootId];
|
||||||
|
while ($queue !== []) {
|
||||||
|
$pid = array_shift($queue);
|
||||||
|
$children = ArticlesCategory::where('cid', $pid)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->column('id');
|
||||||
|
foreach ($children as $id) {
|
||||||
|
$id = (int) $id;
|
||||||
|
if ($id > 0 && !in_array($id, $ids, true)) {
|
||||||
|
$ids[] = $id;
|
||||||
|
$queue[] = $id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取金蝶新闻详情
|
* 获取新闻详情
|
||||||
|
* @param int $id 文章ID
|
||||||
|
* @return Json
|
||||||
*/
|
*/
|
||||||
public function getKingdeeNewsDetail(int $id): Json
|
public function getNewsDetail(int $id): Json
|
||||||
{
|
{
|
||||||
$article = Articles::where('id', $id)
|
try {
|
||||||
->where('delete_time', null)
|
$baseUrl = $this->request->get('baseUrl', '');
|
||||||
->where('status', 2)
|
if (!empty($baseUrl)) {
|
||||||
->field('id,title,cate,image,desc,author,content,publisher,publish_date,views,likes,is_trans,transurl')
|
$this->tenantId = BaseController::getTenantIdByDomain($baseUrl);
|
||||||
->find();
|
}
|
||||||
|
|
||||||
if (!$article) {
|
$tid = $this->getTenantId();
|
||||||
return json(['code' => 404, 'msg' => '文章不存在', 'data' => null]);
|
$query = Articles::published()->where('id', $id);
|
||||||
|
if ($tid > 0) {
|
||||||
|
$query->where('tid', $tid);
|
||||||
|
}
|
||||||
|
$article = $query->find();
|
||||||
|
if (!$article) {
|
||||||
|
return json([
|
||||||
|
'code' => 404,
|
||||||
|
'msg' => '文章不存在',
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => $article,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return json([
|
||||||
|
'code' => 500,
|
||||||
|
'msg' => '获取新闻详情失败:' . $e->getMessage(),
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\index\controller;
|
||||||
|
|
||||||
|
use app\index\BaseController;
|
||||||
|
use think\response\Json;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Banner 控制器
|
||||||
|
*/
|
||||||
|
class BannerController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取 Banner 列表
|
||||||
|
* @return Json
|
||||||
|
*/
|
||||||
|
public function getBanners()
|
||||||
|
{
|
||||||
|
$baseUrl = $this->request->get('baseUrl', '');
|
||||||
|
|
||||||
|
if (!empty($baseUrl)) {
|
||||||
|
$this->tenantId = BaseController::getTenantIdByDomain($baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tid = $this->getTenantId();
|
||||||
|
|
||||||
|
if (empty($tid)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '无法识别租户信息',
|
||||||
|
'list' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询该租户下的 Banner
|
||||||
|
$banners = Db::name('mete_apps_cms_banner')
|
||||||
|
->where('tid', $tid)
|
||||||
|
->whereNull('delete_time')
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->order('id', 'desc')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 处理图片路径
|
||||||
|
foreach ($banners as &$banner) {
|
||||||
|
if (!empty($banner['image'])) {
|
||||||
|
// 如果图片路径已经是完整 URL,直接返回
|
||||||
|
if (!preg_match('/^https?:\/\//', $banner['image'])) {
|
||||||
|
// 拼接完整 URL
|
||||||
|
$banner['image'] = $this->request->scheme() . '://' . $this->request->host() .
|
||||||
|
(strpos($banner['image'], '/') === 0 ? '' : '/') . $banner['image'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'list' => $banners,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
+415
-10
@@ -6,19 +6,368 @@ namespace app\index\controller;
|
|||||||
|
|
||||||
use app\model\Banner;
|
use app\model\Banner;
|
||||||
use app\index\BaseController;
|
use app\index\BaseController;
|
||||||
use app\model\FrontMenu;
|
use app\model\Cms\FrontMenu;
|
||||||
use app\model\OnePage;
|
use app\model\Cms\OnePage;
|
||||||
|
use app\model\System\SystemSiteSetting;
|
||||||
|
use app\service\ThemeService;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use think\facade\Env;
|
use think\facade\Env;
|
||||||
use app\model\System\SystemSiteSettings;
|
use think\facade\Request;
|
||||||
|
use app\model\Cms\TemplateSiteConfig;
|
||||||
|
use app\model\Cms\Friendlink;
|
||||||
|
use app\model\Cms\Services;
|
||||||
|
use app\model\Cms\Products;
|
||||||
|
use app\model\Tenant\Tenant;
|
||||||
|
use app\model\Cms\Articles;
|
||||||
|
use app\model\Cms\ArticlesCategory;
|
||||||
|
|
||||||
class Index extends BaseController
|
class Index extends BaseController
|
||||||
{
|
{
|
||||||
|
private ThemeService $themeService;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->themeService = new ThemeService();
|
||||||
|
}
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
// 获取请求对象
|
||||||
|
$request = $this->request ?? Request::instance();
|
||||||
|
|
||||||
|
// 优先从请求对象获取中间件设置的租户ID(通过域名解析)
|
||||||
|
$tid = $request->tenantId ?? 0;
|
||||||
|
|
||||||
|
// 兼容:从header获取
|
||||||
|
if ($tid == 0) {
|
||||||
|
$headerTid = $request->header('X-Tenant-Id');
|
||||||
|
$tid = $headerTid ? (int) $headerTid : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调试:检查tid
|
||||||
|
if ($tid === 0) {
|
||||||
|
die('tenantId未获取到,请检查域名解析');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取租户选择的模板
|
||||||
|
$themeKey = 'default';
|
||||||
|
if ($tid > 0) {
|
||||||
|
// 不使用软删除过滤
|
||||||
|
$config = TemplateSiteConfig::where('tid', $tid)
|
||||||
|
->where('key', 'current_theme')
|
||||||
|
->withoutField('delete_time')
|
||||||
|
->find();
|
||||||
|
$themeKey = $config['value'] ?? 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板路径:/themes/{theme_key}/,优先使用index.php,其次index.html
|
||||||
|
$themeBasePath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $themeKey;
|
||||||
|
$themeUrlPath = '/themes/' . $themeKey . '/';
|
||||||
|
|
||||||
|
if (is_file($themeBasePath . DIRECTORY_SEPARATOR . 'index.php')) {
|
||||||
|
// 渲染PHP模板(直接include)
|
||||||
|
return $this->renderPhpTemplate($themeBasePath . DIRECTORY_SEPARATOR . 'index.php', $themeUrlPath);
|
||||||
|
} elseif (is_file($themeBasePath . DIRECTORY_SEPARATOR . 'index.html')) {
|
||||||
|
// 读取HTML模板内容
|
||||||
|
$content = file_get_contents($themeBasePath . DIRECTORY_SEPARATOR . 'index.html');
|
||||||
|
// 修复资源路径:将相对路径转换为绝对路径
|
||||||
|
$content = $this->fixTemplateAssets($content, $themeUrlPath);
|
||||||
|
return response($content, 200, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板不存在,返回默认
|
||||||
return view('index/index');
|
return view('index/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用页面渲染
|
||||||
|
* 根据页面名称(如 about, blog, portfolio 等)渲染对应模板
|
||||||
|
* @param string $page 页面名称
|
||||||
|
* @return \think\response|\think\response\View
|
||||||
|
*/
|
||||||
|
public function page(string $page = 'index')
|
||||||
|
{
|
||||||
|
$request = $this->request ?? Request::instance();
|
||||||
|
|
||||||
|
// 获取租户ID
|
||||||
|
$tid = $request->tenantId ?? 0;
|
||||||
|
if ($tid == 0) {
|
||||||
|
$headerTid = $request->header('X-Tenant-Id');
|
||||||
|
$tid = $headerTid ? (int) $headerTid : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tid === 0) {
|
||||||
|
die('tenantId未获取到,请检查域名解析');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取租户选择的模板
|
||||||
|
$themeKey = 'default';
|
||||||
|
if ($tid > 0) {
|
||||||
|
$config = TemplateSiteConfig::where('tid', $tid)
|
||||||
|
->where('key', 'current_theme')
|
||||||
|
->withoutField('delete_time')
|
||||||
|
->find();
|
||||||
|
$themeKey = $config['value'] ?? 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板路径
|
||||||
|
$themeBasePath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $themeKey;
|
||||||
|
$themeUrlPath = '/themes/' . $themeKey . '/';
|
||||||
|
|
||||||
|
// 安全检查:只允许字母、数字、中划线
|
||||||
|
$page = preg_replace('/[^a-zA-Z0-9\-]/', '', $page);
|
||||||
|
if (empty($page)) {
|
||||||
|
$page = 'index';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找 PHP 模板(优先)或 HTML 模板
|
||||||
|
$templateFile = $themeBasePath . DIRECTORY_SEPARATOR . $page . '.php';
|
||||||
|
$templateHtmlFile = $themeBasePath . DIRECTORY_SEPARATOR . $page . '.html';
|
||||||
|
|
||||||
|
if (is_file($templateFile)) {
|
||||||
|
return $this->renderPhpTemplate($templateFile, $themeUrlPath);
|
||||||
|
} elseif (is_file($templateHtmlFile)) {
|
||||||
|
$content = file_get_contents($templateHtmlFile);
|
||||||
|
$content = $this->fixTemplateAssets($content, $themeUrlPath);
|
||||||
|
return response($content, 200, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板不存在
|
||||||
|
return response('页面不存在', 404, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章详情页
|
||||||
|
* @param int $id 文章ID
|
||||||
|
* @return \think\response
|
||||||
|
*/
|
||||||
|
public function articleDetail(int $id = 0)
|
||||||
|
{
|
||||||
|
$request = $this->request ?? Request::instance();
|
||||||
|
|
||||||
|
// 获取租户ID
|
||||||
|
$tid = $request->tenantId ?? 0;
|
||||||
|
if ($tid == 0) {
|
||||||
|
$headerTid = $request->header('X-Tenant-Id');
|
||||||
|
$tid = $headerTid ? (int) $headerTid : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tid === 0) {
|
||||||
|
die('tenantId未获取到,请检查域名解析');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 与 NewsCenterController::getNewsDetail 一致:已发布 + 当前租户(网页直出,非 JSON)
|
||||||
|
$templateVars = $this->buildArticleDetailTemplateVars($id, $tid);
|
||||||
|
if ($templateVars === null) {
|
||||||
|
return response('文章不存在', 404, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取租户选择的模板
|
||||||
|
$themeKey = 'default';
|
||||||
|
if ($tid > 0) {
|
||||||
|
$config = TemplateSiteConfig::where('tid', $tid)
|
||||||
|
->where('key', 'current_theme')
|
||||||
|
->withoutField('delete_time')
|
||||||
|
->find();
|
||||||
|
$themeKey = $config['value'] ?? 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板路径
|
||||||
|
$themeBasePath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $themeKey;
|
||||||
|
$themeUrlPath = '/themes/' . $themeKey . '/';
|
||||||
|
|
||||||
|
// 查找文章详情模板
|
||||||
|
$templateFile = $themeBasePath . DIRECTORY_SEPARATOR . 'article_detail.php';
|
||||||
|
$templateHtmlFile = $themeBasePath . DIRECTORY_SEPARATOR . 'article_detail.html';
|
||||||
|
$blogDetailsFile = $themeBasePath . DIRECTORY_SEPARATOR . 'blog-details.php';
|
||||||
|
$blogDetailsHtmlFile = $themeBasePath . DIRECTORY_SEPARATOR . 'blog-details.html';
|
||||||
|
|
||||||
|
// 优先使用 article_detail 模板
|
||||||
|
if (is_file($templateFile)) {
|
||||||
|
return $this->renderPhpTemplate($templateFile, $themeUrlPath, $templateVars);
|
||||||
|
} elseif (is_file($templateHtmlFile)) {
|
||||||
|
$content = file_get_contents($templateHtmlFile);
|
||||||
|
$content = $this->fixTemplateAssets($content, $themeUrlPath);
|
||||||
|
return response($content, 200, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
} elseif (is_file($blogDetailsFile)) {
|
||||||
|
return $this->renderPhpTemplate($blogDetailsFile, $themeUrlPath, $templateVars);
|
||||||
|
} elseif (is_file($blogDetailsHtmlFile)) {
|
||||||
|
$content = file_get_contents($blogDetailsHtmlFile);
|
||||||
|
$content = $this->fixTemplateAssets($content, $themeUrlPath);
|
||||||
|
return response($content, 200, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response('文章不存在', 404, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装文章详情页模板变量(数据源与 getNewsDetail 一致,并限定租户 + 已发布)
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>|null
|
||||||
|
*/
|
||||||
|
private function buildArticleDetailTemplateVars(int $id, int $tid): ?array
|
||||||
|
{
|
||||||
|
$article = Articles::published()
|
||||||
|
->where('id', $id)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (!$article) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = $article->toArray();
|
||||||
|
|
||||||
|
$categoryName = '未分类';
|
||||||
|
if (!empty($row['cate'])) {
|
||||||
|
$cat = ArticlesCategory::where('id', $row['cate'])
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if ($cat) {
|
||||||
|
$categoryName = (string) $cat['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$coverPath = $row['image'] ?? '';
|
||||||
|
if ($coverPath === '' && !empty($row['cate'])) {
|
||||||
|
$category = ArticlesCategory::where('id', $row['cate'])
|
||||||
|
->where('delete_time', null)
|
||||||
|
->find();
|
||||||
|
if ($category && !empty($category['image'])) {
|
||||||
|
$coverPath = (string) $category['image'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiUrl = rtrim((string) (Env::get('app.api_url', '') ?: 'https://api.yunzer.cn'), '/');
|
||||||
|
$articleCoverUrl = $this->resolveArticleMediaUrl($coverPath, $apiUrl);
|
||||||
|
|
||||||
|
$descPlain = strip_tags((string) ($row['desc'] ?? ''));
|
||||||
|
$title = (string) ($row['title'] ?? '详情');
|
||||||
|
$descShort = $descPlain !== ''
|
||||||
|
? (function_exists('mb_substr') ? mb_substr($descPlain, 0, 160) : substr($descPlain, 0, 160))
|
||||||
|
: $title;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'article' => $row,
|
||||||
|
'articleCoverUrl' => $articleCoverUrl,
|
||||||
|
'articleCategoryName' => $categoryName,
|
||||||
|
'pageTitle' => $title . ' - 新闻详情',
|
||||||
|
'pageDescription' => $descShort,
|
||||||
|
'pageKeywords' => $title,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章封面等资源 URL(与列表页逻辑一致:相对路径拼 API 域名)
|
||||||
|
*/
|
||||||
|
private function resolveArticleMediaUrl(string $path, string $apiUrl): string
|
||||||
|
{
|
||||||
|
if ($path === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (strpos($path, 'http://') === 0 || strpos($path, 'https://') === 0) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
if (strpos($path, '/') === 0) {
|
||||||
|
return $apiUrl . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $apiUrl . '/' . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修复模板中的资源路径
|
||||||
|
* 将相对路径 (assets/, css/, js/, images/) 转换为绝对路径 (/themes/xxx/)
|
||||||
|
*/
|
||||||
|
private function fixTemplateAssets(string $content, string $themeUrlPath): string
|
||||||
|
{
|
||||||
|
// 需要修复的资源目录
|
||||||
|
$assetsDirs = ['assets', 'css', 'js', 'images', 'img', 'fonts', 'plugins', 'libs'];
|
||||||
|
|
||||||
|
foreach ($assetsDirs as $dir) {
|
||||||
|
// 匹配 src="assets/..." 或 href="css/..." 等相对路径
|
||||||
|
// 不匹配已以 / 开头的绝对路径
|
||||||
|
$content = preg_replace(
|
||||||
|
'/(src|href)=["\'](' . $dir . '\/[^"\']*)["\']/',
|
||||||
|
'$1="' . $themeUrlPath . '$2"',
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
// 匹配 src='assets/...'
|
||||||
|
$content = preg_replace(
|
||||||
|
'/(src|href)=[\']([^\/][^\'\"]*\/[^\'\"]*)[\']/',
|
||||||
|
'$1="' . $themeUrlPath . '$2"',
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渲染PHP模板文件
|
||||||
|
*/
|
||||||
|
private function renderPhpTemplate(string $templateFile, string $themeUrlPath = '', array $templateVars = [])
|
||||||
|
{
|
||||||
|
// 定义模板基础URL常量,供模板使用
|
||||||
|
if (!defined('THEME_URL')) {
|
||||||
|
define('THEME_URL', $themeUrlPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
// 获取URL参数
|
||||||
|
$getParams = Request::get();
|
||||||
|
extract($getParams, EXTR_OVERWRITE);
|
||||||
|
extract($templateVars, EXTR_OVERWRITE);
|
||||||
|
include $templateFile;
|
||||||
|
$content = ob_get_clean();
|
||||||
|
|
||||||
|
// 修复PHP模板输出中的资源路径
|
||||||
|
$content = $this->fixTemplateAssets($content, $themeUrlPath);
|
||||||
|
|
||||||
|
return response($content, 200, ['Content-Type' => 'text/html; charset=utf-8']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前端初始化接口 - 返回当前模板和填充数据
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
// 优先从请求对象获取中间件设置的租户ID(通过域名解析)
|
||||||
|
$tid = $this->request->tenantId ?? 0;
|
||||||
|
|
||||||
|
// 兼容:URL参数传递的tid作为备用
|
||||||
|
$tid = $tid > 0 ? $tid : Request::param('tid', 0, 'int');
|
||||||
|
|
||||||
|
// 从TemplateSiteConfig获取配置(根据租户ID)
|
||||||
|
$config = null;
|
||||||
|
if ($tid > 0) {
|
||||||
|
$config = TemplateSiteConfig::where('tid', $tid)
|
||||||
|
->where('key', 'current_theme')
|
||||||
|
->find();
|
||||||
|
}
|
||||||
|
|
||||||
|
$themeKey = $config['value'] ?? 'default';
|
||||||
|
|
||||||
|
// 模板路径:/themes/{theme_key}/,优先使用index.php,其次index.html
|
||||||
|
$themeBasePath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $themeKey;
|
||||||
|
|
||||||
|
if (is_file($themeBasePath . DIRECTORY_SEPARATOR . 'index.php')) {
|
||||||
|
$themePath = '/themes/' . $themeKey . '/index.php';
|
||||||
|
} else {
|
||||||
|
$themePath = '/themes/' . $themeKey . '/index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 200,
|
||||||
|
'msg' => 'success',
|
||||||
|
'data' => [
|
||||||
|
'theme_key' => $themeKey,
|
||||||
|
'theme_path' => $themePath
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取日志列表
|
* 获取日志列表
|
||||||
*/
|
*/
|
||||||
@@ -177,26 +526,82 @@ class Index extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前端底部数据
|
* 获取首页综合数据
|
||||||
* @return \think\response\Json
|
* @return \think\response\Json
|
||||||
*/
|
*/
|
||||||
public function getFooterData()
|
public function getHomeData()
|
||||||
{
|
{
|
||||||
|
$baseUrl = Request::param('baseUrl', '');
|
||||||
|
|
||||||
|
if (empty($baseUrl)) {
|
||||||
|
return json(['code' => 400, 'msg' => '缺少 baseUrl 参数']);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$footerData = SystemSiteSettings::where('delete_time', null)
|
// 通过域名获取租户ID
|
||||||
->field('label, value')
|
$tid = BaseController::getTenantIdByDomain($baseUrl);
|
||||||
|
|
||||||
|
if (empty($tid)) {
|
||||||
|
return json([
|
||||||
|
'code' => 400,
|
||||||
|
'msg' => '无法识别租户信息',
|
||||||
|
'data' => []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取站点基础信息 (normalinfos)
|
||||||
|
$normalInfos = SystemSiteSetting::where('tid', $tid)
|
||||||
|
->field('sitename,logo,logow,ico,description,copyright,companyname,icp,companyintroduction')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// 获取特色服务列表
|
||||||
|
$servicesList = Services::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->field('id,title,desc,thumb,url')
|
||||||
->select()
|
->select()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
|
// 获取企业产品列表
|
||||||
|
$productsList = Products::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->field('id,title,desc,content,thumb,url')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 获取友情链接列表
|
||||||
|
$friendlinkList = Friendlink::where('delete_time', null)
|
||||||
|
->where('tid', $tid)
|
||||||
|
->where('status', 1)
|
||||||
|
->order('sort', 'asc')
|
||||||
|
->field('id,link_name,link_url,link_logo')
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// 获取联系方式
|
||||||
|
$contact = Tenant::where('id', $tid)
|
||||||
|
->where('status', 1)
|
||||||
|
->where('delete_time', null)
|
||||||
|
->field('contact_phone,contact_email,address,worktime')
|
||||||
|
->find();
|
||||||
|
|
||||||
|
// 合并返回
|
||||||
return json([
|
return json([
|
||||||
'code' => 200,
|
'code' => 200,
|
||||||
'msg' => 'success',
|
'msg' => 'success',
|
||||||
'data' => $footerData
|
'data' => [
|
||||||
|
'normal' => $normalInfos ?: (object) [],
|
||||||
|
'contact' => $contact ?: (object) [],
|
||||||
|
'services' => $servicesList,
|
||||||
|
'products' => $productsList,
|
||||||
|
'links' => $friendlinkList
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
} catch (DbException $e) {
|
} catch (\Exception $e) {
|
||||||
return json([
|
return json([
|
||||||
'code' => 500,
|
'code' => 500,
|
||||||
'msg' => 'fail:' . $e->getMessage(),
|
'msg' => '服务器错误:' . $e->getMessage(),
|
||||||
'data' => null
|
'data' => null
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
\app\common\middleware\AllowCrossDomain::class,
|
\app\common\middleware\AllowCrossDomain::class,
|
||||||
|
\app\common\middleware\DomainParse::class,
|
||||||
\think\middleware\SessionInit::class,
|
\think\middleware\SessionInit::class,
|
||||||
];
|
];
|
||||||
+22
-18
@@ -5,30 +5,34 @@ use think\facade\Route;
|
|||||||
Route::get('/', 'app\index\controller\Index@index');
|
Route::get('/', 'app\index\controller\Index@index');
|
||||||
Route::get('index/index', 'app\index\controller\Index@index');
|
Route::get('index/index', 'app\index\controller\Index@index');
|
||||||
|
|
||||||
// --- 前端底部数据路由 ---
|
// --- 模板通用页面路由 ---
|
||||||
|
Route::get('article_detail/:id', 'app\index\controller\Index@articleDetail');
|
||||||
|
Route::get(':page', 'app\index\controller\Index@page')
|
||||||
|
->pattern(['page' => 'about|blog|blog-details|contact|portfolio|portfolio-details|service-details|services|team|articles']);
|
||||||
|
|
||||||
|
// --- 模板初始化接口 ---
|
||||||
|
Route::get('init', 'app\index\controller\Index@init');
|
||||||
|
|
||||||
|
// --- Banner 路由 ---
|
||||||
|
Route::get('getBanners', 'app\index\controller\BannerController@getBanners');
|
||||||
|
|
||||||
|
// --- 前端其他数据路由 ---
|
||||||
Route::get('footerdata', 'app\index\controller\Index@getFooterData');
|
Route::get('footerdata', 'app\index\controller\Index@getFooterData');
|
||||||
|
Route::get('companyInfos', 'app\index\controller\Index@getCompanyInfos');
|
||||||
|
Route::post('requirement', 'app\index\controller\Index@requirement');
|
||||||
|
Route::get('homeData', 'app\index\controller\Index@getHomeData');
|
||||||
|
|
||||||
// --- 文章详情路由 ---
|
// --- 新闻中心列表路由 ---
|
||||||
Route::get('kingdeenews/detail/:id', 'app\index\controller\Article\NewsCenterController@getKingdeeNewsDetail');
|
Route::get('getCenterNews', 'app\index\controller\Article\NewsCenterController@getCenterNews');
|
||||||
Route::get('companynews/detail/:id', 'app\index\controller\Article\NewsCenterController@getCompanyNewsDetail');
|
Route::get('getNewsDetail/:id', 'app\index\controller\Article\NewsCenterController@getNewsDetail');
|
||||||
|
|
||||||
// --- 文章列表路由 ---
|
|
||||||
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('getArticleCategories', 'app\index\controller\Article\ArticleController@getArticleCategories');
|
||||||
|
|
||||||
|
// --- 新闻中心互动路由 ---
|
||||||
Route::post('articleViews/:id', 'app\index\controller\Article\ArticleController@articleViews');
|
Route::post('articleViews/:id', 'app\index\controller\Article\ArticleController@articleViews');
|
||||||
Route::post('articleLikes/:id', 'app\index\controller\Article\ArticleController@articleLikes');
|
Route::post('articleLikes/:id', 'app\index\controller\Article\ArticleController@articleLikes');
|
||||||
Route::post('articleUnlikes/:id', 'app\index\controller\Article\ArticleController@articleUnlikes');
|
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');
|
|
||||||
@@ -15,6 +15,7 @@ class AdminModules extends Model
|
|||||||
|
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'mid' => 'integer',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'code' => 'string',
|
'code' => 'string',
|
||||||
'path' => 'string',
|
'path' => 'string',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -36,6 +36,7 @@ class Articles extends Model
|
|||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'cate' => 'integer',
|
'cate' => 'integer',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -36,6 +36,11 @@ class ArticlesCategory extends Model
|
|||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'cid' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'name' => 'string',
|
||||||
|
'image' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -23,11 +23,12 @@ class Banner extends Model
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_banner';
|
protected $name = 'mete_apps_cms_banner';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'title' => 'string',
|
'title' => 'string',
|
||||||
'desc' => 'string',
|
'desc' => 'string',
|
||||||
'url' => 'string',
|
'url' => 'string',
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章分类模型
|
||||||
|
*/
|
||||||
|
class Demand extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_demand';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'title' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
|
'applicant' => 'string',
|
||||||
|
'phone' => 'string',
|
||||||
|
'status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -17,22 +17,22 @@ use think\model\concern\SoftDelete;
|
|||||||
/**
|
/**
|
||||||
* 文章分类模型
|
* 文章分类模型
|
||||||
*/
|
*/
|
||||||
class AdminUser extends Model
|
class DemandCategory extends Model
|
||||||
{
|
{
|
||||||
// 启用软删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_admin_user';
|
protected $name = 'mete_demand_category';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
'sex' => 'integer',
|
'title' => 'string',
|
||||||
'group_id' => 'integer',
|
'desc' => 'string',
|
||||||
'login_count' => 'integer',
|
'applicant' => 'string',
|
||||||
|
'phone' => 'string',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
'api_key_status' => 'integer',
|
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
'delete_time' => 'datetime',
|
'delete_time' => 'datetime',
|
||||||
@@ -40,3 +40,4 @@ class AdminUser extends Model
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章分类模型
|
||||||
|
*/
|
||||||
|
class Friendlink extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_friendlink';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'link_name' => 'string',
|
||||||
|
'link_url' => 'string',
|
||||||
|
'link_logo' => 'string',
|
||||||
|
'description' => 'string',
|
||||||
|
'sort' => 'integer',
|
||||||
|
'status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -23,16 +23,19 @@ class FrontMenu extends Model
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_front_menu';
|
protected $name = 'mete_apps_cms_front_menu';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
'pid' => 'integer',
|
'pid' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'title' => 'string',
|
'title' => 'string',
|
||||||
|
'image' => 'string',
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'path' => 'string',
|
'path' => 'string',
|
||||||
'component_path' => 'string',
|
'component_path' => 'string',
|
||||||
|
'sort' => 'integer',
|
||||||
'desc' => 'string',
|
'desc' => 'string',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\Cms;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -23,11 +23,12 @@ class OnePage extends Model
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_onepage';
|
protected $name = 'mete_apps_cms_onepage';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'title' => 'string',
|
'title' => 'string',
|
||||||
'content' => 'string',
|
'content' => 'string',
|
||||||
'path' => 'string',
|
'path' => 'string',
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特色服务模型
|
||||||
|
*/
|
||||||
|
class Products extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_products';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'title' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
|
'content' => 'string',
|
||||||
|
'thumb' => 'string',
|
||||||
|
'url' => 'string',
|
||||||
|
'sort' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特色服务模型
|
||||||
|
*/
|
||||||
|
class ProductsTypes extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_products_types';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'pid' => 'integer',
|
||||||
|
'title' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
|
'sort' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特色服务模型
|
||||||
|
*/
|
||||||
|
class Services extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_services';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'title' => 'string',
|
||||||
|
'desc' => 'string',
|
||||||
|
'thumb' => 'string',
|
||||||
|
'url' => 'string',
|
||||||
|
'sort' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网站模板模型
|
||||||
|
*/
|
||||||
|
class TemplateSiteConfig extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_template_site_config';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'key' => 'string',
|
||||||
|
'value' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Cms;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网站模板数据模型
|
||||||
|
*/
|
||||||
|
class TemplateThemeData extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_cms_template_theme_data';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'theme_key' => 'string',
|
||||||
|
'field_key' => 'string',
|
||||||
|
'field_value' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Erp;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工模型
|
||||||
|
*/
|
||||||
|
class Employee extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_apps_erp_employee';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'account' => 'string',
|
||||||
|
'password' => 'string',
|
||||||
|
'name' => 'string',
|
||||||
|
'gender' => 'integer',
|
||||||
|
'birthday' => 'date',
|
||||||
|
'affiliate_unit' => 'string',
|
||||||
|
'department' => 'string',
|
||||||
|
'position' => 'string',
|
||||||
|
'nation' => 'string',
|
||||||
|
'phone' => 'string',
|
||||||
|
'wechat' => 'string',
|
||||||
|
'email' => 'string',
|
||||||
|
'home_address' => 'string',
|
||||||
|
'account_status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -28,13 +28,14 @@ class Organization extends Model
|
|||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
'tenant_id' => 'integer',
|
'tid' => 'integer',
|
||||||
'org_name' => 'string',
|
'org_name' => 'string',
|
||||||
'org_code' => 'string',
|
'org_code' => 'string',
|
||||||
'parent_id' => 'integer',
|
'parent_id' => 'integer',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'leader_id' => 'integer',
|
'leader_id' => 'integer',
|
||||||
'remark' => 'string',
|
'remark' => 'string',
|
||||||
|
'is_company' => 'integer',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\System;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文章分类模型
|
||||||
|
*/
|
||||||
|
class AdminUser extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_admin_user';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'account' => 'string',
|
||||||
|
'password' => 'string',
|
||||||
|
'name' => 'string',
|
||||||
|
'birth' => 'date',
|
||||||
|
'phone' => 'string',
|
||||||
|
'email' => 'string',
|
||||||
|
'qq' => 'string',
|
||||||
|
'sex' => 'integer',
|
||||||
|
'avatar' => 'string',
|
||||||
|
'group_id' => 'integer',
|
||||||
|
'login_count' => 'integer',
|
||||||
|
'last_login_ip' => 'string',
|
||||||
|
'status' => 'integer',
|
||||||
|
'api_key' => 'string',
|
||||||
|
'api_key_expire' => 'datetime',
|
||||||
|
'api_key_status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\System;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -28,6 +28,7 @@ class AdminUserGroup extends Model
|
|||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
'rights' => 'string',
|
'rights' => 'string',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\System;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -23,11 +23,13 @@ class Files extends Model
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_files';
|
protected $name = 'mete_system_files';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'uid' => 'integer',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'cate' => 'integer',
|
'cate' => 'integer',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\System;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -23,11 +23,13 @@ class FilesCategory extends Model
|
|||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_files_category';
|
protected $name = 'mete_system_files_category';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'uid' => 'integer',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// | Author: Liu21st <liu21st@gmail.com>
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
// +----------------------------------------------------------------------
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
namespace app\model;
|
namespace app\model\System;
|
||||||
|
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use think\model\concern\SoftDelete;
|
use think\model\concern\SoftDelete;
|
||||||
@@ -21,20 +21,28 @@ class OperationLog extends Model
|
|||||||
{
|
{
|
||||||
// 启用软删除
|
// 启用软删除
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
// 数据库表名
|
// 数据库表名
|
||||||
protected $name = 'mete_operation_log';
|
protected $name = 'mete_system_operation_log';
|
||||||
|
|
||||||
// 字段类型转换
|
// 字段类型转换
|
||||||
protected $type = [
|
protected $type = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
'user_id' => 'integer',
|
'user_id' => 'integer',
|
||||||
|
'module' => 'string',
|
||||||
|
'action' => 'string',
|
||||||
|
'method' => 'string',
|
||||||
|
'url' => 'string',
|
||||||
|
'ip' => 'string',
|
||||||
|
'user_agent' => 'string',
|
||||||
|
'request_data' => 'string',
|
||||||
|
'response_data' => 'string',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
|
'error_message' => 'string',
|
||||||
'execution_time' => 'float',
|
'execution_time' => 'float',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
'delete_time' => 'datetime',
|
'delete_time' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\model\System;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信发送任务表(Android 网关轮询获取)
|
||||||
|
*/
|
||||||
|
class SmsTask extends Model
|
||||||
|
{
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_system_sms_tasks';
|
||||||
|
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'api_key' => 'string',
|
||||||
|
'phone' => 'string',
|
||||||
|
'content' => 'string',
|
||||||
|
'status' => 'integer',
|
||||||
|
'code' => 'string',
|
||||||
|
'report_raw' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\System;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统域名池模型
|
||||||
|
*/
|
||||||
|
class SystemDomainPool extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_system_domain_pool';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'main_domain' => 'string',
|
||||||
|
'status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\System;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站点设置模型
|
||||||
|
*/
|
||||||
|
class SystemSiteSetting extends Model
|
||||||
|
{
|
||||||
|
// 启用软删除
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_system_site_setting';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'sitename' => 'string',
|
||||||
|
'logo' => 'string',
|
||||||
|
'logow' => 'string',
|
||||||
|
'ico' => 'string',
|
||||||
|
'companyintroduction' => 'string',
|
||||||
|
'description' => 'string',
|
||||||
|
'copyright' => 'string',
|
||||||
|
'companyname' => 'string',
|
||||||
|
'icp' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ class SystemMenu extends Model
|
|||||||
'icon' => 'string',
|
'icon' => 'string',
|
||||||
'sort' => 'integer',
|
'sort' => 'integer',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
|
'is_visible' => 'integer',
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'permission' => 'string',
|
'permission' => 'string',
|
||||||
'remark' => 'string',
|
'remark' => 'string',
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\model\Template;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
class TemplateSiteConfig extends Model
|
||||||
|
{
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
protected $name = 'mete_template_site_config';
|
||||||
|
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'key' => 'string',
|
||||||
|
'value' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\model\Template;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
use think\model\concern\SoftDelete;
|
||||||
|
|
||||||
|
class TemplateThemeData extends Model
|
||||||
|
{
|
||||||
|
use SoftDelete;
|
||||||
|
|
||||||
|
protected $name = 'mete_template_theme_data';
|
||||||
|
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'theme_key' => 'string',
|
||||||
|
'field_key' => 'string',
|
||||||
|
'field_value' => 'string',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -30,9 +30,14 @@ class Tenant extends Model
|
|||||||
'contact_phone' => 'string',
|
'contact_phone' => 'string',
|
||||||
'contact_email' => 'string',
|
'contact_email' => 'string',
|
||||||
'address' => 'string',
|
'address' => 'string',
|
||||||
|
'worktime' => 'string',
|
||||||
|
'seoTitle' => 'string',
|
||||||
|
'seoKeywords' => 'string',
|
||||||
|
'seoDescription' => 'string',
|
||||||
'status' => 'integer',
|
'status' => 'integer',
|
||||||
'create_time' => 'datetime',
|
'create_time' => 'datetime',
|
||||||
'update_time' => 'datetime',
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
'remark' => 'string',
|
'remark' => 'string',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: Liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace app\model\Tenant;
|
||||||
|
|
||||||
|
use think\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户域名模型
|
||||||
|
*/
|
||||||
|
class TenantDomain extends Model
|
||||||
|
{
|
||||||
|
// 数据库表名
|
||||||
|
protected $name = 'mete_tenant_domain';
|
||||||
|
|
||||||
|
// 字段类型转换
|
||||||
|
protected $type = [
|
||||||
|
'id' => 'integer',
|
||||||
|
'tid' => 'integer',
|
||||||
|
'sub_domain' => 'string',
|
||||||
|
'main_domain' => 'string',
|
||||||
|
'full_domain' => 'string',
|
||||||
|
'status' => 'integer',
|
||||||
|
'create_time' => 'datetime',
|
||||||
|
'update_time' => 'datetime',
|
||||||
|
'delete_time' => 'datetime',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\service;
|
||||||
|
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Config;
|
||||||
|
use app\model\Cms\TemplateSiteConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板服务类
|
||||||
|
* 负责扫描 public/themes 目录,管理模板配置
|
||||||
|
*/
|
||||||
|
class ThemeService
|
||||||
|
{
|
||||||
|
private string $themesPath;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->themesPath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'themes';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有可用模板列表
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getThemeList(): array
|
||||||
|
{
|
||||||
|
$themes = [];
|
||||||
|
$dirs = $this->scanThemeDirs();
|
||||||
|
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
$config = $this->readThemeConfig($dir);
|
||||||
|
$preview = $this->getThemePreview($dir);
|
||||||
|
|
||||||
|
$themes[] = [
|
||||||
|
'key' => $dir,
|
||||||
|
'name' => $config['name'] ?? $dir,
|
||||||
|
'description' => $config['description'] ?? '',
|
||||||
|
'version' => $config['version'] ?? '1.0.0',
|
||||||
|
'author' => $config['author'] ?? '',
|
||||||
|
'preview' => $preview,
|
||||||
|
'path' => '/themes/' . $dir . '/index.html',
|
||||||
|
'fields' => $config['fields'] ?? [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描模板目录
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function scanThemeDirs(): array
|
||||||
|
{
|
||||||
|
$dirs = [];
|
||||||
|
|
||||||
|
if (!is_dir($this->themesPath)) {
|
||||||
|
return $dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = scandir($this->themesPath);
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if ($item === '.' || $item === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullPath = $this->themesPath . DIRECTORY_SEPARATOR . $item;
|
||||||
|
// 检查是否有 index.html 或 index.php
|
||||||
|
if (is_dir($fullPath) && (is_file($fullPath . DIRECTORY_SEPARATOR . 'index.html') || is_file($fullPath . DIRECTORY_SEPARATOR . 'index.php'))) {
|
||||||
|
$dirs[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dirs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取模板配置文件
|
||||||
|
* @param string $themeDir
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function readThemeConfig(string $themeDir): array
|
||||||
|
{
|
||||||
|
$configPath = $this->themesPath . DIRECTORY_SEPARATOR . $themeDir . DIRECTORY_SEPARATOR . 'config.json';
|
||||||
|
|
||||||
|
if (!is_file($configPath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = file_get_contents($configPath);
|
||||||
|
$config = json_decode($content, true);
|
||||||
|
|
||||||
|
return $config ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板预览图
|
||||||
|
* @param string $themeDir
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getThemePreview(string $themeDir): string
|
||||||
|
{
|
||||||
|
$previewPath = '/themes/' . $themeDir . '/preview.png';
|
||||||
|
|
||||||
|
// 如果 preview.png 不存在,使用默认占位图
|
||||||
|
$fullPath = $this->themesPath . DIRECTORY_SEPARATOR . $themeDir . DIRECTORY_SEPARATOR . 'preview.png';
|
||||||
|
if (!is_file($fullPath)) {
|
||||||
|
return 'https://picsum.photos/300/200?random=' . ord($themeDir[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $previewPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前激活的模板Key
|
||||||
|
* @param int $tid 租户ID
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCurrentTheme(int $tid)
|
||||||
|
{
|
||||||
|
// 直接通过 tid 查询对应的 value
|
||||||
|
$value = TemplateSiteConfig::where('tid', $tid)->value('value');
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换当前模板
|
||||||
|
* @param int $tid 租户ID
|
||||||
|
* @param string $themeKey
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function switchTheme(int $tid, string $themeKey): bool
|
||||||
|
{
|
||||||
|
// 验证模板是否存在
|
||||||
|
$themes = $this->getThemeList();
|
||||||
|
$exists = false;
|
||||||
|
foreach ($themes as $theme) {
|
||||||
|
if ($theme['key'] === $themeKey) {
|
||||||
|
$exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 查找或创建配置记录
|
||||||
|
$where = [['key', '=', 'current_theme'], ['delete_time', '=', null]];
|
||||||
|
if ($tid > 0) {
|
||||||
|
$where[] = ['tid', '=', $tid];
|
||||||
|
}
|
||||||
|
$config = TemplateSiteConfig::where($where)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
if ($config) {
|
||||||
|
TemplateSiteConfig::where('id', $config['id'])->update([
|
||||||
|
'value' => $themeKey,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
TemplateSiteConfig::insert([
|
||||||
|
'tid' => $tid,
|
||||||
|
'key' => 'current_theme',
|
||||||
|
'value' => $themeKey,
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板数据(用于前端渲染)
|
||||||
|
* @param int $tid 租户ID
|
||||||
|
* @param string|null $themeKey
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getThemeData(int $tid = 0, ?string $themeKey = null): array
|
||||||
|
{
|
||||||
|
$themeKey = $themeKey ?? $this->getCurrentTheme($tid);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($tid > 0) {
|
||||||
|
$where[] = ['tid', '=', $tid];
|
||||||
|
}
|
||||||
|
$configData = TemplateSiteConfig::where($where)
|
||||||
|
->select()
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ($configData as $item) {
|
||||||
|
// 去掉 field_ 前缀
|
||||||
|
$fieldKey = substr($item['key'], 6);
|
||||||
|
$data[$fieldKey] = $item['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'theme_key' => $themeKey,
|
||||||
|
'theme_path' => '/themes/' . $themeKey . '/index.html',
|
||||||
|
'data' => $data
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return [
|
||||||
|
'theme_key' => $themeKey,
|
||||||
|
'theme_path' => '/themes/' . $themeKey . '/index.html',
|
||||||
|
'data' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存模板字段数据
|
||||||
|
* @param int $tid 租户ID
|
||||||
|
* @param string $themeKey
|
||||||
|
* @param string $fieldKey
|
||||||
|
* @param mixed $fieldValue
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveThemeField(int $tid, string $themeKey, string $fieldKey, $fieldValue): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 使用 TemplateSiteConfig 表,key 格式为 field_xxx
|
||||||
|
$configKey = 'field_' . $fieldKey;
|
||||||
|
$where = [
|
||||||
|
['key', '=', $configKey],
|
||||||
|
['delete_time', '=', null]
|
||||||
|
];
|
||||||
|
if ($tid > 0) {
|
||||||
|
$where[] = ['tid', '=', $tid];
|
||||||
|
}
|
||||||
|
$existing = TemplateSiteConfig::where($where)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
$value = is_array($fieldValue) ? json_encode($fieldValue, JSON_UNESCAPED_UNICODE) : $fieldValue;
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
TemplateSiteConfig::where('id', $existing['id'])
|
||||||
|
->update([
|
||||||
|
'value' => $value,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
TemplateSiteConfig::insert([
|
||||||
|
'tid' => $tid,
|
||||||
|
'key' => $configKey,
|
||||||
|
'value' => $value,
|
||||||
|
'create_time' => $now,
|
||||||
|
'update_time' => $now
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\utils;
|
||||||
|
|
||||||
|
// 引入极验 SDK 的核心类
|
||||||
|
use geetest\GeetestLib;
|
||||||
|
use app\model\System\SystemSiteSettings;
|
||||||
|
|
||||||
|
class Geetest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 极验 3.0 的 ID 和 KEY
|
||||||
|
* 优先从系统配置表 SystemSiteSettings 中读取 geetest3ID / geetest3KEY
|
||||||
|
*/
|
||||||
|
private $captchaId;
|
||||||
|
private $privateKey;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// 默认值可以为空,避免硬编码
|
||||||
|
$this->captchaId = null;
|
||||||
|
$this->privateKey = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从系统设置表中读取极验3.0配置
|
||||||
|
$settings = SystemSiteSettings::where('delete_time', null)
|
||||||
|
->whereIn('label', ['geetest3ID', 'geetest3KEY'])
|
||||||
|
->column('value', 'label');
|
||||||
|
|
||||||
|
if (!empty($settings['geetest3ID']) && !empty($settings['geetest3KEY'])) {
|
||||||
|
$this->captchaId = $settings['geetest3ID'];
|
||||||
|
$this->privateKey = $settings['geetest3KEY'];
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// 读取配置失败时,不抛出致命错误,留给上层决定是否启用极验
|
||||||
|
error_log('加载极验配置失败: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化极验验证(前端获取验证参数)
|
||||||
|
* @return string JSON 字符串
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$gtLib = new GeetestLib($this->captchaId, $this->privateKey);
|
||||||
|
// 用户唯一标识(可传用户ID、IP等,不能为空)
|
||||||
|
$userId = request()->ip();
|
||||||
|
// 预处理验证
|
||||||
|
$status = $gtLib->pre_process($userId);
|
||||||
|
// 保存状态到 session
|
||||||
|
session('gtserver', $status);
|
||||||
|
session('gt_user_id', $userId);
|
||||||
|
// 返回前端需要的验证参数
|
||||||
|
return $gtLib->get_response_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证前端提交的极验数据
|
||||||
|
* @param array $data 前端提交的 geetest_challenge/validate/seccode
|
||||||
|
* @return bool 验证结果
|
||||||
|
*/
|
||||||
|
public function verify(array $data)
|
||||||
|
{
|
||||||
|
$gtLib = new GeetestLib($this->captchaId, $this->privateKey);
|
||||||
|
$userId = session('gt_user_id');
|
||||||
|
$status = session('gtserver');
|
||||||
|
|
||||||
|
if ($status == 1) {
|
||||||
|
// 正常模式验证
|
||||||
|
$result = $gtLib->success_validate(
|
||||||
|
$data['geetest_challenge'],
|
||||||
|
$data['geetest_validate'],
|
||||||
|
$data['geetest_seccode'],
|
||||||
|
$userId
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 宕机模式验证
|
||||||
|
$result = $gtLib->fail_validate(
|
||||||
|
$data['geetest_challenge'],
|
||||||
|
$data['geetest_validate'],
|
||||||
|
$data['geetest_seccode']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -34,7 +34,8 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"app\\": "app"
|
"app\\": "app",
|
||||||
|
"geetest\\": "extend/geetest/"
|
||||||
},
|
},
|
||||||
"psr-0": {
|
"psr-0": {
|
||||||
"": "extend/"
|
"": "extend/"
|
||||||
|
|||||||
Generated
+86
-86
@@ -608,6 +608,91 @@
|
|||||||
},
|
},
|
||||||
"time": "2021-10-29T13:26:27+00:00"
|
"time": "2021-10-29T13:26:27+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.33.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-12-23T08:48:59+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "topthink/framework",
|
"name": "topthink/framework",
|
||||||
"version": "v8.1.4",
|
"version": "v8.1.4",
|
||||||
@@ -1037,91 +1122,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-09-25T14:21:43+00:00"
|
"time": "2024-09-25T14:21:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfony/polyfill-mbstring",
|
|
||||||
"version": "v1.33.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
|
||||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
|
||||||
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-iconv": "*",
|
|
||||||
"php": ">=7.2"
|
|
||||||
},
|
|
||||||
"provide": {
|
|
||||||
"ext-mbstring": "*"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"ext-mbstring": "For best performance"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"thanks": {
|
|
||||||
"url": "https://github.com/symfony/polyfill",
|
|
||||||
"name": "symfony/polyfill"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"files": [
|
|
||||||
"bootstrap.php"
|
|
||||||
],
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nicolas Grekas",
|
|
||||||
"email": "p@tchwork.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Symfony polyfill for the Mbstring extension",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"compatibility",
|
|
||||||
"mbstring",
|
|
||||||
"polyfill",
|
|
||||||
"portable",
|
|
||||||
"shim"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/nicolas-grekas",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2024-12-23T08:48:59+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v6.4.32",
|
"version": "v6.4.32",
|
||||||
@@ -1319,5 +1319,5 @@
|
|||||||
"php": ">=8.0.0"
|
"php": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"platform-dev": {},
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.9.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ return [
|
|||||||
// 应用映射(自动多应用模式有效)
|
// 应用映射(自动多应用模式有效)
|
||||||
'app_map' => [],
|
'app_map' => [],
|
||||||
// 域名绑定(自动多应用模式有效)
|
// 域名绑定(自动多应用模式有效)
|
||||||
|
// 多租户二级域名池场景下,不建议在这里写死具体主域名/子域名
|
||||||
|
// 否则后续新增租户域名需要反复改配置
|
||||||
'domain_bind' => [],
|
'domain_bind' => [],
|
||||||
// 禁止URL访问的应用列表(自动多应用模式有效)
|
// 禁止URL访问的应用列表(自动多应用模式有效)
|
||||||
'deny_app_list' => [],
|
'deny_app_list' => [],
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
server
|
||||||
|
{
|
||||||
|
listen 80;
|
||||||
|
listen 443 ssl;
|
||||||
|
listen 443 quic;
|
||||||
|
http2 on;
|
||||||
|
server_name dh2.fun ~^(?<subdomain>.+)\.dh2\.fun$;
|
||||||
|
index index.php index.html index.htm default.php default.htm default.html;
|
||||||
|
root /www/wwwroot/api.yunzer.cn/public;
|
||||||
|
|
||||||
|
#CERT-APPLY-CHECK--START
|
||||||
|
include /www/server/panel/vhost/nginx/well-known/dh2.fun.conf;
|
||||||
|
#CERT-APPLY-CHECK--END
|
||||||
|
include /www/server/panel/vhost/nginx/extension/dh2.fun/*.conf;
|
||||||
|
|
||||||
|
# 根目录的 *.html 和 *.php,交给 ThinkPHP 处理
|
||||||
|
location ~* ^/(.+\.(html|php))$ {
|
||||||
|
try_files $uri /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 所有 /themes/... 直接当静态文件返回(模板静态资源)
|
||||||
|
location ^~ /themes/ {
|
||||||
|
root /www/wwwroot/api.yunzer.cn/public;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
expires 12h;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# /template1..100/... 预览入口
|
||||||
|
location ~ ^/(template(?:[1-9]\d?|100))/(.*)$ {
|
||||||
|
alias /www/wwwroot/api.yunzer.cn/public/themes/$1/$2;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
expires 12h;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
|
||||||
|
#error_page 404/404.html;
|
||||||
|
#HTTP_TO_HTTPS_START
|
||||||
|
set $isRedcert 1;
|
||||||
|
if ($server_port != 443) {
|
||||||
|
set $isRedcert 2;
|
||||||
|
}
|
||||||
|
if ( $uri ~ /\.well-known/ ) {
|
||||||
|
set $isRedcert 1;
|
||||||
|
}
|
||||||
|
if ($isRedcert != 1) {
|
||||||
|
rewrite ^(/.*)$ https://$host$1 permanent;
|
||||||
|
}
|
||||||
|
#HTTP_TO_HTTPS_END
|
||||||
|
ssl_certificate /www/server/panel/vhost/cert/dh2.fun/fullchain.pem;
|
||||||
|
ssl_certificate_key /www/server/panel/vhost/cert/dh2.fun/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_session_tickets on;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000";
|
||||||
|
add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
|
||||||
|
error_page 497 https://$host$request_uri;
|
||||||
|
#SSL-END
|
||||||
|
|
||||||
|
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
|
||||||
|
error_page 404 /404.html;
|
||||||
|
#ERROR-PAGE-END
|
||||||
|
|
||||||
|
#PHP-INFO-START PHP引用配置,可以注释或修改
|
||||||
|
include enable-php-82.conf;
|
||||||
|
#PHP-INFO-END
|
||||||
|
|
||||||
|
#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
|
||||||
|
include /www/server/panel/vhost/rewrite/dh2.fun.conf;
|
||||||
|
#REWRITE-END
|
||||||
|
|
||||||
|
# 禁止访问的敏感文件
|
||||||
|
location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 禁止访问的敏感目录
|
||||||
|
location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
#一键申请SSL证书验证目录相关设置
|
||||||
|
location ~ \.well-known{
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
|
||||||
|
#禁止在证书验证目录放入敏感文件
|
||||||
|
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
|
||||||
|
{
|
||||||
|
expires 30d;
|
||||||
|
error_log /dev/null;
|
||||||
|
access_log /dev/null;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ .*\.(js|css)?$
|
||||||
|
{
|
||||||
|
expires 12h;
|
||||||
|
error_log /dev/null;
|
||||||
|
access_log /dev/null;
|
||||||
|
}
|
||||||
|
|
||||||
|
# PHP 解析 + 传递子域名参数
|
||||||
|
location ~ [^/]\.php(/|$) {
|
||||||
|
include enable-php-82.conf;
|
||||||
|
fastcgi_param HTTP_SUBDOMAIN $subdomain;
|
||||||
|
fastcgi_param HTTP_MAIN_DOMAIN dh2.fun;
|
||||||
|
}
|
||||||
|
|
||||||
|
# TP路由重写
|
||||||
|
if (!-e $request_filename) {
|
||||||
|
# 将原始 URI 追加到 /index.php 后面,让 ThinkPHP 从 pathinfo 里拿到 :page
|
||||||
|
rewrite ^(.*)$ /index.php$1$is_args$args last;
|
||||||
|
}
|
||||||
|
|
||||||
|
access_log /www/wwwlogs/dh2.fun.log;
|
||||||
|
error_log /www/wwwlogs/dh2.fun.error.log;
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen 443 ssl;
|
||||||
|
listen 443 quic;
|
||||||
|
http2 on;
|
||||||
|
|
||||||
|
# 捕获子域名变量 $subdomain
|
||||||
|
server_name yunzer.com.cn ~^(?<subdomain>.+)\.yunzer\.com\.cn$;
|
||||||
|
index index.php index.html index.htm default.php default.htm default.html;
|
||||||
|
root /www/wwwroot/api.yunzer.cn/public;
|
||||||
|
|
||||||
|
#CERT-APPLY-CHECK--START
|
||||||
|
include /www/server/panel/vhost/nginx/well-known/yunzer.com.cn.conf;
|
||||||
|
#CERT-APPLY-CHECK--END
|
||||||
|
include /www/server/panel/vhost/nginx/extension/yunzer.com.cn/*.conf;
|
||||||
|
|
||||||
|
# --- SSL 配置 START ---
|
||||||
|
set $isRedcert 1;
|
||||||
|
if ($server_port != 443) {
|
||||||
|
set $isRedcert 2;
|
||||||
|
}
|
||||||
|
if ( $uri ~ /\.well-known/ ) {
|
||||||
|
set $isRedcert 1;
|
||||||
|
}
|
||||||
|
if ($isRedcert != 1) {
|
||||||
|
rewrite ^(/.*)$ https://$host$1 permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_certificate /www/server/panel/vhost/cert/yunzer.com.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /www/server/panel/vhost/cert/yunzer.com.cn/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_session_tickets on;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000";
|
||||||
|
add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
|
||||||
|
error_page 497 https://$host$request_uri;
|
||||||
|
# --- SSL 配置 END ---
|
||||||
|
|
||||||
|
#ERROR-PAGE-START
|
||||||
|
error_page 404 /404.html;
|
||||||
|
#ERROR-PAGE-END
|
||||||
|
|
||||||
|
# --- 安全与防盗链拦截 START ---
|
||||||
|
location ~* (\.user.ini|\.htaccess|\.htpasswd|\.env.*|\.project|\.bashrc|\.bash_profile|\.bash_logout|\.DS_Store|\.gitignore|\.gitattributes|LICENSE|README\.md|CLAUDE\.md|CHANGELOG\.md|CHANGELOG|CONTRIBUTING\.md|TODO\.md|FAQ\.md|composer\.json|composer\.lock|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml|\.\w+~|\.swp|\.swo|\.bak(up)?|\.old|\.tmp|\.temp|\.log|\.sql(\.gz)?|docker-compose\.yml|docker\.env|Dockerfile|\.csproj|\.sln|Cargo\.toml|Cargo\.lock|go\.mod|go\.sum|phpunit\.xml|phpunit\.xml|pom\.xml|build\.gradl|pyproject\.toml|requirements\.txt|application(-\w+)?\.(ya?ml|properties))$ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* /(\.git|\.svn|\.bzr|\.vscode|\.claude|\.idea|\.ssh|\.github|\.npm|\.yarn|\.pnpm|\.cache|\.husky|\.turbo|\.next|\.nuxt|node_modules|runtime)/ {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.well-known {
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
# --- 安全与防盗链拦截 END ---
|
||||||
|
|
||||||
|
# --- 静态资源与缓存 START ---
|
||||||
|
location ^~ /themes/ {
|
||||||
|
root /www/wwwroot/api.yunzer.cn/public;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
expires 12h;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(template(?:[1-9]\d?|100))/(.*)$ {
|
||||||
|
alias /www/wwwroot/api.yunzer.cn/public/themes/$1/$2;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
expires 12h;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
|
||||||
|
expires 30d;
|
||||||
|
error_log /dev/null;
|
||||||
|
access_log /dev/null;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(js|css)$ {
|
||||||
|
expires 12h;
|
||||||
|
error_log /dev/null;
|
||||||
|
access_log /dev/null;
|
||||||
|
}
|
||||||
|
# --- 静态资源与缓存 END ---
|
||||||
|
|
||||||
|
# --- 核心路由与 PHP 解析 START ---
|
||||||
|
# 1. 根目录的 *.html,交给 ThinkPHP 处理
|
||||||
|
location ~* ^/(.+\.html)$ {
|
||||||
|
try_files /themes/template3/$1 /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. 唯一且正确的 PHP 解析块(解决了直接下载的问题)
|
||||||
|
location ~ [^/]\.php(/|$) {
|
||||||
|
# 引入宝塔的 PHP FastCGI 配置,确保 PHP 正常执行
|
||||||
|
include enable-php-82.conf;
|
||||||
|
|
||||||
|
# 传递自定义子域名参数给 ThinkPHP
|
||||||
|
fastcgi_param HTTP_SUBDOMAIN $subdomain;
|
||||||
|
fastcgi_param HTTP_MAIN_DOMAIN yunzer.com.cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. 统一入口(ThinkPHP 默认伪静态):先找真实文件,找不到再交给 index.php
|
||||||
|
location / {
|
||||||
|
# 当访问的路径没有对应静态文件时,将请求回退到 ThinkPHP 前端入口。
|
||||||
|
# 使用 /index.php$uri 让内部请求变成 /index.php/portfolio 这类形式,
|
||||||
|
# 从而使 ThinkPHP 能从 pathinfo 中拿到 portfolio,并匹配 Route::get(':page', ...)
|
||||||
|
# 保留 query_string(用于 ?page=n 之类分页参数)
|
||||||
|
try_files $uri $uri/ /index.php$uri$is_args$args;
|
||||||
|
}
|
||||||
|
# --- 核心路由与 PHP 解析 END ---
|
||||||
|
|
||||||
|
access_log /www/wwwlogs/yunzer.com.cn.log;
|
||||||
|
error_log /www/wwwlogs/yunzer.com.cn.error.log;
|
||||||
|
}
|
||||||
@@ -6,6 +6,16 @@
|
|||||||
RewriteCond %{REQUEST_METHOD} OPTIONS
|
RewriteCond %{REQUEST_METHOD} OPTIONS
|
||||||
RewriteRule ^(.*)$ $1 [R=204,L]
|
RewriteRule ^(.*)$ $1 [R=204,L]
|
||||||
|
|
||||||
|
# 排除静态文件和特定PHP文件
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_URI} !^/themes/
|
||||||
|
RewriteCond %{REQUEST_URI} !^/static/
|
||||||
|
RewriteCond %{REQUEST_URI} !^/storage/
|
||||||
|
RewriteCond %{REQUEST_URI} !^/favicon.ico$
|
||||||
|
RewriteCond %{REQUEST_URI} !^/robots.txt$
|
||||||
|
RewriteRule ^(.*)$ index.php [L]
|
||||||
|
|
||||||
# 添加 CORS 头
|
# 添加 CORS 头
|
||||||
Header set Access-Control-Allow-Origin "http://localhost:5173"
|
Header set Access-Control-Allow-Origin "http://localhost:5173"
|
||||||
Header set Access-Control-Allow-Credentials "true"
|
Header set Access-Control-Allow-Credentials "true"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user