更新租户端网站显示

This commit is contained in:
李志强 2026-03-10 18:05:10 +08:00
parent c00229f2ee
commit 7cdb591f69
5 changed files with 167 additions and 56 deletions

View File

@ -8,6 +8,9 @@ use app\admin\BaseController;
use think\facade\Db; use think\facade\Db;
use think\Request; use think\Request;
use think\facade\Session; use think\facade\Session;
use app\model\Tenant\TenantDomain;
use app\model\Tenant\Tenant;
use app\model\System\SystemDomainPool;
/** /**
* 租户域名绑定控制器 * 租户域名绑定控制器
@ -26,7 +29,7 @@ class TenantDomainController extends BaseController
$subDomain = $request->param('sub_domain', ''); $subDomain = $request->param('sub_domain', '');
$where = [['delete_time', '=', null]]; $where = [['delete_time', '=', null]];
if ($tenantId > 0) { if ($tenantId > 0) {
$where[] = ['tid', '=', $tenantId]; $where[] = ['tid', '=', $tenantId];
} }
@ -37,23 +40,20 @@ class TenantDomainController extends BaseController
$where[] = ['sub_domain', 'like', "%$subDomain%"]; $where[] = ['sub_domain', 'like', "%$subDomain%"];
} }
$list = Db::name('mete_tenant_domain') $list = TenantDomain::where($where)
->where($where)
->page($page, $pageSize) ->page($page, $pageSize)
->order('id', 'desc') ->order('id', 'desc')
->select() ->select()
->toArray(); ->toArray();
$total = Db::name('mete_tenant_domain') $total = TenantDomain::where($where)
->where($where)
->count(); ->count();
// 获取租户名称 // 获取租户名称
$tenantIds = array_column($list, 'tid'); $tenantIds = array_column($list, 'tid');
$tenants = []; $tenants = [];
if ($tenantIds) { if ($tenantIds) {
$tenantList = Db::name('mete_tenant') $tenantList = Tenant::whereIn('id', $tenantIds)
->whereIn('id', $tenantIds)
->select() ->select()
->toArray(); ->toArray();
$tenants = array_column($tenantList, null, 'id'); $tenants = array_column($tenantList, null, 'id');
@ -80,7 +80,7 @@ class TenantDomainController extends BaseController
public function myDomains(Request $request) public function myDomains(Request $request)
{ {
$tid = $request->param('tid', 0, 'int'); $tid = $request->param('tid', 0, 'int');
if ($tid <= 0) { if ($tid <= 0) {
return json([ return json([
'code' => 400, 'code' => 400,
@ -88,8 +88,7 @@ class TenantDomainController extends BaseController
]); ]);
} }
$list = Db::name('mete_tenant_domain') $list = TenantDomain::where('tid', $tid)
->where('tid', $tid)
->where('delete_time', null) ->where('delete_time', null)
->order('id', 'desc') ->order('id', 'desc')
->select() ->select()
@ -141,12 +140,11 @@ class TenantDomainController extends BaseController
} }
// 检查主域名是否存在且启用 // 检查主域名是否存在且启用
$mainDomainInfo = Db::name('mete_system_domain_pool') $mainDomainInfo = SystemDomainPool::where('main_domain', $mainDomain)
->where('main_domain', $mainDomain)
->where('status', 1) ->where('status', 1)
->where('delete_time', null) ->where('delete_time', null)
->find(); ->find();
if (!$mainDomainInfo) { if (!$mainDomainInfo) {
return json([ return json([
'code' => 400, 'code' => 400,
@ -155,12 +153,11 @@ class TenantDomainController extends BaseController
} }
// 检查二级域名是否已被使用 // 检查二级域名是否已被使用
$exists = Db::name('mete_tenant_domain') $exists = TenantDomain::where('sub_domain', $subDomain)
->where('sub_domain', $subDomain)
->where('main_domain', $mainDomain) ->where('main_domain', $mainDomain)
->where('delete_time', null) ->where('delete_time', null)
->find(); ->find();
if ($exists) { if ($exists) {
return json([ return json([
'code' => 400, 'code' => 400,
@ -170,8 +167,8 @@ class TenantDomainController extends BaseController
$fullDomain = $subDomain . '.' . $mainDomain; $fullDomain = $subDomain . '.' . $mainDomain;
$now = date('Y-m-d H:i:s'); $now = date('Y-m-d H:i:s');
$id = Db::name('mete_tenant_domain')->insertGetId([ $id = TenantDomain::insertGetId([
'tid' => $tid, 'tid' => $tid,
'sub_domain' => $subDomain, 'sub_domain' => $subDomain,
'main_domain' => $mainDomain, 'main_domain' => $mainDomain,
@ -203,10 +200,9 @@ class TenantDomainController extends BaseController
]); ]);
} }
$domain = Db::name('mete_tenant_domain') $domain = TenantDomain::where('id', $id)
->where('id', $id)
->find(); ->find();
if (!$domain) { if (!$domain) {
return json([ return json([
'code' => 404, 'code' => 404,
@ -222,16 +218,15 @@ class TenantDomainController extends BaseController
} }
$newStatus = $action === 'approve' ? 1 : 2; // 1-已生效 2-已拒绝 $newStatus = $action === 'approve' ? 1 : 2; // 1-已生效 2-已拒绝
Db::name('mete_tenant_domain') TenantDomain::where('id', $id)
->where('id', $id)
->update([ ->update([
'status' => $newStatus, 'status' => $newStatus,
'update_time' => date('Y-m-d H:i:s') 'update_time' => date('Y-m-d H:i:s')
]); ]);
$msg = $action === 'approve' ? '审核通过' : '已拒绝'; $msg = $action === 'approve' ? '审核通过' : '已拒绝';
return json([ return json([
'code' => 200, 'code' => 200,
'msg' => $msg 'msg' => $msg
@ -244,7 +239,7 @@ class TenantDomainController extends BaseController
public function toggleStatus(Request $request) public function toggleStatus(Request $request)
{ {
$id = $request->param('id', 0, 'int'); $id = $request->param('id', 0, 'int');
if ($id <= 0) { if ($id <= 0) {
return json([ return json([
'code' => 400, 'code' => 400,
@ -252,10 +247,9 @@ class TenantDomainController extends BaseController
]); ]);
} }
$domain = Db::name('mete_tenant_domain') $domain = TenantDomain::where('id', $id)
->where('id', $id)
->find(); ->find();
if (!$domain) { if (!$domain) {
return json([ return json([
'code' => 404, 'code' => 404,
@ -272,8 +266,7 @@ class TenantDomainController extends BaseController
} }
// 切换为禁用状态 // 切换为禁用状态
Db::name('mete_tenant_domain') TenantDomain::where('id', $id)
->where('id', $id)
->update([ ->update([
'status' => 2, 'status' => 2,
'update_time' => date('Y-m-d H:i:s') 'update_time' => date('Y-m-d H:i:s')
@ -297,8 +290,7 @@ class TenantDomainController extends BaseController
]); ]);
} }
Db::name('mete_tenant_domain') TenantDomain::where('id', $id)
->where('id', $id)
->update([ ->update([
'delete_time' => date('Y-m-d H:i:s') 'delete_time' => date('Y-m-d H:i:s')
]); ]);

View File

@ -16,8 +16,9 @@ class ThemeController extends BaseController
{ {
private ThemeService $themeService; private ThemeService $themeService;
public function __construct() public function __construct(\think\App $app)
{ {
parent::__construct($app);
$this->themeService = new ThemeService(); $this->themeService = new ThemeService();
} }
@ -50,9 +51,17 @@ class ThemeController extends BaseController
*/ */
public function switch() public function switch()
{ {
$tid = Request::post('tid', 0, 'int'); // 从当前登录用户获取tid而不是从前端参数
$tid = $this->getTenantId();
$themeKey = Request::post('theme_key', ''); $themeKey = Request::post('theme_key', '');
if (empty($tid) || $tid == 0) {
return json([
'code' => 401,
'msg' => '未获取到租户ID请重新登录'
]);
}
if (empty($themeKey)) { if (empty($themeKey)) {
return json([ return json([
'code' => 400, 'code' => 400,

View File

@ -17,40 +17,53 @@ class DomainParse
{ {
$host = $request->host(true); // 获取完整域名,不带端口 $host = $request->host(true); // 获取完整域名,不带端口
// 排除后台域名和平台官网域名 // 你的后台/平台域名(排除,不走租户逻辑)
$adminDomains = ['admin.xxx.com']; // TODO: 配置后台域名 $adminDomains = ['back.yunzer.cn', 'api.yunzer.cn'];
$platformDomains = ['www.xxx.com', 'xxx.com']; // TODO: 配置平台官网域名 $platformDomains = ['www.yunzer.cn', 'yunzer.cn'];
// 后台/平台/API域名直接放行
if (in_array($host, $adminDomains) || in_array($host, $platformDomains)) { if (in_array($host, $adminDomains) || in_array($host, $platformDomains)) {
return $next($request); return $next($request);
} }
// 解析二级域名 // 解析域名(兼容 yunzer.com.cn/dh2.fun
$domainParts = explode('.', $host); $domainParts = explode('.', $host);
$allowMainDomains = ['yunzer.com.cn', 'dh2.fun'];
// 至少需要三级域名(如 sub.domain.com $mainDomain = '';
if (count($domainParts) < 3) {
return $next($request); 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;
}
}
} }
$subDomain = $domainParts[0]; // 非租户主域名放行走API默认界面可改为跳转到平台
$mainDomain = implode('.', array_slice($domainParts, 1)); if (empty($mainDomain)) {
return $next($request);
}
// 查询租户域名绑定记录 // 查询租户域名绑定记录
$tenantDomain = Db::name('mete_tenant_domain') $tenantDomain = Db::name('mete_tenant_domain')
->where('full_domain', $host) ->where('full_domain', $host)
->where('status', 1) // 只有已生效的域名才能访问 ->where('status', 1)
->where('delete_time', null)
->find(); ->find();
if ($tenantDomain) { if ($tenantDomain) {
// 将租户ID写入请求对象供后续控制器使用 // 1. 写入租户ID到请求核心后续所有逻辑都能获取
$request->tenantId = $tenantDomain['tid']; $request->tenantId = $tenantDomain['tid'];
$request->header('X-Tenant-Id', (string)$tenantDomain['tid']);
// 同时写入header方便前端获取 // 2. 额外:写入租户域名信息,方便模板使用
$request->header['X-Tenant-Id', $tenantDomain['tid']); $request->tenantDomain = $host;
$request->tenantMainDomain = $mainDomain;
} }
return $next($request); return $next($request);
} }
} }

View File

@ -13,7 +13,7 @@ use app\service\ThemeService;
use think\db\exception\DbException; use think\db\exception\DbException;
use think\facade\Env; use think\facade\Env;
use think\facade\Request; use think\facade\Request;
use app\model\Template\TemplateSiteConfig; use app\model\Cms\TemplateSiteConfig;
class Index extends BaseController class Index extends BaseController
{ {
@ -26,8 +26,102 @@ class Index extends BaseController
public function index() public function index()
{ {
// 获取请求对象
$request = $this->request ?? Request::instance();
// 优先从请求对象获取中间件设置的租户ID通过域名解析
$tid = $request->tenantId ?? 0;
// 兼容从header获取
if ($tid == 0) {
$tid = (int)$request->header('X-Tenant-Id', 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');
} }
/**
* 修复模板中的资源路径
* 将相对路径 (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 = '')
{
// 定义模板基础URL常量供模板使用
if (!defined('THEME_URL')) {
define('THEME_URL', $themeUrlPath);
}
ob_start();
// 获取URL参数
$getParams = Request::get();
extract($getParams, 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']);
}
/** /**
* 前端初始化接口 - 返回当前模板和填充数据 * 前端初始化接口 - 返回当前模板和填充数据
@ -35,8 +129,11 @@ class Index extends BaseController
*/ */
public function init() public function init()
{ {
// 获取租户ID从请求参数 // 优先从请求对象获取中间件设置的租户ID通过域名解析
$tid = Request::param('tid', 0, 'int'); $tid = $this->request->tenantId ?? 0;
// 兼容URL参数传递的tid作为备用
$tid = $tid > 0 ? $tid : Request::param('tid', 0, 'int');
// 从TemplateSiteConfig获取配置根据租户ID // 从TemplateSiteConfig获取配置根据租户ID
$config = null; $config = null;

View File

@ -1,4 +1,4 @@
<?php <?php
//000000604800 //000000604800
exit();?> exit();?>
a:7:{s:2:"id";i:2;s:7:"account";s:10:"hero920103";s:4:"name";s:9:"李志强";s:8:"group_id";i:1;s:9:"tenant_id";i:1;s:6:"tenant";O:23:"app\model\Tenant\Tenant":26:{s:3:"get";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:4:"data";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:6:"origin";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:8:"relation";a:0:{}s:8:"together";a:0:{}s:5:"allow";a:0:{}s:8:"withAttr";a:0:{}s:6:"schema";a:13:{s:2:"id";s:7:"integer";s:11:"tenant_code";s:6:"string";s:11:"tenant_name";s:6:"string";s:14:"contact_person";s:6:"string";s:13:"contact_phone";s:6:"string";s:13:"contact_email";s:6:"string";s:7:"address";s:6:"string";s:6:"domain";s:6:"string";s:6:"status";s:7:"integer";s:11:"create_time";s:8:"datetime";s:11:"update_time";s:8:"datetime";s:11:"delete_time";s:8:"datetime";s:6:"remark";s:6:"string";}s:10:"updateTime";s:11:"update_time";s:10:"createTime";s:11:"create_time";s:6:"suffix";s:0:"";s:8:"validate";s:0:"";s:4:"type";a:0:{}s:8:"readonly";a:0:{}s:6:"disuse";a:0:{}s:6:"hidden";a:0:{}s:7:"visible";a:0:{}s:6:"append";a:0:{}s:7:"mapping";a:0:{}s:6:"strict";b:1;s:8:"bindAttr";a:0:{}s:12:"autoRelation";a:0:{}s:18:"autoWriteTimestamp";b:1;s:10:"dateFormat";s:11:"Y-m-d H:i:s";s:2:"pk";s:2:"id";s:6:"exists";b:1;}s:6:"rights";a:46:{i:0;i:31;i:1;i:32;i:2;i:33;i:3;i:4;i:4;i:9;i:5;i:29;i:6;i:5;i:7;i:6;i:8;i:30;i:9;i:27;i:10;i:28;i:11;i:19;i:12;i:12;i:13;i:18;i:14;i:23;i:15;i:25;i:16;i:26;i:17;i:24;i:18;i:7;i:19;i:8;i:20;i:17;i:21;i:21;i:22;i:2;i:23;i:10;i:24;i:11;i:25;i:16;i:26;i:1;i:27;i:20;i:28;i:22;i:29;i:3;i:30;i:15;i:31;i:34;i:32;i:35;i:33;i:36;i:34;i:37;i:35;i:38;i:36;i:39;i:37;i:40;i:38;i:41;i:39;i:42;i:40;i:43;i:41;i:44;i:42;i:45;i:43;i:46;i:44;i:47;i:45;i:48;}} a:7:{s:2:"id";i:2;s:7:"account";s:10:"hero920103";s:4:"name";s:9:"李志强";s:8:"group_id";i:1;s:3:"tid";i:1;s:6:"tenant";O:23:"app\model\Tenant\Tenant":26:{s:3:"get";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:4:"data";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:6:"origin";a:2:{s:2:"id";i:1;s:11:"tenant_name";s:39:"连云港云泽广告传媒有限公司";}s:8:"relation";a:0:{}s:8:"together";a:0:{}s:5:"allow";a:0:{}s:8:"withAttr";a:0:{}s:6:"schema";a:13:{s:2:"id";s:7:"integer";s:11:"tenant_code";s:6:"string";s:11:"tenant_name";s:6:"string";s:14:"contact_person";s:6:"string";s:13:"contact_phone";s:6:"string";s:13:"contact_email";s:6:"string";s:7:"address";s:6:"string";s:6:"domain";s:6:"string";s:6:"status";s:7:"integer";s:11:"create_time";s:8:"datetime";s:11:"update_time";s:8:"datetime";s:11:"delete_time";s:8:"datetime";s:6:"remark";s:6:"string";}s:10:"updateTime";s:11:"update_time";s:10:"createTime";s:11:"create_time";s:6:"suffix";s:0:"";s:8:"validate";s:0:"";s:4:"type";a:0:{}s:8:"readonly";a:0:{}s:6:"disuse";a:0:{}s:6:"hidden";a:0:{}s:7:"visible";a:0:{}s:6:"append";a:0:{}s:7:"mapping";a:0:{}s:6:"strict";b:1;s:8:"bindAttr";a:0:{}s:12:"autoRelation";a:0:{}s:18:"autoWriteTimestamp";b:1;s:10:"dateFormat";s:11:"Y-m-d H:i:s";s:2:"pk";s:2:"id";s:6:"exists";b:1;}s:6:"rights";a:46:{i:0;i:31;i:1;i:32;i:2;i:33;i:3;i:4;i:4;i:9;i:5;i:29;i:6;i:5;i:7;i:6;i:8;i:30;i:9;i:27;i:10;i:28;i:11;i:19;i:12;i:12;i:13;i:18;i:14;i:23;i:15;i:25;i:16;i:26;i:17;i:24;i:18;i:7;i:19;i:8;i:20;i:17;i:21;i:21;i:22;i:2;i:23;i:10;i:24;i:11;i:25;i:16;i:26;i:1;i:27;i:20;i:28;i:22;i:29;i:3;i:30;i:15;i:31;i:34;i:32;i:35;i:33;i:36;i:34;i:37;i:35;i:38;i:36;i:39;i:37;i:40;i:38;i:41;i:39;i:42;i:40;i:43;i:41;i:44;i:42;i:45;i:43;i:46;i:44;i:47;i:45;i:48;}}