继续完善前端登录模块
This commit is contained in:
		
							parent
							
								
									9352fd2a75
								
							
						
					
					
						commit
						b8d3757397
					
				| @ -12,6 +12,7 @@ use think\facade\View; | |||||||
| use think\facade\Env; | use think\facade\Env; | ||||||
| use think\facade\Config; | use think\facade\Config; | ||||||
| use app\admin\controller\Log; | use app\admin\controller\Log; | ||||||
|  | use \think\facade\Filesystem; | ||||||
| 
 | 
 | ||||||
| use app\admin\model\AdminUserGroup; | use app\admin\model\AdminUserGroup; | ||||||
| use app\admin\model\AdminSysMenu; | use app\admin\model\AdminSysMenu; | ||||||
| @ -358,7 +359,7 @@ class IndexController extends Base{ | |||||||
| 			])->check($file); | 			])->check($file); | ||||||
| 			 | 			 | ||||||
| 			// 存储文件到public磁盘的uploads目录
 | 			// 存储文件到public磁盘的uploads目录
 | ||||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads', $files); | 			$info = Filesystem::disk('public')->putFile('uploads', $files); | ||||||
| 			 | 			 | ||||||
| 			// 处理文件路径,统一使用正斜杠
 | 			// 处理文件路径,统一使用正斜杠
 | ||||||
| 			$info = str_replace("\\", "/", $info); | 			$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' | 				'file'=>'fileExt:doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,7z' | ||||||
| 			])->check($file); | 			])->check($file); | ||||||
| 			 | 			 | ||||||
| 			$info = \think\facade\Filesystem::disk('public')->putFile('uploads/files', $files); | 			$info = Filesystem::disk('public')->putFile('uploads/files', $files); | ||||||
| 			 | 			 | ||||||
| 			// 处理文件路径
 | 			// 处理文件路径
 | ||||||
