继续完善前端登录模块
This commit is contained in:
		
							parent
							
								
									9352fd2a75
								
							
						
					
					
						commit
						b8d3757397
					
				| @ -12,6 +12,7 @@ use think\facade\View; | ||||
| use think\facade\Env; | ||||
| use think\facade\Config; | ||||
| use app\admin\controller\Log; | ||||
| use \think\facade\Filesystem; | ||||
| 
 | ||||
| use app\admin\model\AdminUserGroup; | ||||
| use app\admin\model\AdminSysMenu; | ||||
| @ -358,7 +359,7 @@ class IndexController extends Base{ | ||||
| 			])->check($file); | ||||
| 			 | ||||
| 			// 存储文件到public磁盘的uploads目录
 | ||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads', $files); | ||||
| 			$info = Filesystem::disk('public')->putFile('uploads', $files); | ||||
| 			 | ||||
| 			// 处理文件路径,统一使用正斜杠
 | ||||
| 			$info = str_replace("\\", "/", $info); | ||||
| @ -408,7 +409,7 @@ class IndexController extends Base{ | ||||
| 				'file'=>'fileExt:doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,7z' | ||||
| 			])->check($file); | ||||
| 			 | ||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads/files', $files); | ||||
| 			$info = Filesystem::disk('public')->putFile('uploads/files', $files); | ||||
| 			 | ||||
| 			// 处理文件路径
 | ||||
