chore: 首次提交 - 关联 GitHub fnvtk/MBTI_wang

Made-with: Cursor
This commit is contained in:
卡若
2026-03-17 12:39:38 +08:00
commit eb510304c0
259 changed files with 60464 additions and 0 deletions

View File

@@ -0,0 +1,418 @@
<?php
namespace app\controller\admin;
use app\BaseController;
use app\model\SystemConfig as SystemConfigModel;
use app\model\User as UserModel;
use think\facade\Request;
use think\facade\Db;
/**
* 系统设置控制器(普通管理员)
*/
class Settings extends BaseController
{
/**
* 获取系统配置
* @return \think\response\Json
*/
public function index()
{
$user = $this->request->user ?? null;
if (!$user) {
return error('未登录', 401);
}
// 验证是否为管理员
if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
try {
// 获取当前管理员用户名
$jwtUsername = $user['username'] ?? null;
$username = 'admin';
if ($jwtUsername) {
$currentUser = UserModel::where('username', $jwtUsername)
->whereIn('role', ['admin', 'enterprise_admin'])
->find();
if ($currentUser) {
$username = $currentUser->username;
} else {
$username = $jwtUsername;
}
}
return success([
'username' => $username
]);
} catch (\Exception $e) {
return error('获取配置失败:' . $e->getMessage(), 500);
}
}
/**
* 获取可用字体列表
* GET /api/v1/admin/settings/fonts
*/
public function getFonts()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
$fonts = \app\common\service\PosterService::getAvailableFonts();
return success([
'fonts' => $fonts,
'fontDir' => root_path() . 'public/fonts/',
'dirExist' => is_dir(root_path() . 'public/fonts/'),
]);
}
/**
* 获取海报配置
* GET /api/v1/admin/settings/poster
* 有 enterpriseId 则读企业专属行否则读全局enterprise_id=0
*/
public function getPosterConfig()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
$eid = (int)($user['enterpriseId'] ?? 0);
$row = self::getConfig('poster_config', $eid);
$poster = $row ?: ['bgColor' => '#ffffff', 'bgImage' => '', 'elements' => []];
return success(['poster' => $poster]);
}
/**
* 保存海报配置
* PUT /api/v1/admin/settings/poster
*/
public function updatePosterConfig()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
$input = json_decode($this->request->getContent(), true);
if (!is_array($input)) {
$input = [];
}
$data = [
'bgColor' => $input['bgColor'] ?? '#ffffff',
'bgImage' => $input['bgImage'] ?? '',
'elements' => $input['elements'] ?? []
];
$eid = (int)($user['enterpriseId'] ?? 0);
try {
self::saveConfig('poster_config', $data, $eid, '分销海报可视化配置');
return success(null, '海报配置已保存');
} catch (\Exception $e) {
return error('保存失败:' . $e->getMessage(), 500);
}
}
/**
* 读取配置key + enterprise_id有企业专属则取否则降级到 enterprise_id=0
*/
private static function getConfig(string $key, int $enterpriseId = 0, bool $fallbackGlobal = false): ?array
{
$row = Db::name('system_config')
->where('key', $key)
->where('enterprise_id', $enterpriseId)
->find();
if ($row && !empty($row['value'])) {
$val = is_string($row['value']) ? json_decode($row['value'], true) : $row['value'];
if (is_array($val)) return $val;
}
if ($fallbackGlobal && $enterpriseId > 0) {
$row = Db::name('system_config')
->where('key', $key)
->where('enterprise_id', 0)
->find();
if ($row && !empty($row['value'])) {
$val = is_string($row['value']) ? json_decode($row['value'], true) : $row['value'];
if (is_array($val)) return $val;
}
}
return null;
}
/**
* 保存配置key + enterprise_id存在则 update否则 insert
*/
private static function saveConfig(string $key, array $value, int $enterpriseId = 0, string $description = ''): void
{
$now = time();
$json = json_encode($value, JSON_UNESCAPED_UNICODE);
$exists = Db::name('system_config')
->where('key', $key)
->where('enterprise_id', $enterpriseId)
->find();
if ($exists) {
Db::name('system_config')
->where('key', $key)
->where('enterprise_id', $enterpriseId)
->update(['value' => $json, 'updatedAt' => $now]);
} else {
Db::name('system_config')->insert([
'key' => $key,
'enterprise_id' => $enterpriseId,
'value' => $json,
'description' => $description,
'createdAt' => $now,
'updatedAt' => $now,
]);
}
}
/**
* 安全解码 JSON处理可能的多重编码
*/
private static function decodeJsonSafe($raw): ?array
{
if (!$raw) return null;
$val = $raw;
for ($i = 0; $i < 5 && is_string($val); $i++) {
$decoded = json_decode($val, true);
if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) break;
$val = $decoded;
}
return is_array($val) ? $val : null;
}
/**
* 获取小程序配置
* 读取全局 text_configenterprise_id=0作为默认值再用企业专属行覆盖
* GET /api/v1/admin/settings/miniprogram
*/
public function getMiniprogramConfig()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
try {
$eid = (int)($user['enterpriseId'] ?? 0);
// 全局小程序名称(仅超管可改,此处只读)
$miniprogramName = '神仙团队AI性格测试';
$siteInfo = Db::name('system_config')
->where('key', 'site_info')
->where('enterprise_id', 0)
->find();
if ($siteInfo && !empty($siteInfo['value'])) {
$val = is_string($siteInfo['value']) ? json_decode($siteInfo['value'], true) : $siteInfo['value'];
$miniprogramName = (string) ($val['miniprogramName'] ?? $val['siteName'] ?? $miniprogramName);
}
$tcDefaults = [
'analyzingTitle' => '正在分析中',
'startButtonText' => '开始面相测试',
'startButtonEnterprise' => '开始面部测试',
'reportTitle' => '分析报告',
'aiAnalysisText' => '智能分析',
];
// 全局文案enterprise_id=0作为基础
$globalTc = self::getConfig('text_config', 0);
$textConfigData = $globalTc
? array_merge($tcDefaults, array_intersect_key($globalTc, $tcDefaults))
: $tcDefaults;
// 企业专属文案 + 小程序名称 覆盖
if ($eid > 0) {
$eidTc = self::getConfig('text_config', $eid);
if ($eidTc) {
$textConfigData = array_merge($textConfigData, array_intersect_key($eidTc, $tcDefaults));
if (!empty($eidTc['miniprogramName'])) {
$miniprogramName = (string) $eidTc['miniprogramName'];
}
}
}
return success([
'miniprogramName' => $miniprogramName,
'textConfig' => $textConfigData,
]);
} catch (\Exception $e) {
return error('获取配置失败:' . $e->getMessage(), 500);
}
}
/**
* 更新小程序配置
* 写入 text_config 行enterprise_id={eid}(有企业)或 0无企业
* PUT /api/v1/admin/settings/miniprogram
*/
public function updateMiniprogramConfig()
{
$user = $this->request->user ?? null;
if (!$user || !in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
$rawBody = $this->request->getContent();
if (empty($rawBody)) {
$rawBody = file_get_contents('php://input');
}
$input = $rawBody ? json_decode($rawBody, true) : null;
if (!is_array($input)) {
$input = [
'miniprogramName' => Request::param('miniprogramName', ''),
'textConfig' => Request::param('textConfig', []),
];
}
$miniprogramName = trim((string) ($input['miniprogramName'] ?? ''));
$textConfig = $input['textConfig'] ?? [];
if ($miniprogramName === '') {
return error('小程序名称不能为空', 400);
}
$tcKeys = ['analyzingTitle', 'startButtonText', 'startButtonEnterprise', 'reportTitle', 'aiAnalysisText'];
$tcDefaults = [
'analyzingTitle' => '正在分析中',
'startButtonText' => '开始面相测试',
'startButtonEnterprise' => '开始面部测试',
'reportTitle' => '分析报告',
'aiAnalysisText' => '智能分析',
];
$tcData = is_array($textConfig) ? array_intersect_key($textConfig, array_flip($tcKeys)) : [];
$tcMerge = array_merge($tcDefaults, $tcData);
$eid = (int)($user['enterpriseId'] ?? 0);
try {
// eid=0更新 site_info 的小程序名称(全局)
if ($eid === 0) {
$siteRow = Db::name('system_config')->where('key', 'site_info')->where('enterprise_id', 0)->find();
$siteInfo = $siteRow && !empty($siteRow['value'])
? (is_string($siteRow['value']) ? json_decode($siteRow['value'], true) : $siteRow['value'])
: [];
$siteInfo = is_array($siteInfo) ? $siteInfo : [];
$siteInfo['miniprogramName'] = $miniprogramName;
$siteInfo['siteName'] = $siteInfo['siteName'] ?? $miniprogramName;
$siteInfo['updatedAt'] = time();
self::saveConfig('site_info', $siteInfo, 0, '站点信息');
} else {
// 企业专属:把 miniprogramName 一并写入 text_config
$tcMerge['miniprogramName'] = $miniprogramName;
}
// 统一写到 text_config企业行已含 miniprogramName全局行不含
self::saveConfig('text_config', $tcMerge, $eid, $eid > 0 ? "小程序文案配置(企业{$eid}" : '小程序文案配置(全局)');
return success([
'miniprogramName' => $miniprogramName,
'textConfig' => $tcMerge,
], '小程序配置已保存');
} catch (\Exception $e) {
return error('保存失败:' . $e->getMessage(), 500);
}
}
/**
* 更新管理员账户信息
* @return \think\response\Json
*/
public function updateCredentials()
{
$user = $this->request->user ?? null;
if (!$user) {
return error('未登录', 401);
}
// 验证是否为管理员
if (!in_array($user['role'], ['admin', 'enterprise_admin'])) {
return error('无权限访问', 403);
}
// 兼容 axios JSON PUT 与表单提交
$rawBody = $this->request->getContent();
if (empty($rawBody)) {
$rawBody = file_get_contents('php://input');
}
$input = $rawBody ? json_decode($rawBody, true) : null;
if (!is_array($input)) {
$input = [];
}
$username = trim((string)($input['username'] ?? Request::param('username', '')));
$currentPassword = (string)($input['currentPassword'] ?? Request::param('currentPassword', ''));
$newPassword = (string)($input['newPassword'] ?? Request::param('newPassword', ''));
$confirmPassword = (string)($input['confirmPassword'] ?? Request::param('confirmPassword', ''));
if (empty($username)) {
return error('用户名不能为空', 400);
}
try {
// 优先使用JWT中的username来查找用户
$jwtUsername = $user['username'] ?? null;
if (empty($jwtUsername)) {
return error('无法获取用户信息,请重新登录', 400);
}
// 直接通过username查找用户
$userModel = UserModel::where('username', $jwtUsername)
->whereIn('role', ['admin', 'enterprise_admin'])
->find();
if (!$userModel) {
return error('用户不存在,请检查登录状态', 404);
}
// 如果要修改密码,需要验证当前密码
if (!empty($newPassword)) {
if (empty($currentPassword)) {
return error('请输入当前密码', 400);
}
if ($newPassword !== $confirmPassword) {
return error('两次输入的密码不一致', 400);
}
// 验证当前密码User 模型已有原始加密密码)
if (!password_verify($currentPassword, $userModel->password)) {
return error('当前密码错误', 400);
}
// 更新密码:传入明文,交由 User 模型的 setPasswordAttr 自动加密
$userModel->password = $newPassword;
}
// 更新用户名
if ($username !== $userModel->username) {
// 检查用户名是否已存在(排除当前用户)
$exists = UserModel::where('username', $username)
->where('id', '<>', $userModel->id)
->find();
if ($exists) {
return error('用户名已存在', 400);
}
$userModel->username = $username;
}
$userModel->save();
return success([
'username' => $userModel->username
], '账户信息已更新');
} catch (\Exception $e) {
return error('更新失败:' . $e->getMessage(), 500);
}
}
}