443 lines
11 KiB
PHP
443 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* 后台管理系统-首页
|
|
*/
|
|
namespace app\admin\controller;
|
|
use app\admin\controller\Base;
|
|
use think\facade\Db;
|
|
use think\facade\View;
|
|
use think\facade\Env;
|
|
use think\facade\Config;
|
|
|
|
class Index extends Base{
|
|
# 首页
|
|
public function index(){
|
|
$menus = [];
|
|
$menu = [];
|
|
$where = ['group_id'=>$this->aUser['group_id']];
|
|
$role = Db::table('yz_admin_user_group')->where($where)->find();
|
|
if($role){
|
|
$role['rights'] = (isset($role['rights']) && $role['rights']) ? json_decode($role['rights'],true) : [];
|
|
}
|
|
if($role['rights']){
|
|
$where = [
|
|
['smid','in',implode(',',$role['rights']) ],
|
|
['status','=',1]
|
|
];
|
|
// 获取所有菜单
|
|
$menus = Db::table('yz_admin_sys_menu')->order('type,sort desc')->where($where)->select()->toArray();
|
|
|
|
// 构建树形结构菜单
|
|
$menuTree = [];
|
|
$menuMap = [];
|
|
|
|
// 先将所有菜单项映射到一个关联数组中
|
|
foreach($menus as $item){
|
|
$item['children'] = [];
|
|
$menuMap[$item['smid']] = $item;
|
|
}
|
|
|
|
// 构建树形结构
|
|
foreach($menus as $item){
|
|
if($item['parent_id'] == 0){
|
|
// 顶级菜单
|
|
$menuTree[$item['smid']] = &$menuMap[$item['smid']];
|
|
}else{
|
|
// 子菜单,添加到父菜单的children数组中
|
|
if(isset($menuMap[$item['parent_id']])){
|
|
$menuMap[$item['parent_id']]['children'][] = &$menuMap[$item['smid']];
|
|
}
|
|
}
|
|
}
|
|
|
|
$menu = $menuTree;
|
|
}
|
|
|
|
View::assign([
|
|
'role' => $role,
|
|
'menu' => $menu
|
|
]);
|
|
return View::fetch();
|
|
}
|
|
# 欢迎页面
|
|
public function welcome(){
|
|
// 获取今日统计数据
|
|
$today = date('Y-m-d');
|
|
$todayStats = Db::name('yz_daily_stats')
|
|
->where('date', $today)
|
|
->find();
|
|
|
|
// 获取最近7天的访问趋势
|
|
$last7Days = Db::name('yz_daily_stats')
|
|
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
|
|
->where('date', '<=', $today)
|
|
->order('date', 'asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取用户增长趋势
|
|
$userGrowth = Db::name('yz_daily_stats')
|
|
->where('date', '>=', date('Y-m-d', strtotime('-30 days')))
|
|
->where('date', '<=', $today)
|
|
->field('date, new_users, total_users')
|
|
->order('date', 'asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取资源下载统计
|
|
$resourceStats = Db::name('yz_daily_stats')
|
|
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
|
|
->where('date', '<=', $today)
|
|
->field('date, daily_resources, resource_downloads')
|
|
->order('date', 'asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取文章访问统计
|
|
$articleStats = Db::name('yz_daily_stats')
|
|
->where('date', '>=', date('Y-m-d', strtotime('-7 days')))
|
|
->where('date', '<=', $today)
|
|
->field('date, daily_articles, article_views')
|
|
->order('date', 'asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
// 获取最近的活动记录
|
|
$recentActivities = $this->getRecentActivities();
|
|
|
|
// 准备图表数据
|
|
$chartData = [
|
|
'visitTrend' => $this->formatVisitTrendData($last7Days),
|
|
'userGrowth' => $this->formatUserGrowthData($userGrowth),
|
|
'resourceStats' => $this->formatResourceStatsData($resourceStats),
|
|
'articleStats' => $this->formatArticleStatsData($articleStats)
|
|
];
|
|
|
|
// 准备统计数据
|
|
$stats = [
|
|
'total_users' => $todayStats['total_users'] ?? 0,
|
|
'daily_visits' => $todayStats['daily_visits'] ?? 0,
|
|
'total_articles' => $todayStats['total_articles'] ?? 0,
|
|
'total_resources' => $todayStats['total_resources'] ?? 0,
|
|
];
|
|
|
|
return View::fetch('', [
|
|
'stats' => $stats,
|
|
'chartData' => $chartData,
|
|
'recentActivities' => $recentActivities
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 获取最近的活动记录
|
|
*/
|
|
private function getRecentActivities()
|
|
{
|
|
$today = date('Y-m-d');
|
|
$activities = [];
|
|
|
|
// 获取今日新用户
|
|
$newUsers = Db::name('yz_daily_stats')
|
|
->where('date', $today)
|
|
->value('new_users');
|
|
if ($newUsers > 0) {
|
|
$activities[] = [
|
|
'icon' => '👥',
|
|
'title' => '新增用户 ' . $newUsers . ' 人',
|
|
'time' => '今日'
|
|
];
|
|
}
|
|
|
|
// 获取今日文章
|
|
$newArticles = Db::name('yz_daily_stats')
|
|
->where('date', $today)
|
|
->value('daily_articles');
|
|
if ($newArticles > 0) {
|
|
$activities[] = [
|
|
'icon' => '📝',
|
|
'title' => '发布文章 ' . $newArticles . ' 篇',
|
|
'time' => '今日'
|
|
];
|
|
}
|
|
|
|
// 获取今日资源
|
|
$newResources = Db::name('yz_daily_stats')
|
|
->where('date', $today)
|
|
->value('daily_resources');
|
|
if ($newResources > 0) {
|
|
$activities[] = [
|
|
'icon' => '📦',
|
|
'title' => '上传资源 ' . $newResources . ' 个',
|
|
'time' => '今日'
|
|
];
|
|
}
|
|
|
|
return $activities;
|
|
}
|
|
|
|
/**
|
|
* 格式化访问趋势数据
|
|
*/
|
|
private function formatVisitTrendData($data)
|
|
{
|
|
$dates = [];
|
|
$visits = [];
|
|
$uvs = [];
|
|
|
|
foreach ($data as $item) {
|
|
$dates[] = date('m-d', strtotime($item['date']));
|
|
$visits[] = $item['daily_visits'];
|
|
$uvs[] = $item['unique_visitors'];
|
|
}
|
|
|
|
return [
|
|
'dates' => $dates,
|
|
'visits' => $visits,
|
|
'uvs' => $uvs
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 格式化用户增长数据
|
|
*/
|
|
private function formatUserGrowthData($data)
|
|
{
|
|
$dates = [];
|
|
$newUsers = [];
|
|
$totalUsers = [];
|
|
|
|
foreach ($data as $item) {
|
|
$dates[] = date('m-d', strtotime($item['date']));
|
|
$newUsers[] = $item['new_users'];
|
|
$totalUsers[] = $item['total_users'];
|
|
}
|
|
|
|
return [
|
|
'dates' => $dates,
|
|
'newUsers' => $newUsers,
|
|
'totalUsers' => $totalUsers
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 格式化资源统计数据
|
|
*/
|
|
private function formatResourceStatsData($data)
|
|
{
|
|
$dates = [];
|
|
$resources = [];
|
|
$downloads = [];
|
|
|
|
foreach ($data as $item) {
|
|
$dates[] = date('m-d', strtotime($item['date']));
|
|
$resources[] = $item['daily_resources'];
|
|
$downloads[] = $item['resource_downloads'];
|
|
}
|
|
|
|
return [
|
|
'dates' => $dates,
|
|
'resources' => $resources,
|
|
'downloads' => $downloads
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 格式化文章统计数据
|
|
*/
|
|
private function formatArticleStatsData($data)
|
|
{
|
|
$dates = [];
|
|
$articles = [];
|
|
$views = [];
|
|
|
|
foreach ($data as $item) {
|
|
$dates[] = date('m-d', strtotime($item['date']));
|
|
$articles[] = $item['daily_articles'];
|
|
$views[] = $item['article_views'];
|
|
}
|
|
|
|
return [
|
|
'dates' => $dates,
|
|
'articles' => $articles,
|
|
'views' => $views
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 保存附件信息到数据库
|
|
* @param string $name 文件名
|
|
* @param int $type 附件类型
|
|
* @param int $size 文件大小
|
|
* @param string $src 文件路径
|
|
* @return int 附件ID
|
|
*/
|
|
private function saveAttachment($name, $type, $size, $src) {
|
|
$data = [
|
|
'name' => $name,
|
|
'type' => $type,
|
|
'size' => $size,
|
|
'src' => $src,
|
|
'create_time' => time(),
|
|
'update_time' => time()
|
|
];
|
|
return Db::table('yz_attachments')->insertGetId($data);
|
|
}
|
|
|
|
# 图片上传
|
|
public function upload_img(){
|
|
// 获取上传的文件
|
|
$file = request()->file();
|
|
$files = request()->file('file');
|
|
|
|
// 检查是否有文件上传
|
|
if(empty($file)){
|
|
return json(['code'=>1, 'msg'=>'没有文件上传'])->send();
|
|
}
|
|
|
|
try {
|
|
// 验证上传的文件
|
|
validate([
|
|
'image'=>'filesize:10240|fileExt:jpg,png,gif,jpeg'
|
|
])->check($file);
|
|
|
|
// 存储文件到public磁盘的uploads目录
|
|
$info = \think\facade\Filesystem::disk('public')->putFile('uploads', $files);
|
|
|
|
// 处理文件路径,统一使用正斜杠
|
|
$info = str_replace("\\", "/", $info);
|
|
$img = '/storage/'.$info;
|
|
|
|
// 保存附件信息
|
|
$fileName = $files->getOriginalName();
|
|
$fileSize = $files->getSize();
|
|
$attachmentId = $this->saveAttachment($fileName, 1, $fileSize, $img); // 1: 图片
|
|
|
|
// 返回成功信息
|
|
return json([
|
|
'code' => 0,
|
|
'data' => $img,
|
|
'url' => $this->config['admin_domain'].$img,
|
|
'attachment_id' => $attachmentId
|
|
])->send();
|
|
|
|
} catch (\think\exception\ValidateException $e) {
|
|
// 捕获验证异常并返回错误信息
|
|
return json(['code'=>1, 'msg'=>$e->getMessage()])->send();
|
|
} catch (\Exception $e) {
|
|
// 捕获其他异常
|
|
return json(['code'=>1, 'msg'=>'上传失败:'.$e->getMessage()])->send();
|
|
}
|
|
}
|
|
# 清除缓存
|
|
public function clear(){
|
|
$a = delete_dir_file(Env::get('runtime_path').'cache/');
|
|
$b = delete_dir_file(Env::get('runtime_path').'temp/');
|
|
if ($a || $b) {
|
|
$this->returnCode(0, '清除缓存成功');
|
|
} else {
|
|
$this->returnCode(1, '清除缓存失败');
|
|
}
|
|
}
|
|
# 文件上传
|
|
public function upload_file(){
|
|
$file = request()->file();
|
|
$files = request()->file('file');
|
|
if(empty($file)){
|
|
return json(['code'=>1, 'msg'=>'没有文件上传'])->send();
|
|
}
|
|
try {
|
|
// 只验证文件扩展名,不验证大小
|
|
validate([
|
|
'file'=>'fileExt:doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,7z'
|
|
])->check($file);
|
|
|
|
$info = \think\facade\Filesystem::disk('public')->putFile('uploads/files', $files);
|
|
|
|
// 处理文件路径
|
|
$info = str_replace("\\", "/", $info);
|
|
$filePath = '/storage/'.$info;
|
|
|
|
// 保存附件信息
|
|
$fileName = $files->getOriginalName();
|
|
$fileSize = $files->getSize();
|
|
$attachmentId = $this->saveAttachment($fileName, 2, $fileSize, $filePath); // 2: 文件
|
|
|
|
return json([
|
|
'code' => 0,
|
|
'data' => [
|
|
'src' => $filePath,
|
|
'attachment_id' => $attachmentId
|
|
]
|
|
])->send();
|
|
} catch (\think\exception\ValidateException $e) {
|
|
return json(['code'=>1, 'msg'=>$e->getMessage()])->send();
|
|
} catch (\Exception $e) {
|
|
return json(['code'=>1, 'msg'=>'上传失败:'.$e->getMessage()])->send();
|
|
}
|
|
}
|
|
|
|
# 视频上传
|
|
public function upload_video(){
|
|
$file = request()->file();
|
|
$files = request()->file('file');
|
|
if(empty($file)){
|
|
return json(['code'=>1, 'msg'=>'没有文件上传'])->send();
|
|
}
|
|
try {
|
|
validate(['video'=>'filesize:102400|fileExt:mp4,avi,mov,wmv,flv'])->check($file);
|
|
$info = \think\facade\Filesystem::disk('public')->putFile('uploads/videos', $files);
|
|
|
|
// 处理文件路径
|
|
$info = str_replace("\\", "/", $info);
|
|
$videoPath = '/storage/'.$info;
|
|
|
|
// 保存附件信息
|
|
$fileName = $files->getOriginalName();
|
|
$fileSize = $files->getSize();
|
|
$attachmentId = $this->saveAttachment($fileName, 3, $fileSize, $videoPath); // 3: 视频
|
|
|
|
return json([
|
|
'code' => 0,
|
|
'data' => [
|
|
'src' => $videoPath,
|
|
'attachment_id' => $attachmentId
|
|
]
|
|
])->send();
|
|
} catch (\think\exception\ValidateException $e) {
|
|
return json(['code'=>1, 'msg'=>$e->getMessage()])->send();
|
|
}
|
|
}
|
|
|
|
# 音频上传
|
|
public function upload_audio(){
|
|
$file = request()->file();
|
|
$files = request()->file('file');
|
|
if(empty($file)){
|
|
return json(['code'=>1, 'msg'=>'没有文件上传'])->send();
|
|
}
|
|
try {
|
|
validate(['audio'=>'filesize:51200|fileExt:mp3,wav,ogg,m4a'])->check($file);
|
|
$info = \think\facade\Filesystem::disk('public')->putFile('uploads/audios', $files);
|
|
|
|
// 处理文件路径
|
|
$info = str_replace("\\", "/", $info);
|
|
$audioPath = '/storage/'.$info;
|
|
|
|
// 保存附件信息
|
|
$fileName = $files->getOriginalName();
|
|
$fileSize = $files->getSize();
|
|
$attachmentId = $this->saveAttachment($fileName, 4, $fileSize, $audioPath); // 4: 音频
|
|
|
|
return json([
|
|
'code' => 0,
|
|
'data' => [
|
|
'src' => $audioPath,
|
|
'attachment_id' => $attachmentId
|
|
]
|
|
])->send();
|
|
} catch (\think\exception\ValidateException $e) {
|
|
return json(['code'=>1, 'msg'=>$e->getMessage()])->send();
|
|
}
|
|
}
|
|
|
|
} |