chore: 重写初始提交(清空历史,整理后全量提交)

This commit is contained in:
ywxapp
2026-08-16 16:54:14 +08:00
commit 6c1a106bc1
1808 changed files with 238144 additions and 0 deletions
+146
View File
@@ -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.htmlview_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>\...
* 由 appPathaddon/<插件>/)剥 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;
}
}