first commit

This commit is contained in:
2025-07-14 14:48:36 +08:00
commit 0c7237da45
637 changed files with 117431 additions and 0 deletions
+508
View File
@@ -0,0 +1,508 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-文章管理
*/
namespace app\admin\controller;
use app\admin\model\Article\Articles;
use app\admin\model\Article\ArticlesCategory;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
use app\admin\controller\LogController as Log;
use app\admin\controller\BaseController;
class ArticlesController extends BaseController
{
/**
* 获取控制器名称
* @return string
*/
public function getControllerName()
{
return 'Article';
}
// 文章列表
public function articlelist()
{
if (Request::isPost()) {
$category = input('post.category');
$page = intval(input('post.page', 1));
$limit = intval(input('post.limit', 10));
$title = input('post.title');
$author = input('post.author');
$query = Articles::where('delete_time', null)
->where('status', '<>', 3);
// 分类筛选
if (!empty($category)) {
// 先获取分类ID
$cateInfo = ArticlesCategory::where('name', $category)
->where('delete_time', null)
->where('status', 1)
->find();
if ($cateInfo) {
$query = $query->where('cate', $cateInfo['id']);
}
}
// 标题搜索
if (!empty($title)) {
$query = $query->where('title', 'like', '%'.$title.'%');
}
// 作者搜索
if (!empty($author)) {
$query = $query->where('author', 'like', '%'.$author.'%');
}
// 获取总记录数
$count = $query->count();
// 获取分页数据
$lists = $query->order('id DESC')
->page($page, $limit)
->select()
->each(function ($item) {
// 获取分类信息
$cateInfo = ArticlesCategory::where('id', $item['cate'])
->field('name, image')
->find();
// 设置分类名称
$item['cate'] = $cateInfo ? $cateInfo['name'] : '';
// 如果文章没有图片,使用分类的图片
if (empty($item['image']) && $cateInfo && !empty($cateInfo['image'])) {
$item['image'] = $cateInfo['image'];
}
// 格式化时间
$item['create_time'] = is_numeric($item['create_time']) ? date('Y-m-d H:i:s', $item['create_time']) : $item['create_time'];
$item['publishdate'] = is_numeric($item['publishdate']) ? date('Y-m-d H:i:s', $item['publishdate']) : '';
return $item;
});
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $lists
]);
} else {
// 获取所有分类并构建父子结构
$allCategories = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
$categories = [];
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([
'categories' => $categories
]);
return View::fetch();
}
}
// 添加文章
public function add()
{
if (Request::isPost()) {
$data = [
'title' => input('post.title'),
'cate' => input('post.cate'),
'image' => input('post.image'),
'content' => input('post.content'),
'author' => input('post.author'),
'desc' => input('post.desc'),
'status' => input('post.status', 2),
'publishdate' => time(),
'create_time' => time()
];
$insert = Articles::insert($data);
if (empty($insert)) {
Log::record('添加文章', 0, '添加文章失败', '文章管理');
return json(['code' => 1, 'msg' => '添加失败', 'data' => []]);
}
Log::record('添加文章', 1, '', '文章管理');
return json(['code' => 0, 'msg' => '添加成功', 'data' => []]);
} else {
$lists = Articles::order('id DESC')
->select()
->each(function ($item, $key) {
$item['create_time'] = time();
return $item;
});
View::assign([
'lists' => $lists
]);
return View::fetch();
}
}
// 编辑文章
public function edit()
{
if (Request::isPost()) {
$id = input('get.id');
$data = [
'title' => input('post.title'),
'cate' => input('post.cate'),
'image' => input('post.image'),
'content' => input('post.content'),
'author' => input('post.author'),
'desc' => input('post.desc'),
'status' => input('post.status', 2),
'update_time' => time()
];
$update = Articles::where('id', $id)->update($data);
if ($update === false) {
Log::record('编辑文章', 0, '编辑文章失败', '文章管理');
return json(['code' => 1, 'msg' => '更新失败', 'data' => []]);
}
Log::record('编辑文章', 1, '', '文章管理');
return json(['code' => 0, 'msg' => '更新成功', 'data' => []]);
} else {
$id = input('get.id');
$info = Articles::where('id', $id)->find();
if ($info === null) {
return json(['code' => 1, 'msg' => '文章不存在', 'data' => []]);
}
$cates = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
$info['content'] = !empty($info['content']) ? htmlspecialchars_decode(str_replace(["\r\n", "\r", "\n"], '', addslashes($info['content']))) : '';
$currentCate = ArticlesCategory::where('id', $info['cate'])
->where('delete_time', null)
->where('status', 1)
->find();
$info['cate_name'] = $currentCate ? $currentCate['name'] : '';
View::assign([
'info' => $info,
'cates' => $cates
]);
return View::fetch();
}
}
// 删除文章
public function delete()
{
$id = input('post.id');
$data = [
'delete_time' => time(),
];
$delete = Articles::where('id', $id)->update($data);
if ($delete === false) {
Log::record('删除文章', 0, '删除文章失败', '文章管理');
return json(['code' => 1, 'msg' => '删除失败', 'data' => []]);
}
Log::record('删除文章', 1, '', '文章管理');
return json(['code' => 0, 'msg' => '删除成功', 'data' => []]);
}
// 文章分类
public function articlecate()
{
if (Request::isPost()) {
$lists = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
// 构建树形结构
$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]);
}
// 非 POST 请求返回视图
return View::fetch();
}
//获取分类结构
public function getcate()
{
// 获取所有分类
$lists = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
// 构建父子结构
$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]);
}
// 添加文章分类
public function cateadd()
{
if (Request::isPost()) {
$data = [
'name' => input('post.name'),
'image' => input('post.image'),
'cid' => input('post.cid'),
'sort' => input('post.sort', 0),
'status' => input('post.status', 1),
'create_time' => time()
];
$insert = ArticlesCategory::insert($data);
if (empty($insert)) {
Log::record('添加文章分类', 0, '添加文章分类失败', '文章分类');
return json(['code' => 1, 'msg' => '添加失败', 'data' => []]);
}
Log::record('添加文章分类', 1, '', '文章分类');
return json(['code' => 0, 'msg' => '添加成功', 'data' => []]);
} else {
// 获取所有可选的父级分类
$parentCategories = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->where('cid', 0)
->field('id, name')
->select()
->toArray();
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'parentOptions' => $parentCategories
]
]);
}
}
//编辑文章分类
public function cateedit()
{
if (Request::isPost()) {
$data = [
'id' => input('post.id'),
'name' => input('post.name'),
'image' => input('post.image'),
'cid' => input('post.cid'),
'sort' => input('post.sort', 0),
'status' => input('post.status', 1),
'update_time' => time()
];
$update = ArticlesCategory::where('id', $data['id'])
->update($data);
if ($update === false) {
Log::record('编辑文章分类', 0, '更新文章分类失败', '文章分类');
return json(['code' => 1, 'msg' => '更新失败', 'data' => []]);
}
Log::record('编辑文章分类', 1, '', '文章分类');
return json(['code' => 0, 'msg' => '更新成功', 'data' => []]);
} else {
$id = input('get.id');
$info = ArticlesCategory::where('id', $id)->find();
// 获取所有可选的父级分类
$parentCategories = ArticlesCategory::where('delete_time', null)
->where('status', 1)
->where('id', '<>', $id) // 排除自己
->where(function ($query) use ($id) {
// 排除自己的所有子分类
$query->where('cid', '<>', $id);
})
->field('id, name, cid')
->select()
->toArray();
// 构建父级分类选项
$parentOptions = [];
foreach ($parentCategories as $category) {
if ($category['cid'] == 0) {
$parentOptions[] = [
'id' => $category['id'],
'name' => $category['name']
];
}
}
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'info' => $info,
'parentOptions' => $parentOptions
]
]);
}
}
//删除文章分类
public function catedel()
{
$id = input('post.id');
// 检查是否有子分类
$hasChildren = ArticlesCategory::where('cid', $id)
->where('delete_time', null)
->find();
if ($hasChildren) {
Log::record('删除文章分类', 0, '该分类下有子分类,无法删除', '文章分类');
return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]);
}
$delete = ArticlesCategory::where('id', $id)
->update(['delete_time' => time()]);
if ($delete === false) {
Log::record('删除文章分类', 0, '删除文章分类失败', '文章分类');
return json(['code' => 1, 'msg' => '删除失败', 'data' => []]);
}
Log::record('删除文章分类', 1, '', '文章分类');
return json(['code' => 0, 'msg' => '删除成功', 'data' => []]);
}
//统计文章数量
public function counts() {
try {
// 获取文章总数
$total = Articles::where('delete_time', null)
->where('status', '<>', 3)
->count();
// 获取今日新增文章数
$today = strtotime(date('Y-m-d'));
$todayNew = Articles::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '>=', $today)
->count();
// 获取最近7天的文章数据
$dates = [];
$counts = [];
$totalCounts = []; // 存储每天的总文章数
$totalSoFar = 0; // 用于累计总文章数
for ($i = 6; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i days"));
$start = strtotime($date);
$end = $start + 86400;
// 获取当天新增文章数
$count = Articles::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '>=', $start)
->where('create_time', '<', $end)
->count();
// 获取截至当天的总文章数
$totalCount = Articles::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '<', $end)
->count();
$dates[] = $date;
$counts[] = $count;
$totalCounts[] = $totalCount;
}
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'total' => $total,
'todayNew' => $todayNew,
'dates' => $dates,
'counts' => $counts,
'totalCounts' => $totalCounts
]
]);
} catch (\Exception $e) {
return json([
'code' => 1,
'msg' => '获取失败:' . $e->getMessage()
]);
}
}
}
+181
View File
@@ -0,0 +1,181 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-管理员
*/
namespace app\admin\controller;
use app\AppApi;
use think\facade\Db;
use think\facade\View;
use think\facade\Cookie;
use think\facade\Config;
use app\admin\model\YzAdminConfig;
use think\exception\HttpResponseException;
use think\facade\Request;
use think\facade\Route;
use think\App;
class Base
{
protected $app;
protected $request;
public $adminId = null;
public $config = [];
public $aUser = [];
public function __construct()
{
date_default_timezone_set('PRC');
# 获取配置
$YzAdminConfig = new YzAdminConfig();
$this->config = $YzAdminConfig->getAll();
# 获取账户,账户判断
$this->adminId = Cookie::get('admin_id');
if (empty($this->adminId)) {
header('Location:' . $this->config['admin_route'] . 'Login/index');
exit;
}
$this->aUser = Db::table('yz_admin_user')->where('uid', $this->adminId)->find();
if (empty($this->aUser)) {
Cookie::delete('admin_id');
$this->error('管理员账户不存在');
}
if ($this->aUser['status'] != 1) {
Cookie::delete('admin_id');
$this->error('管理员已被禁用');
}
# 获取用户组权限
$group = Db::table('yz_admin_user_group')->where(['group_id' => $this->aUser['group_id']])->find();
if (empty($group)) {
$this->error('对不起,您没有权限');
}
# 获取当前链接,查询是否有权限
$controller = request()->controller();
$action = request()->action();
$key = $controller . '/' . $action;
View::assign([
'aUser' => $this->aUser,
'config' => $this->config
]);
}
/**
* 返回json对象
*/
protected function returnCode($code, $data = [], $count = 10)
{
header('Content-type:application/json');
if ($code == 0) {
$arr = array(
'code' => $code,
'msg' => '操作成功',
'count' => $count,
'data' => $data
);
} else if ($code >= 1 && $code <= 100) {
$arr = array(
'code' => $code,
'msg' => $data
);
} else {
$appapi = new AppApi();
$arr = array(
'code' => $code,
'msg' => $appapi::errorTip($code)
);
}
echo json_encode($arr);
if ($code != 0) {
exit;
}
}
/**
* 操作成功跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @return void
*/
protected function success($msg = '')
{
$result = [
'code' => 1,
'msg' => $msg
];
$type = $this->getResponseType();
if ($type == 'html') {
$response = view(Config::get('app.dispatch_success_tmpl'), $result);
} else if ($type == 'json') {
$response = json($result);
}
throw new HttpResponseException($response);
}
/**
* 操作错误跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @return void
*/
protected function error($msg = '')
{
$result = [
'code' => 0,
'msg' => $msg
];
$response = view(Config::get('app.dispatch_error_tmpl'), $result);
throw new HttpResponseException($response);
}
/**
* 获取当前的response 输出类型
* @access protected
* @return string
*/
protected function getResponseType()
{
return Request::isJson() || Request::isAjax() ? 'json' : 'html';
}
public function initialize(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 检查是否是直接访问具体页面
$controller = $this->request->controller();
$action = $this->request->action();
// 如果不是访问index控制器,且不是通过iframe加载,且不是ajax请求
if (
$controller != 'Index' &&
!$this->request->isAjax() &&
!$this->request->header('X-Requested-With') &&
!$this->request->param('iframe')
) { // 添加iframe参数检查
// 重定向到index页面,并带上当前页面参数
$currentUrl = $controller . '/' . $action;
redirect(url('index/index', ['page' => $currentUrl]))->send();
exit;
}
}
}
+149
View File
@@ -0,0 +1,149 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
declare (strict_types = 1);
namespace app\admin\controller;
use think\App;
use think\exception\ValidateException;
use think\Validate;
/**
* 后台控制器基础类
*/
abstract class BaseController extends Base
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [];
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
parent::__construct();
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize($app);
}
/**
* 初始化
* @access public
* @param App $app 应用对象
*/
public function initialize(App $app)
{
// 注册控制器映射
$this->registerControllerMap();
}
/**
* 注册控制器映射
*/
protected function registerControllerMap()
{
// 获取当前控制器类名
$className = get_class($this);
// 获取不带命名空间的类名
$shortName = substr($className, strrpos($className, '\\') + 1);
// 移除Controller后缀
$mapName = str_replace('Controller', '', $shortName);
// 调试信息
trace("Controller Mapping: {$mapName} => {$className}", 'debug');
// 注册控制器映射
$this->app->route->setControllerMap($mapName, $className);
}
/**
* 获取控制器名称(移除Controller后缀)
* @return string
*/
public function getControllerName()
{
$className = get_class($this);
$className = substr($className, strrpos($className, '\\') + 1);
return str_replace('Controller', '', $className);
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
}
+518
View File
@@ -0,0 +1,518 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-首页
*/
namespace app\admin\controller;
use app\admin\controller\Base;
use app\admin\model\DailyStats;
use app\admin\model\Log\LogsOperation;
use app\index\model\Attachments;
use think\facade\Db;
use think\facade\View;
use think\facade\Env;
use think\facade\Config;
use app\admin\controller\Log;
use \think\facade\Filesystem;
use app\admin\model\AdminUserGroup;
use app\admin\model\AdminSysMenu;
class IndexController extends Base{
# 首页
public function index(){
$menus = [];
$menu = [];
$where = ['group_id'=>$this->aUser['group_id']];
$role = AdminUserGroup::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 = AdminSysMenu::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(){
try {
// 获取最近7天的日期
$dates = [];
for ($i = 6; $i >= 0; $i--) {
$dates[] = date('Y-m-d', strtotime("-$i day"));
}
// 初始化数据数组
$visitData = [];
$userData = [];
$resourceData = [];
$articleData = [];
// 直接查询每天的数据
foreach ($dates as $date) {
$dayStats = Db::name('daily_stats')
->where('date', $date)
->find();
// 访问数据
$visitData[] = [
'date' => $date,
'visits' => $dayStats ? intval($dayStats['daily_visits']) : 0,
'uv' => $dayStats ? intval($dayStats['unique_visitors']) : 0
];
// 用户数据
$userData[] = [
'date' => $date,
'total' => $dayStats ? intval($dayStats['total_users']) : 0,
'new' => $dayStats ? intval($dayStats['new_users']) : 0
];
// 资源数据
$resourceData[] = [
'date' => $date,
'total' => $dayStats ? intval($dayStats['total_resources']) : 0,
'new' => $dayStats ? intval($dayStats['daily_resources']) : 0,
'downloads' => $dayStats ? intval($dayStats['resource_downloads']) : 0
];
// 文章数据
$articleData[] = [
'date' => $date,
'total' => $dayStats ? intval($dayStats['total_articles']) : 0,
'new' => $dayStats ? intval($dayStats['daily_articles']) : 0,
'views' => $dayStats ? intval($dayStats['article_views']) : 0
];
}
// 获取今日统计数据
$today = date('Y-m-d');
$todayStats = Db::name('daily_stats')
->where('date', $today)
->find();
// 获取最近的操作日志
$recentActivities = Db::name('logs_operation')
->field('operation_time, module, operation')
->order('operation_time DESC')
->limit(5)
->select()
->each(function($item) {
$item['content'] = date('Y年m月d日 H:i:s', strtotime($item['operation_time'])) . ' 在 ' .
($item['module'] ?: '未知模块') . ' ' .
($item['operation'] ?: '未知操作');
$item['icon'] = $this->getActivityIcon($item['module'] ?: '其他');
return $item;
});
// 处理图表数据
$chartData = [
'visitTrend' => [
'dates' => array_map(function($item) { return date('m-d', strtotime($item['date'])); }, $visitData),
'visits' => array_column($visitData, 'visits'),
'uvs' => array_column($visitData, 'uv')
],
'userGrowth' => [
'dates' => array_map(function($item) { return date('m-d', strtotime($item['date'])); }, $userData),
'newUsers' => array_column($userData, 'new'),
'totalUsers' => array_column($userData, 'total')
],
'resourceStats' => [
'dates' => array_map(function($item) { return date('m-d', strtotime($item['date'])); }, $resourceData),
'newResources' => array_column($resourceData, 'new'),
'totalResources' => array_column($resourceData, 'total'),
'downloads' => array_column($resourceData, 'downloads')
],
'articleStats' => [
'dates' => array_map(function($item) { return date('m-d', strtotime($item['date'])); }, $articleData),
'newArticles' => array_column($articleData, 'new'),
'totalArticles' => array_column($articleData, 'total'),
'views' => array_column($articleData, 'views')
]
];
// 传递给视图
View::assign([
'todayStats' => $todayStats ?: [
'total_users' => 0,
'new_users' => 0,
'total_visits' => 0,
'daily_visits' => 0,
'unique_visitors' => 0,
'total_articles' => 0,
'daily_articles' => 0,
'article_views' => 0,
'total_resources' => 0,
'daily_resources' => 0,
'resource_downloads' => 0
],
'recentActivities' => $recentActivities,
'chartData' => $chartData
]);
return View::fetch();
} catch (\Exception $e) {
// 记录错误日志
\think\facade\Log::error('获取统计数据失败:' . $e->getMessage());
// 返回空数据
View::assign([
'todayStats' => [
'total_users' => 0,
'new_users' => 0,
'total_visits' => 0,
'daily_visits' => 0,
'unique_visitors' => 0,
'total_articles' => 0,
'daily_articles' => 0,
'article_views' => 0,
'total_resources' => 0,
'daily_resources' => 0,
'resource_downloads' => 0
],
'recentActivities' => [],
'chartData' => [
'visitTrend' => ['dates' => [], 'visits' => [], 'uvs' => []],
'userGrowth' => ['dates' => [], 'newUsers' => [], 'totalUsers' => []],
'resourceStats' => ['dates' => [], 'newResources' => [], 'totalResources' => [], 'downloads' => []],
'articleStats' => ['dates' => [], 'newArticles' => [], 'totalArticles' => [], 'views' => []]
]
]);
return View::fetch();
}
}
/**
* 根据操作类型获取对应的图标
*/
private function getActivityIcon($type)
{
$icons = [
'用户管理' => '👥',
'文章管理' => '📝',
'资源管理' => '📦',
'系统设置' => '⚙️',
'登录' => '🔑',
'退出' => '🚪',
'其他' => '📌'
];
return $icons[$type] ?? '📌';
}
/**
* 格式化访问趋势数据
*/
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 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:51200|fileExt:jpg,png,gif,jpeg'
])->check($file);
// 存储文件到public磁盘的uploads目录
$info = Filesystem::disk('public')->putFile('uploads', $files);
// 处理文件路径,统一使用正斜杠
$info = str_replace("\\", "/", $info);
$img = '/storage/'.$info;
// 保存附件信息
$fileName = $files->getOriginalName();
$fileSize = $files->getSize();
$attachmentId = $this->saveAttachment($fileName, 1, $fileSize, $img); // 1: 图片
// 返回成功信息
return json([
'code' => 0,
'data' => $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 = 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 = 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 = 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();
}
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
namespace app\admin\controller;
use app\admin\controller\Base;
use think\facade\Db;
use think\facade\Request;
use think\facade\View;
use think\facade\Cookie;
use app\admin\model\Log\LogsLogin;
use app\admin\model\Log\LogsOperation;
class LogController extends Base
{
/**
* 登录日志列表
*/
public function login()
{
if (Request::isPost()) {
$page = input('post.page', 1);
$limit = input('post.limit', 10);
$username = input('post.username');
$ip = input('post.ip');
$status = input('post.status');
$startTime = input('post.start_time');
$endTime = input('post.end_time');
// 搜索条件
if ($username) {
$query = LogsLogin::where('username', 'like', "%{$username}%");
}
if ($ip) {
$query = LogsLogin::where('ip_address', 'like', "%{$ip}%");
}
if ($status !== '') {
$query = LogsLogin::where('login_status', $status);
}
if ($startTime) {
$query = LogsLogin::where('login_time', '>=', $startTime);
}
if ($endTime) {
$query = LogsLogin::where('login_time', '<=', $endTime);
}
$count = LogsLogin::count();
$list = LogsLogin::order('id desc')
->page($page, $limit)
->select();
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $list
]);
}
return View::fetch();
}
/**
* 操作日志列表
*/
public function operation()
{
$params = input();
$page = $params['page'] ?? 1;
$limit = $params['limit'] ?? 10;
// 构建搜索条件
$searchFields = [
'username' => ['field' => 'username', 'type' => 'like'],
'module' => ['field' => 'module', 'type' => 'like'],
'operation' => ['field' => 'operation', 'type' => 'like'],
'status' => ['field' => 'status', 'type' => '='],
'start_time' => ['field' => 'operation_time', 'type' => '>='],
'end_time' => ['field' => 'operation_time', 'type' => '<=']
];
$query = LogsOperation::where('1=1');
foreach ($searchFields as $param => $config) {
if (!empty($params[$param])) {
$value = $params[$param];
if ($config['type'] === 'like') {
$value = "%{$value}%";
}
$query = $query->where($config['field'], $config['type'], $value);
}
}
$count = LogsOperation::where('1=1')->count();
$list = LogsOperation::where('1=1')
->order('id desc')
->page($page, $limit)
->select();
if (Request::isAjax()) {
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $list
]);
}
return View::fetch();
}
/**
* 记录操作日志
* @param string $operation 操作名称
* @param int $status 状态 1成功 0失败
* @param string $error_message 错误信息
* @param string $module 模块名称
*/
public static function record($operation, $status = 1, $error_message = '', $module = '')
{
$data = [
'username' => Cookie::get('admin_name') ?: '未知用户',
'module' => $module ?: '系统管理',
'operation' => $operation,
'request_method' => Request::method(),
'request_url' => Request::url(true),
'request_params' => json_encode(Request::param(), JSON_UNESCAPED_UNICODE),
'ip_address' => Request::ip(),
'status' => $status,
'error_message' => $error_message,
'operation_time' => date('Y-m-d H:i:s'),
'execution_time' => 0
];
LogsOperation::insert($data);
}
/**
* 获取操作日志详情
*/
public function getOperationDetail()
{
$id = input('id/d', 0);
if (!$id) {
return json(['code' => 1, 'msg' => '参数错误']);
}
$info = LogsOperation::where('id', $id)
->find();
if (!$info) {
return json(['code' => 1, 'msg' => '日志不存在']);
}
// 格式化请求参数
if (!empty($info['request_params'])) {
$info['request_params'] = json_decode($info['request_params'], true);
}
return json(['code' => 0, 'msg' => '获取成功', 'data' => $info]);
}
}
+195
View File
@@ -0,0 +1,195 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-登录
*/
namespace app\admin\controller;
use think\App;
use app\AppApi;
use think\facade\Db;
use think\facade\View;
use think\facade\Cookie;
use think\facade\Request;
use app\admin\model\YzAdminConfig;
use app\admin\model\AdminUser;
use app\admin\model\Log\LogsLogin;
class LoginController extends Base
{
public $app;
public $config;
public function __construct(App $app)
{
$this->app = $app;
$this->config = new YzAdminConfig();
}
// 登录页面
public function index()
{
# 获取配置
$config = $this->config->getAll();
View::assign([
'config' => $config
]);
return View::fetch();
}
// 记录登录日志
public function recordLoginLog($username, $status, $reason = '')
{
$data = [
'username' => $username,
'ip_address' => Request::ip(),
'location' => $this->getLocation(Request::ip()),
'device_type' => $this->getDeviceType(),
'user_agent' => Request::header('user-agent'),
'login_status' => $status,
'failure_reason' => $reason,
'login_time' => date('Y-m-d H:i:s')
];
LogsLogin::create($data);
}
// 获取IP地址位置
public function getLocation($ip)
{
// 这里可以接入IP地址库或第三方API
return '未知';
}
// 获取设备类型
public function getDeviceType()
{
$agent = Request::header('user-agent');
if (preg_match('/(iPhone|iPod|Android|ios|iPad|Mobile)/i', $agent)) {
return '移动端';
}
return 'PC端';
}
// 登录
public function login()
{
if (Request::isPost()) {
$account = trim(input('post.account'));
if (empty($account)) {
$this->recordLoginLog($account, 0, '账号不能为空');
return json(['code' => 1, 'msg' => '账号不能为空']);
}
$pattern = "/^([0-9A-Za-z-_.]+)@([0-9a-z]+.[a-z]{2,3}(.[a-z]{2})?)$/i";
if (!preg_match($pattern, $account)) {
$this->recordLoginLog($account, 0, '邮箱格式不正确');
return json(['code' => 1, 'msg' => '邮箱格式不正确']);
}
$password = trim(input('post.password'));
if (empty($password)) {
$this->recordLoginLog($account, 0, '密码不能为空');
return json(['code' => 1, 'msg' => '密码不能为空']);
}
$code = trim(input('post.code'));
if ($code == '') {
$this->recordLoginLog($account, 0, '验证码不能为空');
return json(['code' => 1, 'msg' => '验证码不能为空']);
}
if (!captcha_check($code)) {
$this->recordLoginLog($account, 0, '验证码错误');
return json(['code' => 1, 'msg' => '验证码错误']);
}
$aUser = AdminUser::where('account', $account)->find();
if (empty($aUser)) {
$this->recordLoginLog($account, 0, '账号不存在');
return json(['code' => 1, 'msg' => '账号不存在']);
}
if ($aUser['status'] != 1) {
$this->recordLoginLog($account, 0, '账号已被禁用');
return json(['code' => 1, 'msg' => '账号已被禁用']);
}
if ($aUser['password'] != md5($password)) {
$this->recordLoginLog($account, 0, '密码错误');
return json(['code' => 1, 'msg' => '密码错误']);
}
$remember = input('post.remember');
if (!empty($remember)) {
Cookie::set('admin_id', $aUser['uid'], 60 * 60 * 24 * 7);
Cookie::set('admin_name', $aUser['name'], 60 * 60 * 24 * 7);
} else {
Cookie::set('admin_id', $aUser['uid']);
Cookie::set('admin_name', $aUser['name']);
}
AdminUser::where('uid', $aUser['uid'])->update(
['login_count' => $aUser['login_count'] + 1, 'update_time' => time()]
);
// 记录登录成功日志
$this->recordLoginLog($account, 1);
return json(['code' => 0, 'msg' => '登录成功', 'data' => []]);
}
}
// 退出
public function logout()
{
Cookie::delete('admin_id');
Cookie::delete('admin_name');
return json(['code' => 0, 'msg' => '退出成功', 'data' => []]);
}
// 密码重置页面
public function resetpwdindex()
{
return View::fetch('resetpwd');
}
//管理员密码重置
public function resetpwd()
{
$account = trim(input('post.account'));
if (empty($account)) {
return json(['code' => 1, 'msg' => '账号不能为空']);
}
$user = AdminUser::where('account', $account)->find();
if (!$user) {
return json(['code' => 1, 'msg' => '未找到该用户名']);
}
// 使用md5进行密码加密处理
$password = md5('123456');
try {
$res = AdminUser::where('account', $account)
->update(['password' => $password]);
if ($res === false) {
return json(['code' => 1, 'msg' => '数据库更新失败']);
}
if ($res === 0) {
return json(['code' => 1, 'msg' => '密码未发生变化']);
}
return json(['code' => 0, 'msg' => '密码重置成功', 'data' => []]);
} catch (\Exception $e) {
return json(['code' => 1, 'msg' => '系统错误:' . $e->getMessage()]);
}
}
}
@@ -0,0 +1,554 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-资源管理
*/
namespace app\admin\controller;
use app\admin\controller\BaseController;
use app\admin\model\Resource\Resource;
use app\admin\model\Resource\ResourceCategory;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
use app\admin\controller\LogController as Log;
use think\App;
class ResourcesController extends BaseController
{
// 资源列表
public function lists()
{
if (Request::isPost()) {
$params = [
'category' => input('post.category'),
'name' => input('post.name'),
'uploader' => input('post.uploader')
];
$page = (int) input('post.page', 1);
$limit = (int) input('post.limit', 10);
$query = Resource::where('delete_time', null)
->where('status', 1);
// 分类筛选
if (!empty($params['category'])) {
$cateInfo = ResourceCategory::where('name', $params['category'])
->where('delete_time', null)
->where('status', 1)
->field('id')
->find();
if ($cateInfo) {
$query = $query->where('cate', (int) $cateInfo['id']);
}
}
// 名称搜索
if (!empty($params['name'])) {
$query = $query->where('name', 'like', '%' . $params['name'] . '%');
}
// 上传者搜索
if (!empty($params['uploader'])) {
$query = $query->where('uploader', 'like', '%' . $params['uploader'] . '%');
}
$count = $query->count();
$lists = $query->order('id DESC')
->page($page, $limit)
->select()
->each(function ($item) {
// 获取分类信息
$cateInfo = ResourceCategory::where('id', (int) $item['cate'])
->field('name, icon')
->find();
if ($cateInfo) {
$item['cate'] = $cateInfo['name'];
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']);
return $item;
});
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $lists
]);
} else {
$allCategories = ResourceCategory::where('delete_time', null)
->where('status', 1)
->field('id, name, cid, icon')
->order('sort asc, id asc')
->select()
->toArray();
$categories = $this->buildParentChild($allCategories);
View::assign([
'categories' => $categories
]);
return View::fetch();
}
}
// 添加资源
public function add()
{
if (Request::isPost()) {
$data = [
'title' => input('post.title'),
'cate' => input('post.cate'),
'desc' => input('post.desc'),
'icon' => input('post.icon'),
'images' => input('post.images'),
'url' => input('post.url'),
'fileurl' => input('post.fileurl'),
'code' => input('post.code'),
'zipcode' => input('post.zipcode'),
'uploader' => input('post.uploader'),
'content' => input('post.content'),
'number' => input('post.number'),
'status' => input('post.status', 1),
'create_time' => time()
];
$insert = Resource::insert($data);
if (empty($insert)) {
Log::record('添加资源', 0, '添加资源失败', '资源管理');
$this->error('添加失败');
}
Log::record('添加资源', 1, '', '资源管理');
return json(['code' => 0, 'msg' => '添加成功', 'data' => []]);
} else {
// 获取所有分类
$allCategories = ResourceCategory::where('delete_time', null)
->where('status', 1)
->field('id, name, cid, icon, number')
->order('sort asc, id asc')
->select()
->toArray();
$categories = $this->buildParentChild($allCategories);
View::assign([
'categories' => $categories
]);
return View::fetch();
} catch (\Exception $e) {
Log::record('添加资源页面加载', 0, $e->getMessage(), '资源管理');
$this->error('页面加载失败:' . $e->getMessage());
}
}
// 编辑资源
public function edit()
{
if (Request::isPost()) {
$data = input('post.');
$id = input('id/d', 0);
if (!$id) {
Log::record('编辑资源', 0, '参数错误', '资源管理');
return json(['code' => 1, 'msg' => '参数错误']);
}
$updateData = [
'title' => $data['title'],
'cate' => $data['cate'],
'desc' => $data['desc'],
'uploader' => $data['uploader'],
'icon' => $data['icon'],
'images' => $data['images'],
'fileurl' => $data['fileurl'],
'url' => $data['url'],
'code' => $data['code'],
'zipcode' => $data['zipcode'],
'sort' => $data['sort'],
'number' => $data['number'],
'content' => $data['content'],
'update_time' => time()
];
$result = Resource::where('id', $id)
->update($updateData);
if ($result !== false) {
Log::record('编辑资源', 1, '', '资源管理');
return json(['code' => 0, 'msg' => '编辑成功']);
} else {
Log::record('编辑资源', 0, '编辑资源失败', '资源管理');
return json(['code' => 1, 'msg' => '编辑失败']);
}
}
$id = input('id/d', 0);
if (!$id) {
Log::record('编辑资源', 0, '参数错误', '资源管理');
$this->error('参数错误');
}
$resource = Resource::where('id', $id)
->where('delete_time', null)
->find();
if (!$resource) {
Log::record('编辑资源', 0, '资源不存在', '资源管理');
$this->error('资源不存在');
}
// 处理图片路径
if (!empty($resource['images'])) {
$domain = request()->domain();
$images = explode(',', $resource['images']);
// $images = array_map(function ($image) use ($domain) {
// return $domain . $image;
// }, $images);
$resource['images'] = implode(',', $images);
}
View::assign('resource', $resource);
return View::fetch();
}
// 删除资源
public function delete()
{
$id = input('post.id');
$delete = Resource::where('id', $id)
->update(['delete_time' => time()]);
if ($delete === false) {
Log::record('删除资源', 0, '删除资源失败', '资源管理');
return json(['code' => 1, 'msg' => '删除失败', 'data' => []]);
}
Log::record('删除资源', 1, '', '资源管理');
return json(['code' => 0, 'msg' => '删除成功', 'data' => []]);
}
// 资源分类
public function cate()
{
if (Request::isPost()) {
$lists = ResourceCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
$tree = $this->buildTree($lists);
return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]);
}
return View::fetch();
}
//获取分类结构
public function getcate()
{
$lists = ResourceCategory::where('delete_time', null)
->where('status', 1)
->order('sort asc, id asc')
->select()
->toArray();
// 获取每个分类下的资源总数
foreach ($lists as &$item) {
if ($item['cid'] == 0) {
// 父级分类 - 统计所有子分类的资源总数
$childIds = ResourceCategory::where('cid', $item['id'])
->where('delete_time', null)
->where('status', 1)
->column('id');
$item['total'] = Resource::where('cate', 'in', array_merge([$item['id']], $childIds))
->where('delete_time', null)
->where('status', '<>', 3)
->count();
} else {
// 子分类 - 只统计当前分类的资源
$item['total'] = Resource::where('cate', $item['id'])
->where('delete_time', null)
->where('status', '<>', 3)
->count();
}
}
$tree = $this->buildParentChild($lists);
return json(['code' => 0, 'msg' => '获取成功', 'data' => $tree]);
}
// 添加资源分类
public function cateadd()
{
if (Request::isPost()) {
$data = [
'name' => input('post.name'),
'icon' => input('post.icon'),
'cid' => input('post.cid'),
'number' => input('post.number'),
'sort' => input('post.sort', 0),
'status' => input('post.status', 1),
'create_time' => time()
];
$insert = ResourceCategory::insert($data);
if (empty($insert)) {
Log::record('添加资源分类', 0, '添加资源分类失败', '资源分类');
return json(['code' => 1, 'msg' => '添加失败', 'data' => []]);
}
Log::record('添加资源分类', 1, '', '资源分类');
return json(['code' => 0, 'msg' => '添加成功', 'data' => []]);
} else {
$parentCategories = ResourceCategory::where('delete_time', null)
->where('status', 1)
->where('cid', 0)
->field('id, name')
->select()
->toArray();
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'parentOptions' => $parentCategories
]
]);
}
}
//编辑资源分类
public function cateedit()
{
if (Request::isPost()) {
$data = [
'id' => input('post.id'),
'name' => input('post.name'),
'icon' => input('post.icon'),
'cid' => input('post.cid'),
'number' => input('post.number'),
'sort' => input('post.sort', 0),
'status' => input('post.status', 1),
'update_time' => time()
];
$update = ResourceCategory::where('id', $data['id'])
->update($data);
if ($update === false) {
Log::record('编辑资源分类', 0, '更新资源分类失败', '资源分类');
return json(['code' => 1, 'msg' => '更新失败', 'data' => []]);
}
Log::record('编辑资源分类', 1, '', '资源分类');
return json(['code' => 0, 'msg' => '更新成功', 'data' => []]);
} else {
$id = input('get.id');
$info = ResourceCategory::where('id', $id)->find();
$parentCategories = ResourceCategory::where('delete_time', null)
->where('status', 1)
->where('cid', 0)
->where('id', '<>', $id)
->field('id, name')
->select()
->toArray();
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'info' => $info,
'parentOptions' => $parentCategories
]
]);
}
}
//删除资源分类
public function catedel()
{
$id = input('post.id');
// 检查是否有子分类
$hasChildren = ResourceCategory::where('cid', $id)
->where('delete_time', null)
->find();
if ($hasChildren) {
Log::record('删除资源分类', 0, '该分类下有子分类,无法删除', '资源分类');
return json(['code' => 1, 'msg' => '该分类下有子分类,无法删除', 'data' => []]);
}
$delete = ResourceCategory::where('id', $id)
->update(['delete_time' => time()]);
if ($delete === false) {
Log::record('删除资源分类', 0, '删除资源分类失败', '资源分类');
return json(['code' => 1, 'msg' => '删除失败', 'data' => []]);
}
Log::record('删除资源分类', 1, '', '资源分类');
return json(['code' => 0, 'msg' => '删除成功', 'data' => []]);
}
/**
* 获取资源详情
*/
public function get()
{
$id = input('id/d', 0);
if (!$id) {
Log::record('获取资源详情', 0, '参数错误', '资源管理');
return json(['code' => 1, 'msg' => '参数错误']);
}
$resource = Resource::where('id', $id)
->where('delete_time', null)
->find();
if (!$resource) {
Log::record('获取资源详情', 0, '资源不存在', '资源管理');
return json(['code' => 1, 'msg' => '资源不存在']);
}
// 获取分类信息
$cateInfo = ResourceCategory::where('id', $resource['cate'])
->field('name')
->find();
if ($cateInfo) {
$resource['cate_name'] = $cateInfo['name'];
}
Log::record('获取资源详情', 1, '', '资源管理');
return json(['code' => 0, 'msg' => '获取成功', 'data' => $resource]);
}
//统计资源数量
public function counts()
{
try {
// 获取资源总数
$total = Resource::where('delete_time', null)
->where('status', '<>', 3)
->count();
// 获取今日新增资源数
$today = strtotime(date('Y-m-d'));
$todayNew = Resource::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '>=', $today)
->count();
// 获取最近7天的资源数据
$dates = [];
$counts = [];
$totalCounts = []; // 存储每天的总资源数
for ($i = 6; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i days"));
$start = strtotime($date);
$end = $start + 86400;
// 获取当天新增资源数
$count = Resource::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '>=', $start)
->where('create_time', '<', $end)
->count();
// 获取截至当天的总资源数
$totalCount = Resource::where('delete_time', null)
->where('status', '<>', 3)
->where('create_time', '<', $end)
->count();
$dates[] = $date;
$counts[] = $count;
$totalCounts[] = $totalCount;
}
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'total' => $total,
'todayNew' => $todayNew,
'dates' => $dates,
'counts' => $counts,
'totalCounts' => $totalCounts
]
]);
} catch (\Exception $e) {
return json([
'code' => 1,
'msg' => '获取失败:' . $e->getMessage()
]);
}
}
// 构建树形结构
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;
}
}
+98
View File
@@ -0,0 +1,98 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-用户管理
*/
namespace app\admin\controller;
use app\admin\controller\BaseController;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
use app\admin\controller\Log;
use think\App;
use app\admin\model\User\Users;
class UsersController extends BaseController
{
/**
* 统计用户数量
*/
public function counts()
{
try {
// 统计用户总数
$total = Users::where('delete_time', 0)
->where('status', 1)
->count();
// 获取今日新增用户数
$today = strtotime(date('Y-m-d'));
$todayNew = Users::where('delete_time', 0)
->where('status', 1)
->where('create_time', '>=', $today)
->count();
// 获取最近7天的用户数据
$dates = [];
$counts = [];
$totalCounts = []; // 存储每天的总用户数
for ($i = 6; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i days"));
$start = strtotime($date);
$end = $start + 86400;
// 获取当天新增用户数
$count = Users::where('delete_time', 0)
->where('status', 1)
->where('create_time', '>=', $start)
->where('create_time', '<', $end)
->count();
// 获取截至当天的总用户数
$totalCount = Users::where('delete_time', 0)
->where('status', 1)
->where('create_time', '<', $end)
->count();
$dates[] = $date;
$counts[] = $count;
$totalCounts[] = $totalCount;
}
return json([
'code' => 0,
'msg' => '获取成功',
'data' => [
'total' => $total,
'todayNew' => $todayNew,
'dates' => $dates,
'counts' => $counts,
'totalCounts' => $totalCounts
]
]);
} catch (\Exception $e) {
return json([
'code' => 1,
'msg' => '获取失败:' . $e->getMessage()
]);
}
}
}
+556
View File
@@ -0,0 +1,556 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
/**
* 后台管理系统-核心功能
*/
namespace app\admin\controller;
use app\admin\controller\Base;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
use app\admin\model\YzAdminConfig;
use app\admin\controller\LogController as Log;
use app\admin\model\AdminSysMenu;
use app\admin\model\AdminUserGroup;
use app\admin\model\AdminConfig;
use app\admin\model\ZIconfont;
use app\admin\model\MailConfig;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
class YunzerController extends Base
{
# 菜单列表
public function menuinfo()
{
$lists = AdminSysMenu::where('parent_id', 0)->order('sort DESC,smid DESC')->select();
View::assign([
'lists' => $lists
]);
return View::fetch();
}
# 菜单添加
public function menuadd()
{
$req = request();
if ($req->isPost()) {
$data['label'] = trim(input('post.label'));
if (empty($data['label'])) {
Log::record('添加菜单', 0, '请输入菜单名称', '菜单管理');
$this->returnCode(1, '请输入菜单名称');
}
$data['icon_class'] = trim(input('post.icon_class'));
$data['sort'] = (int) trim(input('post.sort'));
$data['status'] = (int) trim(input('post.status'));
$data['type'] = (int) trim(input('post.type', 0));
if ($data['type'] == 1) {
$data['src'] = trim(input('post.src1'));
if (empty($data['src'])) {
Log::record('添加菜单', 0, '请输入内部跳转地址', '菜单管理');
$this->returnCode(1, '请输入内部跳转地址');
}
} else if ($data['type'] == 2) {
$data['src'] = trim(input('post.src2'));
if (empty($data['src'])) {
Log::record('添加菜单', 0, '请输入超链接地址', '菜单管理');
$this->returnCode(1, '请输入超链接地址');
}
} else {
$data['src'] = '';
}
// 保存菜单
$res = AdminSysMenu::insert($data);
if (!$res) {
Log::record('添加菜单', 0, '添加菜单失败', '菜单管理');
$this->returnCode(1, '添加菜单失败');
}
// 获取新插入的菜单ID
$newMenuId = AdminSysMenu::getLastInsID();
// 获取所有管理员用户组
$adminGroups = AdminUserGroup::select();
foreach ($adminGroups as $group) {
// 获取现有权限
$rights = [];
if (!empty($group['rights'])) {
$rights = json_decode($group['rights'], true);
}
// 添加新菜单ID到权限列表
if (!in_array($newMenuId, $rights)) {
$rights[] = $newMenuId;
// 更新用户组权限
AdminUserGroup::where('group_id', $group['group_id'])
->update(['rights' => json_encode($rights)]);
}
}
Log::record('添加菜单', 1, '', '菜单管理');
$this->returnCode(0);
} else {
$iconfont = ZIconfont::where('status', 1)->select();
View::assign([
'iconfont' => $iconfont
]);
return View::fetch();
}
}
# 菜单修改
public function menuedit()
{
$req = request();
if ($req->isPost()) {
$smid = (int) input('post.smid');
$data['label'] = trim(input('post.label'));
if (!$data['label']) {
Log::record('编辑菜单', 0, '请输入菜单名称', '菜单管理');
$this->returnCode(1, '请输入菜单名称');
}
$data['icon_class'] = trim(input('post.icon_class'));
$data['sort'] = (int) trim(input('post.sort'));
$data['status'] = (int) trim(input('post.status'));
$data['type'] = (int) trim(input('post.type', 0));
if ($data['type'] == 1) {
$data['src'] = trim(input('post.src1'));
if (empty($data['src'])) {
Log::record('编辑菜单', 0, '请输入内部跳转地址', '菜单管理');
$this->returnCode(1, '请输入内部跳转地址');
}
} else if ($data['type'] == 2) {
$data['src'] = trim(input('post.src2'));
if (empty($data['src'])) {
Log::record('编辑菜单', 0, '请输入超链接地址', '菜单管理');
$this->returnCode(1, '请输入超链接地址');
}
} else {
$data['src'] = '';
}
// 保存用户
$res = AdminSysMenu::where('smid', $smid)->update($data);
if (!$res) {
Log::record('编辑菜单', 0, '修改菜单失败', '菜单管理');
$this->returnCode(1, '修改菜单失败');
}
Log::record('编辑菜单', 1, '', '菜单管理');
$this->returnCode(0);
} else {
$smid = (int) input('get.smid');
$lists = AdminSysMenu::where('smid', $smid)->find();
$iconfont = ZIconfont::where('status', 1)->select();
View::assign([
'lists' => $lists,
'iconfont' => $iconfont
]);
return View::fetch();
}
}
# 菜单删除
public function menudel()
{
$smid = (int) input('post.smid');
$count = AdminSysMenu::where('parent_id', $smid)->count();
if ($count > 0) {
Log::record('删除菜单', 0, '该菜单下还有子菜单,不能删除', '菜单管理');
$this->returnCode(1, '该菜单下还有子菜单,不能删除');
}
$res = AdminSysMenu::where('smid', $smid)->delete();
if (empty($res)) {
Log::record('删除菜单', 0, '删除菜单失败', '菜单管理');
$this->returnCode(1, '删除菜单失败');
}
Log::record('删除菜单', 1, '', '菜单管理');
$this->returnCode(0);
}
# 按钮管理
public function buttoninfo()
{
$smid = (int) input('get.smid');
$lists = AdminSysMenu::where('parent_id', $smid)->order('sort DESC')->select()->toArray();
if (!empty($lists)) {
foreach ($lists as &$v) {
switch ($v['type']) {
case 0:
$v['type_name'] = '顶级菜单';
break;
case 1:
$v['type_name'] = '内部跳转';
break;
case 2:
$v['type_name'] = '超链接';
break;
default:
$v['type_name'] = '未规划类型';
break;
}
}
}
View::assign([
'lists' => $lists,
'smid' => $smid
]);
return View::fetch();
}
# 按钮添加
public function buttonadd()
{
$req = request();
if ($req->isPost()) {
$smid = (int) input('post.smid');
$data['label'] = trim(input('post.label'));
if (!$data['label']) {
Log::record('添加按钮', 0, '请输入按钮名称', '按钮管理');
$this->returnCode(1, '请输入按钮名称');
}
$data['icon_class'] = trim(input('post.icon_class'));
$data['sort'] = (int) trim(input('post.sort'));
$data['status'] = (int) trim(input('post.status'));
$data['type'] = (int) trim(input('post.type'));
if (empty($data['type'])) {
Log::record('添加按钮', 0, '请选择按钮类型', '按钮管理');
$this->returnCode(1, '请选择按钮类型');
}
if ($data['type'] == 1) {
$data['src'] = trim(input('post.src1'));
if (empty($data['src'])) {
Log::record('添加按钮', 0, '请输入内部跳转地址', '按钮管理');
$this->returnCode(1, '请输入内部跳转地址');
}
} else if ($data['type'] == 2) {
$data['src'] = trim(input('post.src2'));
if (empty($data['src'])) {
Log::record('添加按钮', 0, '请输入超链接地址', '按钮管理');
$this->returnCode(1, '请输入超链接地址');
}
}
$data['parent_id'] = $smid;
$res = AdminSysMenu::insert($data);
if (!$res) {
Log::record('添加按钮', 0, '添加按钮失败', '按钮管理');
$this->returnCode(1, '添加按钮失败');
}
Log::record('添加按钮', 1, '', '按钮管理');
$this->returnCode(0);
} else {
$smid = (int) input('get.smid');
$iconfont = ZIconfont::where('status', 1)->select();
View::assign([
'smid' => $smid,
'iconfont' => $iconfont
]);
return View::fetch();
}
}
# 按钮修改
public function buttonedit()
{
$req = request();
if ($req->isPost()) {
$smid = (int) input('post.smid');
$data['label'] = trim(input('post.label'));
if (!$data['label']) {
Log::record('编辑按钮', 0, '请输入按钮名称', '按钮管理');
$this->returnCode(1, '请输入按钮名称');
}
$data['icon_class'] = trim(input('post.icon_class'));
$data['sort'] = (int) trim(input('post.sort'));
$data['status'] = (int) trim(input('post.status'));
$data['type'] = (int) trim(input('post.type'));
if (empty($data['type'])) {
Log::record('编辑按钮', 0, '请选择按钮类型', '按钮管理');
$this->returnCode(1, '请选择按钮类型');
}
if ($data['type'] == 1) {
$data['src'] = trim(input('post.src1'));
if (empty($data['src'])) {
Log::record('编辑按钮', 0, '请输入内部跳转地址', '按钮管理');
$this->returnCode(1, '请输入内部跳转地址');
}
} else if ($data['type'] == 2) {
$data['src'] = trim(input('post.src2'));
if (empty($data['src'])) {
Log::record('编辑按钮', 0, '请输入超链接地址', '按钮管理');
$this->returnCode(1, '请输入超链接地址');
}
}
$res = AdminSysMenu::where('smid', $smid)->update($data);
if (!$res) {
Log::record('编辑按钮', 0, '修改按钮失败', '按钮管理');
$this->returnCode(1, '修改按钮失败');
}
Log::record('编辑按钮', 1, '', '按钮管理');
$this->returnCode(0);
} else {
$smid = (int) input('get.smid');
$lists = AdminSysMenu::where('smid', $smid)->find();
$iconfont = ZIconfont::where('status', 1)->select();
View::assign([
'lists' => $lists,
'iconfont' => $iconfont
]);
return View::fetch();
}
}
# 按钮删除
public function buttondel()
{
$smid = (int) input('post.smid');
$res = AdminSysMenu::where('smid', $smid)->delete();
if (empty($res)) {
Log::record('删除按钮', 0, '删除按钮失败', '按钮管理');
$this->returnCode(1, '删除按钮失败');
}
Log::record('删除按钮', 1, '', '按钮管理');
$this->returnCode(0);
}
# 配置列表
public function configlist()
{
$req = request();
if ($req->isPost()) {
$page = (int) input('post.page', 1);
$limit = (int) input('post.limit', $this->config['admin_page']);
$count = AdminConfig::count();
$lists = AdminConfig::page($page, $limit)->order('config_sort DESC,config_id DESC')->select();
$this->returnCode(0, $lists, $count);
} else {
return View::fetch();
}
}
# 配置添加
public function configadd()
{
$req = request();
if ($req->isPost()) {
$data['config_name'] = trim(input('post.config_name'));
if (empty($data['config_name'])) {
Log::record('添加配置', 0, '请输入关键词', '系统配置');
$this->returnCode(1, '请输入关键词');
}
$data['config_info'] = trim(input('post.config_info'));
if (empty($data['config_info'])) {
Log::record('添加配置', 0, '请输入作用', '系统配置');
$this->returnCode(1, '请输入作用');
}
$data['config_type'] = trim(input('post.config_type'));
$data['config_desc'] = trim(input('post.config_desc'));
$data['config_status'] = trim(input('post.config_status'));
$data['config_sort'] = trim(input('post.config_sort'));
$res = AdminConfig::insert($data);
if (empty($res)) {
Log::record('添加配置', 0, '添加配置失败', '系统配置');
$this->returnCode(1, '添加配置失败');
}
Log::record('添加配置', 1, '', '系统配置');
$this->returnCode(0);
} else {
return View::fetch();
}
}
# 配置修改
public function configedit()
{
$req = request();
if ($req->isPost()) {
$config_id = (int) input('post.config_id');
if (empty($config_id)) {
Log::record('编辑配置', 0, '请选择一条数据', '系统配置');
$this->returnCode(1, '请选择一条数据');
}
$data['config_name'] = trim(input('post.config_name'));
if (empty($data['config_name'])) {
Log::record('编辑配置', 0, '请输入关键词', '系统配置');
$this->returnCode(1, '请输入关键词');
}
$data['config_info'] = trim(input('post.config_info'));
if (empty($data['config_info'])) {
Log::record('编辑配置', 0, '请输入作用', '系统配置');
$this->returnCode(1, '请输入作用');
}
$data['config_type'] = trim(input('post.config_type'));
$data['config_desc'] = trim(input('post.config_desc'));
$data['config_status'] = trim(input('post.config_status'));
$data['config_sort'] = trim(input('post.config_sort'));
$res = AdminConfig::where('config_id', $config_id)->update($data);
if (empty($res)) {
Log::record('编辑配置', 0, '修改配置失败', '系统配置');
$this->returnCode(1, '修改配置失败');
}
Log::record('编辑配置', 1, '', '系统配置');
$this->returnCode(0);
} else {
$config_id = (int) input('get.config_id');
$find = AdminConfig::where('config_id', $config_id)->find();
View::assign([
'find' => $find
]);
return View::fetch();
}
}
# 配置删除
public function configdel()
{
$config_id = (int) input('post.config_id');
if (empty($config_id)) {
Log::record('删除配置', 0, '请选择一条数据', '系统配置');
$this->returnCode(1, '请选择一条数据');
}
$res = AdminConfig::where('config_id', $config_id)->delete();
if (empty($res)) {
Log::record('删除配置', 0, '删除配置失败', '系统配置');
$this->returnCode(1, '删除配置失败');
}
Log::record('删除配置', 1, '', '系统配置');
$this->returnCode(0);
}
# 配置值
public function configvalue()
{
$req = request();
if ($req->isPost()) {
$post = input('post.');
if (empty($post)) {
Log::record('更新配置值', 0, '数据不能为空', '系统配置');
$this->returnCode(1, '数据不能为空');
}
// 获取所有配置项,检查 config_type 为 4 的项
$allConfigs = AdminConfig::order('config_sort DESC,config_id')->select();
foreach ($allConfigs as $config) {
if ($config['config_type'] == 4) {
$checkboxName = $config['config_name'] . '_checkbox';
$configName = $config['config_name'];
if (!isset($post[$checkboxName])) {
// 复选框未选中,手动添加对应的值为 0
$post[$configName] = 0;
} else {
// 复选框选中,确保值为 1
$post[$configName] = 1;
}
// 移除 checkbox 字段
unset($post[$checkboxName]);
}
}
$oConfig = new YzAdminConfig();
$updateAll = $oConfig->updateAll($post);
if (empty($updateAll)) {
Log::record('更新配置值', 0, '更新配置值失败', '系统配置');
$this->returnCode(1, '更新配置值失败');
}
Log::record('更新配置值', 1, '', '系统配置');
$this->returnCode(0);
} else {
$lists = AdminConfig::order('config_sort DESC,config_id')->select();
View::assign([
'lists' => $lists
]);
return View::fetch();
}
}
// 邮件配置
public function mailconfig()
{
if (Request::isPost()) {
$data = [
'smtp_host' => input('post.smtp_host'),
'smtp_port' => input('post.smtp_port'),
'smtp_email' => input('post.smtp_email'),
'smtp_password' => input('post.smtp_password'),
'smtp_name' => input('post.smtp_name')
];
// 验证必填字段
if (empty($data['smtp_host']) || empty($data['smtp_port']) || empty($data['smtp_email']) || empty($data['smtp_password'])) {
// Log::record('修改邮件配置', 0, '必填字段不能为空', '邮件配置');
return json(['code' => 1, 'msg' => '必填字段不能为空']);
}
$res = MailConfig::where('id', 1)->update($data);
if ($res === false) {
// Log::record('修改邮件配置', 0, '更新邮件配置失败', '邮件配置');
return json(['code' => 1, 'msg' => '更新邮件配置失败']);
}
// Log::record('修改邮件配置', 1, '', '邮件配置');
return json(['code' => 0, 'msg' => '更新成功']);
}
$config = MailConfig::where('id', 1)->find();
View::assign([
'config' => $config
]);
return View::fetch();
}
// 获取邮件配置
public function getMailConfig()
{
$config = MailConfig::where('id', 1)->find();
if ($config) {
return json(['code' => 0, 'msg' => '获取成功', 'data' => $config]);
}
return json(['code' => 1, 'msg' => '获取配置失败']);
}
// 测试邮件配置
public function testMailConfig()
{
if (!Request::isPost()) {
return json(['code' => 1, 'msg' => '请求方法无效']);
}
$email = input('post.email');
$config = input('post.config');
if (empty($email) || empty($config)) {
return json(['code' => 1, 'msg' => '参数错误']);
}
try {
// 配置邮件服务器
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = $config['smtp_host'];
$mail->Port = $config['smtp_port'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_email'];
$mail->Password = $config['smtp_password'];
$mail->SMTPSecure = 'ssl';
$mail->CharSet = 'UTF-8';
// 设置发件人
$mail->setFrom($config['smtp_email'], $config['smtp_name']);
$mail->addAddress($email);
// 设置邮件内容
$mail->isHTML(true);
$mail->Subject = '邮件配置测试';
$mail->Body = '这是一封测试邮件,如果您收到这封邮件,说明邮件配置正确。';
$mail->send();
return json(['code' => 0, 'msg' => '发送成功']);
} catch (\Exception $e) {
//Log::record('测试邮件配置', 0, $e->getMessage(), '邮件配置');
return json(['code' => 1, 'msg' => '发送失败:' . $e->getMessage()]);
}
}
}
File diff suppressed because it is too large Load Diff
+184
View File
@@ -0,0 +1,184 @@
<?php
/**
* 商业使用授权协议
*
* Copyright (c) 2025 [云泽网]. 保留所有权利.
*
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
*
* 授权购买请联系: 357099073@qq.com
* 官方网站: https://www.yunzer.cn
*
* 评估用户须知:
* 1. 禁止移除版权声明
* 2. 禁止用于生产环境
* 3. 禁止转售或分发
*/
namespace app\admin\controller;
use app\admin\controller\Base;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
class Yunzertest extends Base{
public function icon_list(){
$lists = Db::table('yz_z_iconfont')->where('status','=',1)->select();
View::assign([
'lists' => $lists
]);
return View::fetch();
}
public function test_list(){
if(Request::isPost()){
$count = Db::table('yz_z_test')->count();
$page = (int)input('post.page',1);
$limit = (int)input('post.limit',10);
$lists = Db::table('yz_z_test')->order('test_id DESC')->page($page,$limit)->select()->each(function($item, $key){
if($item['test_reference'] == 1){
$item['test_reference'] = '开启';
}else{
$item['test_reference'] = '关闭';
}
$item['test_time'] = date('Y-m-d H:i:s',$item['test_time']);
return $item;
});
$this->returnCode(0,$lists,$count);
}else{
return View::fetch();
}
}
public function test_add(){
if(Request::isPost()){
$data['test_input'] = input('post.test_input');
$data['test_reference'] = input('post.test_reference');
$data['test_time'] = input('post.test_time');
if(!empty($data['test_time'])){
$data['test_time'] = strtotime($data['test_time']);
}
$data['test_data'] = input('post.test_data');
$data['test_datatime'] = input('post.test_datatime');
$data['test_img'] = input('post.test_img');
$data['test_rich_baidu'] = input('post.test_rich_baidu');
$data['test_url'] = input('post.test_url');
$insert = Db::table('yz_z_test')->insert($data);
if(empty($insert)){
$this->returnCode('91000001');
}
$this->returnCode(0);
}else{
return View::fetch();
}
}
public function test_edit(){
if(Request::isPost()){
$test_id = input('post.test_id');
$data['test_input'] = input('post.test_input');
$data['test_reference'] = input('post.test_reference');
$data['test_time'] = input('post.test_time');
if(!empty($data['test_time'])){
$data['test_time'] = strtotime($data['test_time']);
}
$data['test_data'] = input('post.test_data');
$data['test_datatime'] = input('post.test_datatime');
$data['test_img'] = input('post.test_img');
$data['test_rich'] = input('post.test_rich');
$data['test_rich_baidu'] = input('post.test_rich_baidu');
$data['test_url'] = input('post.test_url');
$update = Db::table('yz_z_test')->where('test_id',$test_id)->update($data);
if(empty($update)){
$this->returnCode('91000002');
}
$this->returnCode(0);
}else{
$test_id = input('get.test_id');
$find = Db::table('yz_z_test')->where('test_id',$test_id)->find();
if(!empty($find)){
$find['test_time'] = date('Y-m-d H:i:s',$find['test_time']);
}
View::assign([
'find' => $find
]);
return View::fetch();
}
}
public function test_del(){
$test_id = (int)input('post.test_id');
$res = Db::table('yz_z_test')->where('test_id',$test_id)->delete();
if(empty($res)){
$this->returnCode('91000003');
}
$this->returnCode(0);
}
public function test_static_list(){
$lists = Db::table('yz_z_test')
->order('test_id DESC')
->paginate();
View::assign([
'lists' => $lists
]);
return View::fetch();
}
public function test_static_add(){
if(Request::isPost()){
$data['test_input'] = input('post.test_input');
$data['test_reference'] = input('post.test_reference');
$data['test_time'] = input('post.test_time');
if(!empty($data['test_time'])){
$data['test_time'] = strtotime($data['test_time']);
}
$data['test_data'] = input('post.test_data');
$data['test_datatime'] = input('post.test_datatime');
$data['test_img'] = input('post.test_img');
$data['test_rich_baidu'] = input('post.test_rich_baidu');
$data['test_url'] = input('post.test_url');
$insert = Db::table('yz_z_test')->insert($data);
if(empty($insert)){
$this->returnCode('91000001');
}
$this->returnCode(0);
}else{
return View::fetch();
}
}
public function test_static_edit(){
if(Request::isPost()){
$test_id = input('post.test_id');
$data['test_input'] = input('post.test_input');
$data['test_reference'] = input('post.test_reference');
$data['test_time'] = input('post.test_time');
if(!empty($data['test_time'])){
$data['test_time'] = strtotime($data['test_time']);
}
$data['test_data'] = input('post.test_data');
$data['test_datatime'] = input('post.test_datatime');
$data['test_img'] = input('post.test_img');
$data['test_rich'] = input('post.test_rich');
$data['test_rich_baidu'] = input('post.test_rich_baidu');
$data['test_url'] = input('post.test_url');
$update = Db::table('yz_z_test')->where('test_id',$test_id)->update($data);
if(empty($update)){
$this->returnCode('91000002');
}
$this->returnCode(0);
}else{
$test_id = input('get.test_id');
$find = Db::table('yz_z_test')->where('test_id',$test_id)->find();
if(!empty($find)){
$find['test_time'] = date('Y-m-d H:i:s',$find['test_time']);
if(!empty($find['test_img'])){
$find['test_img_s'] = explode(';',$find['test_img']);
}
}
View::assign([
'find' => $find
]);
return View::fetch();
}
}
}