chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ywxapp\controller;
|
||||
|
||||
use ywxapp\library\SkinVariables;
|
||||
use ywxapp\model\MemberUser;
|
||||
|
||||
/**
|
||||
* 会员中心控制器基类(MemberBase)
|
||||
*
|
||||
* 同时服务于两类场景:
|
||||
* 1) 会员中心本体(app/member 应用):view_path = app/member/view/,layout = common/layout
|
||||
* 2) 插件用户中心(addon/<插件>/controller/member/):view_path = addon/<插件>/view/member/,layout = member/layout
|
||||
*
|
||||
* 鉴权:容器 auth 在 AppService 中默认已绑定 \ywxapp\library\Auth(会员鉴权),
|
||||
* 故会员登录态由 BaseController::verifyAuth 自动校验(设置 $noNeedLogin 可放行)。
|
||||
*
|
||||
* 用法:
|
||||
* // 会员中心本体控制器
|
||||
* namespace app\member\controller;
|
||||
* use ywxapp\controller\MemberBase;
|
||||
* class Index extends MemberBase { ... }
|
||||
*
|
||||
* // 插件用户中心控制器
|
||||
* namespace addon\blog\controller\member;
|
||||
* use ywxapp\controller\MemberBase;
|
||||
* class Index extends MemberBase { ... }
|
||||
*/
|
||||
class MemberBase extends BaseController
|
||||
{
|
||||
/**
|
||||
* 视图类实例
|
||||
* @var \think\View
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* 控制器初始化
|
||||
*/
|
||||
public function _initialize()
|
||||
{
|
||||
MemberUser::ensureSchema(); // 用户中心核心表自愈(缺表/缺列兜底)
|
||||
$this->view = $this->app->view;
|
||||
$appName = $this->app->http->getName();
|
||||
// 全局 layout 模式:会员中心本体套 view/layout,插件用户中心套各自的 view/member/layout。
|
||||
// 不需要套 layout 的页面(如会员中心 iframe 主框架页)可在控制器内调用 $this->view->layout(false) 关闭。
|
||||
$layout = 'common/layout';
|
||||
if ($appName === 'member') {
|
||||
// 会员中心本体:视图根目录为 app/member/view/,layout 为 view/layout.html
|
||||
$viewPath = $this->app->getAppPath() . 'view' . DIRECTORY_SEPARATOR;
|
||||
} else {
|
||||
// 插件用户中心:视图根目录为 addon/<插件>/view/member/
|
||||
$addon = $this->currentAddon();
|
||||
$viewPath = $addon
|
||||
? root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR
|
||||
. 'view' . DIRECTORY_SEPARATOR . 'member' . DIRECTORY_SEPARATOR
|
||||
: $this->app->getAppPath() . 'view' . DIRECTORY_SEPARATOR . 'member' . DIRECTORY_SEPARATOR;
|
||||
// 插件内使用插件自己的 view/member/layout.html(view_path 已含 member/)
|
||||
$layout = 'common/layout';
|
||||
}
|
||||
$this->view->config([
|
||||
'view_suffix' => 'html',
|
||||
'view_path' => $viewPath,
|
||||
'layout_on' => true,
|
||||
'layout_name' => $layout,
|
||||
]);
|
||||
|
||||
// 登录与权限校验:统一走 Base 的 verifyAuth + $noNeedLogin 机制
|
||||
// (未登录且非免登录 action 时整页 302 跳登录页,AJAX 返回 401,与后台一致)。
|
||||
// 注意:verifyAuth 内部会 tokenParse() 还原登录态,无需在中间件重复处理。
|
||||
$this->auth->verifyAuth($this->noNeedLogin, $this->noNeedVerify);
|
||||
|
||||
if ($this->auth && $this->auth->isLogin) {
|
||||
$this->view->assign('member', $this->auth->info);
|
||||
}
|
||||
$siteConf = \ywxapp\model\Configure::cache(true)->column('value', 'name');
|
||||
$this->view->assign('siteConf', $siteConf);
|
||||
$links = \ywxapp\model\Links::cache(true)->where('status', 1)->order('sort desc')->select();
|
||||
$this->view->assign('links', $links);
|
||||
// 注入站点信息(route_base / site.module / site.controller 等),供前端 route.js 使用
|
||||
$this->assignSite();
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 子类初始化钩子
|
||||
*/
|
||||
protected function initialize() {}
|
||||
|
||||
/**
|
||||
* 获取当前登录会员信息(未登录直接报错)
|
||||
* @return \ywxapp\model\Member
|
||||
*/
|
||||
protected function user()
|
||||
{
|
||||
if ($this->auth && $this->auth->isLogin) {
|
||||
return $this->auth->info;
|
||||
}
|
||||
$this->result->error('请先登录会员中心');
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前插件名(addon\<name>\...)
|
||||
* 由 appPath(addon/<插件>/)剥 rootPath 取首段,无需正则。
|
||||
*/
|
||||
protected function currentAddon(): string
|
||||
{
|
||||
$rel = trim(substr($this->app->getAppPath(), strlen($this->app->getRootPath())), DIRECTORY_SEPARATOR);
|
||||
$seg = explode(DIRECTORY_SEPARATOR, $rel);
|
||||
return $seg[0] === 'addon' && isset($seg[1]) ? $seg[1] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染模板:优先使用已激活模板的覆盖页(Discuz 式局部覆盖),未命中回退插件默认视图。
|
||||
*/
|
||||
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
|
||||
{
|
||||
$addon = $this->currentAddon();
|
||||
$restore = null;
|
||||
if ($addon && $overlay = \ywxapp\library\SkinOverlay::resolve($addon, 'member')) {
|
||||
// 把视图根目录切到「插件视图 + 皮肤覆盖」合并层,使 extend 的 layout 也走皮肤
|
||||
$restore = \think\facade\View::getConfig('view_path');
|
||||
\think\facade\View::config(['view_path' => $overlay]);
|
||||
}
|
||||
$result = \think\facade\View::fetch($template, $vars, $replace, $config);
|
||||
if ($restore !== null) {
|
||||
\think\facade\View::config(['view_path' => $restore]);
|
||||
}
|
||||
// 注入皮肤变量 CSS(Discuz 式配色层,无需改 HTML)
|
||||
$style = SkinVariables::styleTag($addon, 'member');
|
||||
if ($style !== '' && ($pos = stripos($result, '</head>')) !== false) {
|
||||
$result = substr($result, 0, $pos) . $style . "\n" . substr($result, $pos);
|
||||
} elseif ($style !== '') {
|
||||
$result = $style . $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user