修复资源用mvc
This commit is contained in:
		
							parent
							
								
									f4f4bc600b
								
							
						
					
					
						commit
						a7b82e1e26
					
				| @ -4,12 +4,14 @@ | |||||||
|  */ |  */ | ||||||
| namespace app\admin\controller; | namespace app\admin\controller; | ||||||
| use app\admin\controller\Base; | use app\admin\controller\Base; | ||||||
|  | use app\admin\model\Article\Article; | ||||||
|  | use app\admin\model\ArticleCategory; | ||||||
| use think\facade\Db; | use think\facade\Db; | ||||||
| use think\facade\View; | use think\facade\View; | ||||||
| use think\facade\Request; | use think\facade\Request; | ||||||
| use app\admin\controller\Log; | use app\admin\controller\Log; | ||||||
| 
 | 
 | ||||||
| class Article extends Base | class Articles extends Base | ||||||
| { | { | ||||||
|     // 文章列表
 |     // 文章列表
 | ||||||
|     public function articlelist() |     public function articlelist() | ||||||
| @ -21,14 +23,14 @@ class Article extends Base | |||||||
|             $title = input('post.title'); |             $title = input('post.title'); | ||||||
|             $author = input('post.author'); |             $author = input('post.author'); | ||||||
|              |              | ||||||
|             $query = Db::table('yz_article') |             $query = Db::name('article') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', '<>', 3); |                 ->where('status', '<>', 3); | ||||||
|              |              | ||||||
|             // 分类筛选
 |             // 分类筛选
 | ||||||
|             if (!empty($category)) { |             if (!empty($category)) { | ||||||
|                 // 先获取分类ID
 |                 // 先获取分类ID
 | ||||||
|                 $cateInfo = Db::table('yz_article_category') |                 $cateInfo = Db::name('article_category') | ||||||
|                     ->where('name', $category) |                     ->where('name', $category) | ||||||
|                     ->where('delete_time', null) |                     ->where('delete_time', null) | ||||||
|                     ->where('status', 1) |                     ->where('status', 1) | ||||||
| @ -58,7 +60,7 @@ class Article extends Base | |||||||
|                 ->select() |                 ->select() | ||||||
|                 ->each(function ($item) { |                 ->each(function ($item) { | ||||||
|                     // 获取分类信息
 |                     // 获取分类信息
 | ||||||
|                     $cateInfo = Db::table('yz_article_category') |                     $cateInfo = Db::name('article_category') | ||||||
|                         ->where('id', $item['cate']) |                         ->where('id', $item['cate']) | ||||||
|                         ->field('name, image') |                         ->field('name, image') | ||||||
|                         ->find(); |                         ->find(); | ||||||
| @ -86,7 +88,7 @@ class Article extends Base | |||||||
|             ]); |             ]); | ||||||
|         } else { |         } else { | ||||||
|             // 获取所有分类并构建父子结构
 |             // 获取所有分类并构建父子结构
 | ||||||
|             $allCategories = Db::table('yz_article_category') |             $allCategories = Db::name('article_category') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->order('sort asc, id asc') |                 ->order('sort asc, id asc') | ||||||
| @ -129,7 +131,7 @@ class Article extends Base | |||||||
|                 'create_time' => time() |                 'create_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $insert = Db::table('yz_article')->insert($data); |             $insert = Db::name('article')->insert($data); | ||||||
|             if (empty($insert)) { |             if (empty($insert)) { | ||||||
|                 Log::record('添加文章', 0, '添加文章失败', '文章管理'); |                 Log::record('添加文章', 0, '添加文章失败', '文章管理'); | ||||||
|                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); | ||||||
| @ -137,7 +139,7 @@ class Article extends Base | |||||||
|             Log::record('添加文章', 1, '', '文章管理'); |             Log::record('添加文章', 1, '', '文章管理'); | ||||||
|             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             $lists = Db::table('yz_article') |             $lists = Db::name('article') | ||||||
|                 ->order('id DESC') |                 ->order('id DESC') | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->each(function ($item, $key) { |                 ->each(function ($item, $key) { | ||||||
| @ -167,7 +169,7 @@ class Article extends Base | |||||||
|                 'update_time' => time() |                 'update_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $update = Db::table('yz_article')->where('id', $id)->update($data); |             $update = Db::name('article')->where('id', $id)->update($data); | ||||||
|             if ($update === false) { |             if ($update === false) { | ||||||
|                 Log::record('编辑文章', 0, '编辑文章失败', '文章管理'); |                 Log::record('编辑文章', 0, '编辑文章失败', '文章管理'); | ||||||
|                 return json(['code' => 1, 'msg' => '更新失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '更新失败', 'data' => []]); | ||||||
| @ -176,12 +178,12 @@ class Article extends Base | |||||||
|             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             $id = input('get.id'); |             $id = input('get.id'); | ||||||
|             $info = Db::table('yz_article')->where('id', $id)->find(); |             $info = Db::name('article')->where('id', $id)->find(); | ||||||
|             if ($info === null) { |             if ($info === null) { | ||||||
|                 return json(['code' => 1, 'msg' => '文章不存在', 'data' => []]); |                 return json(['code' => 1, 'msg' => '文章不存在', 'data' => []]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             $cates = Db::table('yz_article_category') |             $cates = Db::name('article_category') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->order('sort asc, id asc') |                 ->order('sort asc, id asc') | ||||||
| @ -190,7 +192,7 @@ class Article extends Base | |||||||
| 
 | 
 | ||||||
|             $info['content'] = !empty($info['content']) ? htmlspecialchars_decode(str_replace(["\r\n", "\r", "\n"], '', addslashes($info['content']))) : ''; |             $info['content'] = !empty($info['content']) ? htmlspecialchars_decode(str_replace(["\r\n", "\r", "\n"], '', addslashes($info['content']))) : ''; | ||||||
| 
 | 
 | ||||||
|             $currentCate = Db::table('yz_article_category') |             $currentCate = Db::name('article_category') | ||||||
|                 ->where('id', $info['cate']) |                 ->where('id', $info['cate']) | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
| @ -212,7 +214,7 @@ class Article extends Base | |||||||
|         $data = [ |         $data = [ | ||||||
|             'delete_time' => time(), |             'delete_time' => time(), | ||||||
|         ]; |         ]; | ||||||
|         $delete = Db::table('yz_article')->where('id', $id)->update($data); |         $delete = Db::name('article')->where('id', $id)->update($data); | ||||||
|         if ($delete === false) { |         if ($delete === false) { | ||||||
|             Log::record('删除文章', 0, '删除文章失败', '文章管理'); |             Log::record('删除文章', 0, '删除文章失败', '文章管理'); | ||||||
|             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); |             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); | ||||||
| @ -225,7 +227,7 @@ class Article extends Base | |||||||
|     public function articlecate() |     public function articlecate() | ||||||
|     { |     { | ||||||
|         if (Request::isPost()) { |         if (Request::isPost()) { | ||||||
|             $lists = Db::table('yz_article_category') |             $lists = Db::name('article_category') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->order('sort asc, id asc') |                 ->order('sort asc, id asc') | ||||||
| @ -268,7 +270,7 @@ class Article extends Base | |||||||
|     public function getcate() |     public function getcate() | ||||||
|     { |     { | ||||||
|         // 获取所有分类
 |         // 获取所有分类
 | ||||||
|         $lists = Db::table('yz_article_category') |         $lists = Db::name('article_category') | ||||||
|             ->where('delete_time', null) |             ->where('delete_time', null) | ||||||
|             ->where('status', 1) |             ->where('status', 1) | ||||||
|             ->order('sort asc, id asc') |             ->order('sort asc, id asc') | ||||||
| @ -311,7 +313,7 @@ class Article extends Base | |||||||
|                 'create_time' => time() |                 'create_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $insert = Db::table('yz_article_category')->insert($data); |             $insert = Db::name('article_category')->insert($data); | ||||||
|             if (empty($insert)) { |             if (empty($insert)) { | ||||||
|                 Log::record('添加文章分类', 0, '添加文章分类失败', '文章分类'); |                 Log::record('添加文章分类', 0, '添加文章分类失败', '文章分类'); | ||||||
|                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); | ||||||
| @ -320,7 +322,7 @@ class Article extends Base | |||||||
|             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             // 获取所有可选的父级分类
 |             // 获取所有可选的父级分类
 | ||||||
|             $parentCategories = Db::table('yz_article_category') |             $parentCategories = Db::name('article_category') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->where('cid', 0) |                 ->where('cid', 0) | ||||||
| @ -352,7 +354,7 @@ class Article extends Base | |||||||
|                 'update_time' => time() |                 'update_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $update = Db::table('yz_article_category') |             $update = Db::name('article_category') | ||||||
|                 ->where('id', $data['id']) |                 ->where('id', $data['id']) | ||||||
|                 ->update($data); |                 ->update($data); | ||||||
| 
 | 
 | ||||||
| @ -364,10 +366,10 @@ class Article extends Base | |||||||
|             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             $id = input('get.id'); |             $id = input('get.id'); | ||||||
|             $info = Db::table('yz_article_category')->where('id', $id)->find(); |             $info = Db::name('article_category')->where('id', $id)->find(); | ||||||
|              |              | ||||||
|             // 获取所有可选的父级分类
 |             // 获取所有可选的父级分类
 | ||||||
|             $parentCategories = Db::table('yz_article_category') |             $parentCategories = Db::name('article_category') | ||||||
|                 ->where('delete_time', null) |                 ->where('delete_time', null) | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->where('id', '<>', $id) // 排除自己
 |                 ->where('id', '<>', $id) // 排除自己
 | ||||||
| @ -407,7 +409,7 @@ class Article extends Base | |||||||
|         $id = input('post.id'); |         $id = input('post.id'); | ||||||
| 
 | 
 | ||||||
|         // 检查是否有子分类
 |         // 检查是否有子分类
 | ||||||
|         $hasChildren = Db::table('yz_article_category') |         $hasChildren = Db::name('article_category') | ||||||
|             ->where('cid', $id) |             ->where('cid', $id) | ||||||
|             ->where('delete_time', null) |             ->where('delete_time', null) | ||||||
|             ->find(); |             ->find(); | ||||||
| @ -417,7 +419,7 @@ class Article extends Base | |||||||
|             return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]); |             return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $delete = Db::table('yz_article_category') |         $delete = Db::name('article_category') | ||||||
|             ->where('id', $id) |             ->where('id', $id) | ||||||
|             ->update(['delete_time' => time()]); |             ->update(['delete_time' => time()]); | ||||||
| 
 | 
 | ||||||
| @ -431,7 +433,7 @@ class Article extends Base | |||||||
| 
 | 
 | ||||||
|     //统计文章数量
 |     //统计文章数量
 | ||||||
|     public function counts()  { |     public function counts()  { | ||||||
|         $total = Db::table('yz_article') |         $total = Db::name('article') | ||||||
|             ->where('delete_time', null) |             ->where('delete_time', null) | ||||||
|             ->where('status', '<>', 3) |             ->where('status', '<>', 3) | ||||||
|             ->count(); |             ->count(); | ||||||
| @ -15,7 +15,7 @@ class Index extends Base{ | |||||||
| 		$menus = []; | 		$menus = []; | ||||||
| 		$menu = []; | 		$menu = []; | ||||||
| 		$where = ['group_id'=>$this->aUser['group_id']]; | 		$where = ['group_id'=>$this->aUser['group_id']]; | ||||||
| 		$role = Db::table('yz_admin_user_group')->where($where)->find(); | 		$role = Db::name('admin_user_group')->where($where)->find(); | ||||||
| 		if($role){ | 		if($role){ | ||||||
| 			$role['rights'] = (isset($role['rights']) && $role['rights']) ? json_decode($role['rights'],true) : []; | 			$role['rights'] = (isset($role['rights']) && $role['rights']) ? json_decode($role['rights'],true) : []; | ||||||
| 		} | 		} | ||||||
| @ -25,7 +25,7 @@ class Index extends Base{ | |||||||
| 				['status','=',1] | 				['status','=',1] | ||||||
| 			]; | 			]; | ||||||
| 			// 获取所有菜单
 | 			// 获取所有菜单
 | ||||||
| 			$menus = Db::table('yz_admin_sys_menu')->order('type,sort desc')->where($where)->select()->toArray(); | 			$menus = Db::name('admin_sys_menu')->order('type,sort desc')->where($where)->select()->toArray(); | ||||||
| 			 | 			 | ||||||
| 			// 构建树形结构菜单
 | 			// 构建树形结构菜单
 | ||||||
| 			$menuTree = []; | 			$menuTree = []; | ||||||
| @ -63,12 +63,12 @@ class Index extends Base{ | |||||||
| 	public function welcome(){ | 	public function welcome(){ | ||||||
| 		// 获取今日统计数据
 | 		// 获取今日统计数据
 | ||||||
| 		$today = date('Y-m-d'); | 		$today = date('Y-m-d'); | ||||||
| 		$todayStats = Db::name('yz_daily_stats') | 		$todayStats = Db::name('daily_stats') | ||||||
| 			->where('date', $today) | 			->where('date', $today) | ||||||
| 			->find(); | 			->find(); | ||||||
| 
 | 
 | ||||||
| 		// 获取最近7天的访问趋势
 | 		// 获取最近7天的访问趋势
 | ||||||
| 		$last7Days = Db::name('yz_daily_stats') | 		$last7Days = Db::name('daily_stats') | ||||||
| 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | ||||||
| 			->where('date', '<=', $today) | 			->where('date', '<=', $today) | ||||||
| 			->order('date', 'asc') | 			->order('date', 'asc') | ||||||
| @ -76,7 +76,7 @@ class Index extends Base{ | |||||||
| 			->toArray(); | 			->toArray(); | ||||||
| 
 | 
 | ||||||
| 		// 获取用户增长趋势
 | 		// 获取用户增长趋势
 | ||||||
| 		$userGrowth = Db::name('yz_daily_stats') | 		$userGrowth = Db::name('daily_stats') | ||||||
| 			->where('date', '>=', date('Y-m-d', strtotime('-30 days'))) | 			->where('date', '>=', date('Y-m-d', strtotime('-30 days'))) | ||||||
| 			->where('date', '<=', $today) | 			->where('date', '<=', $today) | ||||||
| 			->field('date, new_users, total_users') | 			->field('date, new_users, total_users') | ||||||
| @ -85,7 +85,7 @@ class Index extends Base{ | |||||||
| 			->toArray(); | 			->toArray(); | ||||||
| 
 | 
 | ||||||
| 		// 获取资源下载统计
 | 		// 获取资源下载统计
 | ||||||
| 		$resourceStats = Db::name('yz_daily_stats') | 		$resourceStats = Db::name('daily_stats') | ||||||
| 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | ||||||
| 			->where('date', '<=', $today) | 			->where('date', '<=', $today) | ||||||
| 			->field('date, daily_resources, resource_downloads') | 			->field('date, daily_resources, resource_downloads') | ||||||
| @ -94,7 +94,7 @@ class Index extends Base{ | |||||||
| 			->toArray(); | 			->toArray(); | ||||||
| 
 | 
 | ||||||
| 		// 获取文章访问统计
 | 		// 获取文章访问统计
 | ||||||
| 		$articleStats = Db::name('yz_daily_stats') | 		$articleStats = Db::name('daily_stats') | ||||||
| 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | 			->where('date', '>=', date('Y-m-d', strtotime('-7 days'))) | ||||||
| 			->where('date', '<=', $today) | 			->where('date', '<=', $today) | ||||||
| 			->field('date, daily_articles, article_views') | 			->field('date, daily_articles, article_views') | ||||||
| @ -137,7 +137,7 @@ class Index extends Base{ | |||||||
| 		$activities = []; | 		$activities = []; | ||||||
| 
 | 
 | ||||||
| 		// 获取今日新用户
 | 		// 获取今日新用户
 | ||||||
| 		$newUsers = Db::name('yz_daily_stats') | 		$newUsers = Db::name('daily_stats') | ||||||
| 			->where('date', $today) | 			->where('date', $today) | ||||||
| 			->value('new_users'); | 			->value('new_users'); | ||||||
| 		if ($newUsers > 0) { | 		if ($newUsers > 0) { | ||||||
| @ -149,7 +149,7 @@ class Index extends Base{ | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// 获取今日文章
 | 		// 获取今日文章
 | ||||||
| 		$newArticles = Db::name('yz_daily_stats') | 		$newArticles = Db::name('daily_stats') | ||||||
| 			->where('date', $today) | 			->where('date', $today) | ||||||
| 			->value('daily_articles'); | 			->value('daily_articles'); | ||||||
| 		if ($newArticles > 0) { | 		if ($newArticles > 0) { | ||||||
| @ -161,7 +161,7 @@ class Index extends Base{ | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// 获取今日资源
 | 		// 获取今日资源
 | ||||||
| 		$newResources = Db::name('yz_daily_stats') | 		$newResources = Db::name('daily_stats') | ||||||
| 			->where('date', $today) | 			->where('date', $today) | ||||||
| 			->value('daily_resources'); | 			->value('daily_resources'); | ||||||
| 		if ($newResources > 0) { | 		if ($newResources > 0) { | ||||||
| @ -280,7 +280,7 @@ class Index extends Base{ | |||||||
| 			'create_time' => time(), | 			'create_time' => time(), | ||||||
| 			'update_time' => time() | 			'update_time' => time() | ||||||
| 		]; | 		]; | ||||||
| 		return Db::table('yz_attachments')->insertGetId($data); | 		return Db::name('attachments')->insertGetId($data); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	# 图片上传
 | 	# 图片上传
 | ||||||
|  | |||||||
| @ -4,10 +4,13 @@ | |||||||
|  */ |  */ | ||||||
| namespace app\admin\controller; | namespace app\admin\controller; | ||||||
| use app\admin\controller\Base; | use app\admin\controller\Base; | ||||||
| use think\facade\Db; | use app\admin\model\Resource\Resource; | ||||||
|  | use app\admin\model\Resource\ResourceCategory; | ||||||
| use think\facade\View; | use think\facade\View; | ||||||
| use think\facade\Request; | use think\facade\Request; | ||||||
|  | use think\facade\Db; | ||||||
| use app\admin\controller\Log; | use app\admin\controller\Log; | ||||||
|  | use think\App; | ||||||
| 
 | 
 | ||||||
| class Resources extends Base | class Resources extends Base | ||||||
| { | { | ||||||
| @ -15,95 +18,75 @@ class Resources extends Base | |||||||
|     public function lists() |     public function lists() | ||||||
|     { |     { | ||||||
|         if (Request::isPost()) { |         if (Request::isPost()) { | ||||||
|             $category = input('post.category'); |             $params = [ | ||||||
|             $page = input('post.page', 1); |                 'category' => input('post.category'), | ||||||
|             $limit = input('post.limit', 10); |                 'name' => input('post.name'), | ||||||
|             $name = input('post.name'); |                 'uploader' => input('post.uploader') | ||||||
|             $uploader = input('post.uploader'); |             ]; | ||||||
|              |             $page = (int)input('post.page', 1); | ||||||
|             $query = Db::table('yz_resources') |             $limit = (int)input('post.limit', 10); | ||||||
|                 ->where('delete_time', null) | 
 | ||||||
|                 ->where('status', '<>', 3); |             $query = Resource::where('delete_time', null) | ||||||
|  |                 ->where('status', 1); | ||||||
|              |              | ||||||
|             // 分类筛选
 |             // 分类筛选
 | ||||||
|             if (!empty($category)) { |             if (!empty($params['category'])) { | ||||||
|                 // 先获取分类ID
 |                 $cateInfo = ResourceCategory::where('name', $params['category']) | ||||||
|                 $cateInfo = Db::table('yz_resources_category') |  | ||||||
|                     ->where('name', $category) |  | ||||||
|                     ->where('delete_time', null) |                     ->where('delete_time', null) | ||||||
|                     ->where('status', 1) |                     ->where('status', 1) | ||||||
|  |                     ->field('id') | ||||||
|                     ->find(); |                     ->find(); | ||||||
|                  |                  | ||||||
|                 if ($cateInfo) { |                 if ($cateInfo) { | ||||||
|                     $query = $query->where('cate', $cateInfo['id']); |                     $query = $query->where('cate', (int)$cateInfo['id']); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 名称搜索
 |             // 名称搜索
 | ||||||
|             if (!empty($name)) { |             if (!empty($params['name'])) { | ||||||
|                 $query = $query->where('name', 'like', '%'.$name.'%'); |                 $query = $query->where('name', 'like', '%'.$params['name'].'%'); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 上传者搜索
 |             // 上传者搜索
 | ||||||
|             if (!empty($uploader)) { |             if (!empty($params['uploader'])) { | ||||||
|                 $query = $query->where('uploader', 'like', '%'.$uploader.'%'); |                 $query = $query->where('uploader', 'like', '%'.$params['uploader'].'%'); | ||||||
|             } |             } | ||||||
|              | 
 | ||||||
|             // 获取总记录数
 |  | ||||||
|             $count = $query->count(); |             $count = $query->count(); | ||||||
|              | 
 | ||||||
|             // 获取分页数据
 |  | ||||||
|             $lists = $query->order('id DESC') |             $lists = $query->order('id DESC') | ||||||
|                 ->page($page, $limit) |                 ->page($page, $limit) | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->each(function ($item) { |                 ->each(function ($item) { | ||||||
|                     // 获取分类信息
 |                     // 获取分类信息
 | ||||||
|                     $cateInfo = Db::table('yz_resources_category') |                     $cateInfo = ResourceCategory::where('id', (int)$item['cate']) | ||||||
|                         ->where('id', $item['cate']) |  | ||||||
|                         ->field('name, icon') |                         ->field('name, icon') | ||||||
|                         ->find(); |                         ->find(); | ||||||
| 
 |                     if ($cateInfo) { | ||||||
|                     // 设置分类名称
 |                         $item['cate'] = $cateInfo['name']; | ||||||
|                     $item['cate'] = $cateInfo['name']; |                         if (empty($item['icon']) && !empty($cateInfo['icon'])) { | ||||||
| 
 |                             $item['icon'] = $cateInfo['icon']; | ||||||
|                     // 如果资源没有图标,使用分类的图标
 |                         } | ||||||
|                     if (empty($item['icon']) && !empty($cateInfo['icon'])) { |  | ||||||
|                         $item['icon'] = $cateInfo['icon']; |  | ||||||
|                     } |                     } | ||||||
| 
 |                     $item['create_time'] = date('Y-m-d H:i:s', (int)$item['create_time']); | ||||||
|                     // 格式化时间
 |  | ||||||
|                     $item['create_time'] = date('Y-m-d H:i:s', $item['create_time']); |  | ||||||
| 
 |  | ||||||
|                     return $item; |                     return $item; | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|             return json([ |             return json([ | ||||||
|                 'code' => 0,  |                 'code' => 0, | ||||||
|                 'msg' => '获取成功',  |                 'msg' => '获取成功', | ||||||
|                 'count' => $count, |                 'count' => $count, | ||||||
|                 'data' => $lists |                 'data' => $lists | ||||||
|             ]); |             ]); | ||||||
|         } else { |         } else { | ||||||
|             // 获取所有分类并构建父子结构
 |             $allCategories = ResourceCategory::where('delete_time', null) | ||||||
|             $allCategories = Db::table('yz_resources_category') |  | ||||||
|                 ->where('delete_time', null) |  | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|  |                 ->field('id, name, cid, icon') | ||||||
|                 ->order('sort asc, id asc') |                 ->order('sort asc, id asc') | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->toArray(); |                 ->toArray(); | ||||||
| 
 |              | ||||||
|             $categories = []; |             $categories = $this->buildParentChild($allCategories); | ||||||
|             foreach ($allCategories as $category) { |  | ||||||
|                 if ($category['cid'] == 0) { |  | ||||||
|                     $category['children'] = []; |  | ||||||
|                     foreach ($allCategories as $subCategory) { |  | ||||||
|                         if ($subCategory['cid'] == $category['id']) { |  | ||||||
|                             $category['children'][] = $subCategory; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     $categories[] = $category; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             View::assign([ |             View::assign([ | ||||||
|                 'categories' => $categories |                 'categories' => $categories | ||||||
| @ -128,7 +111,7 @@ class Resources extends Base | |||||||
|                 'create_time' => time() |                 'create_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $insert = Db::table('yz_resources')->insert($data); |             $insert = Resource::insert($data); | ||||||
|             if (empty($insert)) { |             if (empty($insert)) { | ||||||
|                 Log::record('添加资源', 0, '添加资源失败', '资源管理'); |                 Log::record('添加资源', 0, '添加资源失败', '资源管理'); | ||||||
|                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); | ||||||
| @ -136,13 +119,10 @@ class Resources extends Base | |||||||
|             Log::record('添加资源', 1, '', '资源管理'); |             Log::record('添加资源', 1, '', '资源管理'); | ||||||
|             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             $lists = Db::table('yz_resources') |             $lists = Resource::where('delete_time', null) | ||||||
|                 ->order('id DESC') |                 ->where('status', '<>', 3) | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->each(function ($item, $key) { |                 ->toArray(); | ||||||
|                     $item['create_time'] = time(); |  | ||||||
|                     return $item; |  | ||||||
|                 }); |  | ||||||
|             View::assign([ |             View::assign([ | ||||||
|                 'lists' => $lists |                 'lists' => $lists | ||||||
|             ]); |             ]); | ||||||
| @ -154,10 +134,8 @@ class Resources extends Base | |||||||
|     public function delete() |     public function delete() | ||||||
|     { |     { | ||||||
|         $id = input('post.id'); |         $id = input('post.id'); | ||||||
|         $data = [ |         $delete = Resource::where('id', $id) | ||||||
|             'delete_time' => time(), |             ->update(['delete_time' => time()]); | ||||||
|         ]; |  | ||||||
|         $delete = Db::table('yz_resources')->where('id', $id)->update($data); |  | ||||||
|         if ($delete === false) { |         if ($delete === false) { | ||||||
|             Log::record('删除资源', 0, '删除资源失败', '资源管理'); |             Log::record('删除资源', 0, '删除资源失败', '资源管理'); | ||||||
|             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); |             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); | ||||||
| @ -170,76 +148,26 @@ class Resources extends Base | |||||||
|     public function cate() |     public function cate() | ||||||
|     { |     { | ||||||
|         if (Request::isPost()) { |         if (Request::isPost()) { | ||||||
|             $lists = Db::table('yz_resources_category') |             $lists = ResourceCategory::where('delete_time', null) | ||||||
|                 ->where('delete_time', null) |  | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->order('sort asc, id asc') |                 ->order('sort asc, id asc') | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->toArray(); |                 ->toArray(); | ||||||
| 
 |             $tree = $this->buildTree($lists); | ||||||
|             // 构建树形结构
 |  | ||||||
|             $tree = []; |  | ||||||
|             foreach ($lists as $item) { |  | ||||||
|                 if ($item['cid'] == 0) { |  | ||||||
|                     $node = [ |  | ||||||
|                         'id' => $item['id'], |  | ||||||
|                         'title' => $item['name'], |  | ||||||
|                         'children' => [] |  | ||||||
|                     ]; |  | ||||||
|                      |  | ||||||
|                     // 查找子分类
 |  | ||||||
|                     foreach ($lists as $subItem) { |  | ||||||
|                         if ($subItem['cid'] == $item['id']) { |  | ||||||
|                             $node['children'][] = [ |  | ||||||
|                                 'id' => $subItem['id'], |  | ||||||
|                                 'title' => $subItem['name'], |  | ||||||
|                                 'children' => [] |  | ||||||
|                             ]; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                      |  | ||||||
|                     $tree[] = $node; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]); |             return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]); | ||||||
|         } |         } | ||||||
|          |  | ||||||
|         // 非 POST 请求返回视图
 |  | ||||||
|         return View::fetch(); |         return View::fetch(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //获取分类结构
 |     //获取分类结构
 | ||||||
|     public function getcate() |     public function getcate() | ||||||
|     { |     { | ||||||
|         // 获取所有分类
 |         $lists = ResourceCategory::where('delete_time', null) | ||||||
|         $lists = Db::table('yz_resources_category') |  | ||||||
|             ->where('delete_time', null) |  | ||||||
|             ->where('status', 1) |             ->where('status', 1) | ||||||
|             ->order('sort asc, id asc') |             ->order('sort asc, id asc') | ||||||
|             ->select() |             ->select() | ||||||
|             ->toArray(); |             ->toArray(); | ||||||
| 
 |         $tree = $this->buildParentChild($lists); | ||||||
|         // 构建父子结构
 |  | ||||||
|         $tree = []; |  | ||||||
|         foreach ($lists as $item) { |  | ||||||
|             if ($item['cid'] == 0) { |  | ||||||
|                 // 顶级分类
 |  | ||||||
|                 $tree[] = $item; |  | ||||||
|             } else { |  | ||||||
|                 // 子分类
 |  | ||||||
|                 foreach ($tree as &$parent) { |  | ||||||
|                     if ($parent['id'] == $item['cid']) { |  | ||||||
|                         if (!isset($parent['children'])) { |  | ||||||
|                             $parent['children'] = []; |  | ||||||
|                         } |  | ||||||
|                         $parent['children'][] = $item; |  | ||||||
|                         break; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]); |         return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -256,7 +184,7 @@ class Resources extends Base | |||||||
|                 'create_time' => time() |                 'create_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $insert = Db::table('yz_resources_category')->insert($data); |             $insert = ResourceCategory::insert($data); | ||||||
|             if (empty($insert)) { |             if (empty($insert)) { | ||||||
|                 Log::record('添加资源分类', 0, '添加资源分类失败', '资源分类'); |                 Log::record('添加资源分类', 0, '添加资源分类失败', '资源分类'); | ||||||
|                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '添加失败', 'data' => []]); | ||||||
| @ -264,15 +192,12 @@ class Resources extends Base | |||||||
|             Log::record('添加资源分类', 1, '', '资源分类'); |             Log::record('添加资源分类', 1, '', '资源分类'); | ||||||
|             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '添加成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             // 获取所有可选的父级分类
 |             $parentCategories = ResourceCategory::where('delete_time', null) | ||||||
|             $parentCategories = Db::table('yz_resources_category') |  | ||||||
|                 ->where('delete_time', null) |  | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->where('cid', 0) |                 ->where('cid', 0) | ||||||
|                 ->field('id, name') |                 ->field('id, name') | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->toArray(); |                 ->toArray(); | ||||||
| 
 |  | ||||||
|             return json([ |             return json([ | ||||||
|                 'code' => 0, |                 'code' => 0, | ||||||
|                 'msg' => '获取成功', |                 'msg' => '获取成功', | ||||||
| @ -297,10 +222,8 @@ class Resources extends Base | |||||||
|                 'update_time' => time() |                 'update_time' => time() | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $update = Db::table('yz_resources_category') |             $update = ResourceCategory::where('id', $data['id']) | ||||||
|                 ->where('id', $data['id']) |  | ||||||
|                 ->update($data); |                 ->update($data); | ||||||
| 
 |  | ||||||
|             if ($update === false) { |             if ($update === false) { | ||||||
|                 Log::record('编辑资源分类', 0, '更新资源分类失败', '资源分类'); |                 Log::record('编辑资源分类', 0, '更新资源分类失败', '资源分类'); | ||||||
|                 return json(['code' => 1, 'msg' => '更新失败', 'data' => []]); |                 return json(['code' => 1, 'msg' => '更新失败', 'data' => []]); | ||||||
| @ -309,38 +232,21 @@ class Resources extends Base | |||||||
|             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); |             return json(['code' => 0, 'msg' => '更新成功', 'data' => []]); | ||||||
|         } else { |         } else { | ||||||
|             $id = input('get.id'); |             $id = input('get.id'); | ||||||
|             $info = Db::table('yz_resources_category')->where('id', $id)->find(); |             $info = ResourceCategory::where('id', $id)->find(); | ||||||
|              |             $parentCategories = ResourceCategory::where('delete_time', null) | ||||||
|             // 获取所有可选的父级分类
 |  | ||||||
|             $parentCategories = Db::table('yz_resources_category') |  | ||||||
|                 ->where('delete_time', null) |  | ||||||
|                 ->where('status', 1) |                 ->where('status', 1) | ||||||
|                 ->where('id', '<>', $id) // 排除自己
 |                 ->where('cid', 0) | ||||||
|                 ->where(function ($query) use ($id) { |                 ->where('id', '<>', $id) | ||||||
|                     // 排除自己的所有子分类
 |                 ->field('id, name') | ||||||
|                     $query->where('cid', '<>', $id); |  | ||||||
|                 }) |  | ||||||
|                 ->field('id, name, cid') |  | ||||||
|                 ->select() |                 ->select() | ||||||
|                 ->toArray(); |                 ->toArray(); | ||||||
| 
 | 
 | ||||||
|             // 构建父级分类选项
 |  | ||||||
|             $parentOptions = []; |  | ||||||
|             foreach ($parentCategories as $category) { |  | ||||||
|                 if ($category['cid'] == 0) { |  | ||||||
|                     $parentOptions[] = [ |  | ||||||
|                         'id' => $category['id'], |  | ||||||
|                         'name' => $category['name'] |  | ||||||
|                     ]; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return json([ |             return json([ | ||||||
|                 'code' => 0, |                 'code' => 0, | ||||||
|                 'msg' => '获取成功', |                 'msg' => '获取成功', | ||||||
|                 'data' => [ |                 'data' => [ | ||||||
|                     'info' => $info, |                     'info' => $info, | ||||||
|                     'parentOptions' => $parentOptions |                     'parentOptions' => $parentCategories | ||||||
|                 ] |                 ] | ||||||
|             ]); |             ]); | ||||||
|         } |         } | ||||||
| @ -352,20 +258,16 @@ class Resources extends Base | |||||||
|         $id = input('post.id'); |         $id = input('post.id'); | ||||||
| 
 | 
 | ||||||
|         // 检查是否有子分类
 |         // 检查是否有子分类
 | ||||||
|         $hasChildren = Db::table('yz_resources_category') |         $hasChildren = ResourceCategory::where('cid', $id) | ||||||
|             ->where('cid', $id) |  | ||||||
|             ->where('delete_time', null) |             ->where('delete_time', null) | ||||||
|             ->find(); |             ->find(); | ||||||
| 
 |  | ||||||
|         if ($hasChildren) { |         if ($hasChildren) { | ||||||
|             Log::record('删除资源分类', 0, '该分类下有子分类,无法删除', '资源分类'); |             Log::record('删除资源分类', 0, '该分类下有子分类,无法删除', '资源分类'); | ||||||
|             return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]); |             return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $delete = Db::table('yz_resources_category') |         $delete = ResourceCategory::where('id', $id) | ||||||
|             ->where('id', $id) |  | ||||||
|             ->update(['delete_time' => time()]); |             ->update(['delete_time' => time()]); | ||||||
| 
 |  | ||||||
|         if ($delete === false) { |         if ($delete === false) { | ||||||
|             Log::record('删除资源分类', 0, '删除资源分类失败', '资源分类'); |             Log::record('删除资源分类', 0, '删除资源分类失败', '资源分类'); | ||||||
|             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); |             return json(['code' => 1, 'msg' => '删除失败', 'data' => []]); | ||||||
| @ -385,8 +287,7 @@ class Resources extends Base | |||||||
|             return json(['code' => 1, 'msg' => '参数错误']); |             return json(['code' => 1, 'msg' => '参数错误']); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $resource = Db::table('yz_resources') |         $resource = Resource::where('id', $id) | ||||||
|             ->where('id', $id) |  | ||||||
|             ->where('delete_time', null) |             ->where('delete_time', null) | ||||||
|             ->find(); |             ->find(); | ||||||
|              |              | ||||||
| @ -396,8 +297,7 @@ class Resources extends Base | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // 获取分类信息
 |         // 获取分类信息
 | ||||||
|         $cateInfo = Db::table('yz_resources_category') |         $cateInfo = ResourceCategory::where('id', $resource['cate']) | ||||||
|             ->where('id', $resource['cate']) |  | ||||||
|             ->field('name') |             ->field('name') | ||||||
|             ->find(); |             ->find(); | ||||||
| 
 | 
 | ||||||
| @ -417,14 +317,13 @@ class Resources extends Base | |||||||
|         if (Request::isPost()) { |         if (Request::isPost()) { | ||||||
|             $data = input('post.'); |             $data = input('post.'); | ||||||
|             $id = input('id/d', 0); |             $id = input('id/d', 0); | ||||||
|              | 
 | ||||||
|             if (!$id) { |             if (!$id) { | ||||||
|                 Log::record('编辑资源', 0, '参数错误', '资源管理'); |                 Log::record('编辑资源', 0, '参数错误', '资源管理'); | ||||||
|                 return json(['code' => 1, 'msg' => '参数错误']); |                 return json(['code' => 1, 'msg' => '参数错误']); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 更新数据
 |             $updateData = [ | ||||||
|             $result = Db::table('yz_resources')->where('id', $id)->update([ |  | ||||||
|                 'title' => $data['title'], |                 'title' => $data['title'], | ||||||
|                 'cate' => $data['cate'], |                 'cate' => $data['cate'], | ||||||
|                 'desc' => $data['desc'], |                 'desc' => $data['desc'], | ||||||
| @ -435,7 +334,10 @@ class Resources extends Base | |||||||
|                 'code' => $data['code'], |                 'code' => $data['code'], | ||||||
|                 'sort' => $data['sort'], |                 'sort' => $data['sort'], | ||||||
|                 'update_time' => time() |                 'update_time' => time() | ||||||
|             ]); |             ]; | ||||||
|  | 
 | ||||||
|  |             $result = Resource::where('id', $id) | ||||||
|  |                 ->update($updateData); | ||||||
| 
 | 
 | ||||||
|             if ($result !== false) { |             if ($result !== false) { | ||||||
|                 Log::record('编辑资源', 1, '', '资源管理'); |                 Log::record('编辑资源', 1, '', '资源管理'); | ||||||
| @ -452,7 +354,10 @@ class Resources extends Base | |||||||
|             $this->error('参数错误'); |             $this->error('参数错误'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $resource = Db::table('yz_resources')->where('id', $id)->find(); |         $resource = Resource::where('id', $id) | ||||||
|  |             ->where('delete_time', null) | ||||||
|  |             ->find(); | ||||||
|  |              | ||||||
|         if (!$resource) { |         if (!$resource) { | ||||||
|             Log::record('编辑资源', 0, '资源不存在', '资源管理'); |             Log::record('编辑资源', 0, '资源不存在', '资源管理'); | ||||||
|             $this->error('资源不存在'); |             $this->error('资源不存在'); | ||||||
| @ -463,12 +368,11 @@ class Resources extends Base | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     //统计资源数量
 |     //统计资源数量
 | ||||||
|     public function counts()  { |     public function counts() | ||||||
|         $total = Db::table('yz_resources') |     { | ||||||
|             ->where('delete_time', null) |         $total = Resource::where('delete_time', null) | ||||||
|             ->where('status', '<>', 3) |             ->where('status', '<>', 3) | ||||||
|             ->count(); |             ->count(); | ||||||
|              |  | ||||||
|         return json([ |         return json([ | ||||||
|             'code' => 0, |             'code' => 0, | ||||||
|             'msg' => '获取成功', |             'msg' => '获取成功', | ||||||
| @ -478,4 +382,56 @@ class Resources extends Base | |||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // 构建树形结构
 | ||||||
|  |     private function buildTree($lists) | ||||||
|  |     { | ||||||
|  |         $tree = []; | ||||||
|  |         foreach ($lists as $item) { | ||||||
|  |             if ($item['cid'] == 0) { | ||||||
|  |                 $node = [ | ||||||
|  |                     'id' => $item['id'], | ||||||
|  |                     'title' => $item['name'], | ||||||
|  |                     'children' => [] | ||||||
|  |                 ]; | ||||||
|  |                  | ||||||
|  |                 // 查找子分类
 | ||||||
|  |                 foreach ($lists as $subItem) { | ||||||
|  |                     if ($subItem['cid'] == $item['id']) { | ||||||
|  |                         $node['children'][] = [ | ||||||
|  |                             'id' => $subItem['id'], | ||||||
|  |                             'title' => $subItem['name'], | ||||||
|  |                             'children' => [] | ||||||
|  |                         ]; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 $tree[] = $node; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $tree; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 构建父子结构
 | ||||||
|  |     private function buildParentChild($lists) | ||||||
|  |     { | ||||||
|  |         $tree = []; | ||||||
|  |         foreach ($lists as $item) { | ||||||
|  |             if ($item['cid'] == 0) { | ||||||
|  |                 // 顶级分类
 | ||||||
|  |                 $tree[] = $item; | ||||||
|  |             } else { | ||||||
|  |                 // 子分类
 | ||||||
|  |                 foreach ($tree as &$parent) { | ||||||
|  |                     if ($parent['id'] == $item['cid']) { | ||||||
|  |                         if (!isset($parent['children'])) { | ||||||
|  |                             $parent['children'] = []; | ||||||
|  |                         } | ||||||
|  |                         $parent['children'][] = $item; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $tree; | ||||||
|  |     } | ||||||
| } | } | ||||||
							
								
								
									
										13
									
								
								app/admin/model/Article/Article.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/admin/model/Article/Article.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | namespace app\admin\model\Article; | ||||||
|  | 
 | ||||||
|  | use think\Model; | ||||||
|  | 
 | ||||||
|  | class Article extends Model | ||||||
|  | { | ||||||
|  |     // 设置当前模型对应的数据表名称(不含前缀)
 | ||||||
|  |     protected $name = 'article'; | ||||||
|  |      | ||||||
|  |     // 设置主键
 | ||||||
|  |     protected $pk = 'id'; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								app/admin/model/Article/ArticleCategory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/admin/model/Article/ArticleCategory.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | namespace app\admin\model\Article; | ||||||
|  | 
 | ||||||
|  | use think\Model; | ||||||
|  | 
 | ||||||
|  | class ArticleCategory extends Model | ||||||
|  | { | ||||||
|  |     // 设置当前模型对应的数据表名称(不含前缀)
 | ||||||
|  |     protected $name = 'article_category'; | ||||||
|  |      | ||||||
|  |     // 设置主键
 | ||||||
|  |     protected $pk = 'id'; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								app/admin/model/Resource/Resource.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/admin/model/Resource/Resource.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | namespace app\admin\model\Resource; | ||||||
|  | 
 | ||||||
|  | use think\Model; | ||||||
|  | 
 | ||||||
|  | class Resource extends Model | ||||||
|  | { | ||||||
|  |     // 设置当前模型对应的数据表名称(不含前缀)
 | ||||||
|  |     protected $name = 'resources'; | ||||||
|  |      | ||||||
|  |     // 设置主键
 | ||||||
|  |     protected $pk = 'id'; | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								app/admin/model/Resource/ResourceCategory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/admin/model/Resource/ResourceCategory.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | namespace app\admin\model\Resource; | ||||||
|  | 
 | ||||||
|  | use think\Model; | ||||||
|  | 
 | ||||||
|  | class ResourceCategory extends Model | ||||||
|  | { | ||||||
|  |     // 设置当前模型对应的数据表名称(不含前缀)
 | ||||||
|  |     protected $name = 'resources_category'; | ||||||
|  |      | ||||||
|  |     // 设置主键
 | ||||||
|  |     protected $pk = 'id'; | ||||||
|  | } | ||||||
| @ -3,10 +3,17 @@ | |||||||
| * 配置表 | * 配置表 | ||||||
| */ | */ | ||||||
| namespace app\admin\model; | namespace app\admin\model; | ||||||
| use app\admin\model\Base; |  | ||||||
| 
 | 
 | ||||||
| class YzAdminConfig extends Base{ | use think\Model; | ||||||
|  | 
 | ||||||
|  | class YzAdminConfig extends Model | ||||||
|  | { | ||||||
|  | 	// 设置当前模型对应的数据表名称(不含前缀)
 | ||||||
|  | 	protected $name = 'admin_config'; | ||||||
|  | 	 | ||||||
|  | 	// 设置主键
 | ||||||
| 	protected $pk = 'config_id'; | 	protected $pk = 'config_id'; | ||||||
|  | 
 | ||||||
| 	/** | 	/** | ||||||
| 	* 列出全部配置,key对应value | 	* 列出全部配置,key对应value | ||||||
| 	*/ | 	*/ | ||||||
| @ -22,6 +29,7 @@ class YzAdminConfig extends Base{ | |||||||
| 		} | 		} | ||||||
| 		return $return; | 		return $return; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	/** | 	/** | ||||||
| 	* 多条数据更新 | 	* 多条数据更新 | ||||||
| 	*/ | 	*/ | ||||||
|  | |||||||
| @ -322,7 +322,7 @@ | |||||||
|                 // 初始化分类列表
 |                 // 初始化分类列表
 | ||||||
|                 that.initCategoryList = function () { |                 that.initCategoryList = function () { | ||||||
|                     $.ajax({ |                     $.ajax({ | ||||||
|                         url: '/admin/article/articlecate', |                         url: '/admin/articles/articlecate', | ||||||
|                         type: 'POST', |                         type: 'POST', | ||||||
|                         success: function (res) { |                         success: function (res) { | ||||||
|                             if (res.code === 0) { |                             if (res.code === 0) { | ||||||
| @ -387,7 +387,7 @@ | |||||||
| 
 | 
 | ||||||
|                 // 加载分类信息
 |                 // 加载分类信息
 | ||||||
|                 that.loadCategoryInfo = function (id) { |                 that.loadCategoryInfo = function (id) { | ||||||
|                     $.get('/admin/article/cateedit?id=' + id, function (res) { |                     $.get('/admin/articles/cateedit?id=' + id, function (res) { | ||||||
|                         if (res.code === 0) { |                         if (res.code === 0) { | ||||||
|                             that.showCategoryForm(0, res.data); |                             that.showCategoryForm(0, res.data); | ||||||
|                         } |                         } | ||||||
| @ -413,7 +413,7 @@ | |||||||
|                     $select.empty().append('<option value="0">顶级分类</option>'); |                     $select.empty().append('<option value="0">顶级分类</option>'); | ||||||
|                     // 获取所有分类作为父级选项
 |                     // 获取所有分类作为父级选项
 | ||||||
|                     $.ajax({ |                     $.ajax({ | ||||||
|                         url: '/admin/article/articlecate', |                         url: '/admin/articles/articlecate', | ||||||
|                         type: 'POST', |                         type: 'POST', | ||||||
|                         async: false, |                         async: false, | ||||||
|                         success: function (res) { |                         success: function (res) { | ||||||
| @ -472,7 +472,7 @@ | |||||||
| 
 | 
 | ||||||
|                 // 监听表单提交
 |                 // 监听表单提交
 | ||||||
|                 form.on('submit(saveCategory)', function (data) { |                 form.on('submit(saveCategory)', function (data) { | ||||||
|                     var url = data.field.id ? '/admin/article/cateedit' : '/admin/article/cateadd'; |                     var url = data.field.id ? '/admin/articles/cateedit' : '/admin/articles/cateadd'; | ||||||
|                     $.post(url, data.field, function (res) { |                     $.post(url, data.field, function (res) { | ||||||
|                         if (res.code === 0) { |                         if (res.code === 0) { | ||||||
|                             layer.msg(res.msg, { icon: 1 }); |                             layer.msg(res.msg, { icon: 1 }); | ||||||
| @ -490,7 +490,7 @@ | |||||||
|                     if (!id) return; |                     if (!id) return; | ||||||
| 
 | 
 | ||||||
|                     layer.confirm('确定要删除该分类吗?', function (index) { |                     layer.confirm('确定要删除该分类吗?', function (index) { | ||||||
|                         $.post('/admin/article/catedel', { id: id }, function (res) { |                         $.post('/admin/articles/catedel', { id: id }, function (res) { | ||||||
|                             if (res.code === 0) { |                             if (res.code === 0) { | ||||||
|                                 layer.msg(res.msg, { icon: 1 }); |                                 layer.msg(res.msg, { icon: 1 }); | ||||||
|                                 that.initCategoryList(); |                                 that.initCategoryList(); | ||||||
|  | |||||||
| @ -87,7 +87,7 @@ | |||||||
|         // 初始化表格
 |         // 初始化表格
 | ||||||
|         table.render({ |         table.render({ | ||||||
|             elem: '#articleTable', |             elem: '#articleTable', | ||||||
|             url: '/admin/article/articlelist', |             url: '/admin/articles/articlelist', | ||||||
|             method: 'post', |             method: 'post', | ||||||
|             cols: [[ |             cols: [[ | ||||||
|                 { field: 'id', title: 'ID', align: 'center', width: 80 }, |                 { field: 'id', title: 'ID', align: 'center', width: 80 }, | ||||||
| @ -174,18 +174,18 @@ | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function add() { |     function add() { | ||||||
|         window.location.href = '/admin/article/add'; |         window.location.href = '/admin/articles/add'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function edit(id) { |     function edit(id) { | ||||||
|         window.location.href = '/admin/article/edit?id=' + id; |         window.location.href = '/admin/articles/edit?id=' + id; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function del(id) { |     function del(id) { | ||||||
|         layer.confirm('确定要删除该文章吗?', { |         layer.confirm('确定要删除该文章吗?', { | ||||||
|             btn: ['确定', '取消'] |             btn: ['确定', '取消'] | ||||||
|         }, function () { |         }, function () { | ||||||
|             $.post('/admin/article/delete', { id: id }, function (res) { |             $.post('/admin/articles/delete', { id: id }, function (res) { | ||||||
|                 if (res.code == 0) { |                 if (res.code == 0) { | ||||||
|                     layer.msg(res.msg, { icon: 1 }); |                     layer.msg(res.msg, { icon: 1 }); | ||||||
|                     setTimeout(function () { |                     setTimeout(function () { | ||||||
|  | |||||||
| @ -57,13 +57,13 @@ | |||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <script type="text/html" id="statusTemplate"> | <script type="text/html" id="statusTemplate"> | ||||||
|     {{#  if(d.status === 0){ }}
 |     {{#  if(d.status == '0'){ }}
 | ||||||
|     <span style="color:red;">未审核</span> |     <span style="color:red;">未审核</span> | ||||||
|     {{#  } else if(d.status === 1){ }}
 |     {{#  } else if(d.status == '1'){ }}
 | ||||||
|     <span style="color:orange;">待审核</span> |     <span style="color:orange;">待审核</span> | ||||||
|     {{#  } else if(d.status === 2){ }}
 |     {{#  } else if(d.status == '2'){ }}
 | ||||||
|     <span style="color:green;">已发布</span> |     <span style="color:green;">已发布</span> | ||||||
|     {{#  } else if(d.status === 3){ }}
 |     {{#  } else if(d.status == '3'){ }}
 | ||||||
|     <span style="color:gray;">已下架</span> |     <span style="color:gray;">已下架</span> | ||||||
|     {{#  } }}
 |     {{#  } }}
 | ||||||
| </script> | </script> | ||||||
| @ -157,7 +157,13 @@ | |||||||
| 
 | 
 | ||||||
|     function reloadTable() { |     function reloadTable() { | ||||||
|         var categoryId = $('#categoryFilter').val(); |         var categoryId = $('#categoryFilter').val(); | ||||||
|         var categoryName = categoryId ? $('#categoryFilter option[value="' + categoryId + '"]').text() : ''; |         var categoryName = ''; | ||||||
|  |         if (categoryId) { | ||||||
|  |             var selectedOption = $('#categoryFilter option[value="' + categoryId + '"]'); | ||||||
|  |             if (selectedOption.length > 0) { | ||||||
|  |                 categoryName = selectedOption.text().trim(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         var nameKeyword = $('#nameSearch').val().trim(); |         var nameKeyword = $('#nameSearch').val().trim(); | ||||||
|         var uploaderKeyword = $('#uploaderSearch').val().trim(); |         var uploaderKeyword = $('#uploaderSearch').val().trim(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -192,13 +192,14 @@ | |||||||
| 
 | 
 | ||||||
|     .prev-article a, |     .prev-article a, | ||||||
|     .next-article a { |     .next-article a { | ||||||
|         color: #333;
 |         color: #333 !important;
 | ||||||
|         text-decoration: none; |         text-decoration: none; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .prev-article a:hover, |     .prev-article a:hover, | ||||||
|     .next-article a:hover { |     .next-article a:hover { | ||||||
|         color: #f57005;
 |         color: #f57005 !important;
 | ||||||
|  |         transition: all 0.3s ease; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .disabled { |     .disabled { | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ return [ | |||||||
|             // 数据库编码默认采用utf8
 |             // 数据库编码默认采用utf8
 | ||||||
|             'charset'         => env('database.charset', 'utf8'), |             'charset'         => env('database.charset', 'utf8'), | ||||||
|             // 数据库表前缀
 |             // 数据库表前缀
 | ||||||
|             'prefix'          => env('database.prefix', ''), |             'prefix'          => env('database.prefix', 'yz_'), | ||||||
| 
 | 
 | ||||||
|             // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
 |             // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
 | ||||||
|             'deploy'          => 0, |             'deploy'          => 0, | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:3:{s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\index\welcome.php";i:1746709977;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\tail.php";i:1746709977;}*/ ?>
 | <?php /*a:3:{s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\index\welcome.php";i:1747615358;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\tail.php";i:1746709977;}*/ ?>
 | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 	<head> | 	<head> | ||||||
| @ -93,80 +93,207 @@ | |||||||
| 		</script> | 		</script> | ||||||
| 	</head> | 	</head> | ||||||
| 	<body style="padding:10px; box-sizing: border-box;"> | 	<body style="padding:10px; box-sizing: border-box;"> | ||||||
|  | <script src="/static/js/jquery.min.js"></script> | ||||||
| <style> | <style> | ||||||
|     .dashboard-container { |     .dashboard-container { | ||||||
|         padding: 20px; |         padding: 24px; | ||||||
|         font-family: 'Helvetica Neue', Arial, sans-serif; |         font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; | ||||||
|  |         /* background-color: #f5f7fa; */ | ||||||
|  |         /* min-height: calc(100vh - 60px); */ | ||||||
|     } |     } | ||||||
|     .welcome-header { |     .welcome-header { | ||||||
|         text-align: center; |         background: linear-gradient(135deg, #3881fd 0%, #2c5fd9 100%);
 | ||||||
|         margin-bottom: 30px; |         border-radius: 12px; | ||||||
|  |         padding: 30px; | ||||||
|  |         color: white; | ||||||
|  |         margin-bottom: 24px; | ||||||
|  |         box-shadow: 0 4px 20px rgba(56, 129, 253, 0.15); | ||||||
|     } |     } | ||||||
|     .welcome-header h1 { |     .welcome-header h1 { | ||||||
|         color: #3881fd;
 |  | ||||||
|         font-weight: 300; |  | ||||||
|         font-size: 28px; |         font-size: 28px; | ||||||
|         margin-bottom: 10px; |         font-weight: 600; | ||||||
|  |         margin-bottom: 8px; | ||||||
|  |     } | ||||||
|  |     .welcome-header p { | ||||||
|  |         font-size: 15px; | ||||||
|  |         opacity: 0.9; | ||||||
|  |         margin: 0; | ||||||
|     } |     } | ||||||
|     .stats-container { |     .stats-container { | ||||||
|         display: flex; |         display: grid; | ||||||
|         flex-wrap: wrap; |         grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); | ||||||
|         gap: 20px; |         gap: 24px; | ||||||
|         justify-content: center; |         margin-bottom: 24px; | ||||||
|         margin-bottom: 30px; |  | ||||||
|     } |     } | ||||||
|     .stat-card { |     .stat-card { | ||||||
|         background-color: #fff;
 |         background: white; | ||||||
|         border-radius: 8px; |         border-radius: 12px; | ||||||
|         box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); |         padding: 24px; | ||||||
|         padding: 20px; |         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04); | ||||||
|         min-width: 200px; |  | ||||||
|         flex: 1; |  | ||||||
|         transition: all 0.3s ease; |         transition: all 0.3s ease; | ||||||
|  |         position: relative; | ||||||
|  |         overflow: hidden; | ||||||
|  |     } | ||||||
|  |     .stat-card::before { | ||||||
|  |         content: ''; | ||||||
|  |         position: absolute; | ||||||
|  |         top: 0; | ||||||
|  |         left: 0; | ||||||
|  |         width: 4px; | ||||||
|  |         height: 100%; | ||||||
|  |         background: #3881fd;
 | ||||||
|     } |     } | ||||||
|     .stat-card:hover { |     .stat-card:hover { | ||||||
|         transform: translateY(-5px); |         transform: translateY(-5px); | ||||||
|         box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); |         box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); | ||||||
|     } |     } | ||||||
|     .stat-card .stat-value { |     .stat-card .stat-value { | ||||||
|         font-size: 24px; |         font-size: 32px; | ||||||
|         font-weight: bold; |         font-weight: 600; | ||||||
|         color: #3881fd;
 |         color: #2c3e50;
 | ||||||
|         margin: 10px 0; |         margin: 12px 0; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: baseline; | ||||||
|     } |     } | ||||||
|     .stat-card .stat-title { |     .stat-card .stat-title { | ||||||
|         color: #7f8c8d;
 |         color: #64748b;
 | ||||||
|         font-size: 14px; |         font-size: 14px; | ||||||
|  |         font-weight: 500; | ||||||
|  |         text-transform: uppercase; | ||||||
|  |         letter-spacing: 0.5px; | ||||||
|  |     } | ||||||
|  |     .stat-card .stat-icon { | ||||||
|  |         position: absolute; | ||||||
|  |         right: 20px; | ||||||
|  |         top: 50%; | ||||||
|  |         transform: translateY(-50%); | ||||||
|  |         font-size: 48px; | ||||||
|  |         opacity: 0.1; | ||||||
|     } |     } | ||||||
|     .quick-actions { |     .quick-actions { | ||||||
|         background-color: #fff;
 |         background: white; | ||||||
|         border-radius: 8px; |         border-radius: 12px; | ||||||
|         box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); |         padding: 24px; | ||||||
|         padding: 20px; |         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04); | ||||||
|         margin-bottom: 20px; |  | ||||||
|     } |     } | ||||||
|     .quick-actions h2 { |     .quick-actions h2 { | ||||||
|         color: #2c3e50;
 |         color: #1e293b;
 | ||||||
|         font-size: 18px; |         font-size: 18px; | ||||||
|         margin-bottom: 15px; |         font-weight: 600; | ||||||
|         font-weight: 500; |         margin-bottom: 20px; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  |     .quick-actions h2::before { | ||||||
|  |         content: ''; | ||||||
|  |         display: inline-block; | ||||||
|  |         width: 4px; | ||||||
|  |         height: 18px; | ||||||
|  |         background: #3881fd;
 | ||||||
|  |         margin-right: 8px; | ||||||
|  |         border-radius: 2px; | ||||||
|     } |     } | ||||||
|     .action-buttons { |     .action-buttons { | ||||||
|         display: flex; |         display: grid; | ||||||
|         flex-wrap: wrap; |         grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); | ||||||
|         gap: 10px; |         gap: 16px; | ||||||
|     } |     } | ||||||
|     .action-button { |     .action-button { | ||||||
|         background-color: #f8f9fa;
 |         background: #f8fafc;
 | ||||||
|         border: none; |         border: 1px solid #e2e8f0;
 | ||||||
|         border-radius: 4px; |         border-radius: 8px; | ||||||
|         padding: 10px 15px; |         padding: 12px 16px; | ||||||
|         color: #3881fd;
 |         color: #1e293b;
 | ||||||
|  |         font-weight: 500; | ||||||
|         cursor: pointer; |         cursor: pointer; | ||||||
|         transition: background-color 0.3s; |         transition: all 0.2s ease; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         text-decoration: none; | ||||||
|     } |     } | ||||||
|     .action-button:hover { |     .action-button:hover { | ||||||
|         background-color: #e9ecef;
 |         background: #3881fd;
 | ||||||
|  |         color: white; | ||||||
|  |         border-color: #3881fd;
 | ||||||
|  |         transform: translateY(-2px); | ||||||
|  |     } | ||||||
|  |     .action-button i { | ||||||
|  |         margin-right: 8px; | ||||||
|  |     } | ||||||
|  |     .recent-activity { | ||||||
|  |         margin-top: 24px; | ||||||
|  |         background: white; | ||||||
|  |         border-radius: 12px; | ||||||
|  |         padding: 24px; | ||||||
|  |         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04); | ||||||
|  |     } | ||||||
|  |     .activity-list { | ||||||
|  |         margin-top: 16px; | ||||||
|  |     } | ||||||
|  |     .activity-item { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         padding: 12px 0; | ||||||
|  |         border-bottom: 1px solid #f1f5f9;
 | ||||||
|  |     } | ||||||
|  |     .activity-item:last-child { | ||||||
|  |         border-bottom: none; | ||||||
|  |     } | ||||||
|  |     .activity-icon { | ||||||
|  |         width: 36px; | ||||||
|  |         height: 36px; | ||||||
|  |         border-radius: 8px; | ||||||
|  |         background: #f1f5f9;
 | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         margin-right: 12px; | ||||||
|  |     } | ||||||
|  |     .activity-content { | ||||||
|  |         flex: 1; | ||||||
|  |     } | ||||||
|  |     .activity-title { | ||||||
|  |         font-weight: 500; | ||||||
|  |         color: #1e293b;
 | ||||||
|  |         margin-bottom: 4px; | ||||||
|  |     } | ||||||
|  |     .activity-time { | ||||||
|  |         font-size: 12px; | ||||||
|  |         color: #64748b;
 | ||||||
|  |     } | ||||||
|  |     .charts-container { | ||||||
|  |         display: grid; | ||||||
|  |         grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); | ||||||
|  |         gap: 24px; | ||||||
|  |         margin-top: 24px; | ||||||
|  |     } | ||||||
|  |     .chart-card { | ||||||
|  |         background: white; | ||||||
|  |         border-radius: 12px; | ||||||
|  |         padding: 24px; | ||||||
|  |         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04); | ||||||
|  |     } | ||||||
|  |     .chart-card h2 { | ||||||
|  |         color: #1e293b;
 | ||||||
|  |         font-size: 18px; | ||||||
|  |         font-weight: 600; | ||||||
|  |         margin-bottom: 20px; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |     } | ||||||
|  |     .chart-card h2::before { | ||||||
|  |         content: ''; | ||||||
|  |         display: inline-block; | ||||||
|  |         width: 4px; | ||||||
|  |         height: 18px; | ||||||
|  |         background: #3881fd;
 | ||||||
|  |         margin-right: 8px; | ||||||
|  |         border-radius: 2px; | ||||||
|  |     } | ||||||
|  |     .chart-container { | ||||||
|  |         height: 300px; | ||||||
|  |         width: 100%; | ||||||
|     } |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| @ -179,34 +306,84 @@ | |||||||
|     <div class="stats-container"> |     <div class="stats-container"> | ||||||
|         <div class="stat-card"> |         <div class="stat-card"> | ||||||
|             <div class="stat-title">用户总数</div> |             <div class="stat-title">用户总数</div> | ||||||
|             <div class="stat-value">1,234</div> |             <div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_users'])); ?></div>
 | ||||||
|  |             <div class="stat-icon">👥</div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="stat-card"> |         <div class="stat-card"> | ||||||
|             <div class="stat-title">今日访问</div> |             <div class="stat-title">今日访问</div> | ||||||
|             <div class="stat-value">256</div> |             <div class="stat-value"><?php echo htmlentities((string) number_format($stats['daily_visits'])); ?></div>
 | ||||||
|  |             <div class="stat-icon">📊</div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="stat-card"> |         <div class="stat-card"> | ||||||
|             <div class="stat-title">数据总量</div> |             <div class="stat-title">文章总数</div> | ||||||
|             <div class="stat-value">8,642</div> |             <div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_articles'])); ?></div>
 | ||||||
|  |             <div class="stat-icon">📝</div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="stat-card"> |         <div class="stat-card"> | ||||||
|             <div class="stat-title">系统消息</div> |             <div class="stat-title">资源总数</div> | ||||||
|             <div class="stat-value">12</div> |             <div class="stat-value"><?php echo htmlentities((string) number_format($stats['total_resources'])); ?></div>
 | ||||||
|  |             <div class="stat-icon">📦</div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|      |      | ||||||
|     <div class="quick-actions"> |     <div class="quick-actions"> | ||||||
|         <h2>快捷操作</h2> |         <h2>快捷操作</h2> | ||||||
|         <div class="action-buttons"> |         <div class="action-buttons"> | ||||||
|             <button class="action-button">用户管理</button> |             <a href="<?php echo url('user/index'); ?>" class="action-button"> | ||||||
|             <button class="action-button">内容发布</button> |                 <i class="fas fa-users"></i>用户管理 | ||||||
|             <button class="action-button">数据统计</button> |             </a> | ||||||
|             <button class="action-button">系统设置</button> |             <a href="<?php echo url('content/publish'); ?>" class="action-button"> | ||||||
|             <button class="action-button">清除缓存</button> |                 <i class="fas fa-edit"></i>内容发布 | ||||||
|  |             </a> | ||||||
|  |             <a href="<?php echo url('statistics/index'); ?>" class="action-button"> | ||||||
|  |                 <i class="fas fa-chart-bar"></i>数据统计 | ||||||
|  |             </a> | ||||||
|  |             <a href="<?php echo url('system/settings'); ?>" class="action-button"> | ||||||
|  |                 <i class="fas fa-cog"></i>系统设置 | ||||||
|  |             </a> | ||||||
|  |             <a href="<?php echo url('system/clear_cache'); ?>" class="action-button"> | ||||||
|  |                 <i class="fas fa-broom"></i>清除缓存 | ||||||
|  |             </a> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  | 
 | ||||||
|  |     <div class="recent-activity"> | ||||||
|  |         <h2>最近动态</h2> | ||||||
|  |         <div class="activity-list"> | ||||||
|  |             <?php if(is_array($recentActivities) || $recentActivities instanceof \think\Collection || $recentActivities instanceof \think\Paginator): $i = 0; $__LIST__ = $recentActivities;if( count($__LIST__)==0 ) : echo "" ;else: foreach($__LIST__ as $key=>$activity): $mod = ($i % 2 );++$i;?>
 | ||||||
|  |             <div class="activity-item"> | ||||||
|  |                 <div class="activity-icon"><?php echo htmlentities((string) $activity['icon']); ?></div>
 | ||||||
|  |                 <div class="activity-content"> | ||||||
|  |                     <div class="activity-title"><?php echo htmlentities((string) $activity['title']); ?></div>
 | ||||||
|  |                     <div class="activity-time"><?php echo htmlentities((string) $activity['time']); ?></div>
 | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |             <?php endforeach; endif; else: echo "" ;endif; ?>
 | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="charts-container"> | ||||||
|  |     <div class="chart-card"> | ||||||
|  |         <h2>访问趋势</h2> | ||||||
|  |         <div id="visitTrend" class="chart-container"></div> | ||||||
|  |     </div> | ||||||
|  |     <div class="chart-card"> | ||||||
|  |         <h2>用户增长</h2> | ||||||
|  |         <div id="userGrowth" class="chart-container"></div> | ||||||
|  |     </div> | ||||||
|  |     <div class="chart-card"> | ||||||
|  |         <h2>资源统计</h2> | ||||||
|  |         <div id="resourceStats" class="chart-container"></div> | ||||||
|  |     </div> | ||||||
|  |     <div class="chart-card"> | ||||||
|  |         <h2>文章统计</h2> | ||||||
|  |         <div id="articleStats" class="chart-container"></div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | <script src="/static/js/echarts.min.js"></script> | ||||||
| <script> | <script> | ||||||
| function updateTime() { | function updateTime() { | ||||||
|     var now = new Date(); |     var now = new Date(); | ||||||
| @ -217,12 +394,10 @@ function updateTime() { | |||||||
|     var minutes = now.getMinutes(); |     var minutes = now.getMinutes(); | ||||||
|     var seconds = now.getSeconds(); |     var seconds = now.getSeconds(); | ||||||
| 
 | 
 | ||||||
|     // 补零函数
 |  | ||||||
|     var padZero = function(num) { |     var padZero = function(num) { | ||||||
|         return num < 10 ? '0' + num : num; |         return num < 10 ? '0' + num : num; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // 格式化时间
 |  | ||||||
|     var timeString = year + '年' +  |     var timeString = year + '年' +  | ||||||
|                      padZero(month) + '月' +  |                      padZero(month) + '月' +  | ||||||
|                      padZero(date) + '日 ' +  |                      padZero(date) + '日 ' +  | ||||||
| @ -233,11 +408,296 @@ function updateTime() { | |||||||
|     document.getElementById('current-time').innerHTML = timeString; |     document.getElementById('current-time').innerHTML = timeString; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 页面加载完立即执行一次
 | // 获取文章统计数据
 | ||||||
| updateTime(); | function getArticleCounts() { | ||||||
|  |     fetch('<?php echo url("article/counts"); ?>') | ||||||
|  |         .then(response => response.json()) | ||||||
|  |         .then(res => { | ||||||
|  |             console.log('文章统计接口返回数据:', res); | ||||||
|  |             if (res.code === 0 && res.data) { | ||||||
|  |                 // 更新文章总数
 | ||||||
|  |                 document.querySelector('.stat-card:nth-child(3) .stat-value').textContent = res.data.total.toLocaleString(); | ||||||
|  |             } else { | ||||||
|  |                 console.warn('文章统计接口返回异常:', res); | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .catch(error => { | ||||||
|  |             console.error('获取文章统计失败:', error); | ||||||
|  |         }); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| // 每秒更新一次时间
 | // 获取资源统计数据
 | ||||||
|  | function getResourcesCounts() { | ||||||
|  |     fetch('<?php echo url("resources/counts"); ?>') | ||||||
|  |         .then(response => response.json()) | ||||||
|  |         .then(res => { | ||||||
|  |             console.log('资源统计接口返回数据:', res); | ||||||
|  |             if (res.code === 0 && res.data) { | ||||||
|  |                 // 更新资源总数
 | ||||||
|  |                 document.querySelector('.stat-card:nth-child(4) .stat-value').textContent = res.data.total.toLocaleString(); | ||||||
|  |             } else { | ||||||
|  |                 console.warn('资源统计接口返回异常:', res); | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .catch(error => { | ||||||
|  |             console.error('获取资源统计失败:', error); | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | updateTime(); | ||||||
| setInterval(updateTime, 1000); | setInterval(updateTime, 1000); | ||||||
|  | 
 | ||||||
|  | // 页面加载完成后获取统计数据
 | ||||||
|  | document.addEventListener('DOMContentLoaded', function() { | ||||||
|  |     getArticleCounts(); | ||||||
|  |     getResourcesCounts(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | // 访问趋势图表
 | ||||||
|  | function initVisitTrend() { | ||||||
|  |     var chart = echarts.init(document.getElementById('visitTrend')); | ||||||
|  |     var option = { | ||||||
|  |         tooltip: { | ||||||
|  |             trigger: 'axis', | ||||||
|  |             axisPointer: { | ||||||
|  |                 type: 'shadow' | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         legend: { | ||||||
|  |             data: ['访问量', '独立访客'] | ||||||
|  |         }, | ||||||
|  |         grid: { | ||||||
|  |             left: '3%', | ||||||
|  |             right: '4%', | ||||||
|  |             bottom: '3%', | ||||||
|  |             containLabel: true | ||||||
|  |         }, | ||||||
|  |         xAxis: { | ||||||
|  |             type: 'category', | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['dates'])); ?>,
 | ||||||
|  |             axisLine: { | ||||||
|  |                 lineStyle: { | ||||||
|  |                     color: '#e2e8f0' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         yAxis: { | ||||||
|  |             type: 'value', | ||||||
|  |             axisLine: { | ||||||
|  |                 lineStyle: { | ||||||
|  |                     color: '#e2e8f0' | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             splitLine: { | ||||||
|  |                 lineStyle: { | ||||||
|  |                     color: '#f1f5f9' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         series: [{ | ||||||
|  |             name: '访问量', | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['visits'])); ?>,
 | ||||||
|  |             type: 'line', | ||||||
|  |             smooth: true, | ||||||
|  |             areaStyle: { | ||||||
|  |                 opacity: 0.1 | ||||||
|  |             }, | ||||||
|  |             itemStyle: { | ||||||
|  |                 color: '#3881fd' | ||||||
|  |             }, | ||||||
|  |             lineStyle: { | ||||||
|  |                 width: 3 | ||||||
|  |             } | ||||||
|  |         }, { | ||||||
|  |             name: '独立访客', | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['visitTrend']['uvs'])); ?>,
 | ||||||
|  |             type: 'line', | ||||||
|  |             smooth: true, | ||||||
|  |             itemStyle: { | ||||||
|  |                 color: '#10b981' | ||||||
|  |             }, | ||||||
|  |             lineStyle: { | ||||||
|  |                 width: 3 | ||||||
|  |             } | ||||||
|  |         }] | ||||||
|  |     }; | ||||||
|  |     chart.setOption(option); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 用户增长图表
 | ||||||
|  | function initUserGrowth() { | ||||||
|  |     var chart = echarts.init(document.getElementById('userGrowth')); | ||||||
|  |     var option = { | ||||||
|  |         tooltip: { | ||||||
|  |             trigger: 'axis', | ||||||
|  |             axisPointer: { | ||||||
|  |                 type: 'cross', | ||||||
|  |                 label: { | ||||||
|  |                     backgroundColor: '#6a7985' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         legend: { | ||||||
|  |             data: ['新增用户', '总用户数'] | ||||||
|  |         }, | ||||||
|  |         grid: { | ||||||
|  |             left: '3%', | ||||||
|  |             right: '4%', | ||||||
|  |             bottom: '3%', | ||||||
|  |             containLabel: true | ||||||
|  |         }, | ||||||
|  |         xAxis: { | ||||||
|  |             type: 'category', | ||||||
|  |             boundaryGap: false, | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['dates'])); ?>
 | ||||||
|  |         }, | ||||||
|  |         yAxis: { | ||||||
|  |             type: 'value' | ||||||
|  |         }, | ||||||
|  |         series: [ | ||||||
|  |             { | ||||||
|  |                 name: '新增用户', | ||||||
|  |                 type: 'bar', | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['newUsers'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#3881fd' | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 name: '总用户数', | ||||||
|  |                 type: 'line', | ||||||
|  |                 smooth: true, | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['userGrowth']['totalUsers'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#10b981' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }; | ||||||
|  |     chart.setOption(option); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 资源统计图表
 | ||||||
|  | function initResourceStats() { | ||||||
|  |     var chart = echarts.init(document.getElementById('resourceStats')); | ||||||
|  |     var option = { | ||||||
|  |         tooltip: { | ||||||
|  |             trigger: 'axis', | ||||||
|  |             axisPointer: { | ||||||
|  |                 type: 'cross', | ||||||
|  |                 label: { | ||||||
|  |                     backgroundColor: '#6a7985' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         legend: { | ||||||
|  |             data: ['新增资源', '下载量'] | ||||||
|  |         }, | ||||||
|  |         grid: { | ||||||
|  |             left: '3%', | ||||||
|  |             right: '4%', | ||||||
|  |             bottom: '3%', | ||||||
|  |             containLabel: true | ||||||
|  |         }, | ||||||
|  |         xAxis: { | ||||||
|  |             type: 'category', | ||||||
|  |             boundaryGap: false, | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['dates'])); ?>
 | ||||||
|  |         }, | ||||||
|  |         yAxis: { | ||||||
|  |             type: 'value' | ||||||
|  |         }, | ||||||
|  |         series: [ | ||||||
|  |             { | ||||||
|  |                 name: '新增资源', | ||||||
|  |                 type: 'bar', | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['resources'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#3881fd' | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 name: '下载量', | ||||||
|  |                 type: 'line', | ||||||
|  |                 smooth: true, | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['resourceStats']['downloads'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#10b981' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }; | ||||||
|  |     chart.setOption(option); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 文章统计图表
 | ||||||
|  | function initArticleStats() { | ||||||
|  |     var chart = echarts.init(document.getElementById('articleStats')); | ||||||
|  |     var option = { | ||||||
|  |         tooltip: { | ||||||
|  |             trigger: 'axis', | ||||||
|  |             axisPointer: { | ||||||
|  |                 type: 'cross', | ||||||
|  |                 label: { | ||||||
|  |                     backgroundColor: '#6a7985' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         legend: { | ||||||
|  |             data: ['新增文章', '访问量'] | ||||||
|  |         }, | ||||||
|  |         grid: { | ||||||
|  |             left: '3%', | ||||||
|  |             right: '4%', | ||||||
|  |             bottom: '3%', | ||||||
|  |             containLabel: true | ||||||
|  |         }, | ||||||
|  |         xAxis: { | ||||||
|  |             type: 'category', | ||||||
|  |             boundaryGap: false, | ||||||
|  |             data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['dates'])); ?>
 | ||||||
|  |         }, | ||||||
|  |         yAxis: { | ||||||
|  |             type: 'value' | ||||||
|  |         }, | ||||||
|  |         series: [ | ||||||
|  |             { | ||||||
|  |                 name: '新增文章', | ||||||
|  |                 type: 'bar', | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['articles'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#3881fd' | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 name: '访问量', | ||||||
|  |                 type: 'line', | ||||||
|  |                 smooth: true, | ||||||
|  |                 data: <?php echo htmlentities((string) json_encode($chartData['articleStats']['views'])); ?>,
 | ||||||
|  |                 itemStyle: { | ||||||
|  |                     color: '#10b981' | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }; | ||||||
|  |     chart.setOption(option); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 初始化所有图表
 | ||||||
|  | document.addEventListener('DOMContentLoaded', function() { | ||||||
|  |     initVisitTrend(); | ||||||
|  |     initUserGrowth(); | ||||||
|  |     initResourceStats(); | ||||||
|  |     initArticleStats(); | ||||||
|  |      | ||||||
|  |     // 监听窗口大小变化,重绘图表
 | ||||||
|  |     window.addEventListener('resize', function() { | ||||||
|  |         var charts = document.querySelectorAll('.chart-container'); | ||||||
|  |         charts.forEach(function(chart) { | ||||||
|  |             echarts.getInstanceByDom(chart)?.resize(); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| 	</body> | 	</body> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:2:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\resources\lists.php";i:1747386799;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | <?php /*a:2:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\resources\lists.php";i:1747624589;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 	<head> | 	<head> | ||||||
| @ -151,13 +151,13 @@ | |||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <script type="text/html" id="statusTemplate"> | <script type="text/html" id="statusTemplate"> | ||||||
|     {{#  if(d.status === 0){ }}
 |     {{#  if(d.status == '0'){ }}
 | ||||||
|     <span style="color:red;">未审核</span> |     <span style="color:red;">未审核</span> | ||||||
|     {{#  } else if(d.status === 1){ }}
 |     {{#  } else if(d.status == '1'){ }}
 | ||||||
|     <span style="color:orange;">待审核</span> |     <span style="color:orange;">待审核</span> | ||||||
|     {{#  } else if(d.status === 2){ }}
 |     {{#  } else if(d.status == '2'){ }}
 | ||||||
|     <span style="color:green;">已发布</span> |     <span style="color:green;">已发布</span> | ||||||
|     {{#  } else if(d.status === 3){ }}
 |     {{#  } else if(d.status == '3'){ }}
 | ||||||
|     <span style="color:gray;">已下架</span> |     <span style="color:gray;">已下架</span> | ||||||
|     {{#  } }}
 |     {{#  } }}
 | ||||||
| </script> | </script> | ||||||
| @ -185,13 +185,12 @@ | |||||||
|             method: 'post', |             method: 'post', | ||||||
|             cols: [[ |             cols: [[ | ||||||
|                 { field: 'id', title: 'ID', align: 'center', width: 80 }, |                 { field: 'id', title: 'ID', align: 'center', width: 80 }, | ||||||
|                 { field: 'name', title: '资源名称' }, |                 { field: 'title', title: '资源名称' }, | ||||||
|                 { field: 'cate', title: '分类', align: 'center', width: 120 }, |                 { field: 'cate', title: '分类', align: 'center', width: 120 }, | ||||||
|                 { field: 'icon', title: '图标', templet: '#iconTemplate', align: 'center', width: 100 }, |                 { field: 'icon', title: '图标', templet: '#iconTemplate', align: 'center', width: 100 }, | ||||||
|                 { field: 'uploader', title: '上传者', align: 'center', width: 100 }, |                 { field: 'uploader', title: '上传者', align: 'center', width: 100 }, | ||||||
|                 { field: 'desc', title: '描述', width: 200 }, |                 { field: 'desc', title: '描述', width: 200 }, | ||||||
|                 { field: 'status', title: '状态', templet: '#statusTemplate', align: 'center', width: 80 }, |                 { field: 'status', title: '状态', templet: '#statusTemplate', align: 'center', width: 80 }, | ||||||
|                 { field: 'upload_time', title: '上传时间', align: 'center', width: 160 }, |  | ||||||
|                 { title: '操作', toolbar: '#operationBar', align: 'center', width: 150, fixed: 'right' } |                 { title: '操作', toolbar: '#operationBar', align: 'center', width: 150, fixed: 'right' } | ||||||
|             ]], |             ]], | ||||||
|             page: true, |             page: true, | ||||||
| @ -252,7 +251,13 @@ | |||||||
| 
 | 
 | ||||||
|     function reloadTable() { |     function reloadTable() { | ||||||
|         var categoryId = $('#categoryFilter').val(); |         var categoryId = $('#categoryFilter').val(); | ||||||
|         var categoryName = categoryId ? $('#categoryFilter option[value="' + categoryId + '"]').text() : ''; |         var categoryName = ''; | ||||||
|  |         if (categoryId) { | ||||||
|  |             var selectedOption = $('#categoryFilter option[value="' + categoryId + '"]'); | ||||||
|  |             if (selectedOption.length > 0) { | ||||||
|  |                 categoryName = selectedOption.text().trim(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         var nameKeyword = $('#nameSearch').val().trim(); |         var nameKeyword = $('#nameSearch').val().trim(); | ||||||
|         var uploaderKeyword = $('#uploaderSearch').val().trim(); |         var uploaderKeyword = $('#uploaderSearch').val().trim(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:1:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\index\index.php";i:1747370724;}*/ ?>
 | <?php /*a:1:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\index\index.php";i:1747615358;}*/ ?>
 | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 
 | 
 | ||||||
| @ -110,7 +110,7 @@ | |||||||
| 						<li class="layui-nav-item" data-name="index/welcome"> | 						<li class="layui-nav-item" data-name="index/welcome"> | ||||||
| 							<a href="javascript:;" lay-tips="工作台" lay-direction="2" | 							<a href="javascript:;" lay-tips="工作台" lay-direction="2" | ||||||
| 								onclick="menuFire('index/welcome',1)"> | 								onclick="menuFire('index/welcome',1)"> | ||||||
| 								<i class="layui-icon layui-icon-home" style="margin-top: -30px;"></i> | 								<i class="layui-icon layui-icon-home" style="margin-top: -20px;"></i> | ||||||
| 								<cite>工作台</cite> | 								<cite>工作台</cite> | ||||||
| 							</a> | 							</a> | ||||||
| 						</li> | 						</li> | ||||||
|  | |||||||
							
								
								
									
										267
									
								
								runtime/admin/temp/8f74a562a9b39596b131b5ce2a04e10e.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								runtime/admin/temp/8f74a562a9b39596b131b5ce2a04e10e.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,267 @@ | |||||||
|  | <?php /*a:2:{s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\log\operation.php";i:1747615358;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | 	<head> | ||||||
|  | 		<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
 | ||||||
|  | 		<meta name="renderer" content="webkit"> | ||||||
|  | 		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||||||
|  | 		<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0"> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/> | ||||||
|  | 		<style type="text/css"> | ||||||
|  | 			.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
 | ||||||
|  | 			.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
 | ||||||
|  | 			.header button{float:right;margin-top:-5px;} | ||||||
|  | 			.pagination { | ||||||
|  | 				display: inline-block; | ||||||
|  | 				padding-left: 0; | ||||||
|  | 				margin: 20px 0; | ||||||
|  | 				border-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li { | ||||||
|  | 				display: inline; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li > a, | ||||||
|  | 			.pagination > li > span { | ||||||
|  | 				position: relative; | ||||||
|  | 				float: left; | ||||||
|  | 				padding: 6px 12px; | ||||||
|  | 				margin-left: -1px; | ||||||
|  | 				line-height: 1.42857143; | ||||||
|  | 				color: #337ab7;
 | ||||||
|  | 				text-decoration: none; | ||||||
|  | 				background-color: #fff;
 | ||||||
|  | 				border: 1px solid #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > li:first-child > a, | ||||||
|  | 			.pagination > li:first-child > span { | ||||||
|  | 				margin-left: 0; | ||||||
|  | 				border-top-left-radius: 4px; | ||||||
|  | 				border-bottom-left-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li:last-child > a, | ||||||
|  | 			.pagination > li:last-child > span { | ||||||
|  | 				border-top-right-radius: 4px; | ||||||
|  | 				border-bottom-right-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li > a:hover, | ||||||
|  | 			.pagination > li > span:hover, | ||||||
|  | 			.pagination > li > a:focus, | ||||||
|  | 			.pagination > li > span:focus { | ||||||
|  | 				z-index: 2; | ||||||
|  | 				color: #23527c;
 | ||||||
|  | 				background-color: #eee;
 | ||||||
|  | 				border-color: #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > .active > a, | ||||||
|  | 			.pagination > .active > span, | ||||||
|  | 			.pagination > .active > a:hover, | ||||||
|  | 			.pagination > .active > span:hover, | ||||||
|  | 			.pagination > .active > a:focus, | ||||||
|  | 			.pagination > .active > span:focus { | ||||||
|  | 				z-index: 3; | ||||||
|  | 				color: #fff;
 | ||||||
|  | 				cursor: default; | ||||||
|  | 				background-color: #337ab7;
 | ||||||
|  | 				border-color: #337ab7;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > .disabled > span, | ||||||
|  | 			.pagination > .disabled > span:hover, | ||||||
|  | 			.pagination > .disabled > span:focus, | ||||||
|  | 			.pagination > .disabled > a, | ||||||
|  | 			.pagination > .disabled > a:hover, | ||||||
|  | 			.pagination > .disabled > a:focus { | ||||||
|  | 				color: #777;
 | ||||||
|  | 				cursor: not-allowed; | ||||||
|  | 				background-color: #fff;
 | ||||||
|  | 				border-color: #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;} | ||||||
|  | 		</style> | ||||||
|  | 		<script type="text/javascript" src="/static/layui/layui.js"></script> | ||||||
|  | 		<script type="text/javascript"> | ||||||
|  | 			layui.use(['layer','form','table','laydate','element','upload'],function(){ | ||||||
|  | 				layer = layui.layer;		// layui 弹框
 | ||||||
|  | 				form = layui.form;			// layui form表单
 | ||||||
|  | 				table = layui.table;		// layui 表格
 | ||||||
|  | 				laydate = layui.laydate;	// layui 时间框
 | ||||||
|  | 				element = layui.element;	// layui element
 | ||||||
|  | 				upload = layui.upload;		// layui 上传
 | ||||||
|  | 				$ = layui.jquery;			// layui jquery
 | ||||||
|  | 			}) | ||||||
|  | 		</script> | ||||||
|  | 	</head> | ||||||
|  | 	<body style="padding:10px; box-sizing: border-box;"> | ||||||
|  |     <div class="layui-card"> | ||||||
|  |         <div class="layui-card-header"> | ||||||
|  |             <span class="layui-badge layui-bg-blue">操作日志</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="layui-card-body"> | ||||||
|  |             <form class="layui-form layui-form-pane" action=""> | ||||||
|  |                 <div class="layui-form-item"> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">用户名</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">模块</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <input type="text" name="module" placeholder="请输入模块" autocomplete="off" class="layui-input"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">操作</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <input type="text" name="operation" placeholder="请输入操作" autocomplete="off" class="layui-input"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">状态</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <select name="status"> | ||||||
|  |                                 <option value="">全部</option> | ||||||
|  |                                 <option value="1">成功</option> | ||||||
|  |                                 <option value="0">失败</option> | ||||||
|  |                             </select> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">时间范围</label> | ||||||
|  |                         <div class="layui-input-inline" style="width: 300px;"> | ||||||
|  |                             <input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <button class="layui-btn" lay-submit lay-filter="searchForm"> | ||||||
|  |                             <i class="layui-icon layui-icon-search"></i> 搜索 | ||||||
|  |                         </button> | ||||||
|  |                         <button type="reset" class="layui-btn layui-btn-primary">重置</button> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </form> | ||||||
|  | 
 | ||||||
|  |             <table id="operationLogTable" lay-filter="operationLogTable"></table> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <script src="/static/layui/layui.js"></script> | ||||||
|  |     <script> | ||||||
|  |     layui.use(['table', 'form', 'laydate', 'layer'], function(){ | ||||||
|  |         var table = layui.table; | ||||||
|  |         var form = layui.form; | ||||||
|  |         var laydate = layui.laydate; | ||||||
|  |         var layer = layui.layer; | ||||||
|  |          | ||||||
|  |         // 初始化时间范围选择器
 | ||||||
|  |         laydate.render({ | ||||||
|  |             elem: '#timeRange', | ||||||
|  |             type: 'datetime', | ||||||
|  |             range: true | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 初始化表格
 | ||||||
|  |         table.render({ | ||||||
|  |             elem: '#operationLogTable', | ||||||
|  |             url: '<?php echo url("log/operation"); ?>', | ||||||
|  |             method: 'get', | ||||||
|  |             defaultToolbar: ['filter', 'exports', 'print'], | ||||||
|  |             parseData: function(res) { | ||||||
|  |                 return { | ||||||
|  |                     "code": 0, | ||||||
|  |                     "msg": res.msg || '获取成功', | ||||||
|  |                     "count": res.count || 0, | ||||||
|  |                     "data": res.data || [] | ||||||
|  |                 }; | ||||||
|  |             }, | ||||||
|  |             cols: [[ | ||||||
|  |                 {field: 'id', title: 'ID', width: 80, sort: true, align: 'center'}, | ||||||
|  |                 {field: 'username', title: '操作人', width: 120, align: 'center'}, | ||||||
|  |                 {field: 'module', title: '模块', width: 120, align: 'center'}, | ||||||
|  |                 {field: 'operation', title: '操作', width: 150, align: 'center'}, | ||||||
|  |                 {field: 'request_method', title: '请求方法', width: 100, align: 'center'}, | ||||||
|  |                 {field: 'request_url', title: '请求地址', align: 'center'}, | ||||||
|  |                 {field: 'ip_address', title: 'IP地址', width: 120, align: 'center'}, | ||||||
|  |                 {field: 'status', title: '状态', width: 100, align: 'center', templet: function(d){ | ||||||
|  |                     return d.status == 1 ? '<span class="layui-badge layui-bg-green">成功</span>' : '<span class="layui-badge layui-bg-red">失败</span>'; | ||||||
|  |                 }}, | ||||||
|  |                 {field: 'operation_time', title: '操作时间', width: 180, align: 'center'}, | ||||||
|  |                 {field: 'execution_time', title: '执行时间(ms)', width: 120, align: 'center'}, | ||||||
|  |                 {title: '操作', width: 120, toolbar: '#operationBar', fixed: 'right', align: 'center'} | ||||||
|  |             ]], | ||||||
|  |             page: true, | ||||||
|  |             limit: 10, | ||||||
|  |             limits: [10, 20, 50, 100] | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 监听搜索表单提交
 | ||||||
|  |         form.on('submit(searchForm)', function(data){ | ||||||
|  |             var timeRange = data.field.time_range; | ||||||
|  |             if(timeRange){ | ||||||
|  |                 var times = timeRange.split(' - '); | ||||||
|  |                 data.field.start_time = times[0]; | ||||||
|  |                 data.field.end_time = times[1]; | ||||||
|  |             } | ||||||
|  |             delete data.field.time_range; | ||||||
|  |              | ||||||
|  |             table.reload('operationLogTable', { | ||||||
|  |                 where: data.field, | ||||||
|  |                 page: {curr: 1} | ||||||
|  |             }); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 监听工具条
 | ||||||
|  |         table.on('tool(operationLogTable)', function(obj){ | ||||||
|  |             var data = obj.data; | ||||||
|  |             if(obj.event === 'detail'){ | ||||||
|  |                 // 获取详情
 | ||||||
|  |                 $.ajax({ | ||||||
|  |                     url: '<?php echo url("log/getOperationDetail"); ?>', | ||||||
|  |                     type: 'GET', | ||||||
|  |                     data: {id: data.id}, | ||||||
|  |                     success: function(res){ | ||||||
|  |                         if(res.code === 0){ | ||||||
|  |                             var detail = res.data; | ||||||
|  |                             var content = '<div class="layui-card">' + | ||||||
|  |                                 '<div class="layui-card-body">' + | ||||||
|  |                                 '<table class="layui-table" lay-skin="nob">' + | ||||||
|  |                                 '<colgroup><col width="100"><col></colgroup>' + | ||||||
|  |                                 '<tbody>' + | ||||||
|  |                                 '<tr><td>操作人:</td><td>' + detail.username + '</td></tr>' + | ||||||
|  |                                 '<tr><td>模块:</td><td>' + detail.module + '</td></tr>' + | ||||||
|  |                                 '<tr><td>操作:</td><td>' + detail.operation + '</td></tr>' + | ||||||
|  |                                 '<tr><td>请求方法:</td><td>' + detail.request_method + '</td></tr>' + | ||||||
|  |                                 '<tr><td>请求地址:</td><td>' + detail.request_url + '</td></tr>' + | ||||||
|  |                                 '<tr><td>请求参数:</td><td><pre>' + JSON.stringify(detail.request_params, null, 2) + '</pre></td></tr>' + | ||||||
|  |                                 '<tr><td>IP地址:</td><td>' + detail.ip_address + '</td></tr>' + | ||||||
|  |                                 '<tr><td>状态:</td><td>' + (detail.status == 1 ? '成功' : '失败') + '</td></tr>' + | ||||||
|  |                                 '<tr><td>错误信息:</td><td>' + (detail.error_message || '无') + '</td></tr>' + | ||||||
|  |                                 '<tr><td>操作时间:</td><td>' + detail.operation_time + '</td></tr>' + | ||||||
|  |                                 '<tr><td>执行时间:</td><td>' + detail.execution_time + 'ms</td></tr>' + | ||||||
|  |                                 '</tbody></table></div></div>'; | ||||||
|  |                                  | ||||||
|  |                             layer.open({ | ||||||
|  |                                 type: 1, | ||||||
|  |                                 title: '操作日志详情', | ||||||
|  |                                 area: ['800px', '600px'], | ||||||
|  |                                 content: content | ||||||
|  |                             }); | ||||||
|  |                         } else { | ||||||
|  |                             layer.msg(res.msg); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <!-- 表格工具栏模板 --> | ||||||
|  |     <script type="text/html" id="operationBar"> | ||||||
|  |         <a class="layui-btn layui-btn-xs" lay-event="detail">详情</a> | ||||||
|  |     </script> | ||||||
|  | </body> | ||||||
|  | </html>  | ||||||
							
								
								
									
										260
									
								
								runtime/admin/temp/c4cb272f04d884533b2554471a2dc765.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								runtime/admin/temp/c4cb272f04d884533b2554471a2dc765.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,260 @@ | |||||||
|  | <?php /*a:2:{s:57:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\log\login.php";i:1747615358;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | 	<head> | ||||||
|  | 		<title><?php echo htmlentities((string) $config['admin_name']); ?></title>
 | ||||||
|  | 		<meta name="renderer" content="webkit"> | ||||||
|  | 		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||||||
|  | 		<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0"> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/layui/css/layui.css" media="all"/> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/css/moban.css" media="all"/> | ||||||
|  | 		<link rel="stylesheet" type="text/css" href="/static/css/wangeditor.css" media="all"/> | ||||||
|  | 		<style type="text/css"> | ||||||
|  | 			.header span{background:#009688;margin-left:30px;padding:10px;color:#ffffff;}
 | ||||||
|  | 			.header div{border-bottom:solid 2px #009688;margin-top: 8px;}
 | ||||||
|  | 			.header button{float:right;margin-top:-5px;} | ||||||
|  | 			.pagination { | ||||||
|  | 				display: inline-block; | ||||||
|  | 				padding-left: 0; | ||||||
|  | 				margin: 20px 0; | ||||||
|  | 				border-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li { | ||||||
|  | 				display: inline; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li > a, | ||||||
|  | 			.pagination > li > span { | ||||||
|  | 				position: relative; | ||||||
|  | 				float: left; | ||||||
|  | 				padding: 6px 12px; | ||||||
|  | 				margin-left: -1px; | ||||||
|  | 				line-height: 1.42857143; | ||||||
|  | 				color: #337ab7;
 | ||||||
|  | 				text-decoration: none; | ||||||
|  | 				background-color: #fff;
 | ||||||
|  | 				border: 1px solid #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > li:first-child > a, | ||||||
|  | 			.pagination > li:first-child > span { | ||||||
|  | 				margin-left: 0; | ||||||
|  | 				border-top-left-radius: 4px; | ||||||
|  | 				border-bottom-left-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li:last-child > a, | ||||||
|  | 			.pagination > li:last-child > span { | ||||||
|  | 				border-top-right-radius: 4px; | ||||||
|  | 				border-bottom-right-radius: 4px; | ||||||
|  | 			} | ||||||
|  | 			.pagination > li > a:hover, | ||||||
|  | 			.pagination > li > span:hover, | ||||||
|  | 			.pagination > li > a:focus, | ||||||
|  | 			.pagination > li > span:focus { | ||||||
|  | 				z-index: 2; | ||||||
|  | 				color: #23527c;
 | ||||||
|  | 				background-color: #eee;
 | ||||||
|  | 				border-color: #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > .active > a, | ||||||
|  | 			.pagination > .active > span, | ||||||
|  | 			.pagination > .active > a:hover, | ||||||
|  | 			.pagination > .active > span:hover, | ||||||
|  | 			.pagination > .active > a:focus, | ||||||
|  | 			.pagination > .active > span:focus { | ||||||
|  | 				z-index: 3; | ||||||
|  | 				color: #fff;
 | ||||||
|  | 				cursor: default; | ||||||
|  | 				background-color: #337ab7;
 | ||||||
|  | 				border-color: #337ab7;
 | ||||||
|  | 			} | ||||||
|  | 			.pagination > .disabled > span, | ||||||
|  | 			.pagination > .disabled > span:hover, | ||||||
|  | 			.pagination > .disabled > span:focus, | ||||||
|  | 			.pagination > .disabled > a, | ||||||
|  | 			.pagination > .disabled > a:hover, | ||||||
|  | 			.pagination > .disabled > a:focus { | ||||||
|  | 				color: #777;
 | ||||||
|  | 				cursor: not-allowed; | ||||||
|  | 				background-color: #fff;
 | ||||||
|  | 				border-color: #ddd;
 | ||||||
|  | 			} | ||||||
|  | 			.close-img { background: url(/static/images/close_img.png); background-size: 20px 20px; width:20px; height: 20px; position: absolute; right: 5px; top: 5px; z-index: 2;} | ||||||
|  | 		</style> | ||||||
|  | 		<script type="text/javascript" src="/static/layui/layui.js"></script> | ||||||
|  | 		<script type="text/javascript"> | ||||||
|  | 			layui.use(['layer','form','table','laydate','element','upload'],function(){ | ||||||
|  | 				layer = layui.layer;		// layui 弹框
 | ||||||
|  | 				form = layui.form;			// layui form表单
 | ||||||
|  | 				table = layui.table;		// layui 表格
 | ||||||
|  | 				laydate = layui.laydate;	// layui 时间框
 | ||||||
|  | 				element = layui.element;	// layui element
 | ||||||
|  | 				upload = layui.upload;		// layui 上传
 | ||||||
|  | 				$ = layui.jquery;			// layui jquery
 | ||||||
|  | 			}) | ||||||
|  | 		</script> | ||||||
|  | 	</head> | ||||||
|  | 	<body style="padding:10px; box-sizing: border-box;"> | ||||||
|  |     <div class="layui-card"> | ||||||
|  |         <div class="layui-card-header"> | ||||||
|  |             <span class="layui-badge layui-bg-blue">登录日志</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="layui-card-body"> | ||||||
|  |             <form class="layui-form layui-form-pane" action=""> | ||||||
|  |                 <div class="layui-form-item"> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">用户名</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">IP地址</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <input type="text" name="ip" placeholder="请输入IP地址" autocomplete="off" class="layui-input"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">状态</label> | ||||||
|  |                         <div class="layui-input-inline"> | ||||||
|  |                             <select name="status"> | ||||||
|  |                                 <option value="">全部</option> | ||||||
|  |                                 <option value="1">成功</option> | ||||||
|  |                                 <option value="0">失败</option> | ||||||
|  |                             </select> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <label class="layui-form-label">时间范围</label> | ||||||
|  |                         <div class="layui-input-inline" style="width: 300px;"> | ||||||
|  |                             <input type="text" name="time_range" class="layui-input" id="timeRange" placeholder="请选择时间范围"> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="layui-inline"> | ||||||
|  |                         <button class="layui-btn" lay-submit lay-filter="searchForm"> | ||||||
|  |                             <i class="layui-icon layui-icon-search"></i> 搜索 | ||||||
|  |                         </button> | ||||||
|  |                         <button type="reset" class="layui-btn layui-btn-primary">重置</button> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </form> | ||||||
|  | 
 | ||||||
|  |             <table id="loginLogTable" lay-filter="loginLogTable"></table> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <script type="text/html" id="tableToolbar"> | ||||||
|  |         <div class="layui-btn-container"> | ||||||
|  |             <button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="clearAll"> | ||||||
|  |                 <i class="layui-icon layui-icon-delete"></i> 清空日志 | ||||||
|  |             </button> | ||||||
|  |         </div> | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script type="text/html" id="tableBar"> | ||||||
|  |         <a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a> | ||||||
|  |     </script> | ||||||
|  | 
 | ||||||
|  |     <script src="/static/layui/layui.js"></script> | ||||||
|  |     <script> | ||||||
|  |     layui.use(['table', 'form', 'laydate'], function(){ | ||||||
|  |         var table = layui.table; | ||||||
|  |         var form = layui.form; | ||||||
|  |         var laydate = layui.laydate; | ||||||
|  |          | ||||||
|  |         // 初始化时间范围选择器
 | ||||||
|  |         laydate.render({ | ||||||
|  |             elem: '#timeRange', | ||||||
|  |             type: 'datetime', | ||||||
|  |             range: true | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 初始化表格
 | ||||||
|  |         table.render({ | ||||||
|  |             elem: '#loginLogTable', | ||||||
|  |             url: '<?php echo url("log/login"); ?>', | ||||||
|  |             method: 'post', | ||||||
|  |             toolbar: '#tableToolbar', | ||||||
|  |             defaultToolbar: ['filter', 'exports', 'print'], | ||||||
|  |             parseData: function(res) { | ||||||
|  |                 return { | ||||||
|  |                     "code": res.code === 0 ? 0 : 1, | ||||||
|  |                     "msg": res.msg, | ||||||
|  |                     "count": res.count, | ||||||
|  |                     "data": res.data | ||||||
|  |                 }; | ||||||
|  |             }, | ||||||
|  |             cols: [[ | ||||||
|  |                 {field: 'id', title: 'ID', width: 80, sort: true}, | ||||||
|  |                 {field: 'username', title: '用户名', width: 120}, | ||||||
|  |                 {field: 'ip_address', title: 'IP地址', width: 130}, | ||||||
|  |                 {field: 'location', title: '登录地点', width: 120}, | ||||||
|  |                 {field: 'device_type', title: '设备类型', width: 100}, | ||||||
|  |                 {field: 'user_agent', title: '浏览器', width: 200}, | ||||||
|  |                 {field: 'login_status', title: '状态', width: 100, templet: function(d){ | ||||||
|  |                     return d.login_status == 1 ?  | ||||||
|  |                         '<span class="layui-badge layui-bg-green">成功</span>' :  | ||||||
|  |                         '<span class="layui-badge layui-bg-red">失败</span>'; | ||||||
|  |                 }}, | ||||||
|  |                 {field: 'failure_reason', title: '失败原因', width: 150}, | ||||||
|  |                 {field: 'login_time', title: '登录时间', width: 180, sort: true}, | ||||||
|  |                 {title: '操作', toolbar: '#tableBar', width: 80, fixed: 'right'} | ||||||
|  |             ]], | ||||||
|  |             page: true, | ||||||
|  |             limit: 10, | ||||||
|  |             limits: [10, 20, 50, 100] | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 监听搜索表单提交
 | ||||||
|  |         form.on('submit(searchForm)', function(data){ | ||||||
|  |             var timeRange = data.field.time_range; | ||||||
|  |             if(timeRange){ | ||||||
|  |                 var times = timeRange.split(' - '); | ||||||
|  |                 data.field.start_time = times[0]; | ||||||
|  |                 data.field.end_time = times[1]; | ||||||
|  |             } | ||||||
|  |             delete data.field.time_range; | ||||||
|  |              | ||||||
|  |             table.reload('loginLogTable', { | ||||||
|  |                 where: data.field, | ||||||
|  |                 page: {curr: 1} | ||||||
|  |             }); | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 监听工具条
 | ||||||
|  |         table.on('tool(loginLogTable)', function(obj){ | ||||||
|  |             var data = obj.data; | ||||||
|  |             if(obj.event === 'del'){ | ||||||
|  |                 layer.confirm('确定删除这条日志吗?', function(index){ | ||||||
|  |                     $.post('<?php echo url("log/deleteLogin"); ?>', {id: data.id}, function(res){ | ||||||
|  |                         if(res.code === 0){ | ||||||
|  |                             layer.msg(res.msg, {icon: 1}); | ||||||
|  |                             obj.del(); | ||||||
|  |                         }else{ | ||||||
|  |                             layer.msg(res.msg, {icon: 2}); | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                     layer.close(index); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // 监听头工具栏事件
 | ||||||
|  |         table.on('toolbar(loginLogTable)', function(obj){ | ||||||
|  |             if(obj.event === 'clearAll'){ | ||||||
|  |                 layer.confirm('确定要清空所有登录日志吗?', function(index){ | ||||||
|  |                     $.post('<?php echo url("log/clearLogin"); ?>', function(res){ | ||||||
|  |                         if(res.code === 0){ | ||||||
|  |                             layer.msg(res.msg, {icon: 1}); | ||||||
|  |                             table.reload('loginLogTable'); | ||||||
|  |                         }else{ | ||||||
|  |                             layer.msg(res.msg, {icon: 2}); | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                     layer.close(index); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  |     </script> | ||||||
|  | </body> | ||||||
|  | </html>  | ||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:2:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\resources\cate.php";i:1747387682;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | <?php /*a:2:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\resources\cate.php";i:1747620136;s:61:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\public\header.php";i:1746849526;}*/ ?>
 | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html> | <html> | ||||||
| 	<head> | 	<head> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:1:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\login\index.php";i:1747362104;}*/ ?>
 | <?php /*a:1:{s:59:"E:\Demos\DemoOwns\PHP\yunzer\app\admin\view\login\index.php";i:1747615358;}*/ ?>
 | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="zh-CN"> | <html lang="zh-CN"> | ||||||
| 
 | 
 | ||||||
| @ -41,7 +41,7 @@ | |||||||
|                             </div> |                             </div> | ||||||
|                             <div class="layui-col-xs5"> |                             <div class="layui-col-xs5"> | ||||||
|                                 <div style="margin-left:10px;"> |                                 <div style="margin-left:10px;"> | ||||||
|                                     <img src="<?php echo captcha_src(); ?>" class="layadmin-user-login-codeimg" id="img" |                                     <img src="<?php echo captcha_src(); ?>?t=<?php echo time(); ?>" class="layadmin-user-login-codeimg" id="img" | ||||||
|                                         onclick="reloadImg()"> |                                         onclick="reloadImg()"> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
| @ -76,7 +76,8 @@ | |||||||
|     }); |     }); | ||||||
|     // 重新生成验证码
 |     // 重新生成验证码
 | ||||||
|     function reloadImg() { |     function reloadImg() { | ||||||
|         $('#img').attr('src', '<?php echo captcha_src(); ?>?rand=' + Math.random()); |         var timestamp = new Date().getTime(); | ||||||
|  |         $('#img').attr('src', '<?php echo captcha_src(); ?>?t=' + timestamp); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // 登录处理函数
 |     // 登录处理函数
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?php /*a:5:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\article\detail.php";i:1746841528;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1746865131;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1746841528;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1746709977;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1746865126;}*/ ?>
 | <?php /*a:5:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\article\detail.php";i:1747617615;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:1747445574;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> | ||||||
| 
 | 
 | ||||||
| @ -13,25 +13,34 @@ | |||||||
| 
 | 
 | ||||||
|     <script src="/static/layui/layui.js" charset="utf-8"></script> |     <script src="/static/layui/layui.js" charset="utf-8"></script> | ||||||
|     <script src="/static/js/bootstrap.bundle.js"></script> |     <script src="/static/js/bootstrap.bundle.js"></script> | ||||||
|  |     <script charset="UTF-8" id="LA_COLLECT" src="//www.yunzer.cn/plugins/js-sdk-pro.min.js"></script> | ||||||
|  |     <script>LA.init({ id: "KoyzaWWEcLvPzkQn", ck: "KoyzaWWEcLvPzkQn", autoTrack: true, prefix: 'event' })</script> | ||||||
| </head> | </head> | ||||||
| 
 | 
 | ||||||
| <body> | <body> | ||||||
| <div style="display: flex;flex-direction: column;"> | <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%;"> | ||||||
|                 <ul class="list-unstyled topbar-one__info"> |                 <ul class="list-unstyled topbar-one__info"> | ||||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-phone-alt"></span><a |                     <li class="topbar-one__info__item"> | ||||||
|                             href="tel:629-555-0129">(629) 555-0129</a></li> |                         <span class="topbar-one__info__icon fas fa-phone-alt" style="margin-right: 10px;"></span> | ||||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-envelope"></span><a |                         <a href="<?php echo htmlentities((string) $config['admin_phone']); ?>"><?php echo htmlentities((string) $config['admin_phone']); ?></a>
 | ||||||
|                             href="mailto:info@example.com">info@example.com</a></li> |                     </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> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="topbar-one__social" style="width: 30%;"> |             <div class="topbar-one__social" style="width: 30%;"> | ||||||
|                 <a href="https://facebook.com"><i class="fab fa-facebook-f"></i></a> |                 <a href="/index/user/login" class="mr-10"><i class="layui-icon layui-icon-username"></i> 登录</a> | ||||||
|                 <a href="https://twitter.com"><i class="fab fa-twitter"></i></a> |                 <a href="/index/user/register" class="mr-10"><i class="layui-icon layui-icon-user"></i> 注册</a> | ||||||
|                 <a href="https://instagram.com"><i class="fab fa-instagram"></i></a> |                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||||
|                 <a href="https://www.youtube.com/"><i class="fab fa-linkedin"></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> | ||||||
|     </div> |     </div> | ||||||
| @ -43,15 +52,35 @@ | |||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__nav"> |             <div class="main-menu__nav"> | ||||||
|                 <ul class="main-menu__list"> |                 <ul class="main-menu__list"> | ||||||
|                     <li><a href="index.html">首页</a></li> |                     <li><a href="/index.html">首页</a></li> | ||||||
|                     <li><a href="about.html">关于我们</a></li> |                     <li><a href="/about.html">关于我们</a></li> | ||||||
|                     <li><a href="products.html">产品服务</a></li> |                     <li><a href="/products.html">产品服务</a></li> | ||||||
|                     <li><a href="contact.html">联系我们</a></li> |                     <li><a href="/contact.html">联系我们</a></li> | ||||||
|                 </ul> |                 </ul> | ||||||
|             </div> |             </div> | ||||||
|             <div class="main-menu__right"> |             <div class="main-menu__right"> | ||||||
|                 <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> |                 <div class="layui-inline"> | ||||||
|                 <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> |                     <div class="layui-inline" style="position: relative;"> | ||||||
|  |                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||||
|  |                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||||
|  |                         <div class="user-dropdown" id="userDropdownMain"> | ||||||
|  |                             <ul> | ||||||
|  |                                 <li> | ||||||
|  |                                     <a href="/index/user/profile"><i | ||||||
|  |                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||||
|  |                                 </li> | ||||||
|  |                                 <li> | ||||||
|  |                                     <a href="/index/user/settings"><i | ||||||
|  |                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||||
|  |                                 </li> | ||||||
|  |                                 <li> | ||||||
|  |                                     <a href="javascript:;" class="logout-btn"><i | ||||||
|  |                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||||
|  |                                 </li> | ||||||
|  |                             </ul> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| @ -65,58 +94,320 @@ | |||||||
|         </div> |         </div> | ||||||
|         <div class="sticky-nav__menu"> |         <div class="sticky-nav__menu"> | ||||||
|             <ul> |             <ul> | ||||||
|                 <li><a href="index.html">首页</a></li> |                 <li><a href="/index.html">首页</a></li> | ||||||
|                 <li><a href="about.html">关于我们</a></li> |                 <li><a href="/about.html">关于我们</a></li> | ||||||
|                 <li><a href="products.html">产品服务</a></li> |                 <li><a href="/products.html">产品服务</a></li> | ||||||
|                 <li><a href="contact.html">联系我们</a></li> |                 <li><a href="/contact.html">联系我们</a></li> | ||||||
|             </ul> |             </ul> | ||||||
|         </div> |         </div> | ||||||
|         <div class="sticky-nav__right"> |         <div class="sticky-nav__right"> | ||||||
|             <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> |             <div class="main-menu__right"> | ||||||
|             <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> |                 <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"> | ||||||
|  |                         <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> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <style> | ||||||
|     layui.use(['carousel', 'form'], function () { |     /* 用户头像样式 */ | ||||||
|         var carousel = layui.carousel |     #userAvatar {
 | ||||||
|             , form = layui.form; |         width: 40px; | ||||||
|  |         height: 40px; | ||||||
|  |         cursor: pointer; | ||||||
|  |         transition: all 0.3s ease; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         //图片轮播
 |     #userAvatar:hover {
 | ||||||
|         carousel.render({ |         transform: scale(1.05); | ||||||
|             elem: '#test10' |         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||||||
|             , width: '100%' |     } | ||||||
|             , height: '86vh' | 
 | ||||||
|             , interval: 4000 |     /* 下拉菜单容器 */ | ||||||
|  |     .user-dropdown { | ||||||
|  |         position: absolute; | ||||||
|  |         top: 50px; | ||||||
|  |         right: 0; | ||||||
|  |         width: 160px; | ||||||
|  |         background: #fff;
 | ||||||
|  |         border-radius: 4px; | ||||||
|  |         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); | ||||||
|  |         opacity: 0; | ||||||
|  |         visibility: hidden; | ||||||
|  |         transform: translateY(-10px); | ||||||
|  |         transition: all 0.3s ease; | ||||||
|  |         z-index: 9999; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .user-dropdown.show { | ||||||
|  |         opacity: 1; | ||||||
|  |         visibility: visible; | ||||||
|  |         transform: translateY(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单列表 */ | ||||||
|  |     .user-dropdown ul { | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 5px 0; | ||||||
|  |         list-style: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单项 */ | ||||||
|  |     .user-dropdown li { | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单链接 */ | ||||||
|  |     .user-dropdown li a { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         padding: 10px 15px; | ||||||
|  |         color: #333;
 | ||||||
|  |         text-decoration: none; | ||||||
|  |         transition: all 0.3s ease; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单图标 */ | ||||||
|  |     .user-dropdown li a i { | ||||||
|  |         margin-right: 10px; | ||||||
|  |         font-size: 16px; | ||||||
|  |         color: #666;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单文字 */ | ||||||
|  |     .user-dropdown li a span { | ||||||
|  |         font-size: 14px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 下拉菜单悬停效果 */ | ||||||
|  |     .user-dropdown li a:hover { | ||||||
|  |         background: #f5f5f5;
 | ||||||
|  |         color: #1E9FFF;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .user-dropdown li a:hover i { | ||||||
|  |         color: #1E9FFF;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 分隔线 */ | ||||||
|  |     .user-dropdown li:not(:last-child) { | ||||||
|  |         border-bottom: 1px solid #f0f0f0;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #userDropdownSticky a {
 | ||||||
|  |         color: #0d6efd !important;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* Banner样式 */ | ||||||
|  |     .banner-content { | ||||||
|  |         position: relative; | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         overflow: hidden; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-image { | ||||||
|  |         position: absolute; | ||||||
|  |         top: 0; | ||||||
|  |         left: 0; | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-image img { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         object-fit: cover; | ||||||
|  |         object-position: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-text { | ||||||
|  |         position: absolute; | ||||||
|  |         top: 40%; | ||||||
|  |         left: 10%; | ||||||
|  |         z-index: 1; | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         align-items: flex-start; | ||||||
|  |         color: #fff;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-text a { | ||||||
|  |         text-decoration: none; | ||||||
|  |         margin-top: 30px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-title { | ||||||
|  |         font-size: 4em; | ||||||
|  |         font-weight: 600; | ||||||
|  |         margin-bottom: 10px; | ||||||
|  |         text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-desc { | ||||||
|  |         font-size: 2em; | ||||||
|  |         font-weight: 400; | ||||||
|  |         max-width: 800px; | ||||||
|  |         text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-btn { | ||||||
|  |         background: #fff;
 | ||||||
|  |         color: #000;
 | ||||||
|  |         padding: 10px 20px; | ||||||
|  |         border-radius: 5px; | ||||||
|  |         cursor: pointer; | ||||||
|  |         transition: all 0.3s ease; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-btn:hover { | ||||||
|  |         background: #000;
 | ||||||
|  |         color: #fff;
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-slider { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 86vh; | ||||||
|  |         overflow: hidden; | ||||||
|  |         position: relative; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-container { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-slide { | ||||||
|  |         display: block; | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .banner-slide img { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 100%; | ||||||
|  |         object-fit: cover; | ||||||
|  |         /* 关键:等比缩放并铺满 */ | ||||||
|  |         display: block; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .layui-carousel { | ||||||
|  |         background: #f8f8f8;
 | ||||||
|  |         margin: 0; | ||||||
|  |         padding: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* 确保轮播容器和项目的高度正确 */ | ||||||
|  |     #test10,
 | ||||||
|  |     #test10 [carousel-item],
 | ||||||
|  |     #test10 [carousel-item]>* {
 | ||||||
|  |         height: 86vh !important; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #test10 [carousel-item]>* {
 | ||||||
|  |         background: none !important; | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  |     layui.use(['carousel', 'form', 'layer'], function () { | ||||||
|  |         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||||
|  | 
 | ||||||
|  |         // 加载banner数据
 | ||||||
|  |         $.ajax({ | ||||||
|  |             url: '/index/index/bannerlist', | ||||||
|  |             type: 'GET', | ||||||
|  |             success: function (res) { | ||||||
|  |                 if (res.code === 1) { | ||||||
|  |                     var bannerHtml = ''; | ||||||
|  |                     res.banner.forEach(function (banner) { | ||||||
|  |                         bannerHtml += '<div>' + | ||||||
|  |                             '<div class="banner-content">' + | ||||||
|  |                             '<div class="banner-image">' + | ||||||
|  |                             '<img src="' + banner.image + '" alt="' + (banner.title || '') + '">' + | ||||||
|  |                             '</div>' + | ||||||
|  |                             '<div class="banner-text">' + | ||||||
|  |                             '<span class="banner-title">' + (banner.title || '') + '</span>' + | ||||||
|  |                             '<span class="banner-desc">' + (banner.desc || '') + '</span>' + | ||||||
|  |                             '<a href="' + (banner.url || 'javascript:;') + '" class="banner-slide">' + | ||||||
|  |                             '<span class="banner-btn">查看详情</span>' + | ||||||
|  |                             '</a>' + | ||||||
|  |                             '</div>' + | ||||||
|  |                             '</div>' + | ||||||
|  |                             '</div>'; | ||||||
|  |                     }); | ||||||
|  |                     $('#test10 div[carousel-item]').html(bannerHtml); | ||||||
|  | 
 | ||||||
|  |                     // 图片轮播
 | ||||||
|  |                     carousel.render({ | ||||||
|  |                         elem: '#test10', | ||||||
|  |                         width: '100%', | ||||||
|  |                         height: '100vh', | ||||||
|  |                         interval: 4000, | ||||||
|  |                         anim: 'fade', | ||||||
|  |                         autoplay: true, | ||||||
|  |                         full: false, | ||||||
|  |                         arrow: 'hover' | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         var $ = layui.$, active = { |         $(document).ready(function () { | ||||||
|             set: function (othis) { |             // 主导航头像
 | ||||||
|                 var THIS = 'layui-bg-normal' |             $("#userAvatarMain").click(function (e) { | ||||||
|                     , key = othis.data('key') |                 e.stopPropagation(); | ||||||
|                     , options = {}; |                 $("#userDropdownMain").toggleClass("show"); | ||||||
|  |                 $("#userDropdownSticky").removeClass("show"); // 保证只显示一个
 | ||||||
|  |             }); | ||||||
|  |             // 固定导航头像
 | ||||||
|  |             $("#userAvatarSticky").click(function (e) { | ||||||
|  |                 e.stopPropagation(); | ||||||
|  |                 $("#userDropdownSticky").toggleClass("show"); | ||||||
|  |                 $("#userDropdownMain").removeClass("show"); // 保证只显示一个
 | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|                 othis.css('background-color', '#5FB878').siblings().removeAttr('style'); |             // 点击页面其他地方隐藏所有菜单
 | ||||||
|                 options[key] = othis.data('value'); |             $(document).click(function (e) { | ||||||
|                 ins3.reload(options); |                 if (!$(e.target).closest('.user-dropdown, #userAvatarMain, #userAvatarSticky').length) { | ||||||
|             } |                     $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||||
|         }; |                 } | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|         //监听开关
 |             // 点击菜单项时隐藏菜单
 | ||||||
|         form.on('switch(autoplay)', function () { |             $("#userDropdownMain li a, #userDropdownSticky li a").click(function () { | ||||||
|             ins3.reload({ |                 $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||||
|                 autoplay: this.checked |  | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         $('.demoSet').on('keyup', function () { |         // 退出登录
 | ||||||
|             var value = this.value |         $('.logout-btn').on('click', function () { | ||||||
|                 , options = {}; |             layer.confirm('确定要退出登录吗?', { | ||||||
|             if (!/^\d+$/.test(value)) return; |                 btn: ['确定', '取消'] | ||||||
| 
 |             }, function () { | ||||||
|             options[this.name] = value; |                 window.location.href = '/index/user/logout'; | ||||||
|             ins3.reload(options); |             }); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         // 监听滚动事件
 |         // 监听滚动事件
 | ||||||
| @ -128,49 +419,66 @@ | |||||||
|                 $('.sticky-nav').fadeOut(); |                 $('.sticky-nav').fadeOut(); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         // 公众号二维码
 | ||||||
|  |         const trigger = document.querySelector('.qrcode-trigger'); | ||||||
|  |         const popup = document.querySelector('.qrcode-popup'); | ||||||
|  | 
 | ||||||
|  |         // 鼠标移入显示二维码
 | ||||||
|  |         trigger.addEventListener('mouseenter', function () { | ||||||
|  |             popup.style.display = 'block'; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 鼠标移出隐藏二维码
 | ||||||
|  |         trigger.addEventListener('mouseleave', function () { | ||||||
|  |             popup.style.display = 'none'; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 鼠标移入二维码区域时保持显示
 | ||||||
|  |         popup.addEventListener('mouseenter', function () { | ||||||
|  |             popup.style.display = 'block'; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // 鼠标移出二维码区域时隐藏
 | ||||||
|  |         popup.addEventListener('mouseleave', function () { | ||||||
|  |             popup.style.display = 'none'; | ||||||
|  |         }); | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
| <div class="main"> | <div class="main"> | ||||||
|     <div class="location"> |     <div class="location"> | ||||||
|         <div class="container"> |         <div class="container"> | ||||||
|             <div class="location-item"> |             <div class="location-item"> | ||||||
|                 <a href="<?php echo url('index/index/index'); ?>">首页</a> |                 <a href="/">首页</a> | ||||||
|                 <span>></span> |                 <span>></span> | ||||||
|                 <a href="<?php echo url('index/article/index'); ?>">技术文章</a> |                 <a href="/index/article/index" id="cateLink"></a> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     <div class="article-detail-container"> |     <div class="article-detail-container"> | ||||||
|         <div class="article-header"> |         <div class="article-header"> | ||||||
|             <h1 class="article-title"><?php echo htmlentities((string) $article['title']); ?></h1>
 |             <h1 class="article-title" id="articleTitle"></h1> | ||||||
|             <div class="article-meta"> |             <div class="article-meta"> | ||||||
|                 <span class="article-author"><i class="fa fa-user"></i> <?php echo htmlentities((string) $article['author']); ?></span>
 |                 <span class="article-author"><i class="fa fa-user"></i> <span id="articleAuthor"></span></span> | ||||||
|                 <span class="article-date"><i class="fa fa-calendar"></i> <?php echo htmlentities((string) date('Y-m-d H:i',!is_numeric($article['create_time'])? strtotime($article['create_time']) : $article['create_time'])); ?></span>
 |                 <span class="article-date"><i class="fa fa-calendar"></i> <span id="articleDate"></span></span> | ||||||
|                 <span class="article-category"><i class="fa fa-folder"></i> <?php echo htmlentities((string) $cateName); ?></span>
 |                 <span class="article-views"><i class="fa-solid fa-eye"></i> <span id="articleViews"></span> 阅读</span> | ||||||
|                 <span class="article-views"><i class="fa fa-eye"></i> <?php echo htmlentities((string) $article['views']); ?> 阅读</span>
 |  | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="article-content"> |         <div class="article-content" id="articleContent"> | ||||||
|             <?php echo $article['content']; ?>
 |  | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="article-tags"> |         <div class="article-tags"> | ||||||
|             <span class="tag-label">标签:</span> |             <span class="tag-label">标签:</span> | ||||||
|             <?php if(!empty($article['tags'])): foreach($article['tags'] as $tag): ?>
 |             <div id="articleTags"></div> | ||||||
|             <span class="tag-item"><?php echo htmlentities((string) $tag); ?></span>
 |  | ||||||
|             <?php endforeach; else: ?>
 |  | ||||||
|             <span class="no-tags">暂无标签</span> |  | ||||||
|             <?php endif; ?>
 |  | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="article-actions"> |         <div class="article-actions"> | ||||||
|             <div class="action-item like-btn"> |             <div class="action-item like-btn"> | ||||||
|                 <i class="fa fa-thumbs-up"></i> |                 <i class="fa fa-thumbs-up"></i> | ||||||
|                 <span class="action-text">点赞</span> |                 <span class="action-text">点赞</span> | ||||||
|                 <span class="action-count"><?php echo htmlentities((string) (isset($article['likes']) && ($article['likes'] !== '')?$article['likes']:0)); ?></span>
 |                 <span class="action-count" id="articleLikes">0</span> | ||||||
|             </div> |             </div> | ||||||
|             <div class="action-item share-btn"> |             <div class="action-item share-btn"> | ||||||
|                 <i class="fa fa-share-alt"></i> |                 <i class="fa fa-share-alt"></i> | ||||||
| @ -179,73 +487,17 @@ | |||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="article-navigation"> |         <div class="article-navigation"> | ||||||
|             <div class="prev-article"> |             <div class="prev-article" id="prevArticle"> | ||||||
|                 <?php if(!empty($prevArticle)): ?>
 |  | ||||||
|                 <a href="<?php echo url('index/article/index', ['id' => $prevArticle['id']]); ?>"> |  | ||||||
|                     <i class="fa fa-arrow-left"></i> 上一篇:<?php echo htmlentities((string) $prevArticle['title']); ?>
 |  | ||||||
|                 </a> |  | ||||||
|                 <?php else: ?>
 |  | ||||||
|                 <span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span> |  | ||||||
|                 <?php endif; ?>
 |  | ||||||
|             </div> |             </div> | ||||||
|             <div class="next-article"> |             <div class="next-article" id="nextArticle"> | ||||||
|                 <?php if(!empty($nextArticle)): ?>
 |  | ||||||
|                 <a href="<?php echo url('index/article/index', ['id' => $nextArticle['id']]); ?>"> |  | ||||||
|                     下一篇:<?php echo htmlentities((string) $nextArticle['title']); ?> <i class="fa fa-arrow-right"></i>
 |  | ||||||
|                 </a> |  | ||||||
|                 <?php else: ?>
 |  | ||||||
|                 <span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span> |  | ||||||
|                 <?php endif; ?>
 |  | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="related-articles"> |         <div class="related-articles"> | ||||||
|             <h3 class="related-title">相关推荐</h3> |             <h3 class="related-title">相关推荐</h3> | ||||||
|             <div class="related-list"> |             <div class="related-list" id="relatedArticles"> | ||||||
|                 <?php if(!empty($relatedArticles)): foreach($relatedArticles as $related): ?>
 |  | ||||||
|                 <div class="related-item"> |  | ||||||
|                     <a href="<?php echo url('index/article/index', ['id' => $related['id']]); ?>"> |  | ||||||
|                         <div class="related-image"> |  | ||||||
|                             <img src="<?php echo htmlentities((string) $related['image']); ?>" alt="<?php echo htmlentities((string) $related['title']); ?>"> |  | ||||||
|                         </div> |  | ||||||
|                         <div class="related-info"> |  | ||||||
|                             <div class="related-item-title"><?php echo htmlentities((string) $related['title']); ?></div>
 |  | ||||||
|                             <div class="related-item-desc"><?php echo htmlentities((string) $related['desc']); ?></div>
 |  | ||||||
|                         </div> |  | ||||||
|                     </a> |  | ||||||
|                 </div> |  | ||||||
|                 <?php endforeach; else: ?>
 |  | ||||||
|                 <div class="no-related">暂无相关文章</div> |  | ||||||
|                 <?php endif; ?>
 |  | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
| 
 |  | ||||||
|         <!-- <div class="article-comments"> |  | ||||||
|         <h3 class="comments-title">评论区</h3> |  | ||||||
|         <div class="comment-form"> |  | ||||||
|             <textarea placeholder="请输入您的评论..." class="comment-textarea"></textarea> |  | ||||||
|             <button class="comment-submit">发表评论</button> |  | ||||||
|         </div> |  | ||||||
|         <div class="comment-list"> |  | ||||||
|             <?php if(!empty($comments)): foreach($comments as $comment): ?>
 |  | ||||||
|                     <div class="comment-item"> |  | ||||||
|                         <div class="comment-avatar"> |  | ||||||
|                             <img src="<?php echo htmlentities((string) (isset($comment['avatar']) && ($comment['avatar'] !== '')?$comment['avatar']:'/static/images/default-avatar.png')); ?>" alt="用户头像"> |  | ||||||
|                         </div> |  | ||||||
|                         <div class="comment-content"> |  | ||||||
|                             <div class="comment-user"><?php echo htmlentities((string) $comment['username']); ?></div>
 |  | ||||||
|                             <div class="comment-text"><?php echo htmlentities((string) $comment['content']); ?></div>
 |  | ||||||
|                             <div class="comment-footer"> |  | ||||||
|                                 <span class="comment-time"><?php echo htmlentities((string) date('Y-m-d H:i',!is_numeric($comment['create_time'])? strtotime($comment['create_time']) : $comment['create_time'])); ?></span>
 |  | ||||||
|                                 <span class="comment-reply">回复</span> |  | ||||||
|                             </div> |  | ||||||
|                         </div> |  | ||||||
|                     </div> |  | ||||||
|                 <?php endforeach; else: ?>
 |  | ||||||
|                 <div class="no-comments">暂无评论,快来抢沙发吧!</div> |  | ||||||
|             <?php endif; ?>
 |  | ||||||
|         </div> |  | ||||||
|     </div> --> |  | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| @ -259,7 +511,7 @@ | |||||||
|         <div class="row" style="width: 100%;"> |         <div class="row" style="width: 100%;"> | ||||||
|             <div class="row-main"> |             <div class="row-main"> | ||||||
|                 <div class="mr-20"> |                 <div class="mr-20"> | ||||||
|                     <img src="/static/images/logo-l-w.png" alt="" height="70"> |                     <img src="<?php echo htmlentities((string) $config['logo']); ?>" alt="" height="70"> | ||||||
|                     <p class="text-white-50 my-4 f18" style="width: 400px;">美天智能科技,这里是介绍!</p> |                     <p class="text-white-50 my-4 f18" style="width: 400px;">美天智能科技,这里是介绍!</p> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div style="display: flex; justify-content: space-between;width: 100%;margin-right: 200px;"> |                 <div style="display: flex; justify-content: space-between;width: 100%;margin-right: 200px;"> | ||||||
| @ -291,7 +543,7 @@ | |||||||
| 
 | 
 | ||||||
|                 <div> |                 <div> | ||||||
|                     <div class="text-center"> |                     <div class="text-center"> | ||||||
|                         <img src="/static/images/code.png" alt="微信二维码" class="img-fluid" style="max-width: 150px;"> |                         <img src="<?php echo htmlentities((string) $config['admin_wechat']); ?>" alt="微信二维码" class="img-fluid" style="max-width: 150px;"> | ||||||
|                         <p class="text-white-50 mt-2">微信公众号</p> |                         <p class="text-white-50 mt-2">微信公众号</p> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
| @ -305,6 +557,10 @@ | |||||||
|         <p class="copyright__text">Copyright <span class="dynamic-year">2025</span> | All Rights By <a |         <p class="copyright__text">Copyright <span class="dynamic-year">2025</span> | All Rights By <a | ||||||
|                 href="http://www.yunzer.cn">Yunzer</a></p> |                 href="http://www.yunzer.cn">Yunzer</a></p> | ||||||
|     </div> |     </div> | ||||||
|  |     <div class="tongji"> | ||||||
|  |         <script id="LA-DATA-WIDGET" crossorigin="anonymous" charset="UTF-8" | ||||||
|  |             src="https://v6-widget.51.la/v6/KoyzaWWEcLvPzkQn/quote.js?theme=#1690FF,#FFFFFF,#999999,#FFFFFF,#FFFFFF,#1690FF,12&f=12"></script> | ||||||
|  |     </div> | ||||||
| </section> | </section> | ||||||
| 
 | 
 | ||||||
| <style> | <style> | ||||||
| @ -436,13 +692,14 @@ | |||||||
| 
 | 
 | ||||||
|     .prev-article a, |     .prev-article a, | ||||||
|     .next-article a { |     .next-article a { | ||||||
|         color: #333;
 |         color: #333 !important;
 | ||||||
|         text-decoration: none; |         text-decoration: none; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .prev-article a:hover, |     .prev-article a:hover, | ||||||
|     .next-article a:hover { |     .next-article a:hover { | ||||||
|         color: #f57005;
 |         color: #f57005 !important;
 | ||||||
|  |         transition: all 0.3s ease; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .disabled { |     .disabled { | ||||||
| @ -654,33 +911,159 @@ | |||||||
|             height: 36px; |             height: 36px; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .location-item a { | ||||||
|  |         color: #000 !important;
 | ||||||
|  |     } | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|     document.addEventListener('DOMContentLoaded', function () { |     // 格式化日期
 | ||||||
|  |     function formatDate(timestamp) { | ||||||
|  |         const date = new Date(timestamp * 1000); | ||||||
|  |         return date.toLocaleDateString('zh-CN', { | ||||||
|  |             year: 'numeric', | ||||||
|  |             month: '2-digit', | ||||||
|  |             day: '2-digit' | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 渲染文章详情
 | ||||||
|  |     function renderArticleDetail(data) { | ||||||
|  |         // 渲染分类链接
 | ||||||
|  |         document.getElementById('cateLink').textContent = data.cateName; | ||||||
|  |          | ||||||
|  |         // 渲染文章标题
 | ||||||
|  |         document.getElementById('articleTitle').textContent = data.article.title; | ||||||
|  |          | ||||||
|  |         // 渲染文章元信息
 | ||||||
|  |         document.getElementById('articleAuthor').textContent = data.article.author; | ||||||
|  |         document.getElementById('articleDate').textContent = formatDate(data.article.create_time); | ||||||
|  |         document.getElementById('articleViews').textContent = data.article.views; | ||||||
|  |          | ||||||
|  |         // 渲染文章内容
 | ||||||
|  |         document.getElementById('articleContent').innerHTML = data.article.content; | ||||||
|  |          | ||||||
|  |         // 渲染标签
 | ||||||
|  |         const tagsContainer = document.getElementById('articleTags'); | ||||||
|  |         if (data.article.tags && data.article.tags.length > 0) { | ||||||
|  |             tagsContainer.innerHTML = data.article.tags.map(tag =>  | ||||||
|  |                 `<span class="tag-item">${tag}</span>` | ||||||
|  |             ).join(''); | ||||||
|  |         } else { | ||||||
|  |             tagsContainer.innerHTML = '<span class="no-tags">暂无标签</span>'; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // 渲染点赞数
 | ||||||
|  |         document.getElementById('articleLikes').textContent = data.article.likes || 0; | ||||||
|  |          | ||||||
|  |         // 渲染上一篇
 | ||||||
|  |         const prevArticle = document.getElementById('prevArticle'); | ||||||
|  |         if (data.prevArticle) { | ||||||
|  |             prevArticle.innerHTML = ` | ||||||
|  |                 <a href="/index/article/detail?id=${data.prevArticle.id}"> | ||||||
|  |                     <i class="fa fa-arrow-left"></i> 上一篇:${data.prevArticle.title} | ||||||
|  |                 </a> | ||||||
|  |             `; | ||||||
|  |         } else { | ||||||
|  |             prevArticle.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span>'; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // 渲染下一篇
 | ||||||
|  |         const nextArticle = document.getElementById('nextArticle'); | ||||||
|  |         if (data.nextArticle) { | ||||||
|  |             nextArticle.innerHTML = ` | ||||||
|  |                 <a href="/index/article/detail?id=${data.nextArticle.id}"> | ||||||
|  |                     下一篇:${data.nextArticle.title} <i class="fa fa-arrow-right"></i> | ||||||
|  |                 </a> | ||||||
|  |             `; | ||||||
|  |         } else { | ||||||
|  |             nextArticle.innerHTML = '<span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span>'; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // 渲染相关文章
 | ||||||
|  |         const relatedArticles = document.getElementById('relatedArticles'); | ||||||
|  |         if (data.relatedArticles && data.relatedArticles.length > 0) { | ||||||
|  |             relatedArticles.innerHTML = data.relatedArticles.map(article => ` | ||||||
|  |                 <div class="related-item"> | ||||||
|  |                     <a href="/index/article/detail?id=${article.id}"> | ||||||
|  |                         <div class="related-image"> | ||||||
|  |                             <img src="${article.image}" alt="${article.title}"> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="related-info"> | ||||||
|  |                             <div class="related-item-title">${article.title}</div> | ||||||
|  |                             <div class="related-item-desc">${article.desc || ''}</div> | ||||||
|  |                         </div> | ||||||
|  |                     </a> | ||||||
|  |                 </div> | ||||||
|  |             `).join(''); | ||||||
|  |         } else { | ||||||
|  |             relatedArticles.innerHTML = '<div class="no-related">暂无相关文章</div>'; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 页面加载完成后执行
 | ||||||
|  |     document.addEventListener('DOMContentLoaded', function() { | ||||||
|  |         // 获取文章ID
 | ||||||
|  |         const articleId = new URLSearchParams(window.location.search).get('id'); | ||||||
|  |         if (!articleId) { | ||||||
|  |             alert('文章ID不存在'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 获取文章详情
 | ||||||
|  |         fetch(`/index/article/detail?id=${articleId}`, { | ||||||
|  |             headers: { | ||||||
|  |                 'X-Requested-With': 'XMLHttpRequest' | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |             .then(response => { | ||||||
|  |                 console.log('Response status:', response.status); | ||||||
|  |                 console.log('Response headers:', response.headers); | ||||||
|  |                 return response.json(); | ||||||
|  |             }) | ||||||
|  |             .then(result => { | ||||||
|  |                 console.log('API response:', result); | ||||||
|  |                 if (result.code === 1) { | ||||||
|  |                     renderArticleDetail(result.data); | ||||||
|  |                     // 更新访问次数
 | ||||||
|  |                     updateArticleViews(articleId); | ||||||
|  |                 } else { | ||||||
|  |                     console.error('API error:', result.msg); | ||||||
|  |                     alert(result.msg || '获取文章详情失败'); | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .catch(error => { | ||||||
|  |                 console.error('获取文章详情失败:', error); | ||||||
|  |                 console.error('Error details:', { | ||||||
|  |                     message: error.message, | ||||||
|  |                     stack: error.stack | ||||||
|  |                 }); | ||||||
|  |                 alert('获取文章详情失败,请检查网络连接或刷新页面重试'); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|         // 点赞功能
 |         // 点赞功能
 | ||||||
|         const likeBtn = document.querySelector('.like-btn'); |         const likeBtn = document.querySelector('.like-btn'); | ||||||
|         if (likeBtn) { |         if (likeBtn) { | ||||||
|             likeBtn.addEventListener('click', function () { |             likeBtn.addEventListener('click', function() { | ||||||
|                 const articleId = '<?php echo htmlentities((string) $article['id']); ?>'; |  | ||||||
|                 fetch('/index/article/like?id=' + articleId, { |                 fetch('/index/article/like?id=' + articleId, { | ||||||
|                     method: 'POST' |                     method: 'POST' | ||||||
|                 }) |                 }) | ||||||
|                     .then(response => response.json()) |                 .then(response => response.json()) | ||||||
|                     .then(data => { |                 .then(data => { | ||||||
|                         if (data.code === 1) { |                     if (data.code === 1) { | ||||||
|                             const countElement = this.querySelector('.action-count'); |                         const countElement = this.querySelector('.action-count'); | ||||||
|                             let count = parseInt(countElement.textContent); |                         let count = parseInt(countElement.textContent); | ||||||
|                             countElement.textContent = count + 1; |                         countElement.textContent = count + 1; | ||||||
|                             this.classList.add('liked'); |                         this.classList.add('liked'); | ||||||
|                             this.style.color = '#f57005'; |                         this.style.color = '#f57005'; | ||||||
|                         } else { |                     } else { | ||||||
|                             alert('点赞失败:' + data.msg); |                         alert('点赞失败:' + data.msg); | ||||||
|                         } |                     } | ||||||
|                     }) |                 }) | ||||||
|                     .catch(error => { |                 .catch(error => { | ||||||
|                         console.error('点赞请求失败:', error); |                     console.error('点赞请求失败:', error); | ||||||
|                     }); |                 }); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -704,6 +1087,32 @@ | |||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     // 更新文章访问次数
 | ||||||
|  |     function updateArticleViews(articleId) { | ||||||
|  |         fetch('/index/article/updateViews', { | ||||||
|  |             method: 'POST', | ||||||
|  |             headers: { | ||||||
|  |                 'Content-Type': 'application/json', | ||||||
|  |             }, | ||||||
|  |             body: JSON.stringify({ | ||||||
|  |                 id: articleId | ||||||
|  |             }) | ||||||
|  |         }) | ||||||
|  |         .then(response => response.json()) | ||||||
|  |         .then(result => { | ||||||
|  |             if (result.code === 1) { | ||||||
|  |                 // 更新成功,更新页面上的访问次数显示
 | ||||||
|  |                 const viewsElement = document.getElementById('articleViews'); | ||||||
|  |                 if (viewsElement) { | ||||||
|  |                     viewsElement.textContent = result.data.views; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .catch(error => { | ||||||
|  |             console.error('更新访问次数失败:', error); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
| </script> | </script> | ||||||
| </body> | </body> | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user