| 			$info = str_replace("\\", "/", $info); | 			$info = str_replace("\\", "/", $info); | ||||||
| @ -442,7 +443,7 @@ class IndexController extends Base{ | |||||||
| 		} | 		} | ||||||
| 		try { | 		try { | ||||||
| 			validate(['video'=>'filesize:102400|fileExt:mp4,avi,mov,wmv,flv'])->check($file); | 			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); | 			$info = str_replace("\\", "/", $info); | ||||||
| @ -474,7 +475,7 @@ class IndexController extends Base{ | |||||||
| 		} | 		} | ||||||
| 		try { | 		try { | ||||||
| 			validate(['audio'=>'filesize:51200|fileExt:mp3,wav,ogg,m4a'])->check($file); | 			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); | 			$info = str_replace("\\", "/", $info); | ||||||
|  | |||||||
| @ -14,6 +14,8 @@ use app\index\model\Articles\ArticlesCategory; | |||||||
| use app\index\model\Resources\Resources; | use app\index\model\Resources\Resources; | ||||||
| use app\index\model\Articles\Articles; | use app\index\model\Articles\Articles; | ||||||
| use app\index\model\MailConfig; | use app\index\model\MailConfig; | ||||||
|  | use \think\facade\Filesystem; | ||||||
|  | use app\index\model\Attachments; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class IndexController extends BaseController | 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 think\Controller; | ||||||
| use app\index\model\Users; | use app\index\model\Users; | ||||||
| use think\facade\Redirect; | use think\facade\Redirect; | ||||||
|  | use think\facade\View; | ||||||
| use \think\facade\Log; | use \think\facade\Log; | ||||||
| use \think\facade\Cache; | use \think\facade\Cache; | ||||||
| use PHPMailer\PHPMailer\PHPMailer; | use PHPMailer\PHPMailer\PHPMailer; | ||||||
| @ -48,12 +49,20 @@ class UserController extends BaseController | |||||||
|                 session('user_name', $user->name); |                 session('user_name', $user->name); | ||||||
|                 session('user_avatar', $user->avatar ?? '/static/images/avatar.png'); |                 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'); |                 Log::record('用户登录成功:' . $user->account, 'info'); | ||||||
| 
 | 
 | ||||||
|                 return json(['code' => 0, 'msg' => '登录成功']); |                 return json(['code' => 0, 'msg' => '登录成功']); | ||||||
| 
 | 
 | ||||||
|             } catch (\Exception $e) { |             } catch (\Exception $e) { | ||||||
|  |                 Log::record('登录失败:' . $e->getMessage(), 'error'); | ||||||
|                 return json(['code' => 1, 'msg' => '登录失败:' . $e->getMessage()]); |                 return json(['code' => 1, 'msg' => '登录失败:' . $e->getMessage()]); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -130,25 +139,39 @@ class UserController extends BaseController | |||||||
|      */ |      */ | ||||||
|     public function logout() |     public function logout() | ||||||
|     { |     { | ||||||
|         // 增加日志记录,记录用户退出登录操作
 |         try { | ||||||
|  |             // 记录退出日志
 | ||||||
|             Log::record('用户退出登录', 'info'); |             Log::record('用户退出登录', 'info'); | ||||||
| 
 | 
 | ||||||
|         // 销毁当前会话中的所有数据
 |             // 1. 清除所有 session
 | ||||||
|             session(null); |             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(); |             Cache::tag('user_cache')->clear(); | ||||||
| 
 | 
 | ||||||
|         // 清除cookie
 |             // 4. 返回成功状态,并告诉前端清除 localStorage
 | ||||||
|         cookie('user_id', null); |             return json([ | ||||||
|         cookie('user_name', null); |                 'code' => 0, | ||||||
|         cookie('user_avatar', null); |                 'msg' => '退出成功', | ||||||
|         cookie('expire_time', null); |                 'data' => [ | ||||||
|         cookie('is_auto_login', null); |                     'clear_storage' => true | ||||||
|         cookie('auto_login_attempted', null); |                 ] | ||||||
|  |             ]); | ||||||
| 
 | 
 | ||||||
|         // 返回成功状态
 |         } catch (\Exception $e) { | ||||||
|         return json(['code' => 0, 'msg' => '退出成功']); |             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]); |             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 | <?php | ||||||
| // 获取当前登录状态
 | // 获取当前登录状态
 | ||||||
| $isLoggedIn = false; | $isLoggedIn = false; | ||||||
|  | $userInfo = [ | ||||||
|  |     'is_login' => false, | ||||||
|  |     'name' => '', | ||||||
|  |     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||||
|  | ]; | ||||||
| 
 | 
 | ||||||
| // 检查session
 | // 检查cookie
 | ||||||
| if (session('user_id')) { | $userAccount = cookie('user_account'); | ||||||
|  | if ($userAccount) { | ||||||
|     $isLoggedIn = true; |     $isLoggedIn = true; | ||||||
| } |     $userInfo = [ | ||||||
| // 如果session未登录,检查cookie
 |         'is_login' => true, | ||||||
| else { |         'name' => cookie('user_name'), | ||||||
|     $userAccount = cookie('user_account'); |         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||||
|     if ($userAccount) { |     ]; | ||||||
|         // 恢复session
 |  | ||||||
|         session('user_id', cookie('user_id')); |  | ||||||
|         session('user_name', cookie('user_name')); |  | ||||||
|         session('user_avatar', cookie('user_avatar')); |  | ||||||
|         $isLoggedIn = true; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 添加一个隐藏的div来存储登录状态
 | // 添加一个隐藏的div来存储登录状态
 | ||||||
| @ -23,44 +23,13 @@ $loginStatus = [ | |||||||
|     'isLoggedIn' => $isLoggedIn, |     'isLoggedIn' => $isLoggedIn, | ||||||
|     'userAccount' => $userAccount ?? '' |     '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来存储登录状态 --> | ||||||
| <div id="loginStatus" style="display: none;"  | <div id="loginStatus" style="display: none;" data-is-logged-in="{$isLoggedIn}" data-user-account="{$userAccount ?? ''}"> | ||||||
|     data-is-logged-in="{$isLoggedIn}"  |  | ||||||
|     data-user-account="{$userAccount ?? ''}"> |  | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <div style="display: flex;flex-direction: column;"> | <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="main-menu"> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
| @ -76,11 +45,16 @@ $userInfo = [ | |||||||
|                 </ul> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__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"> |                 <div class="layui-inline"> | ||||||
|                     <!-- 根据登录状态显示不同的内容 --> |                     <!-- 根据登录状态显示不同的内容 --> | ||||||
|                     <?php if ($isLoggedIn): ?>
 |                     <?php if ($isLoggedIn): ?>
 | ||||||
|                         <div class="layui-inline" style="position: relative;"> |                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||||
|                             <img src="/static/images/avatar.png" class="layui-circle" |                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||||
|                             <div class="user-dropdown" id="userDropdownSticky"> |                             <div class="user-dropdown" id="userDropdownSticky"> | ||||||
|                                 <ul> |                                 <ul> | ||||||
| @ -127,11 +101,16 @@ $userInfo = [ | |||||||
|         </div> |         </div> | ||||||
|         <div class="sticky-nav__right"> |         <div class="sticky-nav__right"> | ||||||
|             <div class="main-menu__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"> |                 <div class="layui-inline"> | ||||||
|                     <!-- 根据登录状态显示不同的内容 --> |                     <!-- 根据登录状态显示不同的内容 --> | ||||||
|                     <?php if ($isLoggedIn): ?>
 |                     <?php if ($isLoggedIn): ?>
 | ||||||
|                         <div class="layui-inline" style="position: relative;"> |                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||||
|                             <img src="/static/images/avatar.png" class="layui-circle" |                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||||
|                             <div class="user-dropdown" id="userDropdownSticky"> |                             <div class="user-dropdown" id="userDropdownSticky"> | ||||||
|                                 <ul> |                                 <ul> | ||||||
| @ -361,11 +340,21 @@ $userInfo = [ | |||||||
|     #test10 [carousel-item]>* {
 |     #test10 [carousel-item]>* {
 | ||||||
|         background: none !important; |         background: none !important; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .main-menu__right { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .username { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|     // 在页面加载时立即执行
 |     // 在页面加载时立即执行
 | ||||||
|     (function() { |     (function () { | ||||||
|         // 检查是否已经刷新过
 |         // 检查是否已经刷新过
 | ||||||
|         if (sessionStorage.getItem('has_refreshed') === 'true') { |         if (sessionStorage.getItem('has_refreshed') === 'true') { | ||||||
|             return; |             return; | ||||||
| @ -453,46 +442,6 @@ $userInfo = [ | |||||||
|         // 页面加载时检查自动登录
 |         // 页面加载时检查自动登录
 | ||||||
|         checkAutoLogin(); |         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 () { |         $(document).ready(function () { | ||||||
|             // 主导航头像
 |             // 主导航头像
 | ||||||
|             $("#userAvatarMain").click(function (e) { |             $("#userAvatarMain").click(function (e) { | ||||||
|  | |||||||
| @ -1,21 +1,21 @@ | |||||||
| <?php | <?php | ||||||
| // 获取当前登录状态
 | // 获取当前登录状态
 | ||||||
| $isLoggedIn = false; | $isLoggedIn = false; | ||||||
|  | $userInfo = [ | ||||||
|  |     'is_login' => false, | ||||||
|  |     'name' => '', | ||||||
|  |     'avatar' => '/static/images/avatar.png' // 默认头像
 | ||||||
|  | ]; | ||||||
| 
 | 
 | ||||||
| // 检查session
 | // 检查cookie
 | ||||||
| if (session('user_id')) { | $userAccount = cookie('user_account'); | ||||||
|  | if ($userAccount) { | ||||||
|     $isLoggedIn = true; |     $isLoggedIn = true; | ||||||
| } |     $userInfo = [ | ||||||
| // 如果session未登录,检查cookie
 |         'is_login' => true, | ||||||
| else { |         'name' => cookie('user_name'), | ||||||
|     $userAccount = cookie('user_account'); |         'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png' | ||||||
|     if ($userAccount) { |     ]; | ||||||
|         // 恢复session
 |  | ||||||
|         session('user_id', cookie('user_id')); |  | ||||||
|         session('user_name', cookie('user_name')); |  | ||||||
|         session('user_avatar', cookie('user_avatar')); |  | ||||||
|         $isLoggedIn = true; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 添加一个隐藏的div来存储登录状态
 | // 添加一个隐藏的div来存储登录状态
 | ||||||
| @ -23,12 +23,6 @@ $loginStatus = [ | |||||||
|     'isLoggedIn' => $isLoggedIn, |     'isLoggedIn' => $isLoggedIn, | ||||||
|     'userAccount' => $userAccount ?? '' |     '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来存储登录状态 --> | ||||||
| @ -74,10 +68,15 @@ $userInfo = [ | |||||||
|                 </ul> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__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"> |                 <div class="layui-inline"> | ||||||
|                     <!-- 根据登录状态显示不同的内容 --> |                     <!-- 根据登录状态显示不同的内容 --> | ||||||
|                     <?php if ($userInfo['is_login']): ?>
 |                     <?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" |                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||||
|                             <div class="user-dropdown" id="userDropdownMain"> |                             <div class="user-dropdown" id="userDropdownMain"> | ||||||
| @ -140,7 +139,7 @@ $userInfo = [ | |||||||
|                 <div class="layui-inline"> |                 <div class="layui-inline"> | ||||||
|                     <!-- 根据登录状态显示不同的内容 --> |                     <!-- 根据登录状态显示不同的内容 --> | ||||||
|                     <?php if ($userInfo['is_login']): ?>
 |                     <?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" |                             <img src="{$userInfo.avatar}" class="layui-circle" | ||||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||||
|                             <div class="user-dropdown" id="userDropdownSticky"> |                             <div class="user-dropdown" id="userDropdownSticky"> | ||||||
| @ -371,6 +370,16 @@ $userInfo = [ | |||||||
|     #test10 [carousel-item]>* {
 |     #test10 [carousel-item]>* {
 | ||||||
|         background: none !important; |         background: none !important; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .main-menu__right { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .username { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <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> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 
 | 
 | ||||||
| @ -18,37 +18,43 @@ | |||||||
| </head> | </head> | ||||||
| 
 | 
 | ||||||
| <body> | <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 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="main-menu"> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <div class="main-menu__logo"> |             <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> | ||||||
|             <div class="main-menu__nav"> |             <div class="main-menu__nav"> | ||||||
|                 <ul class="main-menu__list"> |                 <ul class="main-menu__list"> | ||||||
| @ -59,52 +65,16 @@ | |||||||
|                 </ul> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__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"> | ||||||
|                     <div class="layui-inline" style="position: relative;"> |                     <!-- 根据登录状态显示不同的内容 --> | ||||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" |                     <?php if ($isLoggedIn): ?>
 | ||||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> |                         <div class="layui-inline" style="position: relative;margin-left:20px;"> | ||||||
|                         <div class="user-dropdown" id="userDropdownMain"> |                             <img src="<?php echo htmlentities((string) $userInfo['avatar']); ?>" class="layui-circle" | ||||||
|                             <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" |  | ||||||
|                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||||
|                             <div class="user-dropdown" id="userDropdownSticky"> |                             <div class="user-dropdown" id="userDropdownSticky"> | ||||||
|                                 <ul> |                                 <ul> | ||||||
| @ -123,6 +93,68 @@ | |||||||
|                                 </ul> |                                 </ul> | ||||||
|                             </div> |                             </div> | ||||||
|                         </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> |             </div> | ||||||
|         </div> |         </div> | ||||||
| @ -328,51 +360,107 @@ | |||||||
|     #test10 [carousel-item]>* {
 |     #test10 [carousel-item]>* {
 | ||||||
|         background: none !important; |         background: none !important; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .main-menu__right { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .username { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <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 () { |     layui.use(['carousel', 'form', 'layer'], function () { | ||||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; |         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||||
| 
 | 
 | ||||||
|         // 加载banner数据
 |         // 检查本地存储并自动登录
 | ||||||
|         $.ajax({ |         function checkAutoLogin() { | ||||||
|             url: '/index/index/bannerlist', |             // 如果已经登录,不再执行自动登录
 | ||||||
|             type: 'GET', |             if ($('#userAvatarMain').length > 0) { | ||||||
|             success: function (res) { |                 return; | ||||||
|                 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({ |             if (sessionStorage.getItem('auto_login_attempted') === 'true') { | ||||||
|                         elem: '#test10', |                 return; | ||||||
|                         width: '100%', |             } | ||||||
|                         height: '100vh', | 
 | ||||||
|                         interval: 4000, |             // 从localStorage获取用户账号
 | ||||||
|                         anim: 'fade', |             var userAccount = localStorage.getItem('user_account'); | ||||||
|                         autoplay: true, |             if (userAccount) { | ||||||
|                         full: false, |                 // 标记已尝试自动登录
 | ||||||
|                         arrow: 'hover' |                 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 () { |         $(document).ready(function () { | ||||||
|             // 主导航头像
 |             // 主导航头像
 | ||||||
| @ -406,7 +494,36 @@ | |||||||
|             layer.confirm('确定要退出登录吗?', { |             layer.confirm('确定要退出登录吗?', { | ||||||
|                 btn: ['确定', '取消'] |                 btn: ['确定', '取消'] | ||||||
|             }, function () { |             }, 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.addEventListener('mouseleave', function () { | ||||||
|             popup.style.display = 'none'; |             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> | </script> | ||||||
| <div class="main"> | <div class="main"> | ||||||
| @ -469,6 +642,15 @@ | |||||||
|         <div class="article-content" id="articleContent"> |         <div class="article-content" id="articleContent"> | ||||||
|         </div> |         </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"> |         <div class="article-tags"> | ||||||
|             <span class="tag-label">标签:</span> |             <span class="tag-label">标签:</span> | ||||||
|             <div id="articleTags"></div> |             <div id="articleTags"></div> | ||||||
| @ -615,6 +797,7 @@ | |||||||
|         color: #333;
 |         color: #333;
 | ||||||
|         font-size: 16px; |         font-size: 16px; | ||||||
|         margin-bottom: 30px; |         margin-bottom: 30px; | ||||||
|  |         border-bottom: 1px solid #eee;
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .article-content img { |     .article-content img { | ||||||
| @ -915,6 +1098,28 @@ | |||||||
|     .location-item a { |     .location-item a { | ||||||
|         color: #000 !important;
 |         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> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
| @ -1074,12 +1279,12 @@ | |||||||
|                             // 添加点赞状态
 |                             // 添加点赞状态
 | ||||||
|                             likeBtn.classList.add('liked'); |                             likeBtn.classList.add('liked'); | ||||||
|                             likeBtn.querySelector('i').style.color = '#f57005'; |                             likeBtn.querySelector('i').style.color = '#f57005'; | ||||||
|                             layer.msg('点赞成功', {icon: 1}); |                             layer.msg('点赞成功', { icon: 1 }); | ||||||
|                         } else { |                         } else { | ||||||
|                             // 如果请求失败,恢复按钮状态
 |                             // 如果请求失败,恢复按钮状态
 | ||||||
|                             likeBtn.style.pointerEvents = 'auto'; |                             likeBtn.style.pointerEvents = 'auto'; | ||||||
|                             likeBtn.style.cursor = 'pointer'; |                             likeBtn.style.cursor = 'pointer'; | ||||||
|                             layer.msg('点赞失败:' + data.msg, {icon: 2}); |                             layer.msg('点赞失败:' + data.msg, { icon: 2 }); | ||||||
|                         } |                         } | ||||||
|                     }) |                     }) | ||||||
|                     .catch(error => { |                     .catch(error => { | ||||||
| @ -1087,7 +1292,7 @@ | |||||||
|                         likeBtn.style.pointerEvents = 'auto'; |                         likeBtn.style.pointerEvents = 'auto'; | ||||||
|                         likeBtn.style.cursor = 'pointer'; |                         likeBtn.style.cursor = 'pointer'; | ||||||
|                         console.error('点赞请求失败:', error); |                         console.error('点赞请求失败:', error); | ||||||
|                         layer.msg('点赞失败,请稍后重试', {icon: 2}); |                         layer.msg('点赞失败,请稍后重试', { icon: 2 }); | ||||||
|                     }); |                     }); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -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> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 
 | 
 | ||||||
| @ -16,7 +16,38 @@ | |||||||
| </head> | </head> | ||||||
| 
 | 
 | ||||||
| <body> | <body> | ||||||
|     <div style="display: flex;flex-direction: column;"> |     <?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="topbar-one"> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <div style="width: 70%;"> |             <div style="width: 70%;"> | ||||||
| @ -32,8 +63,6 @@ | |||||||
|                 </ul> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="topbar-one__social" style="width: 30%;"> |             <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> |                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||||
|                 <div class="qrcode-popup" |                 <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;"> |                     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> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__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"> | ||||||
|                     <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"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||||
|                             <div class="user-dropdown" id="userDropdownMain"> |                             <div class="user-dropdown" id="userDropdownMain"> | ||||||
|                                 <ul> |                                 <ul> | ||||||
| @ -78,6 +114,12 @@ | |||||||
|                                 </ul> |                                 </ul> | ||||||
|                             </div> |                             </div> | ||||||
|                         </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> | ||||||
| @ -107,9 +149,16 @@ | |||||||
|         </div> |         </div> | ||||||
|         <div class="sticky-nav__right"> |         <div class="sticky-nav__right"> | ||||||
|             <div class="main-menu__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"> | ||||||
|                     <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"> |                                 style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||||
|                             <div class="user-dropdown" id="userDropdownSticky"> |                             <div class="user-dropdown" id="userDropdownSticky"> | ||||||
|                                 <ul> |                                 <ul> | ||||||
| @ -128,6 +177,12 @@ | |||||||
|                                 </ul> |                                 </ul> | ||||||
|                             </div> |                             </div> | ||||||
|                         </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> | ||||||
| @ -333,12 +388,108 @@ | |||||||
|     #test10 [carousel-item]>* {
 |     #test10 [carousel-item]>* {
 | ||||||
|         background: none !important; |         background: none !important; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .main-menu__right { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .username { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <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 () { |     layui.use(['carousel', 'form', 'layer'], function () { | ||||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; |         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数据
 |         // 加载banner数据
 | ||||||
|         $.ajax({ |         $.ajax({ | ||||||
|             url: '/index/index/bannerlist', |             url: '/index/index/bannerlist', | ||||||
| @ -411,7 +562,36 @@ | |||||||
|             layer.confirm('确定要退出登录吗?', { |             layer.confirm('确定要退出登录吗?', { | ||||||
|                 btn: ['确定', '取消'] |                 btn: ['确定', '取消'] | ||||||
|             }, function () { |             }, 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.addEventListener('mouseleave', function () { | ||||||
|             popup.style.display = 'none'; |             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> | </script> | ||||||
|     <main class="main-content"> |     <main class="main-content"> | ||||||
| @ -536,6 +772,27 @@ | |||||||
|             </div> |             </div> | ||||||
|         </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> |     </div> | ||||||
| </main> | </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) { |     function showNoData(containerId) { | ||||||
|         document.getElementById(containerId).innerHTML = '<div class="no-data">暂无数据</div>'; |         document.getElementById(containerId).innerHTML = '<div class="no-data">暂无数据</div>'; | ||||||
| @ -718,6 +1001,9 @@ | |||||||
|                     case 'programDownload': |                     case 'programDownload': | ||||||
|                         loadCategoryPrograms(selectedCategoryId, 'programDownloadList'); |                         loadCategoryPrograms(selectedCategoryId, 'programDownloadList'); | ||||||
|                         break; |                         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() { |     document.addEventListener('DOMContentLoaded', function() { | ||||||
|         loadWebArticles(); |         loadWebArticles(); | ||||||
|         loadTechArticles(); |         loadTechArticles(); | ||||||
|         loadResources(); |         loadResources(); | ||||||
|         loadPrograms(); |         loadPrograms(); | ||||||
|  |         loadGames(); | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
|     <footer class="footer" style="background-image: url(/static/images/footer-bg-1.png)"> |     <footer class="footer" style="background-image: url(/static/images/footer-bg-1.png)"> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user