| 			$info = str_replace("\\", "/", $info); | ||||
| @ -442,7 +443,7 @@ class IndexController extends Base{ | ||||
| 		} | ||||
| 		try { | ||||
| 			validate(['video'=>'filesize:102400|fileExt:mp4,avi,mov,wmv,flv'])->check($file); | ||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads/videos', $files); | ||||
| 			$info = Filesystem::disk('public')->putFile('uploads/videos', $files); | ||||
| 			 | ||||
| 			// 处理文件路径
 | ||||
| 			$info = str_replace("\\", "/", $info); | ||||
| @ -474,7 +475,7 @@ class IndexController extends Base{ | ||||
| 		} | ||||
| 		try { | ||||
| 			validate(['audio'=>'filesize:51200|fileExt:mp3,wav,ogg,m4a'])->check($file); | ||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads/audios', $files); | ||||
| 			$info = Filesystem::disk('public')->putFile('uploads/audios', $files); | ||||
| 			 | ||||
| 			// 处理文件路径
 | ||||
| 			$info = str_replace("\\", "/", $info); | ||||
|  | ||||
| @ -14,6 +14,8 @@ use app\index\model\Articles\ArticlesCategory; | ||||
| use app\index\model\Resources\Resources; | ||||
| use app\index\model\Articles\Articles; | ||||
| use app\index\model\MailConfig; | ||||
| use \think\facade\Filesystem; | ||||
| use app\index\model\Attachments; | ||||
| 
 | ||||
| 
 | ||||
| class IndexController extends BaseController | ||||
| @ -343,5 +345,66 @@ class IndexController extends BaseController | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     //保存附件信息到数据库
 | ||||
|     private function saveAttachment($name, $type, $size, $src) | ||||
|     { | ||||
|         $data = [ | ||||
|             'name' => $name, | ||||
|             'type' => $type, | ||||
|             'size' => $size, | ||||
|             'src' => $src, | ||||
|             'create_time' => time(), | ||||
|             'update_time' => time() | ||||
|         ]; | ||||
|         return Attachments::insertGetId($data); | ||||
|     } | ||||
| 
 | ||||
|     //上传图片接口
 | ||||
|     public function update_imgs() | ||||
|     { | ||||
|         // 获取上传的文件
 | ||||
|         $file = request()->file(); | ||||
|         $files = request()->file('file'); | ||||
| 
 | ||||
|         // 检查是否有文件上传
 | ||||
|         if (empty($file)) { | ||||
|             return json(['code' => 1, 'msg' => '没有文件上传']); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             // 验证上传的文件
 | ||||
|             validate([ | ||||
|                 'image' => 'filesize:51200|fileExt:jpg,png,gif,jpeg' | ||||
|             ])->check($file); | ||||
| 
 | ||||
|             // 存储文件到public磁盘的uploads目录
 | ||||
|             $info = Filesystem::disk('public')->putFile('uploads', $files); | ||||
| 
 | ||||
|             // 处理文件路径,统一使用正斜杠
 | ||||
|             $info = str_replace("\\", "/", $info); | ||||
|             $img = '/storage/' . $info; | ||||
| 
 | ||||
|             // 保存附件信息
 | ||||
|             $fileName = $files->getOriginalName(); | ||||
|             $fileSize = $files->getSize(); | ||||
|             $attachmentId = $this->saveAttachment($fileName, 1, $fileSize, $img); // 1: 图片
 | ||||
| 
 | ||||
|             // 返回成功信息
 | ||||
|             return json([ | ||||
|                 'code' => 0, | ||||
|                 'data' => [ | ||||
|                     'url' => $img | ||||
|                 ], | ||||
|                 'msg' => '上传成功' | ||||
|             ]); | ||||
| 
 | ||||
|         } catch (\think\exception\ValidateException $e) { | ||||
|             // 捕获验证异常并返回错误信息
 | ||||
|             return json(['code' => 1, 'msg' => $e->getMessage()]); | ||||
|         } catch (\Exception $e) { | ||||
|             // 捕获其他异常
 | ||||
|             return json(['code' => 1, 'msg' => '上传失败:' . $e->getMessage()]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ namespace app\index\controller; | ||||
| use think\Controller; | ||||
| use app\index\model\Users; | ||||
| use think\facade\Redirect; | ||||
| use think\facade\View; | ||||
| use \think\facade\Log; | ||||
| use \think\facade\Cache; | ||||
| use PHPMailer\PHPMailer\PHPMailer; | ||||
| @ -48,12 +49,20 @@ class UserController extends BaseController | ||||
|                 session('user_name', $user->name); | ||||
|                 session('user_avatar', $user->avatar ?? '/static/images/avatar.png'); | ||||
| 
 | ||||
|                 // 设置cookie,有效期7天
 | ||||
|                 $expire = 7 * 24 * 3600; | ||||
|                 cookie('user_id', $user->id, ['expire' => $expire]); | ||||
|                 cookie('user_account', $user->account, ['expire' => $expire]); | ||||
|                 cookie('user_name', $user->name, ['expire' => $expire]); | ||||
|                 cookie('user_avatar', $user->avatar ?? '/static/images/avatar.png', ['expire' => $expire]); | ||||
| 
 | ||||
|                 // 记录登录日志
 | ||||
|                 Log::record('用户登录成功:' . $user->account, 'info'); | ||||
| 
 | ||||
|                 return json(['code' => 0, 'msg' => '登录成功']); | ||||
| 
 | ||||
|             } catch (\Exception $e) { | ||||
|                 Log::record('登录失败:' . $e->getMessage(), 'error'); | ||||
|                 return json(['code' => 1, 'msg' => '登录失败:' . $e->getMessage()]); | ||||
|             } | ||||
|         } | ||||
| @ -130,25 +139,39 @@ class UserController extends BaseController | ||||
|      */ | ||||
|     public function logout() | ||||
|     { | ||||
|         // 增加日志记录,记录用户退出登录操作
 | ||||
|         try { | ||||
|             // 记录退出日志
 | ||||
|             Log::record('用户退出登录', 'info'); | ||||
| 
 | ||||
|         // 销毁当前会话中的所有数据
 | ||||
|             // 1. 清除所有 session
 | ||||
|             session(null); | ||||
| 
 | ||||
|         // 清除缓存中的用户信息
 | ||||
|             // 2. 清除所有 cookie
 | ||||
|             // 正确的删除 cookie 方式
 | ||||
|             cookie('user_id', null, ['expire' => -1]); | ||||
|             cookie('user_account', null, ['expire' => -1]); | ||||
|             cookie('user_name', null, ['expire' => -1]); | ||||
|             cookie('user_avatar', null, ['expire' => -1]); | ||||
|             cookie('expire_time', null, ['expire' => -1]); | ||||
|             cookie('is_auto_login', null, ['expire' => -1]); | ||||
|             cookie('auto_login_attempted', null, ['expire' => -1]); | ||||
| 
 | ||||
|             // 3. 清除缓存
 | ||||
|             Cache::tag('user_cache')->clear(); | ||||
| 
 | ||||
|         // 清除cookie
 | ||||
|         cookie('user_id', null); | ||||
|         cookie('user_name', null); | ||||
|         cookie('user_avatar', null); | ||||
|         cookie('expire_time', null); | ||||
|         cookie('is_auto_login', null); | ||||
|         cookie('auto_login_attempted', null); | ||||
|             // 4. 返回成功状态,并告诉前端清除 localStorage
 | ||||
|             return json([ | ||||
|                 'code' => 0, | ||||
|                 'msg' => '退出成功', | ||||
|                 'data' => [ | ||||
|                     'clear_storage' => true | ||||
|                 ] | ||||
|             ]); | ||||
| 
 | ||||
|         // 返回成功状态
 | ||||
|         return json(['code' => 0, 'msg' => '退出成功']); | ||||
|         } catch (\Exception $e) { | ||||
|             Log::record('退出登录失败:' . $e->getMessage(), 'error'); | ||||
|             return json(['code' => 1, 'msg' => '退出失败:' . $e->getMessage()]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 生成随机用户名
 | ||||
| @ -276,4 +299,127 @@ class UserController extends BaseController | ||||
|             return json(['code' => 1, 'msg' => '发送失败:' . $result]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //个人中心
 | ||||
|     public function profile() | ||||
|     { | ||||
|         // 检查用户是否登录
 | ||||
|         if (!cookie('user_account')) { | ||||
|             return redirect('/index/user/login'); | ||||
|         } | ||||
| 
 | ||||
|         // 获取用户信息
 | ||||
|         $user = Users::where('account', cookie('user_account'))->find(); | ||||
|         // var_dump($user);
 | ||||
|         if (!$user) { | ||||
|             return redirect('/index/user/login'); | ||||
|         } | ||||
| 
 | ||||
|         View::assign('user', $user); | ||||
|         return $this->fetch(); | ||||
|     } | ||||
| 
 | ||||
|     public function saveBasic() | ||||
|     { | ||||
|         // 检查用户是否登录
 | ||||
|         if (!cookie('user_account')) { | ||||
|             return json(['code' => 1, 'msg' => '请先登录']); | ||||
|         } | ||||
| 
 | ||||
|         // 获取用户信息
 | ||||
|         $user = Users::where('account', cookie('user_account'))->find(); | ||||
|         if (!$user) { | ||||
|             return json(['code' => 1, 'msg' => '用户不存在']); | ||||
|         } | ||||
| 
 | ||||
|         // 获取表单数据
 | ||||
|         $data = $this->request->post(); | ||||
| 
 | ||||
|         // 验证用户名
 | ||||
|         if (empty($data['name'])) { | ||||
|             return json(['code' => 1, 'msg' => '用户名不能为空']); | ||||
|         } | ||||
| 
 | ||||
|         // 验证手机号格式
 | ||||
|         if (!empty($data['phone']) && !preg_match('/^1[3-9]\d{9}$/', $data['phone'])) { | ||||
|             return json(['code' => 1, 'msg' => '请检查手机号']); | ||||
|         } | ||||
| 
 | ||||
|         // 检查用户名是否已被使用(排除当前用户)
 | ||||
|         $existingUser = Users::where('name', $data['name']) | ||||
|             ->where('uid', '<>', $user->uid)  // 排除当前用户
 | ||||
|             ->find(); | ||||
| 
 | ||||
|         if ($existingUser) { | ||||
|             return json(['code' => 1, 'msg' => '该用户名已被使用']); | ||||
|         } | ||||
| 
 | ||||
|         // 更新用户信息
 | ||||
|         $user->name = $data['name']; | ||||
|         $user->phone = $data['phone'] ?? ''; | ||||
|         $user->sex = $data['sex'] ?? 0; | ||||
|         $user->qq = $data['qq'] ?? ''; | ||||
|         $user->update_time = time(); | ||||
| 
 | ||||
|         if ($user->save()) { | ||||
|             return json(['code' => 0, 'msg' => '保存成功']); | ||||
|         } else { | ||||
|             return json(['code' => 1, 'msg' => '保存失败']); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //更新头像
 | ||||
|     public function update_avatar() | ||||
|     { | ||||
|         // 检查用户是否登录
 | ||||
|         if (!cookie('user_account')) { | ||||
|             return json(['code' => 1, 'msg' => '请先登录']); | ||||
|         } | ||||
| 
 | ||||
|         // 获取用户信息
 | ||||
|         $user = Users::where('account', cookie('user_account'))->find(); | ||||
|         if (!$user) { | ||||
|             return json(['code' => 1, 'msg' => '用户不存在']); | ||||
|         } | ||||
| 
 | ||||
|         // 获取上传的文件
 | ||||
|         $file = $this->request->file('avatar'); | ||||
|         if (!$file) { | ||||
|             return json(['code' => 1, 'msg' => '请选择要上传的头像']); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             // 验证文件大小和类型
 | ||||
|             if ($file->getSize() > 2097152) { // 2MB
 | ||||
|                 return json(['code' => 1, 'msg' => '图片大小不能超过2MB']); | ||||
|             } | ||||
| 
 | ||||
|             $ext = strtolower($file->getOriginalExtension()); | ||||
|             if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) { | ||||
|                 return json(['code' => 1, 'msg' => '只支持jpg、jpeg、png、gif格式的图片']); | ||||
|             } | ||||
| 
 | ||||
|             // 移动到指定目录
 | ||||
|             $savename = \think\facade\Filesystem::disk('public')->putFile('avatar', $file); | ||||
|             if (!$savename) { | ||||
|                 return json(['code' => 1, 'msg' => '图片上传失败']); | ||||
|             } | ||||
| 
 | ||||
|             // 获取文件URL
 | ||||
|             $avatarUrl = '/storage/' . $savename; | ||||
| 
 | ||||
|             // 更新用户头像
 | ||||
|             $user->avatar = $avatarUrl; | ||||
|             $user->update_time = time(); | ||||
| 
 | ||||
|             if ($user->save()) { | ||||
|                 return json(['code' => 0, 'msg' => '头像更新成功', 'data' => ['url' => $avatarUrl]]); | ||||
|             } else { | ||||
|                 return json(['code' => 1, 'msg' => '头像更新失败']); | ||||
|             } | ||||
|         } catch (\Exception $e) { | ||||
|             return json(['code' => 1, 'msg' => '系统错误:' . $e->getMessage()]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,21 +1,21 @@ | ||||
| <?php | ||||
| // 获取当前登录状态
 | ||||
| $isLoggedIn = false; | ||||
| $userInfo = [ | ||||
|     'is_login' => false, | ||||
|     'name' => '', | ||||
|     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||
| ]; | ||||
| 
 | ||||
| // 检查session
 | ||||
| if (session('user_id')) { | ||||
|     $isLoggedIn = true; | ||||
| } | ||||
| // 如果session未登录,检查cookie
 | ||||
| else { | ||||
| // 检查cookie
 | ||||
| $userAccount = cookie('user_account'); | ||||
| if ($userAccount) { | ||||
|         // 恢复session
 | ||||
|         session('user_id', cookie('user_id')); | ||||
|         session('user_name', cookie('user_name')); | ||||
|         session('user_avatar', cookie('user_avatar')); | ||||
|     $isLoggedIn = true; | ||||
|     } | ||||
|     $userInfo = [ | ||||
|         'is_login' => true, | ||||
|         'name' => cookie('user_name'), | ||||
|         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| // 添加一个隐藏的div来存储登录状态
 | ||||
| @ -23,44 +23,13 @@ $loginStatus = [ | ||||
|     'isLoggedIn' => $isLoggedIn, | ||||
|     'userAccount' => $userAccount ?? '' | ||||
| ]; | ||||
| 
 | ||||
| $userInfo = [ | ||||
|     'is_login' => $isLoggedIn, | ||||
|     'name' => session('user_name'), | ||||
|     'avatar' => session('user_avatar') ? '/static/uploads/avatar/' . session('user_avatar') : '/static/images/avatar.png' | ||||
| ]; | ||||
| ?>
 | ||||
| 
 | ||||
| <!-- 添加一个隐藏的div来存储登录状态 --> | ||||
| <div id="loginStatus" style="display: none;"  | ||||
|     data-is-logged-in="{$isLoggedIn}"  | ||||
|     data-user-account="{$userAccount ?? ''}"> | ||||
| <div id="loginStatus" style="display: none;" data-is-logged-in="{$isLoggedIn}" data-user-account="{$userAccount ?? ''}"> | ||||
| </div> | ||||
| 
 | ||||
| <div style="display: flex;flex-direction: column;"> | ||||
|     <div class="topbar-one"> | ||||
|         <div class="container"> | ||||
|             <div style="width: 70%;"> | ||||
|                 <ul class="list-unstyled topbar-one__info"> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-phone-alt" style="margin-right: 10px;"></span> | ||||
|                         <a href="{$config['admin_phone']}">{$config['admin_phone']}</a> | ||||
|                     </li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-envelope" style="margin-right: 10px;"></span> | ||||
|                         <a href="mailto:{$config['admin_email']}">{$config['admin_email']}</a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="topbar-one__social" style="width: 30%;"> | ||||
|                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||
|                 <div class="qrcode-popup" | ||||
|                     style="display:none;position:absolute;right:54px;top:32px;background:#fff;padding:10px;box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;"> | ||||
|                     <img src="{$config['admin_wechat']}" alt="公众号二维码" style="width:180px;height:180px;"> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <!-- 导航栏 --> | ||||
|     <div class="main-menu"> | ||||
|         <div class="container"> | ||||
| @ -76,11 +45,16 @@ $userInfo = [ | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text">{$userInfo.name}</span> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($isLoggedIn): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;"> | ||||
|                             <img src="/static/images/avatar.png" class="layui-circle" | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                                 <ul> | ||||
| @ -127,11 +101,16 @@ $userInfo = [ | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text">{$userInfo.name}</span> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($isLoggedIn): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;"> | ||||
|                             <img src="/static/images/avatar.png" class="layui-circle" | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                                 <ul> | ||||
| @ -361,6 +340,16 @@ $userInfo = [ | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| 
 | ||||
|     .main-menu__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .username { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| @ -453,46 +442,6 @@ $userInfo = [ | ||||
|         // 页面加载时检查自动登录
 | ||||
|         checkAutoLogin(); | ||||
| 
 | ||||
|         // 加载banner数据
 | ||||
|         $.ajax({ | ||||
|             url: '/index/index/bannerlist', | ||||
|             type: 'GET', | ||||
|             success: function (res) { | ||||
|                 if (res.code === 1) { | ||||
|                     var bannerHtml = ''; | ||||
|                     res.banner.forEach(function (banner) { | ||||
|                         bannerHtml += '<div>' + | ||||
|                             '<div class="banner-content">' + | ||||
|                             '<div class="banner-image">' + | ||||
|                             '<img src="' + banner.image + '" alt="' + (banner.title || '') + '">' + | ||||
|                             '</div>' + | ||||
|                             '<div class="banner-text">' + | ||||
|                             '<span class="banner-title">' + (banner.title || '') + '</span>' + | ||||
|                             '<span class="banner-desc">' + (banner.desc || '') + '</span>' + | ||||
|                             '<a href="' + (banner.url || 'javascript:;') + '" class="banner-slide">' + | ||||
|                             '<span class="banner-btn">查看详情</span>' + | ||||
|                             '</a>' + | ||||
|                             '</div>' + | ||||
|                             '</div>' + | ||||
|                             '</div>'; | ||||
|                     }); | ||||
|                     $('#test10 div[carousel-item]').html(bannerHtml); | ||||
| 
 | ||||
|                     // 图片轮播
 | ||||
|                     carousel.render({ | ||||
|                         elem: '#test10', | ||||
|                         width: '100%', | ||||
|                         height: '100vh', | ||||
|                         interval: 4000, | ||||
|                         anim: 'fade', | ||||
|                         autoplay: true, | ||||
|                         full: false, | ||||
|                         arrow: 'hover' | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         $(document).ready(function () { | ||||
|             // 主导航头像
 | ||||
|             $("#userAvatarMain").click(function (e) { | ||||
|  | ||||
| @ -1,21 +1,21 @@ | ||||
| <?php | ||||
| // 获取当前登录状态
 | ||||
| $isLoggedIn = false; | ||||
| $userInfo = [ | ||||
|     'is_login' => false, | ||||
|     'name' => '', | ||||
|     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||
| ]; | ||||
| 
 | ||||
| // 检查session
 | ||||
| if (session('user_id')) { | ||||
|     $isLoggedIn = true; | ||||
| } | ||||
| // 如果session未登录,检查cookie
 | ||||
| else { | ||||
| // 检查cookie
 | ||||
| $userAccount = cookie('user_account'); | ||||
| if ($userAccount) { | ||||
|         // 恢复session
 | ||||
|         session('user_id', cookie('user_id')); | ||||
|         session('user_name', cookie('user_name')); | ||||
|         session('user_avatar', cookie('user_avatar')); | ||||
|     $isLoggedIn = true; | ||||
|     } | ||||
|     $userInfo = [ | ||||
|         'is_login' => true, | ||||
|         'name' => cookie('user_name'), | ||||
|         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| // 添加一个隐藏的div来存储登录状态
 | ||||
| @ -23,12 +23,6 @@ $loginStatus = [ | ||||
|     'isLoggedIn' => $isLoggedIn, | ||||
|     'userAccount' => $userAccount ?? '' | ||||
| ]; | ||||
| 
 | ||||
| $userInfo = [ | ||||
|     'is_login' => $isLoggedIn, | ||||
|     'name' => session('user_name'), | ||||
|     'avatar' => session('user_avatar') ? '/static/uploads/avatar/' . session('user_avatar') : '/static/images/avatar.png' | ||||
| ]; | ||||
| ?>
 | ||||
| 
 | ||||
| <!-- 添加一个隐藏的div来存储登录状态 --> | ||||
| @ -74,10 +68,15 @@ $userInfo = [ | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text">{$userInfo.name}</span> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;"> | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||
|                             <div class="user-dropdown" id="userDropdownMain"> | ||||
| @ -140,7 +139,7 @@ $userInfo = [ | ||||
|                 <div class="layui-inline"> | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;"> | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
| @ -371,6 +370,16 @@ $userInfo = [ | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| 
 | ||||
|     .main-menu__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .username { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|  | ||||
							
								
								
									
										255
									
								
								app/index/view/user/component/avatar.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								app/index/view/user/component/avatar.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,255 @@ | ||||
| <div class="avatar-section"> | ||||
|     <h2 class="section-title">修改头像</h2> | ||||
|      | ||||
|     <div class="avatar-upload-container"> | ||||
|         <div class="current-avatar"> | ||||
|             <img src="{$user.avatar|default='/static/images/avatar.png'}" alt="当前头像" id="currentAvatar"> | ||||
|             <p class="avatar-tip">当前头像</p> | ||||
|         </div> | ||||
|          | ||||
|         <div class="upload-area" id="uploadArea"> | ||||
|             <i class="layui-icon layui-icon-upload"></i> | ||||
|             <p>点击或拖拽图片到此处上传</p> | ||||
|             <p class="upload-tip">支持 jpg、png、gif 格式,大小不超过 2MB</p> | ||||
|             <input type="file" id="avatarFile" accept="image/*" style="display: none;"> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="avatar-preview" style="display: none;"> | ||||
|         <h3>预览</h3> | ||||
|         <div class="preview-container"> | ||||
|             <img src="" alt="预览图" id="previewImage"> | ||||
|         </div> | ||||
|         <div class="preview-actions"> | ||||
|             <button class="layui-btn" id="confirmUpload">确认上传</button> | ||||
|             <button class="layui-btn layui-btn-primary" id="cancelUpload">取消</button> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .avatar-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .avatar-upload-container { | ||||
|     display: flex; | ||||
|     gap: 40px; | ||||
|     margin-bottom: 32px; | ||||
| } | ||||
| 
 | ||||
| .current-avatar { | ||||
|     text-align: center; | ||||
| } | ||||
| 
 | ||||
| .current-avatar img { | ||||
|     width: 160px; | ||||
|     height: 160px; | ||||
|     border-radius: 50%; | ||||
|     object-fit: cover; | ||||
|     border: 3px solid #f5f5f5;
 | ||||
| } | ||||
| 
 | ||||
| .avatar-tip { | ||||
|     margin-top: 12px; | ||||
|     color: #666;
 | ||||
| } | ||||
| 
 | ||||
| .upload-area { | ||||
|     flex: 1; | ||||
|     border: 2px dashed #d9d9d9;
 | ||||
|     border-radius: 8px; | ||||
|     padding: 40px; | ||||
|     text-align: center; | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s; | ||||
| } | ||||
| 
 | ||||
| .upload-area:hover { | ||||
|     border-color: #1677ff;
 | ||||
| } | ||||
| 
 | ||||
| .upload-area .layui-icon { | ||||
|     font-size: 48px; | ||||
|     color: #999;
 | ||||
|     margin-bottom: 16px; | ||||
| } | ||||
| 
 | ||||
| .upload-area p { | ||||
|     margin: 8px 0; | ||||
|     color: #666;
 | ||||
| } | ||||
| 
 | ||||
| .upload-tip { | ||||
|     font-size: 12px; | ||||
|     color: #999;
 | ||||
| } | ||||
| 
 | ||||
| .avatar-preview { | ||||
|     margin-top: 32px; | ||||
|     padding-top: 32px; | ||||
|     border-top: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .avatar-preview h3 { | ||||
|     font-size: 16px; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 16px; | ||||
| } | ||||
| 
 | ||||
| .preview-container { | ||||
|     text-align: center; | ||||
|     margin-bottom: 24px; | ||||
| } | ||||
| 
 | ||||
| .preview-container img { | ||||
|     max-width: 200px; | ||||
|     max-height: 200px; | ||||
|     border-radius: 8px; | ||||
| } | ||||
| 
 | ||||
| .preview-actions { | ||||
|     text-align: center; | ||||
| } | ||||
| 
 | ||||
| .preview-actions .layui-btn { | ||||
|     margin: 0 8px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .avatar-upload-container { | ||||
|         flex-direction: column; | ||||
|         gap: 24px; | ||||
|     } | ||||
|      | ||||
|     .current-avatar img { | ||||
|         width: 120px; | ||||
|         height: 120px; | ||||
|     } | ||||
|      | ||||
|     .upload-area { | ||||
|         padding: 24px; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['upload', 'layer'], function(){ | ||||
|     var upload = layui.upload; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 点击上传区域触发文件选择
 | ||||
|     document.getElementById('uploadArea').addEventListener('click', function() { | ||||
|         document.getElementById('avatarFile').click(); | ||||
|     }); | ||||
|      | ||||
|     // 处理文件选择
 | ||||
|     document.getElementById('avatarFile').addEventListener('change', function(e) { | ||||
|         var file = e.target.files[0]; | ||||
|         if (!file) return; | ||||
|          | ||||
|         // 检查文件类型
 | ||||
|         if (!['image/jpeg', 'image/png', 'image/gif'].includes(file.type)) { | ||||
|             layer.msg('请上传 jpg、png 或 gif 格式的图片'); | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         // 检查文件大小
 | ||||
|         if (file.size > 2 * 1024 * 1024) { | ||||
|             layer.msg('图片大小不能超过 2MB'); | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         // 预览图片
 | ||||
|         var reader = new FileReader(); | ||||
|         reader.onload = function(e) { | ||||
|             document.getElementById('previewImage').src = e.target.result; | ||||
|             document.querySelector('.avatar-preview').style.display = 'block'; | ||||
|         }; | ||||
|         reader.readAsDataURL(file); | ||||
|     }); | ||||
|      | ||||
|     // 确认上传
 | ||||
|     document.getElementById('confirmUpload').addEventListener('click', function() { | ||||
|         var file = document.getElementById('avatarFile').files[0]; | ||||
|         if (!file) return; | ||||
|          | ||||
|         var formData = new FormData(); | ||||
|         formData.append('avatar', file); | ||||
|          | ||||
|         // 显示上传中
 | ||||
|         var loadIndex = layer.load(2); | ||||
|          | ||||
|         // 发送上传请求
 | ||||
|         fetch('/index/user/update_avatar', { | ||||
|             method: 'POST', | ||||
|             body: formData | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             layer.close(loadIndex); | ||||
|             if (data.code === 0) { | ||||
|                 layer.msg('头像上传成功', {icon: 1}); | ||||
|                 // 更新当前头像显示
 | ||||
|                 document.getElementById('currentAvatar').src = data.data.url; | ||||
|                 // 隐藏预览区域
 | ||||
|                 document.querySelector('.avatar-preview').style.display = 'none'; | ||||
|                 // 清空文件输入
 | ||||
|                 document.getElementById('avatarFile').value = ''; | ||||
|             } else { | ||||
|                 layer.msg(data.msg || '上传失败', {icon: 2}); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             layer.close(loadIndex); | ||||
|             layer.msg('上传失败,请重试', {icon: 2}); | ||||
|         }); | ||||
|     }); | ||||
|      | ||||
|     // 取消上传
 | ||||
|     document.getElementById('cancelUpload').addEventListener('click', function() { | ||||
|         document.querySelector('.avatar-preview').style.display = 'none'; | ||||
|         document.getElementById('avatarFile').value = ''; | ||||
|     }); | ||||
|      | ||||
|     // 拖拽上传
 | ||||
|     var uploadArea = document.getElementById('uploadArea'); | ||||
|      | ||||
|     uploadArea.addEventListener('dragover', function(e) { | ||||
|         e.preventDefault(); | ||||
|         this.style.borderColor = '#1677ff'; | ||||
|     }); | ||||
|      | ||||
|     uploadArea.addEventListener('dragleave', function(e) { | ||||
|         e.preventDefault(); | ||||
|         this.style.borderColor = '#d9d9d9'; | ||||
|     }); | ||||
|      | ||||
|     uploadArea.addEventListener('drop', function(e) { | ||||
|         e.preventDefault(); | ||||
|         this.style.borderColor = '#d9d9d9'; | ||||
|          | ||||
|         var file = e.dataTransfer.files[0]; | ||||
|         if (!file) return; | ||||
|          | ||||
|         // 触发文件选择事件
 | ||||
|         var dataTransfer = new DataTransfer(); | ||||
|         dataTransfer.items.add(file); | ||||
|         document.getElementById('avatarFile').files = dataTransfer.files; | ||||
|          | ||||
|         // 手动触发change事件
 | ||||
|         var event = new Event('change'); | ||||
|         document.getElementById('avatarFile').dispatchEvent(event); | ||||
|     }); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										127
									
								
								app/index/view/user/component/basic.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								app/index/view/user/component/basic.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| <div class="basic-info"> | ||||
|     <h2 class="section-title">个人资料</h2> | ||||
|     <form class="layui-form" lay-filter="basicForm"> | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">用户名</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="text" name="name" value="{$user.name}" placeholder="请输入用户名" class="layui-input"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">账号</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="text" value="{$user.account}" class="layui-input" disabled> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">QQ</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="qq" name="qq" value="{$user.qq}" placeholder="请输入QQ号" class="layui-input"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">手机号</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="tel" name="phone" value="{$user.phone}" placeholder="请输入手机号" class="layui-input"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">性别</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="radio" name="sex" value="1" title="男" {if $user.sex==1}checked{/if}> | ||||
|                 <input type="radio" name="sex" value="2" title="女" {if $user.sex==2}checked{/if}> | ||||
|                 <input type="radio" name="sex" value="0" title="保密" {if $user.sex==0}checked{/if}> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <div class="layui-input-block"> | ||||
|                 <button class="layui-btn" lay-submit lay-filter="saveBasic">保存修改</button> | ||||
|                 <button type="reset" class="layui-btn layui-btn-primary">重置</button> | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
|     .basic-info { | ||||
|         max-width: 800px; | ||||
|         margin: 0 auto; | ||||
|     } | ||||
| 
 | ||||
|     .section-title { | ||||
|         font-size: 20px; | ||||
|         font-weight: 600; | ||||
|         color: #333;
 | ||||
|         margin-bottom: 24px; | ||||
|         padding-bottom: 16px; | ||||
|         border-bottom: 1px solid #f0f0f0;
 | ||||
|     } | ||||
| 
 | ||||
|     .layui-form-label { | ||||
|         width: 100px; | ||||
|     } | ||||
| 
 | ||||
|     .layui-input-block { | ||||
|         margin-left: 130px; | ||||
|     } | ||||
| 
 | ||||
|     .layui-form-item { | ||||
|         margin-bottom: 24px; | ||||
|     } | ||||
| 
 | ||||
|     .layui-textarea { | ||||
|         min-height: 120px; | ||||
|     } | ||||
| 
 | ||||
|     @media (max-width: 768px) { | ||||
|         .layui-form-label { | ||||
|             width: 80px; | ||||
|         } | ||||
| 
 | ||||
|         .layui-input-block { | ||||
|             margin-left: 110px; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     layui.use(['form', 'layer'], function () { | ||||
|         var form = layui.form; | ||||
|         var layer = layui.layer; | ||||
| 
 | ||||
|         // 监听表单提交
 | ||||
|         form.on('submit(saveBasic)', function (data) { | ||||
|             // 发送AJAX请求保存数据
 | ||||
|             fetch('/index/user/saveBasic', { | ||||
|                 method: 'POST', | ||||
|                 headers: { | ||||
|                     'Content-Type': 'application/json', | ||||
|                     'X-Requested-With': 'XMLHttpRequest' | ||||
|                 }, | ||||
|                 body: JSON.stringify(data.field) | ||||
|             }) | ||||
|                 .then(response => response.json()) | ||||
|                 .then(result => { | ||||
|                     if (result.code === 0) { | ||||
|                         layer.msg(result.msg, { icon: 1 }, function () { | ||||
|                             // 保存成功后刷新页面
 | ||||
|                             window.location.reload(); | ||||
|                         }); | ||||
|                     } else { | ||||
|                         layer.msg(result.msg, { icon: 2 }); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(error => { | ||||
|                     console.error('保存失败:', error); | ||||
|                     layer.msg('保存失败,请稍后重试', { icon: 2 }); | ||||
|                 }); | ||||
| 
 | ||||
|             return false; // 阻止表单默认提交
 | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
							
								
								
									
										310
									
								
								app/index/view/user/component/messages.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								app/index/view/user/component/messages.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,310 @@ | ||||
| <div class="messages-section"> | ||||
|     <h2 class="section-title">我的消息</h2> | ||||
|      | ||||
|     <div class="message-tabs"> | ||||
|         <div class="layui-tab layui-tab-brief" lay-filter="messageTabs"> | ||||
|             <ul class="layui-tab-title"> | ||||
|                 <li class="layui-this">全部消息</li> | ||||
|                 <li>未读消息</li> | ||||
|                 <li>已读消息</li> | ||||
|             </ul> | ||||
|             <div class="layui-tab-content"> | ||||
|                 <div class="layui-tab-item layui-show"> | ||||
|                     <div class="message-list" id="allMessages"> | ||||
|                         <!-- 消息列表将通过JavaScript动态加载 --> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="layui-tab-item"> | ||||
|                     <div class="message-list" id="unreadMessages"> | ||||
|                         <!-- 未读消息列表 --> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="layui-tab-item"> | ||||
|                     <div class="message-list" id="readMessages"> | ||||
|                         <!-- 已读消息列表 --> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .messages-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .message-tabs { | ||||
|     margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| .message-list { | ||||
|     margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| .message-item { | ||||
|     padding: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
|     display: flex; | ||||
|     align-items: flex-start; | ||||
|     gap: 16px; | ||||
|     cursor: pointer; | ||||
|     transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .message-item:hover { | ||||
|     background-color: #f9f9f9;
 | ||||
| } | ||||
| 
 | ||||
| .message-item.unread { | ||||
|     background-color: #f0f7ff;
 | ||||
| } | ||||
| 
 | ||||
| .message-avatar { | ||||
|     width: 40px; | ||||
|     height: 40px; | ||||
|     border-radius: 50%; | ||||
|     object-fit: cover; | ||||
| } | ||||
| 
 | ||||
| .message-content { | ||||
|     flex: 1; | ||||
| } | ||||
| 
 | ||||
| .message-title { | ||||
|     font-weight: 500; | ||||
|     margin-bottom: 4px; | ||||
|     color: #333;
 | ||||
| } | ||||
| 
 | ||||
| .message-text { | ||||
|     color: #666;
 | ||||
|     font-size: 14px; | ||||
|     margin-bottom: 8px; | ||||
| } | ||||
| 
 | ||||
| .message-meta { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     font-size: 12px; | ||||
|     color: #999;
 | ||||
| } | ||||
| 
 | ||||
| .message-time { | ||||
|     color: #999;
 | ||||
| } | ||||
| 
 | ||||
| .message-actions { | ||||
|     display: flex; | ||||
|     gap: 8px; | ||||
| } | ||||
| 
 | ||||
| .message-actions button { | ||||
|     padding: 4px 8px; | ||||
|     font-size: 12px; | ||||
|     border-radius: 4px; | ||||
|     background: none; | ||||
|     border: 1px solid #d9d9d9;
 | ||||
|     color: #666;
 | ||||
|     cursor: pointer; | ||||
|     transition: all 0.3s; | ||||
| } | ||||
| 
 | ||||
| .message-actions button:hover { | ||||
|     border-color: #1677ff;
 | ||||
|     color: #1677ff;
 | ||||
| } | ||||
| 
 | ||||
| .empty-message { | ||||
|     text-align: center; | ||||
|     padding: 40px 0; | ||||
|     color: #999;
 | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .message-item { | ||||
|         padding: 12px; | ||||
|     } | ||||
|      | ||||
|     .message-avatar { | ||||
|         width: 32px; | ||||
|         height: 32px; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['element', 'layer'], function(){ | ||||
|     var element = layui.element; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 加载消息列表
 | ||||
|     function loadMessages(type) { | ||||
|         var container = document.getElementById(type + 'Messages'); | ||||
|         var loadIndex = layer.load(2); | ||||
|          | ||||
|         fetch('/index/user/getMessages?type=' + type) | ||||
|             .then(response => response.json()) | ||||
|             .then(data => { | ||||
|                 layer.close(loadIndex); | ||||
|                 if(data.code === 0) { | ||||
|                     renderMessages(container, data.data); | ||||
|                 } else { | ||||
|                     layer.msg(data.msg || '加载失败', {icon: 2}); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 layer.close(loadIndex); | ||||
|                 layer.msg('加载失败,请重试', {icon: 2}); | ||||
|             }); | ||||
|     } | ||||
|      | ||||
|     // 渲染消息列表
 | ||||
|     function renderMessages(container, messages) { | ||||
|         if(!messages || messages.length === 0) { | ||||
|             container.innerHTML = '<div class="empty-message">暂无消息</div>'; | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         var html = ''; | ||||
|         messages.forEach(function(message) { | ||||
|             html += ` | ||||
|                 <div class="message-item ${message.is_read ? '' : 'unread'}" data-id="${message.id}"> | ||||
|                     <img src="${message.avatar || '/static/images/avatar.png'}" class="message-avatar" alt="头像"> | ||||
|                     <div class="message-content"> | ||||
|                         <div class="message-title">${message.title}</div> | ||||
|                         <div class="message-text">${message.content}</div> | ||||
|                         <div class="message-meta"> | ||||
|                             <span class="message-time">${message.create_time}</span> | ||||
|                             <div class="message-actions"> | ||||
|                                 ${!message.is_read ? '<button class="mark-read">标记已读</button>' : ''} | ||||
|                                 <button class="delete-message">删除</button> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             `; | ||||
|         }); | ||||
|          | ||||
|         container.innerHTML = html; | ||||
|          | ||||
|         // 绑定事件
 | ||||
|         bindMessageEvents(container); | ||||
|     } | ||||
|      | ||||
|     // 绑定消息事件
 | ||||
|     function bindMessageEvents(container) { | ||||
|         // 标记已读
 | ||||
|         container.querySelectorAll('.mark-read').forEach(btn => { | ||||
|             btn.addEventListener('click', function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 var messageId = this.closest('.message-item').dataset.id; | ||||
|                 markAsRead(messageId); | ||||
|             }); | ||||
|         }); | ||||
|          | ||||
|         // 删除消息
 | ||||
|         container.querySelectorAll('.delete-message').forEach(btn => { | ||||
|             btn.addEventListener('click', function(e) { | ||||
|                 e.stopPropagation(); | ||||
|                 var messageId = this.closest('.message-item').dataset.id; | ||||
|                 deleteMessage(messageId); | ||||
|             }); | ||||
|         }); | ||||
|          | ||||
|         // 点击消息
 | ||||
|         container.querySelectorAll('.message-item').forEach(item => { | ||||
|             item.addEventListener('click', function() { | ||||
|                 var messageId = this.dataset.id; | ||||
|                 viewMessage(messageId); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 标记已读
 | ||||
|     function markAsRead(messageId) { | ||||
|         fetch('/index/user/markMessageRead', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json' | ||||
|             }, | ||||
|             body: JSON.stringify({id: messageId}) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             if(data.code === 0) { | ||||
|                 layer.msg('已标记为已读', {icon: 1}); | ||||
|                 // 重新加载消息列表
 | ||||
|                 loadMessages('all'); | ||||
|                 loadMessages('unread'); | ||||
|                 loadMessages('read'); | ||||
|             } else { | ||||
|                 layer.msg(data.msg || '操作失败', {icon: 2}); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             layer.msg('操作失败,请重试', {icon: 2}); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 删除消息
 | ||||
|     function deleteMessage(messageId) { | ||||
|         layer.confirm('确定要删除这条消息吗?', { | ||||
|             btn: ['确定','取消'] | ||||
|         }, function(){ | ||||
|             fetch('/index/user/deleteMessage', { | ||||
|                 method: 'POST', | ||||
|                 headers: { | ||||
|                     'Content-Type': 'application/json' | ||||
|                 }, | ||||
|                 body: JSON.stringify({id: messageId}) | ||||
|             }) | ||||
|             .then(response => response.json()) | ||||
|             .then(data => { | ||||
|                 if(data.code === 0) { | ||||
|                     layer.msg('删除成功', {icon: 1}); | ||||
|                     // 重新加载消息列表
 | ||||
|                     loadMessages('all'); | ||||
|                     loadMessages('unread'); | ||||
|                     loadMessages('read'); | ||||
|                 } else { | ||||
|                     layer.msg(data.msg || '删除失败', {icon: 2}); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 layer.msg('删除失败,请重试', {icon: 2}); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 查看消息详情
 | ||||
|     function viewMessage(messageId) { | ||||
|         layer.open({ | ||||
|             type: 2, | ||||
|             title: '消息详情', | ||||
|             area: ['500px', '400px'], | ||||
|             content: '/index/user/messageDetail?id=' + messageId | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 监听标签切换
 | ||||
|     element.on('tab(messageTabs)', function(data){ | ||||
|         var type = ['all', 'unread', 'read'][data.index]; | ||||
|         loadMessages(type); | ||||
|     }); | ||||
|      | ||||
|     // 初始加载全部消息
 | ||||
|     loadMessages('all'); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										210
									
								
								app/index/view/user/component/notifications.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								app/index/view/user/component/notifications.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,210 @@ | ||||
| <div class="notifications-section"> | ||||
|     <h2 class="section-title">系统通知</h2> | ||||
|      | ||||
|     <div class="layui-tab layui-tab-brief" lay-filter="notificationTabs"> | ||||
|         <ul class="layui-tab-title"> | ||||
|             <li class="layui-this">全部通知</li> | ||||
|             <li>未读通知</li> | ||||
|             <li>已读通知</li> | ||||
|         </ul> | ||||
|         <div class="layui-tab-content"> | ||||
|             <div class="layui-tab-item layui-show"> | ||||
|                 <div class="notification-list" id="allNotifications"></div> | ||||
|             </div> | ||||
|             <div class="layui-tab-item"> | ||||
|                 <div class="notification-list" id="unreadNotifications"></div> | ||||
|             </div> | ||||
|             <div class="layui-tab-item"> | ||||
|                 <div class="notification-list" id="readNotifications"></div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .notifications-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .notification-list { | ||||
|     min-height: 200px; | ||||
| } | ||||
| 
 | ||||
| .notification-item { | ||||
|     padding: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
| } | ||||
| 
 | ||||
| .notification-item:hover { | ||||
|     background-color: #f9f9f9;
 | ||||
| } | ||||
| 
 | ||||
| .notification-content { | ||||
|     flex: 1; | ||||
| } | ||||
| 
 | ||||
| .notification-title { | ||||
|     font-size: 16px; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 8px; | ||||
| } | ||||
| 
 | ||||
| .notification-time { | ||||
|     font-size: 12px; | ||||
|     color: #999;
 | ||||
| } | ||||
| 
 | ||||
| .notification-actions { | ||||
|     display: flex; | ||||
|     gap: 8px; | ||||
| } | ||||
| 
 | ||||
| .notification-item.unread .notification-title { | ||||
|     font-weight: 600; | ||||
| } | ||||
| 
 | ||||
| .notification-item.unread::before { | ||||
|     content: ''; | ||||
|     display: inline-block; | ||||
|     width: 8px; | ||||
|     height: 8px; | ||||
|     background-color: #1677ff;
 | ||||
|     border-radius: 50%; | ||||
|     margin-right: 8px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .notification-actions { | ||||
|         flex-direction: column; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['element', 'layer'], function(){ | ||||
|     var element = layui.element; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 加载通知列表
 | ||||
|     function loadNotifications(type) { | ||||
|         var container = document.getElementById(type + 'Notifications'); | ||||
|         container.innerHTML = '<div class="layui-anim layui-anim-upbit layui-anim-loop layui-anim-shrink" style="text-align: center; padding: 20px;"><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>'; | ||||
|          | ||||
|         fetch('/index/user/getNotifications?type=' + type) | ||||
|             .then(response => response.json()) | ||||
|             .then(data => { | ||||
|                 if(data.code === 0) { | ||||
|                     if(data.data.length === 0) { | ||||
|                         container.innerHTML = '<div class="layui-none">暂无通知</div>'; | ||||
|                         return; | ||||
|                     } | ||||
|                      | ||||
|                     var html = ''; | ||||
|                     data.data.forEach(function(notification) { | ||||
|                         html += ` | ||||
|                             <div class="notification-item ${notification.is_read ? '' : 'unread'}" data-id="${notification.id}"> | ||||
|                                 <div class="notification-content"> | ||||
|                                     <div class="notification-title">${notification.title}</div> | ||||
|                                     <div class="notification-time">${notification.create_time}</div> | ||||
|                                 </div> | ||||
|                                 <div class="notification-actions"> | ||||
|                                     <button class="layui-btn layui-btn-xs" onclick="viewNotification(${notification.id})">查看</button> | ||||
|                                     <button class="layui-btn layui-btn-xs layui-btn-danger" onclick="deleteNotification(${notification.id})">删除</button> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         `; | ||||
|                     }); | ||||
|                     container.innerHTML = html; | ||||
|                 } else { | ||||
|                     layer.msg(data.msg || '加载失败', {icon: 2}); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 layer.msg('加载失败,请重试', {icon: 2}); | ||||
|             }); | ||||
|     } | ||||
|      | ||||
|     // 查看通知
 | ||||
|     window.viewNotification = function(notificationId) { | ||||
|         fetch('/index/user/readNotification', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json' | ||||
|             }, | ||||
|             body: JSON.stringify({id: notificationId}) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             if(data.code === 0) { | ||||
|                 layer.open({ | ||||
|                     type: 2, | ||||
|                     title: '通知详情', | ||||
|                     area: ['500px', '400px'], | ||||
|                     content: '/index/user/notificationDetail?id=' + notificationId | ||||
|                 }); | ||||
|                 // 重新加载通知列表
 | ||||
|                 loadNotifications('all'); | ||||
|                 loadNotifications('unread'); | ||||
|                 loadNotifications('read'); | ||||
|             } else { | ||||
|                 layer.msg(data.msg || '操作失败', {icon: 2}); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             layer.msg('操作失败,请重试', {icon: 2}); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 删除通知
 | ||||
|     window.deleteNotification = function(notificationId) { | ||||
|         layer.confirm('确定要删除这条通知吗?', { | ||||
|             btn: ['确定','取消'] | ||||
|         }, function(){ | ||||
|             fetch('/index/user/deleteNotification', { | ||||
|                 method: 'POST', | ||||
|                 headers: { | ||||
|                     'Content-Type': 'application/json' | ||||
|                 }, | ||||
|                 body: JSON.stringify({id: notificationId}) | ||||
|             }) | ||||
|             .then(response => response.json()) | ||||
|             .then(data => { | ||||
|                 if(data.code === 0) { | ||||
|                     layer.msg('删除成功', {icon: 1}); | ||||
|                     // 重新加载通知列表
 | ||||
|                     loadNotifications('all'); | ||||
|                     loadNotifications('unread'); | ||||
|                     loadNotifications('read'); | ||||
|                 } else { | ||||
|                     layer.msg(data.msg || '删除失败', {icon: 2}); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 layer.msg('删除失败,请重试', {icon: 2}); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|     // 监听标签切换
 | ||||
|     element.on('tab(notificationTabs)', function(data){ | ||||
|         var type = ['all', 'unread', 'read'][data.index]; | ||||
|         loadNotifications(type); | ||||
|     }); | ||||
|      | ||||
|     // 初始加载全部通知
 | ||||
|     loadNotifications('all'); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										111
									
								
								app/index/view/user/component/password.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								app/index/view/user/component/password.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | ||||
| <div class="password-section"> | ||||
|     <h2 class="section-title">修改密码</h2> | ||||
|      | ||||
|     <form class="layui-form" lay-filter="passwordForm"> | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">当前密码</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="password" name="oldPassword" placeholder="请输入当前密码" class="layui-input" required> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">新密码</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="password" name="newPassword" placeholder="请输入新密码" class="layui-input" required> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">确认密码</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="password" name="confirmPassword" placeholder="请再次输入新密码" class="layui-input" required> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="layui-form-item"> | ||||
|             <div class="layui-input-block"> | ||||
|                 <button class="layui-btn" lay-submit lay-filter="savePassword">保存修改</button> | ||||
|                 <button type="reset" class="layui-btn layui-btn-primary">重置</button> | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .password-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .layui-form-label { | ||||
|     width: 100px; | ||||
| } | ||||
| 
 | ||||
| .layui-input-block { | ||||
|     margin-left: 130px; | ||||
| } | ||||
| 
 | ||||
| .layui-form-item { | ||||
|     margin-bottom: 24px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .layui-form-label { | ||||
|         width: 80px; | ||||
|     } | ||||
|      | ||||
|     .layui-input-block { | ||||
|         margin-left: 110px; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['form', 'layer'], function(){ | ||||
|     var form = layui.form; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 监听表单提交
 | ||||
|     form.on('submit(savePassword)', function(data){ | ||||
|         // 验证两次密码是否一致
 | ||||
|         if(data.field.newPassword !== data.field.confirmPassword) { | ||||
|             layer.msg('两次输入的密码不一致', {icon: 2}); | ||||
|             return false; | ||||
|         } | ||||
|          | ||||
|         // 发送AJAX请求修改密码
 | ||||
|         fetch('/index/user/changePassword', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json' | ||||
|             }, | ||||
|             body: JSON.stringify(data.field) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             if(data.code === 0) { | ||||
|                 layer.msg('密码修改成功', {icon: 1}); | ||||
|                 // 清空表单
 | ||||
|                 document.querySelector('form').reset(); | ||||
|             } else { | ||||
|                 layer.msg(data.msg || '修改失败', {icon: 2}); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             layer.msg('修改失败,请重试', {icon: 2}); | ||||
|         }); | ||||
|          | ||||
|         return false; | ||||
|     }); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										170
									
								
								app/index/view/user/component/security.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								app/index/view/user/component/security.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | ||||
| <div class="security-section"> | ||||
|     <h2 class="section-title">安全设置</h2> | ||||
|      | ||||
|     <form class="layui-form" lay-filter="securityForm"> | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">登录密码</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <button type="button" class="layui-btn" onclick="changePassword()">修改密码</button> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">手机绑定</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <div class="phone-info"> | ||||
|                     <span id="phoneNumber">未绑定</span> | ||||
|                     <button type="button" class="layui-btn layui-btn-primary" onclick="bindPhone()">绑定手机</button> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">邮箱绑定</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <div class="email-info"> | ||||
|                     <span id="emailAddress">未绑定</span> | ||||
|                     <button type="button" class="layui-btn layui-btn-primary" onclick="bindEmail()">绑定邮箱</button> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">两步验证</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="checkbox" name="twoFactor" lay-skin="switch" lay-text="开启|关闭"> | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .security-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .phone-info, .email-info { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     gap: 16px; | ||||
| } | ||||
| 
 | ||||
| .layui-form-label { | ||||
|     width: 100px; | ||||
| } | ||||
| 
 | ||||
| .layui-input-block { | ||||
|     margin-left: 130px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .layui-form-label { | ||||
|         width: 80px; | ||||
|     } | ||||
|      | ||||
|     .layui-input-block { | ||||
|         margin-left: 110px; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['form', 'layer'], function(){ | ||||
|     var form = layui.form; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 加载用户安全信息
 | ||||
|     loadSecurityInfo(); | ||||
|      | ||||
|     // 监听两步验证开关
 | ||||
|     form.on('switch(twoFactor)', function(data){ | ||||
|         updateTwoFactor(data.elem.checked); | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| // 加载安全信息
 | ||||
| function loadSecurityInfo() { | ||||
|     fetch('/index/user/getSecurityInfo') | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             if(data.code === 0) { | ||||
|                 document.getElementById('phoneNumber').textContent = data.data.phone || '未绑定'; | ||||
|                 document.getElementById('emailAddress').textContent = data.data.email || '未绑定'; | ||||
|                 // 设置两步验证开关状态
 | ||||
|                 layui.form.val('securityForm', { | ||||
|                     twoFactor: data.data.twoFactor | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| // 修改密码
 | ||||
| function changePassword() { | ||||
|     layer.open({ | ||||
|         type: 2, | ||||
|         title: '修改密码', | ||||
|         area: ['500px', '400px'], | ||||
|         content: '/index/user/component/password' | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| // 绑定手机
 | ||||
| function bindPhone() { | ||||
|     layer.open({ | ||||
|         type: 2, | ||||
|         title: '绑定手机', | ||||
|         area: ['500px', '400px'], | ||||
|         content: '/index/user/component/bindPhone' | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| // 绑定邮箱
 | ||||
| function bindEmail() { | ||||
|     layer.open({ | ||||
|         type: 2, | ||||
|         title: '绑定邮箱', | ||||
|         area: ['500px', '400px'], | ||||
|         content: '/index/user/component/bindEmail' | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| // 更新两步验证状态
 | ||||
| function updateTwoFactor(enabled) { | ||||
|     fetch('/index/user/updateTwoFactor', { | ||||
|         method: 'POST', | ||||
|         headers: { | ||||
|             'Content-Type': 'application/json' | ||||
|         }, | ||||
|         body: JSON.stringify({enabled: enabled}) | ||||
|     }) | ||||
|     .then(response => response.json()) | ||||
|     .then(data => { | ||||
|         if(data.code === 0) { | ||||
|             layer.msg(enabled ? '两步验证已开启' : '两步验证已关闭', {icon: 1}); | ||||
|         } else { | ||||
|             layer.msg(data.msg || '操作失败', {icon: 2}); | ||||
|             // 恢复开关状态
 | ||||
|             layui.form.val('securityForm', { | ||||
|                 twoFactor: !enabled | ||||
|             }); | ||||
|         } | ||||
|     }) | ||||
|     .catch(error => { | ||||
|         layer.msg('操作失败,请重试', {icon: 2}); | ||||
|         // 恢复开关状态
 | ||||
|         layui.form.val('securityForm', { | ||||
|             twoFactor: !enabled | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										109
									
								
								app/index/view/user/component/settings.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								app/index/view/user/component/settings.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| <div class="settings-section"> | ||||
|     <h2 class="section-title">基本设置</h2> | ||||
|      | ||||
|     <form class="layui-form" lay-filter="settingsForm"> | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">用户名</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="text" name="username" value="{$user.username}" class="layui-input" lay-verify="required" placeholder="请输入用户名"> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">邮箱</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="email" name="email" value="{$user.email}" class="layui-input" lay-verify="required|email" placeholder="请输入邮箱"> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">手机号</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <input type="text" name="phone" value="{$user.phone}" class="layui-input" lay-verify="phone" placeholder="请输入手机号"> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <label class="layui-form-label">个人简介</label> | ||||
|             <div class="layui-input-block"> | ||||
|                 <textarea name="bio" placeholder="请输入个人简介" class="layui-textarea">{$user.bio}</textarea> | ||||
|             </div> | ||||
|         </div> | ||||
|          | ||||
|         <div class="layui-form-item"> | ||||
|             <div class="layui-input-block"> | ||||
|                 <button class="layui-btn" lay-submit lay-filter="saveSettings">保存设置</button> | ||||
|                 <button type="reset" class="layui-btn layui-btn-primary">重置</button> | ||||
|             </div> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
| .settings-section { | ||||
|     max-width: 800px; | ||||
|     margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| .section-title { | ||||
|     font-size: 20px; | ||||
|     font-weight: 600; | ||||
|     color: #333;
 | ||||
|     margin-bottom: 24px; | ||||
|     padding-bottom: 16px; | ||||
|     border-bottom: 1px solid #f0f0f0;
 | ||||
| } | ||||
| 
 | ||||
| .layui-form-item { | ||||
|     margin-bottom: 24px; | ||||
| } | ||||
| 
 | ||||
| .layui-form-label { | ||||
|     width: 100px; | ||||
| } | ||||
| 
 | ||||
| .layui-input-block { | ||||
|     margin-left: 130px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     .layui-form-label { | ||||
|         width: 80px; | ||||
|     } | ||||
|      | ||||
|     .layui-input-block { | ||||
|         margin-left: 110px; | ||||
|     } | ||||
| } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
| layui.use(['form', 'layer'], function(){ | ||||
|     var form = layui.form; | ||||
|     var layer = layui.layer; | ||||
|      | ||||
|     // 监听表单提交
 | ||||
|     form.on('submit(saveSettings)', function(data){ | ||||
|         fetch('/index/user/updateSettings', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json' | ||||
|             }, | ||||
|             body: JSON.stringify(data.field) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(data => { | ||||
|             if(data.code === 0) { | ||||
|                 layer.msg('设置保存成功', {icon: 1}); | ||||
|             } else { | ||||
|                 layer.msg(data.msg || '保存失败', {icon: 2}); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             layer.msg('保存失败,请重试', {icon: 2}); | ||||
|         }); | ||||
|          | ||||
|         return false; | ||||
|     }); | ||||
| }); | ||||
| </script> | ||||
							
								
								
									
										158
									
								
								app/index/view/user/component/sidebar.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								app/index/view/user/component/sidebar.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| <div class="sidebar"> | ||||
|     <div class="user-info"> | ||||
|         <div class="avatar-wrapper"> | ||||
|             <img src="{$user.avatar|default='/static/images/avatar.png'}" class="avatar" alt="用户头像"> | ||||
|         </div> | ||||
|         <h3 class="username">{$user.name}</h3> | ||||
|         <p class="email">{$user.account}</p> | ||||
|     </div> | ||||
| 
 | ||||
|     <nav class="menu"> | ||||
|         <a href="javascript:;" class="menu-item active" data-target="profile-basic"> | ||||
|             <i class="icon">👤</i> | ||||
|             <span>个人资料</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-avatar"> | ||||
|             <i class="icon">🖼️</i> | ||||
|             <span>修改头像</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-password"> | ||||
|             <i class="icon">🔒</i> | ||||
|             <span>修改密码</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-messages"> | ||||
|             <i class="icon">✉️</i> | ||||
|             <span>我的消息</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-notifications"> | ||||
|             <i class="icon">🔔</i> | ||||
|             <span>系统通知</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-settings"> | ||||
|             <i class="icon">⚙️</i> | ||||
|             <span>基本设置</span> | ||||
|         </a> | ||||
|         <a href="javascript:;" class="menu-item" data-target="profile-security"> | ||||
|             <i class="icon">🛡️</i> | ||||
|             <span>安全设置</span> | ||||
|         </a> | ||||
|     </nav> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
|     .sidebar { | ||||
|         width: 260px; | ||||
|         background: #fff;
 | ||||
|         border-radius: 12px; | ||||
|         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); | ||||
|         padding: 24px 0; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .user-info { | ||||
|         text-align: center; | ||||
|         padding: 0 24px 24px; | ||||
|         border-bottom: 1px solid #f0f0f0;
 | ||||
|         margin-bottom: 24px; | ||||
|     } | ||||
| 
 | ||||
|     .avatar-wrapper { | ||||
|         width: 88px; | ||||
|         height: 88px; | ||||
|         margin: 0 auto 16px; | ||||
|         position: relative; | ||||
|     } | ||||
| 
 | ||||
|     .avatar { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         border-radius: 50%; | ||||
|         object-fit: cover; | ||||
|         border: 3px solid #f5f5f5;
 | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     .avatar:hover { | ||||
|         transform: scale(1.05); | ||||
|     } | ||||
| 
 | ||||
|     .username { | ||||
|         font-size: 18px; | ||||
|         font-weight: 600; | ||||
|         color: #333;
 | ||||
|         margin: 0 0 4px; | ||||
|     } | ||||
| 
 | ||||
|     .email { | ||||
|         font-size: 14px; | ||||
|         color: #666;
 | ||||
|         margin: 0; | ||||
|     } | ||||
| 
 | ||||
|     .menu { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         padding: 0 12px; | ||||
|     } | ||||
| 
 | ||||
|     .menu-item { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         padding: 12px 16px; | ||||
|         color: #666;
 | ||||
|         text-decoration: none; | ||||
|         border-radius: 8px; | ||||
|         margin-bottom: 4px; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     .menu-item:hover { | ||||
|         background: #f5f7fa;
 | ||||
|         color: #1677ff;
 | ||||
|     } | ||||
| 
 | ||||
|     .menu-item.active { | ||||
|         background: #e6f4ff;
 | ||||
|         color: #1677ff;
 | ||||
|         font-weight: 500; | ||||
|     } | ||||
| 
 | ||||
|     .icon { | ||||
|         font-size: 20px; | ||||
|         margin-right: 12px; | ||||
|         width: 24px; | ||||
|         text-align: center; | ||||
|     } | ||||
| 
 | ||||
|     span { | ||||
|         font-size: 15px; | ||||
|     } | ||||
| 
 | ||||
|     /* 响应式适配 */ | ||||
|     @media (max-width: 768px) { | ||||
|         .sidebar { | ||||
|             width: 100%; | ||||
|             border-radius: 0; | ||||
|             box-shadow: none; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     document.addEventListener('DOMContentLoaded', function () { | ||||
|         // 获取当前页面路径
 | ||||
|         const currentPath = window.location.pathname; | ||||
| 
 | ||||
|         // 移除所有active类
 | ||||
|         document.querySelectorAll('.menu-item').forEach(item => { | ||||
|             item.classList.remove('active'); | ||||
|         }); | ||||
| 
 | ||||
|         // 为当前页面对应的菜单项添加active类
 | ||||
|         document.querySelectorAll('.menu-item').forEach(item => { | ||||
|             if (item.getAttribute('href') === currentPath) { | ||||
|                 item.classList.add('active'); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
							
								
								
									
										120
									
								
								app/index/view/user/profile.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								app/index/view/user/profile.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| {include file="component/head" /} | ||||
| {include file="component/header-simple" /} | ||||
| 
 | ||||
| <div class="profile-container"> | ||||
|     <div class="profile-sidebar"> | ||||
|         {include file="user/component/sidebar" /} | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="profile-main"> | ||||
|         <div class="content-area"> | ||||
|             <!-- 个人资料 --> | ||||
|             <div id="profile-basic" class="content-section active"> | ||||
|                 {include file="user/component/basic" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 修改头像 --> | ||||
|             <div id="profile-avatar" class="content-section"> | ||||
|                 {include file="user/component/avatar" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 修改密码 --> | ||||
|             <div id="profile-password" class="content-section"> | ||||
|                 {include file="user/component/password" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 我的消息 --> | ||||
|             <div id="profile-messages" class="content-section"> | ||||
|                 {include file="user/component/messages" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 系统通知 --> | ||||
|             <div id="profile-notifications" class="content-section"> | ||||
|                 {include file="user/component/notifications" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 基本设置 --> | ||||
|             <div id="profile-settings" class="content-section"> | ||||
|                 {include file="user/component/settings" /} | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- 安全设置 --> | ||||
|             <div id="profile-security" class="content-section"> | ||||
|                 {include file="user/component/security" /} | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
|     .profile-container { | ||||
|         display: flex; | ||||
|         max-width: 1200px; | ||||
|         margin: 40px auto; | ||||
|         gap: 24px; | ||||
|         padding: 0 20px; | ||||
|     } | ||||
| 
 | ||||
|     .profile-sidebar { | ||||
|         width: 260px; | ||||
|         flex-shrink: 0; | ||||
|     } | ||||
| 
 | ||||
|     .profile-main { | ||||
|         flex: 1; | ||||
|         background: #fff;
 | ||||
|         border-radius: 12px; | ||||
|         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); | ||||
|         padding: 32px; | ||||
|     } | ||||
| 
 | ||||
|     .content-section { | ||||
|         display: none; | ||||
|     } | ||||
| 
 | ||||
|     .content-section.active { | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     /* 响应式适配 */ | ||||
|     @media (max-width: 768px) { | ||||
|         .profile-container { | ||||
|             flex-direction: column; | ||||
|             margin: 20px auto; | ||||
|         } | ||||
| 
 | ||||
|         .profile-sidebar { | ||||
|             width: 100%; | ||||
|         } | ||||
| 
 | ||||
|         .profile-main { | ||||
|             padding: 20px; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     document.addEventListener('DOMContentLoaded', function () { | ||||
|         const menuItems = document.querySelectorAll('.menu-item'); | ||||
| 
 | ||||
|         menuItems.forEach(item => { | ||||
|             item.addEventListener('click', function () { | ||||
|                 const target = this.getAttribute('data-target'); | ||||
| 
 | ||||
|                 // 移除所有active类
 | ||||
|                 document.querySelectorAll('.menu-item').forEach(menuItem => { | ||||
|                     menuItem.classList.remove('active'); | ||||
|                 }); | ||||
|                 document.querySelectorAll('.content-section').forEach(section => { | ||||
|                     section.classList.remove('active'); | ||||
|                 }); | ||||
| 
 | ||||
|                 // 添加active类
 | ||||
|                 this.classList.add('active'); | ||||
|                 document.getElementById(target).classList.add('active'); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
| 
 | ||||
| {include file="component/foot" /} | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 28 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 71 KiB | 
| @ -1,4 +1,4 @@ | ||||
| <?php /*a:5:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\articles\detail.php";i:1747711602;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1747705841;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
 | ||||
| <?php /*a:5:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\articles\detail.php";i:1747818914;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1748316508;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
 | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| @ -18,37 +18,43 @@ | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
| <?php | ||||
| // 获取当前登录状态
 | ||||
| $isLoggedIn = false; | ||||
| $userInfo = [ | ||||
|     'is_login' => false, | ||||
|     'name' => '', | ||||
|     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||
| ]; | ||||
| 
 | ||||
| // 检查cookie
 | ||||
| $userAccount = cookie('user_account'); | ||||
| if ($userAccount) { | ||||
|     $isLoggedIn = true; | ||||
|     $userInfo = [ | ||||
|         'is_login' => true, | ||||
|         'name' => cookie('user_name'), | ||||
|         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| // 添加一个隐藏的div来存储登录状态
 | ||||
| $loginStatus = [ | ||||
|     'isLoggedIn' => $isLoggedIn, | ||||
|     'userAccount' => $userAccount ?? '' | ||||
| ]; | ||||
| ?>
 | ||||
| 
 | ||||
| <!-- 添加一个隐藏的div来存储登录状态 --> | ||||
| <div id="loginStatus" style="display: none;" data-is-logged-in="<?php echo htmlentities((string) $isLoggedIn); ?>" data-user-account="<?php echo isset($userAccount) ? htmlentities((string) $userAccount) : ''; ?>"> | ||||
| </div> | ||||
| 
 | ||||
| <div style="display: flex;flex-direction: column;"> | ||||
| <div class="topbar-one"> | ||||
|         <div class="container"> | ||||
|             <div style="width: 70%;"> | ||||
|                 <ul class="list-unstyled topbar-one__info"> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-phone-alt" style="margin-right: 10px;"></span> | ||||
|                         <a href="<?php echo htmlentities((string) $config['admin_phone']); ?>"><?php echo htmlentities((string) $config['admin_phone']); ?></a>
 | ||||
|                     </li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-envelope" style="margin-right: 10px;"></span> | ||||
|                         <a href="mailto:<?php echo htmlentities((string) $config['admin_email']); ?>"><?php echo htmlentities((string) $config['admin_email']); ?></a>
 | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="topbar-one__social" style="width: 30%;"> | ||||
|                 <a href="/index/user/login" class="mr-10"><i class="layui-icon layui-icon-username"></i> 登录</a> | ||||
|                 <a href="/index/user/register" class="mr-10"><i class="layui-icon layui-icon-user"></i> 注册</a> | ||||
|                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||
|                 <div class="qrcode-popup" | ||||
|                     style="display:none;position:absolute;right:54px;top:32px;background:#fff;padding:10px;box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;"> | ||||
|                     <img src="<?php echo htmlentities((string) $config['admin_wechat']); ?>" alt="公众号二维码" style="width:180px;height:180px;"> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|     <!-- 导航栏 --> | ||||
|     <div class="main-menu"> | ||||
|         <div class="container"> | ||||
|             <div class="main-menu__logo"> | ||||
|                 <a href="index.html"><img src="/static/images/logo1.png" width="186" alt="Logo"></a> | ||||
|                 <a href="/index.html"><img src="/static/images/logo1.png" width="186" alt="Logo"></a> | ||||
|             </div> | ||||
|             <div class="main-menu__nav"> | ||||
|                 <ul class="main-menu__list"> | ||||
| @ -59,52 +65,16 @@ | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text"><?php echo htmlentities((string) $userInfo['name']); ?></span>
 | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||
|                         <div class="user-dropdown" id="userDropdownMain"> | ||||
|                             <ul> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/profile"><i | ||||
|                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/settings"><i | ||||
|                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="javascript:;" class="logout-btn"><i | ||||
|                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <!-- 固定导航 --> | ||||
| <div class="sticky-nav" style="display: none;"> | ||||
|     <div class="container"> | ||||
|         <div class="sticky-nav__logo"> | ||||
|             <a href="index.html"><img src="/static/images/logo1.png" width="150" alt="Logo"></a> | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($isLoggedIn): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="<?php echo htmlentities((string) $userInfo['avatar']); ?>" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                                 <ul> | ||||
| @ -123,6 +93,68 @@ | ||||
|                                 </ul> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     <?php else: ?>
 | ||||
|                         <div class="layui-inline"> | ||||
|                             <a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a> | ||||
|                             <a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a> | ||||
|                         </div> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <!-- 固定导航 --> | ||||
| <div class="sticky-nav" style="display: none;"> | ||||
|     <div class="container"> | ||||
|         <div class="sticky-nav__logo"> | ||||
|             <a href="/index.html"><img src="/static/images/logo1.png" width="150" alt="Logo"></a> | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text"><?php echo htmlentities((string) $userInfo['name']); ?></span>
 | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($isLoggedIn): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="<?php echo htmlentities((string) $userInfo['avatar']); ?>" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                                 <ul> | ||||
|                                     <li> | ||||
|                                         <a href="/index/user/profile"><i | ||||
|                                                 class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a href="/index/user/settings"><i | ||||
|                                                 class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <a href="javascript:;" class="logout-btn"><i | ||||
|                                                 class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                     </li> | ||||
|                                 </ul> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     <?php else: ?>
 | ||||
|                         <div class="layui-inline"> | ||||
|                             <a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a> | ||||
|                             <a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a> | ||||
|                         </div> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| @ -328,51 +360,107 @@ | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| 
 | ||||
|     .main-menu__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .username { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     // 在页面加载时立即执行
 | ||||
|     (function () { | ||||
|         // 检查是否已经刷新过
 | ||||
|         if (sessionStorage.getItem('has_refreshed') === 'true') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 检查localStorage中是否有用户账号
 | ||||
|         var userAccount = localStorage.getItem('user_account'); | ||||
|         if (userAccount) { | ||||
|             // 同步到cookie
 | ||||
|             document.cookie = "user_account=" + userAccount + "; path=/"; | ||||
| 
 | ||||
|             // 如果有其他必要的数据,也同步到cookie
 | ||||
|             var userId = localStorage.getItem('user_id'); | ||||
|             var userName = localStorage.getItem('user_name'); | ||||
|             var userAvatar = localStorage.getItem('user_avatar'); | ||||
| 
 | ||||
|             if (userId) document.cookie = "user_id=" + userId + "; path=/"; | ||||
|             if (userName) document.cookie = "user_name=" + userName + "; path=/"; | ||||
|             if (userAvatar) document.cookie = "user_avatar=" + userAvatar + "; path=/"; | ||||
| 
 | ||||
|             // 刷新页面以应用新的cookie,并标记已刷新
 | ||||
|             if (!document.cookie.includes('user_id')) { | ||||
|                 sessionStorage.setItem('has_refreshed', 'true'); | ||||
|                 window.location.reload(); | ||||
|             } | ||||
|         } | ||||
|     })(); | ||||
| 
 | ||||
|     layui.use(['carousel', 'form', 'layer'], function () { | ||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||
| 
 | ||||
|         // 加载banner数据
 | ||||
|         $.ajax({ | ||||
|             url: '/index/index/bannerlist', | ||||
|             type: 'GET', | ||||
|             success: function (res) { | ||||
|                 if (res.code === 1) { | ||||
|                     var bannerHtml = ''; | ||||
|                     res.banner.forEach(function (banner) { | ||||
|                         bannerHtml += '<div>' + | ||||
|                             '<div class="banner-content">' + | ||||
|                             '<div class="banner-image">' + | ||||
|                             '<img src="' + banner.image + '" alt="' + (banner.title || '') + '">' + | ||||
|                             '</div>' + | ||||
|                             '<div class="banner-text">' + | ||||
|                             '<span class="banner-title">' + (banner.title || '') + '</span>' + | ||||
|                             '<span class="banner-desc">' + (banner.desc || '') + '</span>' + | ||||
|                             '<a href="' + (banner.url || 'javascript:;') + '" class="banner-slide">' + | ||||
|                             '<span class="banner-btn">查看详情</span>' + | ||||
|                             '</a>' + | ||||
|                             '</div>' + | ||||
|                             '</div>' + | ||||
|                             '</div>'; | ||||
|                     }); | ||||
|                     $('#test10 div[carousel-item]').html(bannerHtml); | ||||
|         // 检查本地存储并自动登录
 | ||||
|         function checkAutoLogin() { | ||||
|             // 如果已经登录,不再执行自动登录
 | ||||
|             if ($('#userAvatarMain').length > 0) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|                     // 图片轮播
 | ||||
|                     carousel.render({ | ||||
|                         elem: '#test10', | ||||
|                         width: '100%', | ||||
|                         height: '100vh', | ||||
|                         interval: 4000, | ||||
|                         anim: 'fade', | ||||
|                         autoplay: true, | ||||
|                         full: false, | ||||
|                         arrow: 'hover' | ||||
|                     }); | ||||
|             // 如果已经尝试过自动登录,不再执行
 | ||||
|             if (sessionStorage.getItem('auto_login_attempted') === 'true') { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // 从localStorage获取用户账号
 | ||||
|             var userAccount = localStorage.getItem('user_account'); | ||||
|             if (userAccount) { | ||||
|                 // 标记已尝试自动登录
 | ||||
|                 sessionStorage.setItem('auto_login_attempted', 'true'); | ||||
| 
 | ||||
|                 // 发送自动登录请求
 | ||||
|                 $.ajax({ | ||||
|                     url: '/index/user/login', | ||||
|                     type: 'POST', | ||||
|                     data: { | ||||
|                         account: userAccount, | ||||
|                         password: atob(localStorage.getItem('user_password')) | ||||
|                     }, | ||||
|                     dataType: 'json', | ||||
|                     success: function (res) { | ||||
|                         if (res.code === 0) { | ||||
|                             // 设置cookie
 | ||||
|                             document.cookie = "user_id=" + res.data.id + "; path=/"; | ||||
|                             document.cookie = "user_name=" + res.data.name + "; path=/"; | ||||
|                             document.cookie = "user_avatar=" + res.data.avatar + "; path=/"; | ||||
|                             document.cookie = "user_account=" + userAccount + "; path=/"; | ||||
| 
 | ||||
|                             // 同时更新localStorage
 | ||||
|                             localStorage.setItem('user_id', res.data.id); | ||||
|                             localStorage.setItem('user_name', res.data.name); | ||||
|                             localStorage.setItem('user_avatar', res.data.avatar); | ||||
| 
 | ||||
|                             // 登录成功,强制刷新页面
 | ||||
|                             window.location.href = window.location.href + '?t=' + new Date().getTime(); | ||||
|                         } else { | ||||
|                             // 登录失败,清除所有相关存储
 | ||||
|                             localStorage.removeItem('user_account'); | ||||
|                             localStorage.removeItem('user_password'); | ||||
|                             sessionStorage.removeItem('auto_login_attempted'); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 页面加载时检查自动登录
 | ||||
|         checkAutoLogin(); | ||||
| 
 | ||||
|         $(document).ready(function () { | ||||
|             // 主导航头像
 | ||||
| @ -406,7 +494,36 @@ | ||||
|             layer.confirm('确定要退出登录吗?', { | ||||
|                 btn: ['确定', '取消'] | ||||
|             }, function () { | ||||
|                 window.location.href = '/index/user/logout'; | ||||
|                 // 先发送退出请求
 | ||||
|                 $.ajax({ | ||||
|                     url: '/index/user/logout', | ||||
|                     type: 'POST', | ||||
|                     dataType: 'json', | ||||
|                     success: function (res) { | ||||
|                         if (res.code === 0) { | ||||
|                             // 清除localStorage
 | ||||
|                             localStorage.removeItem('user_account'); | ||||
|                             localStorage.removeItem('user_password'); | ||||
|                             localStorage.removeItem('user_id'); | ||||
|                             localStorage.removeItem('user_name'); | ||||
|                             localStorage.removeItem('user_avatar'); | ||||
| 
 | ||||
|                             // 清除sessionStorage
 | ||||
|                             sessionStorage.removeItem('auto_login_attempted'); | ||||
|                             sessionStorage.removeItem('has_refreshed'); | ||||
| 
 | ||||
|                             // 清除cookie
 | ||||
|                             document.cookie = "user_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_avatar=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_account=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
| 
 | ||||
|                             // 强制刷新页面,不使用缓存
 | ||||
|                             window.location.href = window.location.href + '?t=' + new Date().getTime(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
| @ -443,6 +560,62 @@ | ||||
|         popup.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
| 
 | ||||
|         form.on('submit(accountLogin)', function (data) { | ||||
|             $.ajax({ | ||||
|                 url: '<?php echo url("index/user/login"); ?>', | ||||
|                 type: 'POST', | ||||
|                 data: data.field, | ||||
|                 dataType: 'json', | ||||
|                 success: function (res) { | ||||
|                     if (res.code === 0) { | ||||
|                         // 存储登录数据,设置7天过期
 | ||||
|                         var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000; | ||||
| 
 | ||||
|                         // 设置localStorage
 | ||||
|                         localStorage.setItem('user_account', data.field.account); | ||||
|                         localStorage.setItem('user_password', btoa(data.field.password)); | ||||
|                         localStorage.setItem('expire_time', expireTime); | ||||
|                         localStorage.setItem('is_auto_login', 'true'); | ||||
| 
 | ||||
|                         // 设置cookie
 | ||||
|                         document.cookie = "user_id=" + res.data.id + "; path=/"; | ||||
|                         document.cookie = "user_name=" + res.data.name + "; path=/"; | ||||
|                         document.cookie = "user_avatar=" + res.data.avatar + "; path=/"; | ||||
|                         document.cookie = "expire_time=" + expireTime + "; path=/"; | ||||
|                         document.cookie = "is_auto_login=true; path=/"; | ||||
|                         document.cookie = "user_account=" + data.field.account + "; path=/"; | ||||
|                         document.cookie = "user_password=" + btoa(data.field.password) + "; path=/"; | ||||
| 
 | ||||
|                         // 设置sessionStorage
 | ||||
|                         sessionStorage.setItem('auto_login_attempted', 'true'); | ||||
| 
 | ||||
|                         layer.msg('登录成功', { | ||||
|                             icon: 1, | ||||
|                             time: 2000, | ||||
|                             shade: 0.3 | ||||
|                         }, function () { | ||||
|                             // 获取当前页面URL
 | ||||
|                             var currentUrl = window.location.href; | ||||
| 
 | ||||
|                             // 如果当前页面是登录页面,则跳转到首页
 | ||||
|                             if (currentUrl.includes('/index/user/login')) { | ||||
|                                 window.location.href = '/index.html'; | ||||
|                             } else { | ||||
|                                 // 否则刷新当前页面
 | ||||
|                                 window.location.href = currentUrl + '?t=' + new Date().getTime(); | ||||
|                             } | ||||
|                         }); | ||||
|                     } else { | ||||
|                         layer.msg(res.msg, { | ||||
|                             icon: 2, | ||||
|                             time: 2000 | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|             return false; | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
| <div class="main"> | ||||
| @ -469,6 +642,15 @@ | ||||
|         <div class="article-content" id="articleContent"> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="disclaimers"> | ||||
|             <div class="disclaimer-item"> | ||||
|                 <div class="disclaimer-title">免责声明:</div> | ||||
|                 <div class="disclaimer-content"> | ||||
|                     <?php echo $config['disclaimers'] ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-tags"> | ||||
|             <span class="tag-label">标签:</span> | ||||
|             <div id="articleTags"></div> | ||||
| @ -615,6 +797,7 @@ | ||||
|         color: #333;
 | ||||
|         font-size: 16px; | ||||
|         margin-bottom: 30px; | ||||
|         border-bottom: 1px solid #eee;
 | ||||
|     } | ||||
| 
 | ||||
|     .article-content img { | ||||
| @ -915,6 +1098,28 @@ | ||||
|     .location-item a { | ||||
|         color: #000 !important;
 | ||||
|     } | ||||
| 
 | ||||
|     .disclaimers { | ||||
|         color: #b1b1b1;
 | ||||
|         width: 80%; | ||||
|         margin: 20px auto; | ||||
|         margin-bottom: 60px; | ||||
|     } | ||||
| 
 | ||||
|     .disclaimer-title { | ||||
|         font-size: 16px; | ||||
|         font-weight: 600; | ||||
|         margin-bottom: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .disclaimer-content { | ||||
|         font-size: 14px; | ||||
|         line-height: 1.6; | ||||
|     } | ||||
| 
 | ||||
|     .disclaimer-content p { | ||||
|         margin-bottom: 0; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <?php /*a:4:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\index\index.php";i:1746865108;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header.php";i:1747445574;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\main.php";i:1747646542;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;}*/ ?>
 | ||||
| <?php /*a:4:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\index\index.php";i:1746865108;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header.php";i:1748316235;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\main.php";i:1747817496;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;}*/ ?>
 | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| @ -16,6 +16,37 @@ | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
|     <?php | ||||
| // 获取当前登录状态
 | ||||
| $isLoggedIn = false; | ||||
| $userInfo = [ | ||||
|     'is_login' => false, | ||||
|     'name' => '', | ||||
|     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||
| ]; | ||||
| 
 | ||||
| // 检查cookie
 | ||||
| $userAccount = cookie('user_account'); | ||||
| if ($userAccount) { | ||||
|     $isLoggedIn = true; | ||||
|     $userInfo = [ | ||||
|         'is_login' => true, | ||||
|         'name' => cookie('user_name'), | ||||
|         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||
|     ]; | ||||
| } | ||||
| 
 | ||||
| // 添加一个隐藏的div来存储登录状态
 | ||||
| $loginStatus = [ | ||||
|     'isLoggedIn' => $isLoggedIn, | ||||
|     'userAccount' => $userAccount ?? '' | ||||
| ]; | ||||
| ?>
 | ||||
| 
 | ||||
| <!-- 添加一个隐藏的div来存储登录状态 --> | ||||
| <div id="loginStatus" style="display: none;" data-is-logged-in="<?php echo htmlentities((string) $isLoggedIn); ?>" data-user-account="<?php echo isset($userAccount) ? htmlentities((string) $userAccount) : ''; ?>"> | ||||
| </div> | ||||
| 
 | ||||
| <div style="display: flex;flex-direction: column;"> | ||||
|     <div class="topbar-one"> | ||||
|         <div class="container"> | ||||
| @ -32,8 +63,6 @@ | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="topbar-one__social" style="width: 30%;"> | ||||
|                 <a href="/index/user/login" class="mr-10"><i class="layui-icon layui-icon-username"></i> 登录</a> | ||||
|                 <a href="/index/user/register" class="mr-10"><i class="layui-icon layui-icon-user"></i> 注册</a> | ||||
|                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||
|                 <div class="qrcode-popup" | ||||
|                     style="display:none;position:absolute;right:54px;top:32px;background:#fff;padding:10px;box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;"> | ||||
| @ -57,9 +86,16 @@ | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text"><?php echo htmlentities((string) $userInfo['name']); ?></span>
 | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="<?php echo htmlentities((string) $userInfo['avatar']); ?>" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||
|                             <div class="user-dropdown" id="userDropdownMain"> | ||||
|                                 <ul> | ||||
| @ -78,6 +114,12 @@ | ||||
|                                 </ul> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     <?php else: ?>
 | ||||
|                         <div class="layui-inline"> | ||||
|                             <a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a> | ||||
|                             <a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a> | ||||
|                         </div> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| @ -107,9 +149,16 @@ | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="username"> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <span class="username-text"><?php echo htmlentities((string) $userInfo['name']); ?></span>
 | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                     <!-- 根据登录状态显示不同的内容 --> | ||||
|                     <?php if ($userInfo['is_login']): ?>
 | ||||
|                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||
|                             <img src="<?php echo htmlentities((string) $userInfo['avatar']); ?>" class="layui-circle" | ||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                             <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                                 <ul> | ||||
| @ -128,6 +177,12 @@ | ||||
|                                 </ul> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     <?php else: ?>
 | ||||
|                         <div class="layui-inline"> | ||||
|                             <a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a> | ||||
|                             <a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a> | ||||
|                         </div> | ||||
|                     <?php endif; ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| @ -333,12 +388,108 @@ | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| 
 | ||||
|     .main-menu__right { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .username { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     // 在页面加载时立即执行
 | ||||
|     (function () { | ||||
|         // 检查是否已经刷新过
 | ||||
|         if (sessionStorage.getItem('has_refreshed') === 'true') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 检查localStorage中是否有用户账号
 | ||||
|         var userAccount = localStorage.getItem('user_account'); | ||||
|         if (userAccount) { | ||||
|             // 同步到cookie
 | ||||
|             document.cookie = "user_account=" + userAccount + "; path=/"; | ||||
| 
 | ||||
|             // 如果有其他必要的数据,也同步到cookie
 | ||||
|             var userId = localStorage.getItem('user_id'); | ||||
|             var userName = localStorage.getItem('user_name'); | ||||
|             var userAvatar = localStorage.getItem('user_avatar'); | ||||
| 
 | ||||
|             if (userId) document.cookie = "user_id=" + userId + "; path=/"; | ||||
|             if (userName) document.cookie = "user_name=" + userName + "; path=/"; | ||||
|             if (userAvatar) document.cookie = "user_avatar=" + userAvatar + "; path=/"; | ||||
| 
 | ||||
|             // 刷新页面以应用新的cookie,并标记已刷新
 | ||||
|             if (!document.cookie.includes('user_id')) { | ||||
|                 sessionStorage.setItem('has_refreshed', 'true'); | ||||
|                 window.location.reload(); | ||||
|             } | ||||
|         } | ||||
|     })(); | ||||
| 
 | ||||
|     layui.use(['carousel', 'form', 'layer'], function () { | ||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||
| 
 | ||||
|         // 检查本地存储并自动登录
 | ||||
|         function checkAutoLogin() { | ||||
|             // 如果已经登录,不再执行自动登录
 | ||||
|             if ($('#userAvatarMain').length > 0) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // 如果已经尝试过自动登录,不再执行
 | ||||
|             if (sessionStorage.getItem('auto_login_attempted') === 'true') { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // 从localStorage获取用户账号
 | ||||
|             var userAccount = localStorage.getItem('user_account'); | ||||
|             if (userAccount) { | ||||
|                 // 标记已尝试自动登录
 | ||||
|                 sessionStorage.setItem('auto_login_attempted', 'true'); | ||||
| 
 | ||||
|                 // 发送自动登录请求
 | ||||
|                 $.ajax({ | ||||
|                     url: '/index/user/login', | ||||
|                     type: 'POST', | ||||
|                     data: { | ||||
|                         account: userAccount, | ||||
|                         password: atob(localStorage.getItem('user_password')) | ||||
|                     }, | ||||
|                     dataType: 'json', | ||||
|                     success: function (res) { | ||||
|                         if (res.code === 0) { | ||||
|                             // 设置cookie
 | ||||
|                             document.cookie = "user_id=" + res.data.id + "; path=/"; | ||||
|                             document.cookie = "user_name=" + res.data.name + "; path=/"; | ||||
|                             document.cookie = "user_avatar=" + res.data.avatar + "; path=/"; | ||||
|                             document.cookie = "user_account=" + userAccount + "; path=/"; | ||||
| 
 | ||||
|                             // 同时更新localStorage
 | ||||
|                             localStorage.setItem('user_id', res.data.id); | ||||
|                             localStorage.setItem('user_name', res.data.name); | ||||
|                             localStorage.setItem('user_avatar', res.data.avatar); | ||||
| 
 | ||||
|                             // 登录成功,强制刷新页面
 | ||||
|                             window.location.href = window.location.href + '?t=' + new Date().getTime(); | ||||
|                         } else { | ||||
|                             // 登录失败,清除所有相关存储
 | ||||
|                             localStorage.removeItem('user_account'); | ||||
|                             localStorage.removeItem('user_password'); | ||||
|                             sessionStorage.removeItem('auto_login_attempted'); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 页面加载时检查自动登录
 | ||||
|         checkAutoLogin(); | ||||
| 
 | ||||
|         // 加载banner数据
 | ||||
|         $.ajax({ | ||||
|             url: '/index/index/bannerlist', | ||||
| @ -411,7 +562,36 @@ | ||||
|             layer.confirm('确定要退出登录吗?', { | ||||
|                 btn: ['确定', '取消'] | ||||
|             }, function () { | ||||
|                 window.location.href = '/index/user/logout'; | ||||
|                 // 先发送退出请求
 | ||||
|                 $.ajax({ | ||||
|                     url: '/index/user/logout', | ||||
|                     type: 'POST', | ||||
|                     dataType: 'json', | ||||
|                     success: function (res) { | ||||
|                         if (res.code === 0) { | ||||
|                             // 清除localStorage
 | ||||
|                             localStorage.removeItem('user_account'); | ||||
|                             localStorage.removeItem('user_password'); | ||||
|                             localStorage.removeItem('user_id'); | ||||
|                             localStorage.removeItem('user_name'); | ||||
|                             localStorage.removeItem('user_avatar'); | ||||
| 
 | ||||
|                             // 清除sessionStorage
 | ||||
|                             sessionStorage.removeItem('auto_login_attempted'); | ||||
|                             sessionStorage.removeItem('has_refreshed'); | ||||
| 
 | ||||
|                             // 清除cookie
 | ||||
|                             document.cookie = "user_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_avatar=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_account=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
|                             document.cookie = "user_password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; | ||||
| 
 | ||||
|                             // 强制刷新页面,不使用缓存
 | ||||
|                             window.location.href = window.location.href + '?t=' + new Date().getTime(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
| @ -448,6 +628,62 @@ | ||||
|         popup.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
| 
 | ||||
|         form.on('submit(accountLogin)', function (data) { | ||||
|             $.ajax({ | ||||
|                 url: '<?php echo url("index/user/login"); ?>', | ||||
|                 type: 'POST', | ||||
|                 data: data.field, | ||||
|                 dataType: 'json', | ||||
|                 success: function (res) { | ||||
|                     if (res.code === 0) { | ||||
|                         // 存储登录数据,设置7天过期
 | ||||
|                         var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000; | ||||
| 
 | ||||
|                         // 设置localStorage
 | ||||
|                         localStorage.setItem('user_account', data.field.account); | ||||
|                         localStorage.setItem('user_password', btoa(data.field.password)); | ||||
|                         localStorage.setItem('expire_time', expireTime); | ||||
|                         localStorage.setItem('is_auto_login', 'true'); | ||||
| 
 | ||||
|                         // 设置cookie
 | ||||
|                         document.cookie = "user_id=" + res.data.id + "; path=/"; | ||||
|                         document.cookie = "user_name=" + res.data.name + "; path=/"; | ||||
|                         document.cookie = "user_avatar=" + res.data.avatar + "; path=/"; | ||||
|                         document.cookie = "expire_time=" + expireTime + "; path=/"; | ||||
|                         document.cookie = "is_auto_login=true; path=/"; | ||||
|                         document.cookie = "user_account=" + data.field.account + "; path=/"; | ||||
|                         document.cookie = "user_password=" + btoa(data.field.password) + "; path=/"; | ||||
| 
 | ||||
|                         // 设置sessionStorage
 | ||||
|                         sessionStorage.setItem('auto_login_attempted', 'true'); | ||||
| 
 | ||||
|                         layer.msg('登录成功', { | ||||
|                             icon: 1, | ||||
|                             time: 2000, | ||||
|                             shade: 0.3 | ||||
|                         }, function () { | ||||
|                             // 获取当前页面URL,如果是从其他页面跳转来的,则返回上一页
 | ||||
|                             var currentUrl = window.location.href; | ||||
|                             var referrer = document.referrer; | ||||
| 
 | ||||
|                             // 如果是从登录页面跳转来的,则返回上一页
 | ||||
|                             if (referrer && referrer.includes('/index/user/login')) { | ||||
|                                 window.location.href = referrer; | ||||
|                             } else { | ||||
|                                 // 否则刷新当前页面
 | ||||
|                                 window.location.href = currentUrl + '?t=' + new Date().getTime(); | ||||
|                             } | ||||
|                         }); | ||||
|                         layer.msg(res.msg, { | ||||
|                             icon: 2, | ||||
|                             time: 2000 | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|             return false; | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
|     <main class="main-content"> | ||||
| @ -536,6 +772,27 @@ | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- 游戏下载模块 --> | ||||
|         <div class="core-block core-module" id="gameDownload" style="order: 3;"> | ||||
|             <div class="module-header"> | ||||
|                 <div> | ||||
|                     <div class="ModuleTitle_titleWrapper"> | ||||
|                         <h3 class="ModuleTitle_title">游戏下载</h3> | ||||
|                         <div class="tab-container"> | ||||
|                             <div class="tab-header"> | ||||
|                                 <div class="tab-item active" data-tab="all">全部</div> | ||||
|                                 <!-- 分类标签将通过JavaScript动态加载 --> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="more-btn">更多</div> | ||||
|             </div> | ||||
|             <div class="product-list" id="gameDownloadList"> | ||||
|                 <!-- 游戏将通过JavaScript动态加载 --> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|     </div> | ||||
| </main> | ||||
| 
 | ||||
| @ -656,6 +913,32 @@ | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     // 加载游戏下载
 | ||||
|     function loadGames() { | ||||
|         fetch('/index/index/gameList') | ||||
|             .then(response => response.json()) | ||||
|             .then(result => { | ||||
|                 if (result.code === 0) { | ||||
|                     // 渲染分类标签
 | ||||
|                     if (result.data.categories) { | ||||
|                         renderCategoryTabs(result.data.categories, 'gameDownload'); | ||||
|                     } | ||||
|                     // 渲染游戏列表
 | ||||
|                     if (result.data.games && result.data.games.length > 0) { | ||||
|                         renderGames(result.data.games, 'gameDownloadList'); | ||||
|                     } else { | ||||
|                         showNoData('gameDownloadList'); | ||||
|                     } | ||||
|                 } else { | ||||
|                     showNoData('gameDownloadList'); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 console.error('请求失败:', error); | ||||
|                 showError('gameDownloadList'); | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     // 显示无数据提示
 | ||||
|     function showNoData(containerId) { | ||||
|         document.getElementById(containerId).innerHTML = '<div class="no-data">暂无数据</div>'; | ||||
| @ -718,6 +1001,9 @@ | ||||
|                     case 'programDownload': | ||||
|                         loadCategoryPrograms(selectedCategoryId, 'programDownloadList'); | ||||
|                         break; | ||||
|                     case 'gameDownload': | ||||
|                         loadCategoryGames(selectedCategoryId, 'gameDownloadList'); | ||||
|                         break; | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
| @ -958,12 +1244,71 @@ | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     // 渲染游戏列表
 | ||||
|     function renderGames(games, containerId) { | ||||
|         const container = document.getElementById(containerId); | ||||
|         if (!container) return; | ||||
| 
 | ||||
|         let html = ''; | ||||
|         if (Array.isArray(games)) { | ||||
|             games.forEach(game => { | ||||
|                 html += createGameHtml(game); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         container.innerHTML = html || '<div class="no-data">暂无数据</div>'; | ||||
|     } | ||||
| 
 | ||||
|     // 创建游戏HTML
 | ||||
|     function createGameHtml(game) { | ||||
|         if (!game) return ''; | ||||
|          | ||||
|         return ` | ||||
|             <div class="opencourse product-item" onclick="window.open('/index/game/detail?id=${game.id || ''}', '_blank')"> | ||||
|                 <div class="video"> | ||||
|                     <img src="${game.icon || '/static/images/default-game.png'}" alt="" class="cover"> | ||||
|                 </div> | ||||
|                 <div class="introduction"> | ||||
|                     <div class="title">${game.title || '无标题'}</div> | ||||
|                     <div class="publishdate">${game.create_time || ''}</div> | ||||
|                 </div> | ||||
|                 <div class="bottom"> | ||||
|                     <div class="views"><i class="fa-solid fa-eye"></i><span style="margin-left: 5px;">${game.views || 0}</span></div> | ||||
|                     <div class="author"><i class="fa-regular fa-user"></i><span style="margin-left: 5px;">${game.uploader || '未知作者'}</span></div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         `; | ||||
|     } | ||||
| 
 | ||||
|     // 加载分类游戏
 | ||||
|     function loadCategoryGames(categoryId, containerId) { | ||||
|         fetch('/index/index/gameList') | ||||
|             .then(response => response.json()) | ||||
|             .then(result => { | ||||
|                 if (result.code === 0) { | ||||
|                     if (categoryId === 'all') { | ||||
|                         renderGames(result.data.games, containerId); | ||||
|                     } else { | ||||
|                         const filteredGames = result.data.games.filter(game => game.cate == categoryId); | ||||
|                         renderGames(filteredGames, containerId); | ||||
|                     } | ||||
|                 } else { | ||||
|                     showNoData(containerId); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 console.error('请求失败:', error); | ||||
|                 showError(containerId); | ||||
|             }); | ||||
|     } | ||||
| 
 | ||||
|     // 页面加载完成后执行
 | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|         loadWebArticles(); | ||||
|         loadTechArticles(); | ||||
|         loadResources(); | ||||
|         loadPrograms(); | ||||
|         loadGames(); | ||||
|     }); | ||||
| </script> | ||||
|     <footer class="footer" style="background-image: url(/static/images/footer-bg-1.png)"> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user