首次上传

master
chenq 2021-08-09 10:38:25 +08:00
parent de93386661
commit d9ef4aadec
1068 changed files with 129054 additions and 0 deletions

19
.env.bak Normal file
View File

@ -0,0 +1,19 @@
APP_DEBUG = true
APP_TRACE = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = 211.149.245.223
DATABASE = dev_bee_cms
USERNAME = dev_bee_cms
PASSWORD = dT7yH5fmd28JG6ER
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = bee_
[LANG]
default_lang = zh-cn

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
.env
/.idea
/.vscode
backup/data/*
/config
*.log
runtime/*
storage/*
public/storage/*
.DS_Store
Test.php
nginx.htaccess
dump.rdb

32
LICENSE.txt Normal file
View File

@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似鼓励代码共享和尊重原作者的著作权
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1 需要给代码的用户一份Apache Licence
2 如果你修改了代码,需要在被修改的文件中说明;
3 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4 如果再发布的产品中包含一个Notice文件则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可但不可以表现为对Apache Licence构成更改。
具体的协议参考http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

1
app/.htaccess Normal file
View File

@ -0,0 +1 @@
deny from all

367
app/common.php Normal file
View File

@ -0,0 +1,367 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\exception\ClassNotFoundException;
// 应用公共文件
if (!function_exists('widget')) {
/**
* 渲染输出Widget
* @param string $name Widget名称
* @param array $data 传入的参数
* @return mixed
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function widget($name, $data = [])
{
return action($name, $data, 'widget');
}
}
if (!function_exists('action')) {
/**
* 调用模块的操作方法 参数格式 [模块/控制器/]操作
* @param string $url 调用地址
* @param string|array $vars 调用参数 支持字符串和数组
* @param string $layer 要调用的控制层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return mixed
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
{
$info = pathinfo($url);
$action = $info['basename'];
$module = '.' != $info['dirname'] ? $info['dirname'] : request()->controller();
$class = controller($module, $layer);
if (is_scalar($vars)) {
if (strpos($vars, '=')) {
parse_str($vars, $vars);
} else {
$vars = [$vars];
}
}
return app()->invokeMethod([$class, $action . config('route.action_suffix')], $vars);
}
}
if (!function_exists('controller')) {
/**
* 实例化(分层)控制器 格式:[模块名/]控制器名
* @access public
* @param string $name 资源地址
* @param string $layer 控制层名称
* @param bool $appendSuffix 是否添加类名后缀
* @param string $empty 空控制器名称
* @return object
* @throws ClassNotFoundException
*
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function controller($name, $layer = 'controller', $empty = '')
{
$class = parseClass($name, $layer);
if (class_exists($class)) {
return app()->make($class);
} elseif ($empty && class_exists($emptyClass = app()->parseClass($layer, $empty))) {
return app()->make($emptyClass);
}
throw new ClassNotFoundException('class not exists:' . $class, $class);
}
}
if (!function_exists('parseClass')) {
/**
* 解析模块和类名
* @access protected
* @param string $name 资源地址
* @param string $layer 验证层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return array
*
* milo 2019-05-08 从TP5.1代码中拿来修改的
*/
function parseClass($name, $layer)
{
if (false !== strpos($name, '\\')) {
$class = $name;
} else {
if (strpos($name, '/')) {
$names = explode('/', $name, 2);
$name = $names[1];
}
$class = app()->parseClass($layer,$name);
}
return $class;
}
}
if (!function_exists('randomStr')) {
/**
* 获取随机字符串
* @param int $type 0:数字(默认)1全部2:小写字母;3:大写字母4字母
* @param int $len 字符串长度
* @return string
*/
function randomStr($type = 0,$len = 5)
{
$strPol = "0123456789";
if($type == 1) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ0123456789abcdefghijklmopqrstuvwyz";
} elseif ($type == 2) {
$strPol = "abcdefghijklmopqrstuvwyz";
} elseif ($type == 3) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZ";
} elseif ($type == 4) {
$strPol = "ABCDEFGHIJKLMOPQRSTUVWYZabcdefghijklmopqrstuvwyz";
}
$max = strlen($strPol) - 1;
$str = '';
for ($i=0;$i<$len;$i++) {
$str .= $strPol[rand(0,$max)];
}
return $str;
}
}
if(!function_exists('isMobile')){
//判断访问终端是否为移动端
function isMobile()
{
// 如果有HTTP_X_WAP_PROFILE则一定是移动设备
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
// 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
if (isset($_SERVER['HTTP_VIA'])) {
// 找不到为flase,否则为true
return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
}
// 脑残法,判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$clientkeywords = ['nokia','sony','ericsson','mot','samsung','htc','sgh','lg','sharp','sie-','philips','panasonic','alcatel','lenovo','iphone','ipod','blackberry','meizu','android','netfront','symbian','ucweb','windowsce','palm','operamini','operamobi','openwave','nexusone','cldc','midp','wap','mobile','MicroMessenger'];
// 从HTTP_USER_AGENT中查找手机浏览器的关键字
if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
}
// 协议法,因为有可能不准确,放到最后判断
if (isset ($_SERVER['HTTP_ACCEPT'])) {
// 如果只支持wml并且不支持html那一定是移动设备
// 如果支持wml和html但是wml在html之前则是移动设备
if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
return true;
}
}
return false;
}
}
//根据栏目获取路径
if(!function_exists('getUri')){
function getUri($cate)
{
$url = '';
if(!empty($cate)){
if($cate['is_index']){
$url = '/';
}elseif(!empty($cate['url'])){
$url = $cate['url'];
}else{
$url = url($cate['template'].'/index', ['category_id' => $cate['id']]);
}
}
return $url;
}
}
//根据文件大小转换为文字
if(!function_exists('sizeToStr')){
function sizeToStr($size)
{
if(!is_numeric($size) || $size <= 0){
return '';
}
$size = $size / 1024;
if($size < 1024){
return sprintf("%.2fK", $size);
}
$size = $size / 1024;
if($size < 1024){
return sprintf("%.2fM", $size);
}
$size = $size / 1024;
return sprintf("%.2fG", $size);
}
}
//根据路径获取文件名
if(!function_exists('getKeyByPath')){
function getKeyByPath($path)
{
return substr($path, strrpos($path, '/')+1);
}
}
//富文本中提取图片路径
if(!function_exists('getImageUrlFromText')){
function getImageUrlFromText($content)
{
preg_match_all('/<img.*?src="(.*?)".*?>/is', $content, $imgs);
$data = [];
if(!empty($imgs) && !empty($imgs[1])){
foreach($imgs[1] as $img){
if(substr($img, 0, 4) != 'http'){
$key = getKeyByPath($img);
$data[$key] = $img;
}
}
}
return $data;
}
}
//富文本中提取视频路径
if(!function_exists('getVideoUrlFromText')){
function getVideoUrlFromText($content)
{
preg_match_all('/<video.*?src="(.*?)".*?>/is', $content, $videos);
$data = [];
if(!empty($videos) && !empty($videos[1])){
foreach($videos[1] as $video){
if(substr($video, 0, 4) != 'http'){
$key = getKeyByPath($video);
$data[$key] = $video;
}
}
}
return $data;
}
}
//获取目录下的所有文件
if(!function_exists('getAllFilesByPath')){
function getAllFilesByPath($path, $rootPath)
{
if(is_dir($path) && file_exists($path)){
$items = scandir($path);
$files = [];
foreach($items as $item){
if(substr($item, 0, 1) != '.' && strpos($item, '_') == false){
$itemPath = $path . '/' . $item;
if(is_file($itemPath)){
$size = filesize($itemPath);
$files[$item] = [
'path' => str_replace($rootPath, '/', $itemPath),
'realPath' => $itemPath,
'size' => $size,
'sizeStr' => sizeToStr($size),
'suffix' => strtolower(substr($item, strrpos($item, '.')+1)) //后缀
];
}elseif(is_dir($itemPath)){
$childFiles = getAllFilesByPath($itemPath, $rootPath);
if(!empty($childFiles)){
$files = array_merge($files, $childFiles);
}else{
rmdir($itemPath);
}
}
}
}
return $files;
}
return [];
}
}
//过滤get输入
if(!function_exists('getFilter')){
function getFilter($value){
$getFilter = "'|(and|or)\b.+?(>|<|=|in|like)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if(is_array($value)){
$forFilter = implode($value);
$forArray = true;
}else{
$forFilter = $value;
}
if (preg_match("/".$getFilter."/is", $forFilter) == 1){
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
//过滤post录入
if(!function_exists($postFilter)){
function postFilter($value){
$postFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if(is_array($value)){
$forFilter = implode($value);
$forArray = true;
}else{
$forFilter = $value;
}
if (preg_match("/".$postFilter."/is", $forFilter) == 1){
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
//过滤cookie数据
if(!function_exists('cookieFilter')){
function cookieFilter($value){
$cookieFilter = "\b(and|or)\b.{1,6}?(=|>|<|\bin\b|\blike\b)|\/\*.+?\*\/|<\s*script\b|\bEXEC\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\s+(TABLE|DATABASE)";
$forArray = false;
if(is_array($value)){
$forFilter = implode($value);
$forArray = true;
}else{
$forFilter = $value;
}
if (preg_match("/".$cookieFilter."/is", $forFilter) == 1){
$value = $forArray ? [] : '';
}
return filterExp($value);
}
}
if(!function_exists('filterExp')){
function filterExp($value){
$filter = '/^EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN$/i';
$forArray = false;
if(is_array($value)){
$forFilter = implode($value);
$forArray = true;
}else{
$forFilter = $value;
}
if (preg_match($filter, $forFilter) == 1){
$value = $forArray ? [] : '';
}
return $value;
}
}
if(!function_exists('arrayHtmlFilter')){
function arrayHtmlFilter($arr) {
foreach ($arr as $k => $one) {
if(is_array($one)) {
$arr[$k] = arrayHtmlFilter($one);
} else {
$one = trim($one);
$arr[$k] = strip_tags($one);
}
}
return $arr;
}
}

100
app/controller/Article.php Normal file
View File

@ -0,0 +1,100 @@
<?php
namespace app\controller;
use app\model\{Article as MArticle, Category};
use think\facade\View;
class Article extends Base
{
//详情
public function detail($id = 0)
{
if ($id <= 0) {
return $this->error('错误页面');
}
$article = MArticle::getById($id);
if (empty($article)) {
return $this->error('无此文章');
}
MArticle::updateById($id, ['views' => $article['views'] + 1]);
$category = Category::getById($article['category_id']);
$prev = MArticle::getPrevArticleByIdAndCategoryId($id, $article['category_id']);
$next = MArticle::getNextArticleByIdAndCategoryId($id, $article['category_id']);
$keywords = $article['seo_keywords'] ? $article['seo_keywords'] : $this->system['seo_keywords'];
$description = $article['seo_description'] ? $article['seo_description'] : $this->system['seo_description'];
$this->setSeo($article['title'], $keywords, $description);
$this->data['article'] = $article;
$this->data['category'] = $category;
$this->data['categoryId'] = $category['id'];
$this->data['prev'] = $prev;
$this->data['next'] = $next;
return $this->view($category['template_detail'] ?? '');
}
//列表页
public function index()
{
$categoryId = input('category_id/d', 0);
if ($categoryId <= 0) {
return $this->error('错误页面');
}
$category = Category::getById($categoryId);
$page_size = 20;
if( $category['number'])$page_size= $category['number'];
if( $this->request->param("page_size/d")){
$page_size= $this->request->param("page_size/d");
cookie("article_page_size",$this->request->param("page_size/d"));
}else{
if( cookie("?article_page_size"))$page_size= cookie("article_page_size");
}
if (empty($category)) {
return $this->error('错误页面');
}
$childCategory = Category::getChildrenByParentId($categoryId);
$description = $category['description'] ? $category['description'] : $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
$this->data['items'] = MArticle::getListPageByCategory($categoryId, $page_size);
$this->data['category'] = $category;
$this->data['categoryId'] = $categoryId;
$this->data['page_size'] = $page_size;
$this->data['article_count'] = MArticle::getListCount($categoryId);
return $this->view($category['template_list'] ?? '');
}
//查询
public function query()
{
$keyword = $this->request->param("keyword/s");
//无key值跳转到产品
if (!$keyword) $this->redirect((string)url('/articles/12.html'));
$where = [
['category_id', 'in', [5, 12, 13, 14, 15]],
['status', '=', 1],
];
$where[] = ['title', 'like', '%' . $keyword . '%'];
$param['keyword'] = $keyword;
$paginate = [
'list_rows' => 20,
'query' => $param
];
$data = MArticle::where($where)
->order("sort desc")
->paginate($paginate, false);
View::assign("items", $data);
View::assign("keyword", $keyword);
$this->data['category'] = Category::getById(5);
$this->data['categoryId'] = 5;
return $this->view("/article/product _query");
}
}

37
app/controller/Base.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace app\controller;
use app\controller\BaseController;
use app\model\System;
/**
* 控制器基础类
*/
class Base extends BaseController
{
//需要向模板传递的值
protected $data = [];
//系统配置信息
protected $system = [];
// 初始化
protected function initialize()
{
$this->system = System::getSystem();
$this->data['system'] = $this->system;
}
//设置SEO信息
protected function setSeo($title, $keywords, $description)
{
$this->data['seoTitle'] = $title;
$this->data['seoKeywords'] = $keywords;
$this->data['seoDescription'] = $description;
}
//模板
protected function view($template = '')
{
return view($template)->assign($this->data);
}
}

View File

@ -0,0 +1,193 @@
<?php
declare (strict_types = 1);
namespace app\controller;
use think\{App, Validate};
use think\exception\ValidateException;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* 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)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
}
/**
* 验证数据
* @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, '.')) {
// 支持场景
list($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);
}
/**
* 操作成功跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param string $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return void
*/
protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
{
if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
$url = $_SERVER["HTTP_REFERER"];
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 1,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('error/jump',$result));
}
/**
* 操作错误跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param string $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return void
*/
protected function error($msg = '', string $url = null, $data = '', int $wait = 3)
{
if (is_null($url)) {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = $this->request->isAjax() ? '' : '/';
} else {
$url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
}
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('error/jump', $result));
}
/**
* 返回封装后的API数据到客户端
* 以json格式抛出异常
* @access protected
* @param mixed $data 要返回的数据
* @param integer $code 返回的code
* @param mixed $msg 提示信息
* @param string $type 返回数据格式
* @param array $header 发送的Header信息
* @return void
*/
protected function json($code = 0, $msg = 'ok', $data= [])
{
$result = [
'code' => $code,
'msg' => $msg,
'time' => time(),
'data' => $data
];
return json($result);
}
/**
* URL重定向
* @access protected
* @param string $url 跳转的URL表达式
* @param array|integer $params 其它URL参数
* @param integer $code http code
* @param array $with 隐式传参
* @return void
*/
protected function redirect($url)
{
if(!is_string($url)){
$url = $url->__toString();
}
return redirect($url);
}
}

49
app/controller/Error.php Normal file
View File

@ -0,0 +1,49 @@
<?php
namespace app\controller;
class Error extends BaseController
{
public function __call($method, $args)
{
if(request()->isAjax()) {
return $this->json(404, 'error request!');
} else {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = '/';
} else {
$domain = $this->request->domain();
$urlInfo = parse_url($referer);
$scheme = $urlInfo['scheme'] ?? '';
$requestSrc = '';
if (!empty($scheme)) {
$requestSrc = $scheme.'://'.($urlInfo['host'] ?? '');
}
if($domain != $requestSrc) {
$url = '/';
} else {
$url = 'javascript:history.back(-1);';
}
}
$result = [
'code' => 404,
'msg' => '无效请求! 没有找到相关资源',
'data' => [],
'url' => $url,
'wait' => 5,
];
return view('error/400')->assign($result);
}
}
public function jump()
{
$param = request()->param();
return view()->assign($param);
}
}

31
app/controller/Home.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace app\controller;
use app\model\{Category, Block};
use think\facade\View;
class Home extends Base
{
protected $category_id;
protected function initialize()
{
parent::initialize(); // TODO: Change the autogenerated stub
$category = Category::getIndex();
$categoryId = $category['id'] ?? 0;
$this->data['categoryId'] = $categoryId;
$this->setSeo($this->system['seo_title'], $this->system['seo_keywords'], $this->system['seo_description']);
$this->data['blocks'] = Block::getByCategoryId($categoryId);
$this->category_id=$this->request->param("category_id/d");
}
//关于我们
public function aboutUs(){
$Block=["key1"=>"","key2"=>""];
$Block["key1"]=Block::getByKeyword(1,$this->category_id);
$Block["key2"]=Block::getByKeyword(2,$this->category_id);
dump($Block);
View::assign($Block);
return $this->view();
}
}

21
app/controller/Index.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace app\controller;
use app\model\{Category, Block};
use think\facade\View;
class Index extends Base
{
public function index()
{
$category = Category::getIndex();
$categoryId = $category['id'] ?? 0;
$this->data['categoryId'] = $categoryId;
$this->setSeo($this->system['seo_title'], $this->system['seo_keywords'], $this->system['seo_description']);
$this->data['blocks'] = Block::getByCategoryId($categoryId);
$category = Category::getById(1);
View::assign("category",$category);
return $this->view();
}
}

28
app/controller/Page.php Normal file
View File

@ -0,0 +1,28 @@
<?php
namespace app\controller;
use app\model\{Category, Block};
class Page extends Base
{
public function index()
{
$categoryId=$this->request->param("category_id");
$category = Category::getById($this->request->param("category_id"));
if ($category) {
$description = $category['description'] ? $category['description'] : $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
} else {
return $this->error('错误页面');
}
$childCategory = Category::getChildrenByParentId($categoryId);
$this->data['categoryId'] = $categoryId;
$this->data['category'] = $category;
$this->data['childCategory'] = $childCategory;
$this->data['blocks'] = Block::getByCategoryId($categoryId);
return $this->view($category['template_detail']);
}
}

View File

@ -0,0 +1,217 @@
<?php
namespace app\controller\manager;
use app\model\{Article as MArticle, Category, System, Log};
use app\validate\Article as VArticle;
use think\exception\ValidateException;
/**
* 内容管理 - 文章管理
*/
class Article extends Base
{
//批量修改属性
public function attribute()
{
if($this->request->isPost()){
$ids = input('post.id/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$data = [];
foreach(['top', 'hot', 'recommend'] as $key){
$val = input('post.'.$key, 0);
if(in_array($val, [1, 2])){
if($val == 1){
$data[$key] = 1;
}else{
$data[$key] = 0;
}
}
}
if(!empty($data)){
MArticle::whereIn('id', $ids)->update($data);
Log::write('article', 'attribute', '批量修改了文章属性涉及到的文章ID为' . implode(',', $ids));
}
return $this->json();
}
return $this->json(1, '非法请求!');
}
//批量删除
public function batchDel()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$items = MArticle::getListByIds($ids);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
}
MArticle::destroy($delIds);
Log::write('article', 'betchDel', '批量删除了文章涉及到的文章ID为' . implode(',', $delIds));
return $this->json();
}else{
return $this->json(3, '待删除文章列表为空');
}
}
return $this->json(1, '非法请求!');
}
//删除
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$item = MArticle::getById($id);
if(!empty($item)){
MArticle::destroy($id);
Log::write('article', 'del', '删除文章ID' . $id . ',标题:' . $item['title']);
return $this->json();
}
return $this->json(3,'待删除文章不存在');
}
return $this->json(2, '参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MArticle::getById($id);
if(empty($item)){
return $this->json(3, '该文章信息不存在');
}
if($sort == 'up'){
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}else{
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}
$forSortItems = MArticle::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MArticle();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('article', 'sort', "文章排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
//编辑
public function edit()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = input('post.img');
$id = input('post.id/d');
$article = MArticle::getById($id);
if (empty($article)) {
return $this->json(1, '该文章不存在!');
}
if(!empty($img)){
$item['src'] = $img;
}
try {
validate(VArticle::class)->check($item);
$auth = session('auth');
$item['update_time'] = time();
$item['updated'] = $auth['userName'];
MArticle::updateById($id, $item);
Log::write('article', 'edit', "文章编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}else{
$id = input('param.id');
$article = MArticle::getById($id);
$category = Category::getById($article['category_id']);
if($category['img_width'] && $category['img_height']){
$imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素';
}else{
$imgSize = System::getArticleImageSize();
}
$this->data['item'] = $article;
$this->data['category'] = $category;
$this->data['imgSize'] = $imgSize;
return $this->view();
}
}
//添加
public function add()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = input('post.img');
if(!empty($img)){
$item['src'] = $img;
}
try {
validate(VArticle::class)->check($item);
$content = $item['content'] ?? '';
if(isset($item['content'])){
unset($item['content']);
}
$item['content'] = $content;
$article = MArticle::create($item);
Log::write('article', 'add', "文章新增ID{$article->id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}else{
$categoryId = input('param.category_id');
$category = Category::getById($categoryId);
if(count($category) > 0 && $category['img_width'] && $category['img_height']){
$imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素';
}else{
$imgSize = System::getArticleImageSize();
}
$this->data['category'] = $category;
$this->data['imgSize'] = $imgSize;
return $this->view();
}
}
}

View File

@ -0,0 +1,153 @@
<?php
namespace app\controller\manager;
use think\facade\{Db, Config, Env};
use app\model\{Log as MLog};
use app\service\Tool;
class Backup extends Base
{
/**
* 因受mysql 配置参数net_buffer_length和max_allowed_packet大小的限制因此insert语句改为单条插入
* show VARIABLES like "%net_buffer_length%" 默认单条sql语句长度16k
* show VARIABLES like "%max_allowed_packet%" 默认单个sql文件最大容量
* sql 文件注释 -- + 空格之后填写注释内容
* 因根目录文件夹权限限制因此需要手动创建backup/data目录并赋予权限www用户组
*/
public function back()
{
ini_set('max_execution_time', 0);
ini_set("memory_limit",-1);
set_time_limit(0);
$path = Config::get('filesystem.disks.backup.root') . '/';
$dataBase = Env::get('database.database');
// 不要使用单引号,双引号中的变量可以解析,单引号就是绝对的字符串
$eol = "\r\n";
$eolB = "\r\n\r\n";
$info = '-- ------------------------------'.$eol;
$info .= '-- 日期: '.date('Y-m-d H:i:s',time()).$eol;
$info .= '-- MySQL --Database - '.$dataBase.$eol;
$info .= '-- ------------------------------'.$eol;
$info .= 'CREATE DATABASE IF NOT EXISTS `'.$dataBase.'` DEFAULT CHARACTER SET "utf8mb4" COLLATE "utf8mb4_general_ci";'.$eolB;
$info .= 'USE `'.$dataBase.'`;'.$eol;
if(is_dir($path)) {
if(!is_writable($path)) {
chmod($path, 0755);
}
} else {
mkdir($path, 0755, true);
}
$fileName = $path.$dataBase.'_'.date('YmdHis',time()).'.sql';
if(file_exists($fileName)) {
@unlink($fileName);
}
// 以追加的方式写入
file_put_contents($fileName, $info, FILE_APPEND);
$tables = Db::query('show tables');
foreach ($tables as $table) {
// 表结构
$tableName = $table['Tables_in_'.$dataBase];
$sqlTable = 'SHOW CREATE TABLE '.$tableName;
$res = Db::query($sqlTable);
$infoTable = '-- ------------------------------'.$eol;
$infoTable .= '-- Table structure for `'.$tableName.'`'.$eol;
$infoTable .= '-- ------------------------------'.$eolB;
$infoTable .= 'DROP TABLE IF EXISTS `'.$tableName.'`;'.$eolB;
$infoTable .= $res[0]['Create Table'].';'.$eolB;
// 表数据
$infoTable .= '-- ------------------------------'.$eol;
$infoTable .= '-- Data for the table `'.$tableName.'`'.$eol;
$infoTable .= '-- ------------------------------'.$eolB;
file_put_contents($fileName, $infoTable, FILE_APPEND);
$sqlData = 'select * from '.$tableName;
$data = Db::query($sqlData);
$count = count($data);
if ($count > 0) {
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
foreach ($data as $k => $item) {
$valStr = '(';
foreach ($item as $val) {
// 字符串转义
$val = addslashes($val);
$valStr .= '"'.$val.'", ';
}
// 去除最后的逗号和空格
$valStr = substr($valStr,0,strlen($valStr)-2);
// 限制单条sql语句在16K以内可根据mysql配置条件进行调整
$sqlLength = strlen($dataStr) + strlen($valStr);
if($sqlLength >= (1024 * 16 - 10)) {
$dataStr .= $valStr.');'.$eol;
file_put_contents($fileName, $dataStr, FILE_APPEND);
// 提前分段写入后需重置数据语句
if ($k <= ($count-1)) {
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
} else {
$dataStr = '';
}
} else {
if ($k < ($count-1)) {
$dataStr .= $valStr.'),'.$eol;
} else {
$dataStr .= $valStr.');'.$eolB;
}
}
}
file_put_contents($fileName, $dataStr, FILE_APPEND);
}
}
clearstatcache();
$backups = explode('/', $fileName);
$backupName = $backups[count($backups)-1];
$src = Config::get('filesystem.disks.backup.url') . '/';
return $this->json(0, '备份成功:' . $src . $backupName);
}
public function index()
{
$path = Config::get('filesystem.disks.backup.root') . '/';
$src = Config::get('filesystem.disks.backup.url') . '/';
$items = [];
if(is_dir($path)) {
if(!is_readable($path)) {
chmod($path,0755);
}
$files = scandir($path);
foreach ($files as $file) {
if($file != '.' && $file != '..') {
$ext = substr($file, -4);
if ($ext == '.sql') {
$creatTime = substr($file, -18, 14);
$items[] = [
'file' => $file,
'path' => $src . $file,
'time' =>is_numeric($creatTime) ? date('Y-m-d H:i:s', strtotime($creatTime)) : '',
];
}
}
}
}
clearstatcache();
$this->data['items'] = $items;
$this->data['backupPath'] = str_replace('\\','/', $path);
return $this->view();
}
public function del()
{
if (request()->isPost()) {
$filePath = input('post.id');
Tool::delFile($filePath);
MLog::write('backup', 'del', '删除了备份数据文件,文件路径为:' . $filePath);
return $this->json();
} else {
return $this->json(1, '非法请求');
}
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace app\controller\manager;
use app\controller\BaseController;
/**
* 控制器基础类
*/
class Base extends BaseController
{
protected $data = [];
protected function initialize()
{
$this->middleware = [
'csrf',
'auth' => [
'except' => ['manager.login/index']
]
];
$auth = session('auth');
$this->data['member'] = $auth;
if(session('?__token__')){
$this->data['_token'] = session('__token__');
}else{
$this->data['_token'] = $this->request->buildToken();
}
$this->data['groupId'] = $auth['groupId'] ?? 0;
}
//变量赋值到模板
protected function view()
{
return view()->assign($this->data);
}
protected function error($msg = '', string $url = null, $data = '', int $wait = 3)
{
if (is_null($url)) {
$url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
} elseif ($url) {
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
}
$result = [
'code' => 0,
'msg' => $msg,
'data' => $data,
'url' => $url,
'wait' => $wait,
];
return $this->redirect(url('manager.error/jump', $result));
}
}

View File

@ -0,0 +1,235 @@
<?php
namespace app\controller\manager;
use app\model\{Category as MCategory, Model as MCModel, Log};
use app\validate\Category as VCategory;
use think\exception\ValidateException;
use think\facade\Cache;
class Category extends Base
{
//栏目列表
public function index()
{
$auth = session('auth');
$authCates = array_filter(explode(',', $auth['cates']));
if ($auth['groupId'] == 1) {
$cates = MCategory::getList();
} else {
$cates = MCategory::getList(true, $authCates);
}
$items = MCategory::getCates($cates);
$powerAdd = false;
$ruleNames = Cache::get('rule_names_'.$auth['groupId']);
if (is_array($ruleNames) && in_array('category/add', $ruleNames, true)) {
$powerAdd = true;
}
$this->data['items'] = $items;
$this->data['power_add'] = $powerAdd;
return $this->view();
}
//批量删除
public function batchDel()
{
if($this->request->isPost()){
$ids = input('post.ids/a');
if(is_array($ids)) {
$idsArr = $ids;
} else {
$idsArr = array_filter(explode(',', $ids));
}
if(count($idsArr) == 0) {
return $this->json(1, '无效请求,参数错误!');
}
if (MCategory::hasChildren($idsArr)) {
return $this->json(2, '需删除的栏目下存在下级栏目,不可删除。请检查核实后再操作!');
}
$categories = MCategory::getListByIds($idsArr);
if(!empty($categories)){
$hasIds = [];
foreach($categories as $cate){
$hasIds[] = $cate['id'];
}
MCategory::destroy($hasIds);
Log::write('category', 'betchDel', '批量删除了栏目涉及到的ID为' . implode(',', $hasIds));
return $this->json();
}
return $this->json(3, '删除失败!栏目不存在,请刷新页面后再试!');
}
return $this->json(1, '非法请求!');
}
/**
* 删除
*/
public function del()
{
if($this->request->isPost()){
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
if(MCategory::hasChildren($id)){
return $this->json(4, '此栏目有下级栏目,不可删除。请检查核实后再操作!');
}
$cate = MCategory::getById($id);
if(!empty($cate)){
MCategory::destroy($id);
Log::write('category', 'del', '删除栏目ID' . $id . ',标题:' . $cate['title']);
return $this->json();
}
return $this->json(3, '删除失败!栏目不存在,请刷新页面后再试!');
} else {
return $this->json(2, '无效请求,参数错误!');
}
}
return $this->json(1, '非法请求!');
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MCategory::getById($id);
if(empty($item)) {
return $this->json(3, '无此栏目!');
}
if($sort == 'up'){
$where = "parent_id='{$item['parent_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "parent_id='{$item['parent_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MCategory::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MCategory();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('category', 'sort', "栏目排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
/**
* 更新栏目数据
*/
public function edit()
{
if($this->request->isPost()){
$item = input('post.item/a');
$id = input('post.id');
$img = input('post.img');
if (count($item) > 0 && (is_numeric($id) === true && $id > 0)) {
try {
validate(VCategory::class)->check($item);
if(!empty($img)){
$item['src'] = $img;
}
MCategory::updateById($id, $item);
Log::write('category', 'edit', "栏目编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
return $this->json(1,'传入参数错误,请核对之后再操作!');
} else {
$id = input('param.id');
if (is_numeric($id) === true && $id > 0) {
$item = MCategory::getById($id);
if(empty($item)){
return $this->json(1,'参数错误,无此栏目!');
}
$this->data['item'] = $item;
$this->data['parent'] = MCategory::getById($item['parent_id']);
$this->data['models'] = MCModel::getList();
return $this->view();
}
return $this->json(1,'参数错误,请核对之后再操作!');
}
}
/**
* 栏目添加
*/
public function add()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = input('post.img');
if (is_array($item) === true && count($item) > 0) {
if (!empty($img)) {
$item['src'] = $img;
}
try {
validate(VCategory::class)->check($item);
if(!isset($item['number']) || $item['number'] <= 0){
$item['number'] = 20;
}
if($item['parent_id'] == 0){
$item['path'] = ',0,';
}else{
$parent = MCategory::getById($item['parent_id']);
if(empty($parent)){
$item['path'] = ',0,';
}else{
$item['path'] = $parent['path'] . $parent['id'] . ',';
}
}
$category = MCategory::create($item);
Log::write('category', 'add', "栏目新增ID{$category->id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2,$e->getError());
}
}
return $this->json(1, '传入值错误,请核对之后再操作!');
} else {
$parentId = input('param.id')??input('param.parent_id');
if(empty($parentId)){
$parent = [];
}else{
$parent = MCategory::getById($parentId);
}
$this->data['parent'] = $parent;
$this->data['models'] = MCModel::getList();
return $this->view();
}
}
}

View File

@ -0,0 +1,173 @@
<?php
namespace app\controller\manager;
use app\model\{Category, Article, Block, Log, History};
class Content extends Base
{
//文章
public function article()
{
$categoryId = input('param.category_id');
$keyword = input('param.keyword');
$param = input('param.param/a', []);
$category = Category::getById($categoryId);
if(empty($category)){
return $this->error('无此栏目');
}
$list = Article::getList($categoryId, 20, $keyword, $param);
$this->data['list'] = $list;
$this->data['category'] = $category;
$this->data['keyword'] = $keyword;
$this->data['param'] = $param;
return $this->view();
}
//做页面跳转
public function index()
{
$items = Category::getList();
if(!empty($items)){
$items = Category::getCates($items);
}
if(!empty($items)){
$first = array_shift($items);
if(isset($first['children'])){
$childrenFirst = array_shift($first['children']);
$url = url('manager.content/'.$childrenFirst['manager'],['category_id' => $childrenFirst['id']]);
}else{
$url = url('manager.content/'.$first['manager'],['category_id' => $first['id']]);
}
if(!empty($url)){
return $this->redirect($url);
}
}else{
return $this->redirect(url('manager.category/add'));
}
}
//单页
public function page()
{
if($this->request->isAjax()){
$blocks = input('post.block/a'); //所有文本信息
$texts = input('post.text/a'); //所有富文本信息
$codes = input('post.code/a'); //所有代码信息
$categoryId = input('post.category_id/d');
$category = Category::getById($categoryId);
unset($_POST['block']);
unset($_POST['text']);
unset($_POST['file']);
unset($_POST['code']);
$imgs = []; //图片信息
$videos = []; //视频信息
$groups = []; //组图信息
$groupIds = input('post.groupIds/a', []);
foreach($_POST as $key => $val){
if(strpos($key, '_') !== FALSE){
$keys = explode('_',$key);
if($keys[1] == 'img'){ //图片
$imgs[$keys[2]] = $val;
}elseif($keys[1] == 'video'){ //视频
$videos[$keys[2]][$keys[0]] = $val;
}elseif($keys[1] == 'group'){ //组图
$groups[$keys[2]] = $val;
}
}
}
$data = [];
if(!empty($blocks)){
foreach($blocks as $key => $block){
$data[] = [
'id' => $key,
'value' => $block
];
}
}
if(!empty($texts)){
foreach($texts as $key => $text){
$data[] = [
'id' => $key,
'value' => $text
];
}
}
if(!empty($codes)){
foreach($codes as $key => $code){
$data[] = [
'id' => $key,
'value' => $code
];
}
}
if(!empty($imgs)){
foreach($imgs as $key => $img){
$data[] = [
'id' => $key,
'value' => $img
];
}
}
if(!empty($videos)){
foreach($videos as $key => $video){
$data[] = [
'id' => $key,
'img' => $video['img'],
'value' => $video['video']
];
}
}
if(!empty($groupIds)){
foreach($groupIds as $key => $groupId){
$group = $groups[$groupId] ?? [];
$data[] = [
'id' => $groupId,
'value' => json_encode($group)
];
}
}
$block = new Block;
$block->saveAll($data);
Log::write('content', 'page', "单页编辑栏目ID{$category['id']} ,标题:{$category['title']}");
return $this->json();
}else{
$categoryId = input('param.category_id');
$children = Category::getChildrenByParentId($categoryId);
if(empty($children)){
$category = Category::getById($categoryId);
}else{
$child = Category::getChildrenByParentId($children[0]['id']);
if(empty($child)){
$category = $children[0];
}else{
$category = $child[0];
}
}
if(empty($category)){
return $this->redirect(url('manager.content/index'));
}
$blocks = Block::getByCategoryId($category['id']);
$this->data['categoryId'] = $categoryId;
$this->data['category'] = $category;
$this->data['blocks'] = $blocks;
$this->data['groupId'] = session('auth.groupId');
$this->data['types'] = Block::getTypes();
return $this->view();
}
}
// 发展历程
public function history()
{
$categoryId = input('param.category_id/d', 0);
$category = Category::getById($categoryId);
if(empty($category)){
return $this->redirect(url('manager.content/index'));
}
$this->data['categoryId'] = $categoryId;
$this->data['category'] = $category;
$this->data['items'] = History::getPaginateList($categoryId, 20, false);
return $this->view();
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace app\controller\manager;
class Error
{
public function jump()
{
$param = request()->param();
return view()->assign($param);
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace app\controller\manager;
use app\model\{File as MFile, Article, Block, Category, Link, Slide, Log};
use app\service\Tool;
class File extends Base
{
//删除磁盘上的文件
public function delPath()
{
if ($this->request->isPost()) {
$paths = input('post.paths/a');
if(!empty($paths)){
foreach($paths as $path){
Tool::delFile($path);
}
Log::write('file', 'delPath', '批量删除了磁盘文件,涉及到的文件路径为:' . implode(',', $paths));
return $this->json();
}
return $this->json(2, '待删除文件列表为空');
}
return $this->json(1, '非法请求!');
}
//删除文件记录
public function del()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$items = MFile::getListByIds($ids);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
if($item['type'] == MFile::IMG){
Tool::delFile($item['src'], 1);
}else{
Tool::delFile($item['src']);
}
}
MFile::destroy($delIds);
Log::write('file', 'del', '批量删除了文件涉及到的文件ID为' . implode(',', $delIds));
return $this->json();
}else{
return $this->json(3, '待删除文件列表为空');
}
}
return $this->json(1, '非法请求!');
}
/**
* 未使用文件列表,
* 1. 遍历数据库中使用的图片视频及文件路径
* 2. 遍历上传目录中的文件
* 3. 数据对比,找出存在目录中的文件&不在数据库中的文件
* 4. 页面上显示查找出来的文件
*/
public function unuse()
{
$filesInUse = $this->getAllFilesInUse(); //数据库中在使用的文件
$rootPath = app()->getRootPath();
$uploadPath = $rootPath . 'storage';
$uploadedFiles = getAllFilesByPath($uploadPath, $rootPath); //磁盘上上传的文件
$files = MFile::getAll();
$dbUploadedFiles = []; //数据库中上传的文件
foreach($files as $file){
$src = trim($file['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$dbUploadedFiles[$key] = $file;
}
}
$uploadedNotInUseFiles = array_diff_key($uploadedFiles, $filesInUse); //磁盘上上传未使用的文件
$dbUploadedNotInUseFiles = array_diff_key($dbUploadedFiles, $filesInUse); //数据库中上传未使用的文件
$bothNotInUseFiles = array_intersect_key($uploadedNotInUseFiles, $dbUploadedNotInUseFiles); //磁盘和数据库中,两边都未使用
$this->data['uploadedNotInUseFiles'] = $uploadedNotInUseFiles;
$this->data['dbUploadedNotInUseFiles'] = $dbUploadedNotInUseFiles;
$this->data['bothNotInUseFilesKey'] = array_keys($bothNotInUseFiles);
return $this->view();
}
//获取所有在使用的文件
private function getAllFilesInUse()
{
$files = [];
$blockFiles = Block::getFilesInUse();
if(!empty($blockFiles)){
$files = array_merge($files, $blockFiles);
}
$slideFiles = Slide::getFilesInUse();
if(!empty($slideFiles)){
$files = array_merge($files, $slideFiles);
}
$linkFiles = Link::getFilesInUse();
if(!empty($linkFiles)){
$files = array_merge($files, $linkFiles);
}
$categoryFiles = Category::getFilesInUse();
if(!empty($categoryFiles)){
$files = array_merge($files, $categoryFiles);
}
$articleFiles = Article::getFilesInUse();
if(!empty($articleFiles)){
$files = array_merge($files, $articleFiles);
}
return $files;
}
//ajax获取文件列表
public function ajaxList()
{
if($this->request->isAjax()){
$page = input('param.page/d', 1);
$size = input('param.size/d', 20);
if(!is_integer($page) || $page < 1){
$page = 1;
}
if (!is_integer($size) || $size < 1) {
$size = 20;
}
$type = input('param.type', '');
if(!in_array($type, array_keys(MFile::getTypes()))){
$type = '';
}
$items = MFile::getList($type, $page, $size);
return $this->json(0, 'ok', $items);
}
return $this->json(1, '无此操作');
}
//列表
public function index()
{
$items = MFile::getListPage();
$this->data['items'] = $items;
$this->data['types'] = MFile::getTypes();
return $this->view();
}
}

View File

@ -0,0 +1,141 @@
<?php
namespace app\controller\manager;
use app\model\{AuthGroup, AuthRule, Log};
use app\validate\AuthGroup as VAuthGroup;
use think\exception\ValidateException;
/**
* 角色管理控制器
*/
class Group extends Base
{
/**
* 角色、分组删除
*/
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if (is_numeric($id) === true && $id > 0) {
$item = AuthGroup::getById($id);
if(!empty($item)){
AuthGroup::destroy($id);
Log::write('group', 'del', '删除角色ID' . $id . ',名称:' . $item['title']);
return $this->json();
}
}
return $this->json(2, '传入参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
/**
* 角色、分组权限分配
*/
public function rule()
{
if($this->request->isPost()){
$rules = input('post.rules/a');
$groupId = input('post.group_id/d');
if (is_array($rules) && (is_numeric($groupId) === true && $groupId > 0)) {
$group = AuthGroup::getById($groupId);
if(empty($group)){
return $this->json(2, '无此角色信息,请核对之后再操作!');
}
AuthGroup::updateRules($groupId, $rules);
// 重置该角色对应的权限缓存
AuthGroup::resetGroupRulesCache($groupId);
Log::write('group', 'rule', '角色分配权限ID' . $groupId . ',名称:' . $group['title']);
return $this->json();
}else{
return $this->json(3, '传入参数错误,请核对之后再操作!');
}
} else {
$groupId = input('param.group_id/d');
$group = AuthGroup::getById($groupId);
if(!empty($group)){
$rules = AuthRule::getListTree();
$this->data['group_id'] = $groupId;
$this->data['group'] = $group;
$this->data['rules'] = $rules;
return $this->view();
}else{
return $this->json(1, '无此角色信息,请核对之后再操作!');
}
}
}
/**
* 角色、分组添加
* @param int $status 1:正常0禁止
*/
public function add()
{
if($this->request->isPost()){
$title = trim(input('post.title'));
$status = input('post.status/d');
if (!empty($title) && (is_numeric($status) === true) && ($status == 1 || $status == 0)) {
$item = [
'title' => $title,
'status' => $status
];
try {
validate(VAuthGroup::class)->check($item);
$group = AuthGroup::create($item);
Log::write('group', 'add', "角色新增ID{$group->id} ,标题:{$group->title}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}else{
return $this->view();
}
}
/**
* 角色、分组编辑
*/
public function edit()
{
if($this->request->isPost()){
$title = trim(input('post.title'));
$status = input('post.status/d');
$id = input('post.id/d');
if (!empty($title) && ($status == 1 || $status == 0) && (is_numeric($id) === true && $id > 0)) {
$item = [
'title' => $title,
'status' => $status
];
try {
validate(VAuthGroup::class)->check($item);
AuthGroup::updateById($id, $item);
Log::write('group', 'edit', "角色编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}else{
$id = input('param.id/d');
if (is_numeric($id) === true && $id > 0) {
$item = AuthGroup::getById($id);
$this->data['item'] = $item;
return $this->view();
}
return $this->json(1, '传入参数错误,请核对之后再操作!');
}
}
/**
* 所有角色分组信息
* @return void
*/
public function index()
{
$list = AuthGroup::select()->toArray();
$this->data['list'] = $list;
return $this->view();
}
}

View File

@ -0,0 +1,345 @@
<?php
namespace app\controller\manager;
use app\model\{HistoryInfo as MHistoryInfo, History as MHistory, Category as MCategory, Log as MLog, System};
use think\exception\ValidateException;
use app\validate\{History as VHistory, HistoryInfo as VHistoryInfo};
use think\facade\Db;
/**
* 发展历程
* Class History
* @package app\controller\manager
*/
class History extends Base
{
public function add()
{
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
try {
validate(VHistory::class)->check($params);
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
'category_id' => $params['category_id'],
];
$newItem = MHistory::create($data);
MLog::write('history', 'add', '新增发展历程ID:'.$newItem->id);
} catch (ValidateException $e) {
return $this->json(1, $e->getError());
}
return $this->json();
} else {
$categoryId = input('param.category_id/d', 0);
$category = MCategory::getById($categoryId);
$this->data['category'] = $category;
return $this->view();
}
}
public function edit()
{
$id = input('param.id/d', 0);
$item = MHistory::getById($id);
if(count($item) == 0) {
return $this->json(1, '该历程信息不存在');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
try {
validate(VHistory::class)->check($params);
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
];
MHistory::updateById($id, $data);
MLog::write('history', 'edit', '修改发展历程ID:'.$id);
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
return $this->json();
} else {
$this->data['item'] = $item;
return $this->view();
}
}
public function sort()
{
if(request()->isPost()) {
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MHistory::getById($id);
if(empty($item)){
return $this->json(3, '该历程信息不存在');
}
if($sort == 'up'){
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MHistory::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MHistory();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
MLog::write('history', 'sort', "发展历程排序ID{$id} {$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '无此操作');
}
// 删除历程和历程相关的事例
public function del()
{
if(request()->isPost()) {
$historyId = input('param.id/d', 0);
$item = MHistory::getById($historyId);
if(count($item) == 0) {
return $this->json(2, '该历程信息不存在');
}
Db::startTrans();
try {
MHistory::destroy($historyId);
$hasInfo = MHistoryInfo::countByHistoryId($historyId);
if($hasInfo > 0) {
MHistoryInfo::delByHistoryId($historyId);
}
MLog::write('history','del', '删除历程ID:'.$historyId);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return $this->json(3, '删除失败,'.$e->getMessage());
}
return $this->json();
}
return $this->json(1, '无此操作');
}
public function info()
{
$historyId = input('param.history_id/d', 0);
$history = MHistory::getById($historyId);
$infoItems = [];
$categoryId = $history['category_id'] ?? 0;
if(count($history) > 0) {
$infoItems = MHistoryInfo::getByHistoryId($historyId);
}
$this->data['history'] = $history;
$this->data['categoryId'] = $categoryId;
$this->data['items'] = $infoItems;
return $this->view();
}
// 新增发展历程详情
public function addInfo()
{
$historyId = input('param.history_id/d', 0);
$history = MHistory::getById($historyId);
if(count($history) == 0) {
return $this->json(1, '该历程信息不存在');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
$imgs = input('post.img/a');
if (!empty($imgs) && is_array($imgs)) {
$imgs = json_encode($imgs);
} else {
$imgs = '';
}
try {
validate(VHistoryInfo::class)->check($params);
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
'history_id' => $historyId,
'imgs' => $imgs,
];
$newItem = MHistoryInfo::create($data);
MLog::write('history', 'addInfo', '新增发展历程事例ID:'.$newItem->id);
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
return $this->json();
} else {
$imgSize = '';
$category = MCategory::getById($history['category_id']);
if(count($category) > 0 && $category['img_width'] && $category['img_height']){
$imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素';
}
$this->data['historyId'] = $historyId;
$this->data['history'] = $history;
$this->data['imgSize'] = $imgSize;
return $this->view();
}
}
// 编辑发展历程详情
public function editInfo()
{
$id = input('param.id/d', 0);
$item = MHistoryInfo::getById($id);
if(count($item) == 0) {
return $this->json(1, '该历程事例信息不存在');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
$imgs = input('post.img/a');
if (!empty($imgs) && is_array($imgs)) {
$imgs = json_encode($imgs);
} else {
$imgs = '';
}
try {
validate(VHistoryInfo::class)->check($params);
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
'imgs' => $imgs,
];
MHistoryInfo::updateById($id, $data);
MLog::write('history', 'editInfo', '修改发展历程事例ID:'.$id);
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
return $this->json();
} else {
$history = MHistory::getById($item['history_id']);
$imgSize = '';
if(count($history) > 0) {
$category = MCategory::getById($history['category_id']);
if(count($category) > 0 && $category['img_width'] && $category['img_height']){
$imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素';
}
}
$this->data['item'] = $item;
$this->data['imgSize'] = $imgSize;
return $this->view();
}
}
public function sortInfo()
{
if(request()->isPost()) {
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MHistoryInfo::getById($id);
if(empty($item)){
return $this->json(3, '该历程事例信息不存在');
}
if($sort == 'up'){
$where = "history_id='{$item['history_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "history_id='{$item['history_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MHistoryInfo::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MHistoryInfo();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
MLog::write('history', 'sortInfo', "发展历程事例排序ID{$id} {$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '无此操作');
}
public function delInfo()
{
if(request()->isPost()) {
$infoIds = [];
$ids = input('post.ids', []);
$id = input('post.id', 0);
if(!empty($ids)) {
if(is_array($ids)) {
$infoIds = $ids;
} else {
$infoIds = explode(',', $ids);
}
} elseif($id > 0) {
$infoIds[] = $id;
}
if(count($infoIds) > 0) {
MHistoryInfo::destroy($infoIds);
MLog::write('history','delInfo', '删除历程事例IDs:'.implode(',', $infoIds));
return $this->json();
}
return $this->json(2, '参数错误');
}
return $this->json(1, '无此操作');
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace app\controller\manager;
class Index extends Base
{
//后台首页
public function index()
{
return $this->redirect(url('manager.safe/index'));
}
}

View File

@ -0,0 +1,177 @@
<?php
namespace app\controller\manager;
use app\model\{Link as MLink, System, Log};
use app\validate\Link as VLink;
use think\exception\ValidateException;
class Link extends Base
{
//批量删除
public function batchDel()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$items = MLink::getListByIds($ids);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
}
MLink::destroy($delIds);
Log::write('link', 'betchDel', '批量删除了友情链接涉及到的ID为' . implode(',', $delIds));
return $this->json();
}else{
return $this->json(3, '待删除友情链接为空');
}
}
return $this->json(1, '非法请求!');
}
//删除
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$item = MLink::getById($id);
if(!empty($item)){
MLink::destroy($id);
Log::write('link', 'del', '删除友情链接ID' . $id . ',标题:' . $item['title']);
return $this->json();
}
return $this->json(3, '待删除友情链接不存在');
}
return $this->json(2, '参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MLink::getById($id);
if(empty($item)){
return $this->json(3, '该友情链接信息不存在!');
}
if($sort == 'up'){
$where = "sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MLink::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MLink();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('link', 'sort', "友情链接排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
//编辑
public function edit()
{
if($this->request->isPost()){
$item = input('post.item/a');
$id = input('post.id/d');
$img = input('post.img');
if(is_numeric($id) && $id > 0) {
$link = MLink::getById($id);
if(empty($link)) {
return $this->json(2, '该友情链接信息不存在!');
}
if(!empty($img)){
$item['src'] = $img;
}
try {
validate(VLink::class)->check($item);
MLink::updateById($id, $item);
Log::write('link', 'edit', "友情链接编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
return $this->json(1, '参数错误,请核对之后再操作!');
} else {
$id = input('param.id/d');
$item = MLink::getById($id);
$imgSize = System::getLinkImageSize();
$this->data['item'] = $item;
$this->data['img_size'] = $imgSize;
return $this->view();
}
}
//添加
public function add()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = input('post.img');
if(!empty($img)){
$item['src'] = $img;
}
try {
validate(VLink::class)->check($item);
$link = MLink::create($item);
Log::write('link', 'add', "友情链接新增ID{$link->id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
} else {
$imgSize = System::getLinkImageSize();
$this->data['img_size'] = $imgSize;
return $this->view();
}
}
public function index()
{
$items = MLink::getList();
$this->data['items'] = $items;
return $this->view();
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace app\controller\manager;
use app\model\{Member, AuthRule, LoginLog};
use app\controller\BaseController;
class Login extends BaseController
{
/**
* user lgoin
* use ajax post push
*
* @return void | JSON
*/
public function index()
{
if(request()->isPost()){
$username = trim(input('param.username'));
$password = trim(input('param.password'));
$loginUrl = url('manager.login/index');
if(empty($username) || empty($password)){
session('loginError','用户名和密码不能为空');
return $this->redirect($loginUrl);
}
$member = Member::getByUserName($username);
if(empty($member)){
session('loginError','用户名错误');
return $this->redirect($loginUrl);
}
if($member['password'] != md5($password)){
session('loginError','用户密码错误');
return $this->redirect($loginUrl);
}
$rulesList = AuthRule::userRolesList($member['group_id']);
$rulesIdStr = '';
if (!empty($rulesList)) {
$rulesId = $rulesList['allRulesId'];
$rulesIdStr = implode(',', $rulesId);
}
$authSession = [
'userId' => $member['id'],
'userName' => $member['username'],
'groupId' => $member['group_id'],
'rules' => $rulesIdStr,
'cates' => $member['cates']
];
//记录最后登陆时间
$ip = request()->ip();
$time = time();
Member::updateById($member['id'], [
'login_time' => $time,
'login_ip' => $ip
]);
LoginLog::create([
'member_id' => $member['id'],
'name' => $member['username'],
'ip' => $ip,
'create_time' => $time
]);
session('auth', $authSession);
return redirect(url('manager.index/index'));
}
$viewData = [];
if(session('?loginError')) {
$viewData['error'] = session('loginError');
}
session('loginError', null);
return view()->assign($viewData);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace app\controller\manager;
use app\controller\BaseController;
class Logout extends BaseController
{
public function index()
{
session(null);
return redirect(url('manager.login/index'));
}
}

View File

@ -0,0 +1,181 @@
<?php
namespace app\controller\manager;
use app\model\{Category, AuthGroup, Member as MMember, Log};
use Exception;
use think\facade\Db;
class Member extends Base
{
/**
* 删除管理用户
*/
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if (is_numeric($id) === true && $id > 0) {
$item = MMember::getByID($id);
if(!empty($item)){
MMember::destroy($id);
Log::write('member', 'del', "管理员删除ID{$id}, 管理员:{$item['username']}");
return $this->json();
}
}
return $this->json(2, '参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
/**
* 修改管理用户信息
* 由于try语法中抛出的异常类型与$this->json()抛出的异常类型不一致,因此需要利用$errorMsg 来判断返回情况
*/
public function edit()
{
if($this->request->isPost()){
$id = input('post.id/d');
$username = trim(input('post.username'));
$password = trim(input('post.password'));
$groupId = input('post.group_id/d');
if ((is_numeric($id) === true && $id > 0) && ((is_numeric($groupId) === true && $groupId > 0) && !empty($username))) {
$member = MMember::getByUserName($username);
if(!empty($member) && $member['id'] != $id){
return $this->json(2, '该用户名已被使用!');
}
$errorMsg = '';
Db::startTrans();
try {
$member = MMember::getById($id);
$item = [
'username' => $username,
'group_id' => $groupId
];
//角色权限重新赋值
$group = AuthGroup::getById($groupId);
$item['rules'] = $group['rules'];
if(!empty($password)){
$item['password'] = md5($password);
}
MMember::updateById($id, $item);
Log::write('member', 'edit', "管理员编辑ID{$id}, 管理员:{$item['username']}");
Db::commit();
} catch (Exception $e) {
Db::rollback();
$errorMsg = '用户信息修改失败!'.$e->getMessage();
}
if (empty($errorMsg)) {
return $this->json();
}
return $this->json(3, $errorMsg);
}
return $this->json(1, '参数错误,请核对之后再操作!');
}else{
$id = input('param.id/d');
if (is_numeric($id) === true && $id > 0) {
$member = MMember::getByID($id);
$item = [
'id' => $member['id'],
'username' => $member['username'],
'group_id' => $member['group_id']
];
$auth = session('auth');
$groups = AuthGroup::getListById($auth['groupId']);
$this->data['groups'] = $groups;
$this->data['item'] = $item;
return $this->view();
}
return $this->json(1, '参数错误,请核对之后再操作!');
}
}
/**
* 新增管理用户
*/
public function add()
{
if($this->request->isPost()){
$groupId = input('post.group_id/d');
$username = trim(input('post.username'));
$password = trim(input('post.password'));
if ((is_numeric($groupId) === true && $groupId > 0) && ($username != "" && $password != "")) {
$member = MMember::getByUserName($username);
if(!empty($member)){
return $this->json(2, '该用户名已被使用!');
}
$group = AuthGroup::getById($groupId);
$newMember = MMember::create([
'username' => $username,
'group_id' => $groupId,
'password' => md5($password),
'rules' => $group['rules'],
'cates' => '',
'login_time' => 0,
]);
Log::write('member', 'add', "管理员新增ID{$newMember->id}, 管理员:{$newMember['username']}");
return $this->json();
}
return $this->json(1, '参数错误,请核对之后再操作!');
}
$auth = session('auth');
$groups = AuthGroup::getListById($auth['groupId']);
$this->data['groups'] = $groups;
return $this->view();
}
/**
* 栏目菜单分配
*/
public function menuAlloter()
{
if(request()->isPost()) {
$cates = input('post.cates/a');
$id = input('post.id/d');
if (is_array($cates) && (is_numeric($id) === true && $id > 0)) {
$member = MMember::getById($id);
if(empty($member)){
return $this->json(2, '无此用户信息,请核对之后再操作!');
}
MMember::updateCates($id, $cates);
Log::write('member', 'menuAlloter', "管理员栏目分配ID{$id}, 管理员:{$member['username']}");
return $this->json();
}else{
return $this->json(3, '传入参数错误,请核对之后再操作!');
}
} else {
$id = input('param.id/d');
if (is_numeric($id) && $id > 0) {
$member = MMember::getById($id);
if (empty($member)) {
return $this->json(2, '该管理员信息不存在,请核对之后再操作!');
}
$cates = Category::getListTree(false);
$memberCates = array_filter(explode(',', $member['cates']));
$this->data['id'] = $id;
$this->data['member'] = $member;
$this->data['memberCates'] = $memberCates;
$this->data['cates'] = $cates;
return $this->view();
}
return $this->json(1, '参数错误,请核对之后再操作!',$id);
}
}
/**
* 所有用户列表
*/
public function index()
{
$auth = session('auth');
if ($auth['groupId'] == 1) {
$items = MMember::getList(40);
} else {
$items = MMember::getListByGroup($auth['groupId'], 40);
}
$this->data['items'] = $items;
return $this->view();
}
}

View File

@ -0,0 +1,184 @@
<?php
namespace app\controller\manager;
use app\model\{Model as MModel, Log};
use app\validate\Model as VModel;
use think\exception\ValidateException;
class Model extends Base
{
//批量删除模型
public function batchDel()
{
if($this->request->isPost()){
$ids = input('post.ids/a');
if(is_array($ids)) {
$idsArr = $ids;
} else {
$idsArr = array_filter(explode(',', $ids));
}
if(count($idsArr) == 0) {
return $this->json(1, '无效请求,参数错误!');
}
$items = MModel::getListByIds($idsArr);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
}
MModel::destroy($delIds);
Log::write('model', 'batchDel', "模型批量删除ID" . implode(',', $ids));
return $this->json();
}
return $this->json(2, '无效请求,参数错误!');
}
return $this->json(1, '非法请求!');
}
//删除单个模型
public function del()
{
if($this->request->isPost()){
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$item = MModel::getById($id);
if(!empty($item)) {
MModel::destroy($id);
Log::write('model', 'del', "模型删除ID{$id}, 标题:{$item['name']}");
return $this->json();
}
return $this->json(3, '删除失败!该模型不存在,请刷新页面后再试!');
}
return $this->json(2, '无效请求,参数错误!');
}
return $this->json(1, '非法请求!');
}
//编辑模型
public function edit()
{
if($this->request->isPost()){
$item = [];
$item['name'] = input('post.name');
$item['template'] = input('post.template');
$item['manager'] = input('post.manager');
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$model = MModel::getById($id);
if(empty($model)){
return $this->json(2, '无此模型数据!');
}
try {
validate(VModel::class)->check($item);
MModel::updateById($id, $item);
Log::write('model', 'edit', "模型编辑ID{$id}, 标题:{$item['name']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
return $this->json(1, '无效请求,参数错误!');
}else{
$id = input('param.id/d');
if (is_numeric($id) && $id > 0) {
$item = MModel::getById($id);
$this->data['item'] = $item;
return $this->view();
}
return $this->json(1,'传入参数错误,请核对之后再操作!');
}
}
/**
* 添加模型
*/
public function add()
{
if($this->request->isPost()){
$item = [];
$item['name'] = input('post.name');
$item['template'] = input('post.template');
$item['manager'] = input('post.manager');
try {
validate(VModel::class)->check($item);
$model = MModel::create($item);
Log::write('model', 'add', "模型新增ID{$model->id}, 标题:{$item['name']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}else {
return $this->view();
}
}
/**
* 模型列表
*/
public function index()
{
$items = MModel::getList();
$this->data['items'] = $items;
return $this->view();
}
/**
* 排序
*/
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MModel::getById($id);
if(empty($item)) {
return $this->json(3, '无此模型!');
}
if($sort == 'up'){
$where = "sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MModel::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MModel();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('model', 'sort', "模型排序ID{$id} ,标题:{$item['name']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
}

View File

@ -0,0 +1,467 @@
<?php
namespace app\controller\manager;
use app\model\{Category, Block, Log};
use app\validate\Block as VBlock;
use think\exception\ValidateException;
use app\service\Tool;
class Page extends Base
{
//源码,代码
public function code()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(2, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(3, '键值已存在,请更改键值');
}
Block::updateById($id, $item);
Log::write('page', 'code', "单页代码编辑ID{$id}, 键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(4, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(3, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::CODE;
$block = Block::create($item);
Log::write('page', 'code', "单页代码新增ID{$block->id}, 键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此代码块!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = Block::getById($id);
if(empty($item)){
return $this->json(3, '无此块信息');
}
if($sort == 'up'){
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = Block::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new Block();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('page', 'sort', "单页区块排序ID{$id} ,键值:{$item['keyword']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->error('无此操作');
}
//删除
public function del()
{
if ($this->request->isAjax()) {
$id = input('post.id/d');
$item = Block::getById($id);
if(!empty($item)){
Block::destroy($id);
Log::write('page', 'del', "单页区块删除ID{$id} ,键值:{$item['keyword']}");
return $this->json();
}
return $this->json(1, 'fail');
}
return $this->error('无此操作');
}
//图片
public function img()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = trim(input('post.img'));
$categoryId = input('post.category_id/d');
if (!empty($img) && $img == 'null') {
$img = '';
}
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改键值');
}
if(!empty($img)){
$item['value'] = $img;
}
Block::updateById($id, $item);
Log::write('page', 'img', "单页图片编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!!');
}
if(empty($img)){
return $this->json(3, '图片不可为空');
}
$item['value'] = $img;
$item['type'] = Block::IMG;
$item['category_id'] = $categoryId;
$block = Block::create($item);
Log::write('page', 'img', "单页图片新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此图片!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['categoryId'] = $categoryId;
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
//文字块
public function block()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$id = input('post.id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(1, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改键值');
}
Block::updateById($id, $item);
Log::write('page', 'block', "单页文字块编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$block = Block::create($item);
Log::write('page', 'block', "单页文字块新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此文字块!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//富文本内容
public function text()
{
if($this->request->isPost()){
$item = input('post.item/a');
$categoryId = input('post.category_id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
if(empty($item['value'])){
return $this->json(1, '内容不可为空!');
}
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
Block::updateById($id, $item);
Log::write('page', 'text', "单页富文本编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::TEXT;
$block = Block::create($item);
Log::write('page', 'text', "单页富文本新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此富文本!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
return $this->view();
}
}
//组图
public function group()
{
if($this->request->isPost()){
$item = input('post.item/a');
$imgs = input('post.img/a');
$categoryId = input('post.category_id/d');
if (!empty($imgs) && is_array($imgs)) {
$item['value'] = json_encode($imgs);
} else {
$item['value'] = '';
}
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
Block::updateById($id, $item);
Log::write('page', 'group', "单页组图编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(4, '键值已存在,请更改键值');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::GROUP;
$block = Block::create($item);
Log::write('page', 'group', "单页组图新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此组图!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
//视频
public function video()
{
if($this->request->isPost()){
$item = input('post.item/a');
$img = trim(input('post.img'));
$video = trim(input('post.video'));
$categoryId = input('post.category_id/d');
$item['keyword'] = Tool::trimSpace($item['keyword']);
try{
validate(VBlock::class)->check($item);
$block = Block::getByKeyword($item['keyword'], $categoryId);
$id = input('post.id/d');
if($id){
if(!empty($block) && $block['id'] != $id){
return $this->json(4, '键值已存在,请更改');
}
if(!empty($img)){
$item['img'] = $img;
}
if(!empty($video)){
$item['value'] = $video;
}
Block::updateById($id, $item);
Log::write('page', 'video', "单页视频编辑ID{$id} ,键值:{$item['keyword']}");
}else{
if($categoryId <= 0){
return $this->json(2, '栏目参数错误!');
}
if(!empty($block)){
return $this->json(3, '键值已存在,请更改键值');
}
if(empty($video)){
return $this->json(3, '视频不可为空');
}
$item['category_id'] = $categoryId;
$item['type'] = Block::VIDEO;
$item['value'] = $video;
$item['img'] = $img;
$block = Block::create($item);
Log::write('page', 'video', "单页视频新增ID{$block->id} ,键值:{$item['keyword']}");
}
return $this->json();
} catch (ValidateException $e){
return $this->json(1, $e->getError());
}
}else{
$id = input('param.id/d');
if($id <= 0){ //添加
$categoryId = input('param.category_id/d');
$category = Category::getById($categoryId);
if(empty($category)){
$url = url('manager.content/index')->__toString();
return $this->error('无此栏目', $url);
}
}else{ //修改
$item = Block::getById($id);
if(empty($item)){
return $this->error('无此视频!');
}
$categoryId = $item['category_id'];
$this->data['item'] = $item;
}
$this->data['categoryId'] = $categoryId;
if(isset($item) && $item['width'] && $item['height']){
$imgSize = $item['width'].'px X '.$item['height'].'px';
}else{
$imgSize = '';
}
$this->data['imgSize'] = $imgSize;
$this->data['groupId'] = session('auth.groupId');
return $this->view();
}
}
}

View File

@ -0,0 +1,180 @@
<?php
namespace app\controller\manager;
use app\model\{AuthRule, AuthGroup, Log};
use app\validate\AuthRule as VAuthRule;
use think\exception\ValidateException;
class Rule extends Base
{
/**
* 权限排序
* 暂不允许父级变更
*
* @return void
*/
public function sort()
{
if ($this->request->isAjax()) {
$id = input('post.id');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = AuthRule::getById($id);
if(empty($item)){
return $this->json(3, '权限不存在');
}
if($sort == 'up'){
$where = "parent_id = {$item['parent_id']} and sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "parent_id = {$item['parent_id']} and sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = AuthRule::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new AuthRule();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('rule', 'sort', "权限排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
/**
* 权限删除
*/
public function del()
{
if ($this->request->isAjax()) {
$id = input('post.id/d');
$item = AuthRule::getById($id);
if(empty($item)){
return $this->json(1, '无此权限');
}
$children = AuthRule::getListByParentId($id);
if(!empty($children)){
return $this->json(2, '当前权限有下级权限,不可删除');
}
AuthRule::destroy($id);
AuthGroup::resetGroupRulesCache();
Log::write('rule', 'del', "权限删除ID{$id}, 标题:{$item['title']}");
return $this->json();
}
return $this->json(1, '非法请求!');
}
/**
* 权限修改
*/
public function edit()
{
if($this->request->isPost()){
$item = input('post.item/a');
$id = input('post.id');
$rule = AuthRule::getById($id);
if(empty($rule)){
return $this->json(1, '请选择正确的权限');
}
$rule2 = AuthRule::getByName($item['name']);
if(!empty($rule2) && $rule2['id'] != $id){
return $this->json(2, '已存在相同权限['.$item['name'].']');
}
try {
validate(VAuthRule::class)->check($item);
AuthRule::updateById($id, $item);
AuthGroup::resetGroupRulesCache();
Log::write('rule', 'edit', "权限编辑ID{$id}, 标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
$id = input('param.id/d');
$rule = AuthRule::getById($id);
if(empty($rule)){
return $this->json(1,'无此权限信息,请核对之后再操作!');
}else{
$this->data['item'] = $rule;
if($rule['parent_id'] > 0){
$parent = AuthRule::getById($rule['parent_id']);
$this->data['parent'] = $parent;
}
return $this->view();
}
}
/**
* 权限添加
*/
public function add()
{
if($this->request->isPost()){
$item = input('post.item/a');
try {
validate(VAuthRule::class)->check($item);
$rule = AuthRule::getByName($item['name']);
if(!empty($rule)){
return $this->json(1, '已存在相同权限');
}
$rule = AuthRule::create($item);
//基本权限的话需要重置所有已有角色权限缓存
if ($item['is_base'] > 0) {
AuthGroup::resetGroupRulesCache();
} else {
AuthGroup::resetGroupRulesCache(1);
}
Log::write('rule', 'add', "权限新增ID{$rule->id}, 标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
}
$parentId = input('param.parent_id/d',0);
if($parentId > 0){
$parent = AuthRule::getById($parentId);
$this->data['parent'] = $parent;
}
$this->data['parentId'] = $parentId;
return $this->view();
}
/**
* 权限列表(全部)
*/
public function index()
{
$list = AuthRule::getListTree();
$this->data['items'] = $list;
return $this->view();
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace app\controller\manager;
use app\model\{Member, Log};
class Safe extends Base
{
/**
* 安全设置
* @return Safe
*/
public function index()
{
$auth = session('auth');
if($this->request->isPost()){
if ($auth) {
$authId = $auth['userId'];
$oldPassword = trim(input('post.password_old'));
$password = trim(input('post.password'));
$passwordAgain = trim(input('post.password_again'));
$name = trim(input('post.name'));
$user = Member::getByID($authId);
if (empty($user)) {
return $this->json(1, '登录失效,请重新登录后再试!');
}
if (empty($name)) {
return $this->json(2, '用户名不能为空!');
}
$hasUser = Member::getByUserName($name);
if (!empty($hasUser) && $hasUser['id'] != $authId) {
return $this->json(3, '该用户名已被其他用户使用,请更换!');
}
if (empty($password) || empty($oldPassword)) {
return $this->json(4, '用户密码不能为空!');
}
if ($password != $passwordAgain) {
return $this->json(5, '新密码两次输入不一致!');
}
if (mb_strlen($password) < 6 || mb_strlen($password) > 30) {
return $this->json(6, '新密码长度格式不正确请输入6~30位密码');
}
if ($user['password'] != md5($oldPassword)) {
return $this->json(7,'原密码不正确');
}
$data['password'] = md5($password);
Member::updateById($authId, $data);
Log::write('safe', 'index', "安全设置ID{$authId}, 管理员:{$name}");
session('auth', null);
//cache('rules_'.$authId, null); //当前看代码,这个是无用代码;先注释掉,如果在使用过程中不会用到,再删除。
cache('group_rules_'.$authId, null);
cache('rule_names_'.$authId, null);
return $this->json(0, '修改成功,请重新登录!');
} else {
return $this->json(1, '登录失效,请重新登录后再试!');
}
}else{
$this->data['item'] = $auth;
return $this->view();
}
}
}

View File

@ -0,0 +1,191 @@
<?php
namespace app\controller\manager;
use app\model\{Slide as MSlide, System, Log};
use app\validate\Slide as VSlide;
use think\exception\ValidateException;
class Slide extends Base
{
//批量删除
public function batchDel()
{
if ($this->request->isPost()) {
$ids = input('post.ids/a');
if(empty($ids) || !is_array($ids)) {
return $this->json(2, '参数错误,请核对之后再操作!');
}
$items = MSlide::getListByIds($ids);
if(!empty($items)){
$delIds = [];
foreach($items as $item){
$delIds[] = $item['id'];
}
MSlide::destroy($delIds);
Log::write('link', 'betchDel', '批量删除了友情链接涉及到的ID为' . implode(',', $delIds));
return $this->json();
}else{
return $this->json(3, '待删除友情链接为空');
}
}
return $this->json(1, '非法请求!');
}
//可以删除一个可以批量删除TODO 需要调整
public function del()
{
if ($this->request->isPost()) {
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$item = MSlide::getById($id);
if(!empty($item)){
MSlide::destroy($id);
Log::write('link', 'del', '删除轮播图ID' . $id . ',标题:' . $item['title']);
return $this->json();
}
return $this->json(3, '待删除轮播图不存在');
}
return $this->json(2, '参数错误,请核对之后再操作!');
}
return $this->json(1, '非法请求!');
}
//排序
public function sort()
{
if($this->request->isPost()){
$id = input('post.id/d');
$sort = input('post.sort');
$num = input('post.num/d', 1);
if($num <= 0){
$num = 1;
}
if(!in_array($sort, ['up', 'down'], true)){
return $this->json(2, '参数错误');
}
$item = MSlide::getById($id);
if(empty($item)){
return $this->json(3, '无此轮播图');
}
if($sort == 'up'){
$where = "sort < {$item['sort']}";
$order = "sort desc";
}else{
$where = "sort > {$item['sort']}";
$order = "sort asc";
}
$forSortItems = MSlide::getListByWhereAndOrder($where, $order, $num);
if(!empty($forSortItems)){
$updateData = [];
$forSortCount = count($forSortItems);
for($i = 0; $i < $forSortCount; $i++){
if($i == 0){
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $item['sort']
];
}else{
$updateData[] = [
'id' => $forSortItems[$i]['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
}
}
$updateData[] = [
'id' => $item['id'],
'sort' => $forSortItems[$i - 1]['sort']
];
if(!empty($updateData)){
$model = new MSlide();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('slide', 'sort', "轮播图排序ID{$id} ,标题:{$item['title']}{$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '非法请求!');
}
//编辑
public function edit()
{
if($this->request->isPost()){
$item = input('post.item');
$img = input('post.img_pc');
$imgMobile = input('post.img_mobile');
$id = input('post.id/d');
if(is_numeric($id) && $id > 0) {
$slide = MSlide::getById($id);
if(empty($slide)) {
return $this->json(2, 'id参数错误,没有相关轮播图信息记录!');
}
if(!empty($imgMobile)){
$item['src_mobile'] = $imgMobile;
}
if(!empty($img)){
$item['src'] = $img;
}
try {
validate(VSlide::class)->check($item);
MSlide::updateById($id, $item);
Log::write('slide', 'edit', "轮播图编辑ID{$id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(3, $e->getError());
}
}
return $this->json(1, '参数错误,请核对之后再操作!');
}else{
$id = input('param.id/d');
$item = MSlide::getById($id);
$imgSize = System::getSlideImageSize();
$this->data['item'] = $item;
$this->data['img_size'] = $imgSize;
return $this->view();
}
}
//添加
public function add()
{
if($this->request->isPost()){
$item = input('post.item');
$img = input('post.img_pc');
$imgMobile = input('post.img_mobile');
if (empty($item)) {
return $this->json(1, '参数错误,请核对之后再操作!');
}
if(!empty($img)){
$item['src'] = $img;
}
if(!empty($imgMobile)){
$item['src_mobile'] = $imgMobile;
}
try {
validate(VSlide::class)->check($item);
$slide = MSlide::create($item);
Log::write('slide', 'add', "轮播图新增ID{$slide->id} ,标题:{$item['title']}");
return $this->json();
} catch (ValidateException $e) {
return $this->json(2,$e->getError());
}
}else{
$this->data['img_size'] = System::getSlideImageSize();
return $this->view();
}
}
/**
* 列表
* 暂定只有首页轮播图,后期可以根据需求进行分组管理
* @return Slide
*/
public function index()
{
$items = MSlide::getList();
$this->data['items'] = $items;
return $this->view();
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace app\controller\manager;
use app\service\Tool;
use app\model\{System as MSystem, Log};
use app\service\Image;
use think\facade\Cache;
class System extends Base
{
/**
* 获取当前系统设置
*
* @return void
*/
public function index()
{
if ($this->request->isPost()) {
$item = input('post.item/a');
$img = input('post.img');
$system = MSystem::getSystem();
if (empty($system)) {
if(!empty($img)){
$item['mark_img'] = $img;
}
$system = MSystem::create($item);
Log::write('system', 'index', "系统设置ID{$system->id}");
} else {
if (!empty($img)) {
Image::delImg($system['mark_img']);
$item['mark_img'] = $img;
}
MSystem::update($item, ['id' => $system['id']]);
Log::write('system', 'index', "系统设置ID{$system['id']}");
}
return $this->json();
} else {
$item = MSystem::getSystem();
$positions = Image::getMarkPosition();
$this->data['item'] = $item;
$this->data['positions'] = $positions;
return $this->view();
}
}
public function other()
{
return $this->view();
}
public function clearCache()
{
Cache::clear();
$cachePath = app()->getRuntimePath().'cache';
$tempPath = app()->getRuntimePath().'temp';
Tool::removeByPath($cachePath);
Tool::removeByPath($tempPath);
clearstatcache();
return $this->json();
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace app\controller\manager;
use app\service\Image;
use app\model\{System, File};
use app\validate\Upload as VUpload;
use think\facade\{Filesystem, Config, Lang};
use think\Image as TImage;
use app\controller\BaseController;
class Upload extends BaseController
{
private $isCompress = true;
private $validate;
private $uploadPath;
private $uploadPathIsWritable = 0;
public function __construct()
{
$system = System::getSystem();
if (!empty($system)) {
$this->isCompress = $system['compress']??true;
}
$this->validate = new VUpload();
$this->uploadPath = Config::get('filesystem.disks.local.url');
if(is_writable(app()->getRootPath() . 'public' . $this->uploadPath)){
$this->uploadPathIsWritable = 1;
}
}
//视频上传
public function video()
{
if(!$this->uploadPathIsWritable){
return $this->json(1, '上传文件夹需要写入权限');
}
$video = request()->file('video');
if($this->validate->checkVideo($video)){
$src = Filesystem::disk('video')->putFile(date('Ymd'), $video, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$return['src'] = $src;
File::add($video, $src, 'video'); //加入上传文件表
return $this->json(0, 'ok', $return);
}else{
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//文件上传(通用)
public function file()
{
$file = request()->file('file');
if($this->validate->checkFile($file)){
try{
if(!$this->uploadPathIsWritable){
throw new \Exception('上传文件夹需要写入权限');
}
$src = Filesystem::putFile(date('Ymd'), $file, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$return['src'] = $src;
$return['name'] = $file->getOriginalName();
File::add($file, $src, 'file'); //加入上传文件表
} catch (\Exception $e) {
return $this->json(1, $e->getMessage());
}
return $this->json(0,'ok',$return);
}else{
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//图片上传(通用)
public function image()
{
$image = request()->file('image');
if($this->validate->checkImage($image)){
try{
if(!$this->uploadPathIsWritable){
throw new \Exception('上传文件夹需要写入权限');
}
$src = Filesystem::putFile(date('Ymd'), $image, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$suffix = strtolower($image->getOriginalExtension());
if($suffix == 'gif'){
$return['thumb_src'] = $src; //TODO获取GIF缩略图
}else{
$return['thumb_src'] = Image::getThumb($src, 100, 100, TImage::THUMB_SCALING); //上传返回缩略图宽度为100
}
$return['src'] = $src;
if($this->isCompress){
Image::resize($src);
}
File::add($image, $src); //加入上传文件表
} catch (\Exception $e) {
return $this->json(1, $e->getMessage());
}
return $this->json(0, 'ok', $return);
}else{
$errorMsg = Lang::get($this->validate->getError());
return $this->json(1, $errorMsg);
}
}
//富文本编辑器商城图片
public function wangImage()
{
$imageArr = request()->file('wang_img'); // 该方式前端js上传方法中字段名称必须以数组形式传参 如 wang_img[] = 值
$errno = 0;
$data = [];
if(!$this->uploadPathIsWritable){
$errno = 1;
$data[] = '上传文件夹需要写入权限';
}else{
foreach ($imageArr as $image) {
if($this->validate->checkImage($image)){
$src = Filesystem::putFile(date('Ymd'), $image, 'uniqid');
$src = $this->uploadPath . '/' . $src;
$data[] = $src;
if($this->isCompress){
Image::resize($src);
}
File::add($image, $src); //加入上传文件表
}else{
$errno = 1;
$data = [];
$data[] = Lang::get($this->validate->getError());
break;
}
}
}
$return['errno'] = $errno;
$return['data'] = $data;
return json($return);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace app\controller\manager;
/**
* 微信公众号配置
* Class Wechat
* @package app\controller\manager
*/
class Wechat extends Base
{
// 公众号设置
public function base()
{
// TODO
return 'TODO ...';
}
// 公众号设置
public function menu()
{
// TODO
return 'TODO ...';
}
}

17
app/event.php Normal file
View File

@ -0,0 +1,17 @@
<?php
// 事件定义文件
return [
'bind' => [
],
'listen' => [
'AppInit' => [],
'HttpRun' => [],
'HttpEnd' => [],
'LogLevel' => [],
'LogWrite' => [],
],
'subscribe' => [
],
];

10
app/middleware.php Normal file
View File

@ -0,0 +1,10 @@
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
//\think\middleware\LoadLangPack::class,
// Session初始化
\think\middleware\SessionInit::class,
];

65
app/middleware/Auth.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace app\middleware;
use Closure;
use app\model\AuthRule;
use think\facade\Cache;
class Auth
{
public function handle($request, Closure $next)
{
$auth = session('auth');
if(!$auth){
return redirect(url('manager.login/index'));
}
// 角色权限
$rules = Cache::get('group_rules_'.$auth['groupId']);
$ruleNames = Cache::get('rule_names_'.$auth['groupId']);
//如果是超级管理员,不用验证权限,给予所有权限
if(empty($rules)){
$ruleNames = [];
if($auth['groupId'] == 1){
$rules = AuthRule::getListTree(0);
}else{
// 角色权限 + 基本权限
$rules = AuthRule::getAuthListByRuleIDs($auth['groupId']);
}
foreach($rules as &$rule){
if(!stripos($rule['name'],'/')){
$rule['name'] = $rule['name'].'/index';
}
$ruleNames[] = strtolower($rule['name']);
if(isset($rule['children']) && !empty($rule['children'])){
foreach($rule['children'] as &$child){
if(!stripos($child['name'],'/')){
$child['name'] = $child['name'].'/index';
}
$ruleNames[] = strtolower($child['name']);
}
}
}
// 对角色赋予权限缓存,角色权限更新时需要同步更新缓存
Cache::set('group_rules_'.$auth['groupId'], $rules);
Cache::set('rule_names_'.$auth['groupId'], $ruleNames);
}
if($auth['groupId'] == 1){
return $next($request);
}
$controller = strtolower(request()->controller());
$controller = str_replace('manager.', '', $controller);
$action = request()->action();
$name = strtolower($controller.'/'.$action);
if(!empty($ruleNames) && in_array($name, $ruleNames, true)){
return $next($request);
}
if(request()->isAjax()){
return json(['code' => 1,'msg' => '没有权限']);
}else{
exit('无操作权限') ;
}
}
}

55
app/middleware/Csrf.php Normal file
View File

@ -0,0 +1,55 @@
<?php
namespace app\middleware;
use Closure;
/**
* CSRF校验
*/
class Csrf
{
public function handle($request, Closure $next)
{
if($request->isPost()){
$check = $request->checkToken('__token__');
if(false === $check) {
return $this->csrfError($request);
}
}
return $next($request);
}
protected function csrfError($request, $msg = '非法请求, 用户身份认证失败!')
{
if($request->isAjax()) {
return json(['code' => 401, 'msg' => $msg], 200);
} else {
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if (empty($referer)) {
$url = '/';
} else {
$domain = $request->domain();
$urlInfo = parse_url($referer);
$scheme = $urlInfo['scheme'] ?? '';
$requestSrc = '';
if (!empty($scheme)) {
$requestSrc = $scheme.'://'.($urlInfo['host'] ?? '');
}
if($domain != $requestSrc) {
$url = '/';
} else {
$url = 'javascript:history.back(-1);';
}
}
$errorData = [
'code'=> 401,
'msg' => $msg,
'data' => [],
'wait' => 5,
'url' => $url
];
return view('error/400', $errorData);
// 返回401视图 response type has html、json、jsonp、xml、file、view、redirect
}
}
}

168
app/model/Article.php Normal file
View File

@ -0,0 +1,168 @@
<?php
namespace app\model;
class Article extends Base
{
//获取最高访问的文章列表
public static function getMostVisited($limit = 5)
{
if($limit <= 0){
$limit = 5;
}
return self::order('views', 'desc')
->limit($limit)
->select()
->toArray();
}
//获取栏目下最新记录
public static function getLatestByCategory($categoryId, $limit = 5)
{
if(empty($categoryId)){
return [];
}
if($limit <= 0){
$limit = 5;
}
return self::where('category_id', $categoryId)
->order('create_time', 'desc')
->limit($limit)
->select()
->toArray();
}
//根据文章ID和栏目ID获取下一篇文章
public static function getNextArticleByIdAndCategoryId($id, $categoryId)
{
return self::where('id','<',$id)
->where('category_id', $categoryId)
->where('status', 1)
->order('sort desc')
->findOrEmpty()
->toArray();
}
//根据文章ID和栏目ID获取上一篇文章
public static function getPrevArticleByIdAndCategoryId($id, $categoryId)
{
return self::where('id','>',$id)
->where('category_id',$categoryId)
->where('status', 1)
->order('sort asc')
->findOrEmpty()
->toArray();
}
//根据栏目ID获取文章列表
public static function getListByCategory($categoryId, $limit = 10)
{
return self::where('category_id', $categoryId)
->where('status', 1)
->order("sort desc")
->limit($limit)
->select()
->toArray();
}
//根据栏目ID获取文章分页列表
public static function getListPageByCategory($categoryId, $per = 20, $keyword = '')
{
$where = [
['category_id', '=', $categoryId],
['status', '=', 1],
];
$param['category_id'] = $categoryId;
if($keyword!=''){
$where[] = ['title', 'like', '%'.$keyword.'%'];
$param['keyword'] = $keyword;
}
$paginate = [
'list_rows' => $per,
'query' => $param
];
return self::where($where)
->order("sort desc")
->paginate($paginate,false);
}
//根据栏目ID获取文章分页列表
public static function getListCount($categoryId)
{
$where = [
['category_id', '=', $categoryId],
['status', '=', 1],
];
$param['category_id'] = $categoryId;
return self::where($where)
->order("sort desc")
->count();
}
public static function onAfterInsert($article)
{
$article->sort = $article->id;
$article->create_time = $article->update_time = time();
$auth = session('auth');
$article->created = $article->updated = $auth['userName'];
$article->save();
}
/**
* 获取文章列表
* @param $categoryId 分类ID
* @param int $per 每页数量
* @param string $keyword 关键词
* @param array $param 文章类型:置顶、热门、推荐 ['top','hot','recommend']
* @param int $status 文章状态,-1表示不限制
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public static function getList($categoryId, $per = 20, $keyword = '', $param = [], $status = -1)
{
$whereMap = [];
$pageParam = [];
if(is_numeric($categoryId) && $categoryId > 0) {
$whereMap[] = ['category_id', '=', $categoryId];
$pageParam['category_id'] = $categoryId;
}
if(!empty($keyword)){
$whereMap[] = ['title', 'like', '%'.$keyword.'%'];
$pageParam['keyword'] = $keyword;
}
if (is_array($param) && count($param) > 0) {
$pageParam['param'] = $param;
foreach ($param as $vo) {
if(in_array($vo, ['top','hot','recommend'], true)) {
$whereMap[] = ["{$vo}", '=', 1];
}
}
}
$paginate = [
'list_rows' => $per,
'query' => $pageParam
];
return self::when(count($whereMap) > 0, function($query) use ($whereMap) {
$query->where($whereMap);
})
->order("sort desc")
->paginate($paginate,false);
}
//获取文章涉及到的图片
public static function getFilesInUse()
{
$items = self::select()->toArray();
$data = [];
foreach($items as $item){
$src = trim($item['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$data[$key] = $src;
}
$imgs = getImageUrlFromText($item['content']);
if(!empty($imgs)){
$data = array_merge($data, $imgs);
}
$videos = getVideoUrlFromText($item['content']);
if(!empty($videos)){
$data = array_merge($data, $videos);
}
}
return $data;
}
}

54
app/model/AuthGroup.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace app\model;
use think\facade\Cache;
class AuthGroup extends Base
{
public static function updateRules($groupId, $rules)
{
$rules = implode(',', $rules);
$data = ['rules' => $rules];
self::updateById($groupId, $data);
Member::where('group_id', $groupId)
->update($data);
}
//根据ID获取角色列表ID为1是超级管理员
public static function getListById($groupId = 1)
{
if($groupId < 1){
return [];
}
$group = self::getById($groupId);
if(empty($group)){
return [];
}
if($groupId == 1){
return self::select()
->toArray();
}else{
return self::where('id','<>','1')
->select()
->toArray();
}
}
/**
* 重置角色权限缓存
* @param int $groupId 指定重置的角色ID若不指定则重置所有角色
*/
public static function resetGroupRulesCache($groupId = 0)
{
if(is_numeric($groupId) && $groupId > 0) {
Cache::set('group_rules_'.$groupId, null);
Cache::set('rule_names_'.$groupId, null);
} else {
$groupIds = self::column('id');
foreach ($groupIds as $id){
Cache::set('group_rules_'.$id, null);
Cache::set('rule_names_'.$id, null);
}
}
}
}

271
app/model/AuthRule.php Normal file
View File

@ -0,0 +1,271 @@
<?php
namespace app\model;
class AuthRule extends Base
{
//根据权限IDs获取权限列表
public static function getListByRuleIDs($ruleIds)
{
$items = self::wherein('id',$ruleIds)
//->where('status', 1)
->order('sort', 'asc')
->select()
->toArray();
return self::getChildren($items);
}
//角色权限 + 基本权限
public static function getAuthListByRuleIDs($groupId)
{
$order = ['sort'=>'asc'];
if ($groupId == 1) {
$items = self::order($order)->select()->toArray();
} else {
$group = AuthGroup::getById($groupId);
$rulesArr = [];
if ($group && !empty($group['rules'])) {
$rulesArr = array_filter(explode(',', $group['rules']));
}
if (count($rulesArr) >0) {
$items = self::wherein('id', $rulesArr)->whereOr('is_base', 1)->order($order)->select()->toArray();
} else {
$items = self::where('is_base', 1)->order($order)->select()->toArray();
}
}
$levelItems = self::getChildren($items);
$levelIds = self::getChildrenIds($items);
// 独立写入不在连续分层中的权限,连续分层权限可用于菜单显示
foreach ($items as $item) {
if(!in_array($item['id'], $levelIds)) {
$levelItems[] = $item;
}
}
return $levelItems;
}
//根据上级ID获取下级权限列表
public static function getListTree($forMenu = 0)
{
$items = self::getList($forMenu);
return self::getChildren($items);
}
//根据上级ID获取下级权限列表
public static function getListByParentId($parentId)
{
return self::where('parent_id', $parentId)
->order('sort', 'asc')
->select()
->toArray();
}
/**
* @param array $items
* @param integer $parent_id
* @return array
*/
public static function getChildren($items, $parentId = 0)
{
$data = [];
foreach($items as $item){
if($item['parent_id'] == $parentId){
$childern = self::getChildren($items, $item['id']);
if(!empty($childern)){
$item['hasChildren'] = true;
$item['children'] = $childern;
}
$data[] = $item;
}
}
return $data;
}
public static function getChildrenIds($items, $parentId = 0)
{
$data = [];
foreach($items as $item){
if($item['parent_id'] == $parentId){
$childrenIds = self::getChildrenIds($items, $item['id']);
if(!empty($childrenIds)){
$data = array_merge($data, $childrenIds);
}
$data[] = $item['id'];
}
}
return $data;
}
/**
* @param integer $forMenu 大于0表示获取可显示的权限
* @return void
*/
private static function getList($forMenu = 0)
{
if($forMenu){
return self::where('status', 1)->order('sort', 'asc')->select()->toArray();
}else{
return self::order('sort', 'asc')->select()->toArray();
}
}
//获取可显示权限
public static function getTopListForDisplay()
{
return self::where('status', 1)
->where('parent_id', 0)
->order('sort', 'asc')
->select()
->toArray();
}
//根据两个名字获取权限
public static function getByTwoName($name, $otherName)
{
return self::whereOr('name',$name)
->whereOr('name',$otherName)
->findOrEmpty()
->toArray();
}
//根据name获取权限
public static function getByName($name)
{
return self::where('name', $name)
->findOrEmpty()
->toArray();
}
public static function onAfterInsert($rule)
{
$rule->sort = $rule->id;
$rule->save();
}
/**
* 该情况适合无限级菜单分组显示 当前系统仅支持2级权限因此推荐使用getListTree 方法)
* @param int $forMenu 是否只获取可显示菜单权限
*/
public static function getListTreeSort($forMenu = 0)
{
$items = self::getList($forMenu);
return self::groupSort($items, 0, 1, true, true);
}
/**
* 分组排序(不拆分为子集)
*
* @param $items 数据源
* @param integer $pid
* @param integer $level
* @param bool $clear 是否释放局部变量(外部调用时必须先释放,避免数据被累加;内部不用,需要累加)
* @param bool $isArr 传入的$items是否为数组默认否数据集
* @param string $levelSpare 分层符
* @return void
*/
public static function groupSort($items,$pid = 0, $level = 1, $clear = true, $isArr = false, $levelSpare = '_')
{
static $data = [];
if ($clear) {
$data = [];
static $data = [];
}
if(!empty($levelSpare) && $level > 1) {
$levelSpare = str_repeat($levelSpare, $level-1);
}
if (count($items) > 0) {
if ($isArr) {
foreach ($items as $key => $item) {
if ($item['parent_id'] == $pid) {
$item['level'] = $level;
$item['title'] = $levelSpare.$item['title'];
$data[] = $item;
self::groupSort($items, $item['id'], $level+1, false, $isArr);
}
}
} else {
foreach ($items as $key => $item) {
if ($item->parent_id == $pid) {
$item->level = $level;
$item->title = $levelSpare.$item->title;
$data[] = $item;
self::groupSort($items, $item->id, $level+1, false, $isArr);
}
}
}
}
return $data;
}
/**
* 树形排序 (拆分子集)
*
* @param Collection $items 数据集(非数组)
* @param integer $pid
* @param integer $level
* @return void
*/
public static function treeSort($items,$pid = 0, $level = 1)
{
$data = [];
if (count($items) > 0) {
foreach ($items as $key => $item) {
if ($item->parent_id == $pid) {
$item->level = $level;
$children = self::treeSort($items, $item->id, $level+1);
$item->children = $children;
$data[] = $item;
}
}
}
return $data;
}
/**
* 查询用户权限(登陆时更具角色更新为最新权限)
* 可显示权限和所有权限 角色权限 + 基本权限
*
* @param boolean $groupId 角色ID,超级管理员(对应group_id = 1)
* @return void
*/
public static function userRolesList($groupId = 1)
{
$userRoles = [];
$items = null;
$order = ['sort'=>'asc'];
if ($groupId == 1) {
$items = self::order($order)->select();
} else {
$group = AuthGroup::getById($groupId);
$rulesArr = [];
if ($group && !empty($group['rules'])) {
$rulesArr = array_filter(explode(',', $group['rules']));
}
if (count($rulesArr) >0) {
$items = self::wherein('id', $rulesArr)->whereOr('is_base', 1)->order($order)->select();
} else {
$items = self::where('is_base', 1)->order($order)->select();
}
}
if (empty($items) || $items->isEmpty()) {
return $userRoles;
}
$allRulesId = [];
$displayRules = [];
$displayRulesId = [];
foreach ($items as $key => $item) {
$allRulesId[] = $item->id;
if ($item->status > 0) {
$displayRules[] = $item;
$displayRulesId[] = $item->id;
}
}
$userRoles['allRules'] = $items;
$userRoles['allRulesId'] = $allRulesId;
$userRoles['displayRules'] = $displayRules;
$userRoles['displayRulesId'] = $displayRulesId;
return $userRoles;
}
}

41
app/model/Base.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace app\model;
use think\Model;
class Base extends Model
{
protected $autoWriteTimestamp = false;
//根据Id列表获取列表
public static function getListByIds($ids)
{
if(count($ids) == 0 || empty($ids)) {
return [];
}
return self::where('id', 'in', $ids)->select()->toArray();
}
//根据ID获取单条数据
public static function getById($id)
{
if($id <= 0){
return [];
}
return self::where('id', $id)->findOrEmpty()->toArray();
}
//根据ID更新数据
public static function updateById($id, $data)
{
return self::where('id', $id)->update($data);
}
//根据where条件和排序获取记录
public static function getListByWhereAndOrder($where, $order, $limit = 1)
{
return self::where($where)
->order($order)
->limit($limit)
->select()
->toArray();
}
}

113
app/model/Block.php Normal file
View File

@ -0,0 +1,113 @@
<?php
namespace app\model;
class Block extends Base
{
const BLOCK = 1;
const IMG = 2;
const TEXT = 3;
const GROUP = 4;
const VIDEO = 5;
const CODE = 6;
//获取类型键值对
public static function getTypes()
{
return [
'1' => 'block',
'2' => 'img',
'3' => 'text',
'4' => 'group',
'5' => 'video',
'6' => 'code'
];
}
//根据键值和类目获取数据
public static function getByKeyword($keyword, $categoryId)
{
return self::where('keyword', $keyword)->where('category_id', $categoryId)->findOrEmpty()->toArray();
}
//根据栏目ID获取块列表
public static function getByCategoryId($categoryId)
{
if($categoryId <= 0){
return [];
}
$category = Category::getById($categoryId);
if(empty($category)){
return [];
}
$items = self::where('category_id', $categoryId)
->order('sort asc')
->select()
->toArray();
if(empty($items)){
return [];
}
$data = [];
foreach($items as $item){
$data[$item['keyword']] = $item;
}
return $data;
}
public static function onAfterInsert($item)
{
$item->sort = $item->id;
$item->save();
}
//获取在使用中的文件
public static function getFilesInUse()
{
$items = self::whereIn('type', [self::IMG, self::GROUP, self::VIDEO, self::TEXT])
->select()
->toArray();
$data = [];
foreach($items as $item){
if($item['type'] == self::IMG){
$file = trim($item['value']);
if(!empty($file)){
$key = getKeyByPath($file);
$data[$key] = $file;
}
}elseif($item['type'] == self::GROUP){
$val = trim($item['value']);
if (!empty($val) && $val != '[]' && $val != 'null') {
$files = json_decode($val, true);
foreach($files as $file){
$src = trim($file['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$data[$key] = $src;
}
}
}
}elseif($item['type'] == self::VIDEO){
$video = trim($item['value']);
if(!empty($video)){
$key = getKeyByPath($video);
$data[$key] = $video;
}
$img = trim($item['img']);
if(!empty($img)){
$key = getKeyByPath($img);
$data[$key] = $img;
}
}elseif($item['type'] == self::TEXT){
$imgs = getImageUrlFromText($item['value']);
if(!empty($imgs)){
$data = array_merge($data, $imgs);
}
$videos = getVideoUrlFromText($item['value']);
if(!empty($videos)){
$data = array_merge($data, $videos);
}
}
}
return $data;
}
}

189
app/model/Category.php Normal file
View File

@ -0,0 +1,189 @@
<?php
namespace app\model;
class Category extends Base
{
//获取首页栏目ID
public static function getIndex()
{
return self::where('is_index', 1)->findOrEmpty()->toArray();
}
//根据上级ID和语言获取下级栏目
public static function getChildrenByParentId($parentId)
{
if($parentId <= 0){
return [];
}
$category = self::getById($parentId);
if(empty($category)){
return [];
}
return self::alias('c')
->leftJoin('model m', 'c.model_id=m.id')
->field('c.*, m.manager, m.template, m.name as modelName')
->where('c.parent_id', $parentId)
->order('c.sort','asc')
->select()
->toArray();
}
//重写方法
public static function getById($categoryId)
{
return self::alias('c')
->leftJoin('model m', 'c.model_id = m.id')
->where('c.id', $categoryId)
->field('c.*, m.template')
->findOrEmpty()
->toArray();
}
//查看是否有下级栏目
public static function hasChildren($categoryId)
{
if (is_array($categoryId)) {
$count = self::where('parent_id', 'in', $categoryId)->count();
} else {
$count = self::where(['parent_id'=>$categoryId])->count();
}
return $count ? true : false;
}
//获取前台菜单
public static function getListForFrontMenu()
{
$items = self::alias('c')
->leftJoin('model m','c.model_id=m.id')
->field('c.*, m.manager, m.template')
->where('c.state', 1)
->order('is_index desc, sort asc')
->select()
->toArray();
return self::getCates($items);
}
/**
* 获取栏目
* @param bool $limit 是否限制查询
* @param array $cates 需要限制查询的栏目IDs
*/
public static function getList($limit = false, $cates = [])
{
if ($limit && empty($cates)) {
return [];
}
return self::alias('c')
->leftJoin('model m', 'c.model_id=m.id')
->field('c.*, m.manager, m.name as modelName')
->when($limit, function($query) use($cates) {
$query->whereIn('c.id', $cates);
})
->order('sort','asc')
->select()
->toArray();
}
//获取栏目分级列表
public static function getListTree($isMenu = false)
{
if ($isMenu) {
$items = self::where('c.state', 1) ->order('sort','asc')->select()->toArray();
} else {
$items = self::order('sort','asc')->select()->toArray();
}
return self::getCates($items);
}
//获取递归栏目
public static function getCates($cates,$parentId=0)
{
$menus = [];
foreach($cates as $cate){
if($cate['parent_id'] == $parentId){
$children = self::getCates($cates,$cate['id']);
if(!empty($children)){
$cate['children'] = $children;
}
$menus[] = $cate;
}
}
return $menus;
}
public static function onAfterInsert($category)
{
$category->sort = $category->id;
$category->save();
}
//递归获取栏目名称面包屑
public static function getCatesCrumbs($currentId = 0)
{
$crumbs = [];
$category = self::getById($currentId);
if($category) {
if($category['parent_id'] != 0){
$categoryIds = explode(',', trim($category['path'], ','));
$categories = self::where('id', 'in', $categoryIds)->column('*', 'id');
foreach($categoryIds as $id){
if(isset($categories[$id])){
$crumbs[] = $categories[$id]['title'];
}
}
}
$crumbs[] = $category['title'];
}
return $crumbs;
}
//获取栏目中涉及到的文件
public static function getFilesInUse()
{
$items = self::select()->toArray();
$data = [];
foreach($items as $item){
$src = trim($item['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$data[$key] = $src;
}
}
return $data;
}
//当前分类的最高级分类Id
public static function firstGradeById($id)
{
$res = 0;
$item = self::getById($id);
if ($item) {
$res = $id;
if ($item['parent_id'] > 0) {
$items = self::select()->toArray();
$first = self::getFirstGrade($items, $item['parent_id']);
if (!empty($first)) {
$res = $first['id'];
}
}
}
return $res;
}
public static function getFirstGrade($items, $parentId)
{
$data = [];
foreach ($items as $key=> $item) {
if($item['id'] == $parentId) {
if ($item['parent_id'] > 0) {
unset($items[$key]);
$parent = self::getFirstGrade($items, $item['parent_id']);
if (!empty($parent)) {
$data = $parent;
} else {
$data = $item;
}
} else {
$data = $item;
}
}
}
return $data;
}
}

93
app/model/File.php Normal file
View File

@ -0,0 +1,93 @@
<?php
namespace app\model;
use think\Image;
class File extends Base
{
const IMG = 'img';
const VIDEO = 'video';
const FILE = 'file';
//获取文件类型
public static function getTypes()
{
return [
'img' => '图片',
'video' => '视频',
'file' => '文件'
];
}
//获取文件列表
public static function getList($type = '', $page = 1, $per = 20)
{
$limit = ($page - 1) * $per;
if($type != ''){
if(!in_array($type, array_keys(self::getTypes()))){
return [];
}
$items = self::where('type', $type)
->order('id desc');
}else{
$items = self::order('id desc');
}
$items = $items->limit($limit, $per)->select()->toArray();
foreach($items as &$item){
$item['sizeStr'] = sizeToStr($item['size']);
}
return $items;
}
//获取分页列表
public static function getListPage($type = '', $per = 20)
{
if($type != ''){
if(!in_array($type, array_keys(self::getTypes()))){
return [];
}
return self::where('type', $type)
->order('id desc')
->paginate([
'list_rows' => $per,
'query' => [
'type' => $type
]
], false);
}else{
return self::order('id desc')
->paginate([
'list_rows' => $per
], false);
}
}
//添加,$w_h图片尺寸大小单位像素只对type=img时有效
public static function add($file, $src, $type = 'img')
{
$realPath = app()->getRootPath() . ltrim($src,'/');
if(is_file($realPath) && $type == 'img'){
$img = Image::open($realPath);
list($w,$h) = $img->size();
$w_h = $w . 'px * ' . $h . 'px';
}else{
$w_h = '';
}
return self::create([
'type' => $type,
'name' => $file->getOriginalName(),
'src' => $src,
'size' => $file->getSize(),
'suffix' => $file->getOriginalExtension(),
'mime_type' => $file->getOriginalMime(),
'create_time' => time(),
'w_h' => $w_h
]);
}
//获取所有记录
public static function getAll()
{
return self::select()->toArray();
}
}

45
app/model/History.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace app\model;
class History extends Base
{
public static function onAfterInsert($item)
{
$item->sort = $item->id;
$item->save();
}
public static function getPaginateList($categoryId, $per = 20, $isSample = false)
{
$paginate = [
'list_rows' => $per
];
$items = self::where('category_id', $categoryId)->order('sort', 'asc')->paginate($paginate, $isSample);
if(!$items->isEmpty()) {
$ids = $items->column('id');
$infoList = HistoryInfo::getByHistoryIds($ids);
foreach ($items as $k => $item) {
$items[$k]['info'] = $infoList[$item['id']] ?? [];
}
}
return $items;
}
public static function getByCategoryId($categoryId, $onlyVisible = false)
{
$items = self::where('category_id', $categoryId)
->when($onlyVisible, function($query){
$query->where('visible', 1);
})
->order('sort', 'asc')
->select();
if(!$items->isEmpty()) {
$ids = $items->column('id');
$infoList = HistoryInfo::getByHistoryIds($ids, $onlyVisible);
foreach ($items as $k => $item) {
$items[$k]['info'] = $infoList[$item['id']] ?? [];
}
}
return $items->toArray();
}
}

52
app/model/HistoryInfo.php Normal file
View File

@ -0,0 +1,52 @@
<?php
namespace app\model;
class HistoryInfo extends Base
{
public static function onAfterInsert($item)
{
$item->sort = $item->id;
$item->save();
}
public static function getByHistoryIds($historyIds = [], $onlyVisible = false)
{
if(!is_array($historyIds) || count($historyIds) == 0) {
return [];
}
$list = self::whereIn('history_id', $historyIds)
->when($onlyVisible, function ($query) {
$query->where('visible', 1);
})
->order(['history_id'=>'asc','sort'=>'asc'])
->select()
->toArray();
$data = [];
foreach ($list as $item) {
$item['img_list'] = [];
if(!empty($item['imgs'])) {
$item['img_list'] = array_filter(explode(',', $item['imgs']));
}
$data[$item['history_id']][] = $item;
}
return $data;
}
public static function countByHistoryId($historyId)
{
return self::where('history_id', $historyId)->count();
}
public static function delByHistoryId($historyId)
{
return self::where('history_id', $historyId)->delete();
}
public static function getByHistoryId($historyId)
{
if($historyId <= 0) {
return [];
}
return self::where('history_id', $historyId)->order(['sort'=>'asc'])->select()->toArray();
}
}

39
app/model/Link.php Normal file
View File

@ -0,0 +1,39 @@
<?php
namespace app\model;
class Link extends Base
{
public static function delByIds($ids)
{
return self::whereIn('id', $ids)->delete();
}
//获取友情链接
public static function getList()
{
return self::order('sort asc')
->select()
->toArray();
}
public static function onAfterInsert($item)
{
$item->sort = $item->id;
$item->save();
}
//获取友情链接涉及到的文件
public static function getFilesInUse()
{
$items = self::select()->toArray();
$data = [];
foreach($items as $item){
$src = trim($item['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$data[$key] = $src;
}
}
return $data;
}
}

20
app/model/Log.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace app\model;
class Log extends Base
{
//记录操作日志
public static function write($controller, $action, $content)
{
$auth = session('auth');
return self::create([
'member_id' => $auth['userId'],
'name' => $auth['userName'],
'ip' => request()->ip(),
'create_time' => time(),
'controller' => $controller,
'action' => $action,
'content' => $content
]);
}
}

6
app/model/LoginLog.php Normal file
View File

@ -0,0 +1,6 @@
<?php
namespace app\model;
class LoginLog extends Base
{
}

57
app/model/Member.php Normal file
View File

@ -0,0 +1,57 @@
<?php
namespace app\model;
class Member extends Base
{
public static function getList($limit = 40)
{
$items = self::alias('m')
->leftjoin('auth_group g','g.id=m.group_id')
->field('m.id,m.username,m.login_time,m.group_id,g.title')
->order('m.id', 'asc')
->paginate($limit);
return $items;
}
/**
* 根据角色分组返回用户
* @param int $groupId 角色分组ID
* @param int $limit 每页数量
*/
public static function getListByGroup($groupId, $limit = 40)
{
$items = self::alias('m')
->leftjoin('auth_group g','g.id=m.group_id')
->field('m.id,m.username,m.login_time,m.group_id,g.title')
->where('m.group_id', '=', $groupId)
->order('m.id', 'asc')
->paginate($limit);
return $items;
}
//根据用户名获取管理账号
public static function getByUserName($username)
{
return self::where('username', trim($username))
->findOrEmpty()
->toArray();
}
//根据ID获取管理账户和相关权限
public static function getMemberAndRulesByID($memberId)
{
return self::alias('m')
->join('auth_group g', 'm.group_id = g.id', 'LEFT')
->field('m.group_id,g.rules')
->where('m.id', $memberId)
->findOrEmpty()
->toArray();
}
public static function updateCates($id, $cates)
{
$cates = implode(',', $cates);
$data = ['cates' => $cates];
self::updateById($id, $data);
}
}

14
app/model/Message.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace app\model;
class Message extends Base
{
/**
* 获取留言列表
*/
public static function getList($per = 20)
{
return self::order("create_time desc")
->paginate($per);
}
}

18
app/model/Model.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace app\model;
class Model extends Base
{
//获取模型列表
public static function getList()
{
return self::order('sort asc')
->select()
->toArray();
}
public static function onAfterInsert($model)
{
$model->sort = $model->id;
$model->save();
}
}

43
app/model/Slide.php Normal file
View File

@ -0,0 +1,43 @@
<?php
namespace app\model;
class Slide extends Base
{
public static function delByIds($ids)
{
return self::whereIn('id', $ids)->delete();
}
//获取幻灯片列表
public static function getList()
{
return self::order("sort asc")
->select()
->toArray();
}
public static function onAfterInsert($slide)
{
$slide->sort = $slide->id;
$slide->save();
}
//获取轮播图涉及到的文件
public static function getFilesInUse()
{
$items = self::select()->toArray();
$data = [];
foreach($items as $item){
$src = trim($item['src']);
if(!empty($src)){
$key = getKeyByPath($src);
$data[$key] = $src;
}
$mobileSrc = trim($item['src_mobile']);
if(!empty($mobileSrc)){
$key = getKeyByPath($mobileSrc);
$data[$key] = $mobileSrc;
}
}
return $data;
}
}

54
app/model/System.php Normal file
View File

@ -0,0 +1,54 @@
<?php
namespace app\model;
class System extends Base
{
//获取友情链接上传图片尺寸
public static function getLinkImageSize()
{
$system = self::getSystem();
if(!empty($system['link_w']) && !empty($system['link_h'])){
$linkSize = $system['link_w'] . '像素 X ' . $system['link_h'] . '像素';
}else{
$linkSize = '';
}
return $linkSize;
}
//获取幻灯片上传尺寸
public static function getSlideImageSize()
{
$system = self::getSystem();
if(!empty($system['slide_w']) && !empty($system['slide_h'])){
$slideSize = $system['slide_w'] . '像素 X ' . $system['slide_h'] . '像素';
}else{
$slideSize = '';
}
if(!empty($system['slide_mobile_w']) && !empty($system['slide_mobile_h'])){
$slideMobileSize = $system['slide_mobile_w'] . '像素 X ' . $system['slide_mobile_h'] . '像素';
}else{
$slideMobileSize = '';
}
return [
'slide_size' => $slideSize,
'slide_mobile_size' => $slideMobileSize
];
}
//获取文章图片尺寸
public static function getArticleImageSize()
{
$system = self::getSystem();
if(!empty($system['article_w']) && !empty($system['article_h'])){
$articleSize = $system['article_w'] . '像素 X ' . $system['article_h'] . '像素';
}else{
$articleSize = '';
}
return $articleSize;
}
//获取系统配置信息
public static function getSystem()
{
return self::order('id asc')
->findOrEmpty()
->toArray();
}
}

17
app/service/File.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace app\service;
use think\file\UploadedFile;
class File
{
//上传文件移动到上传文件夹
public static function move(UploadedFile $file)
{
$upload_path = 'uploads/' . date('Ymd');
$path = app()->getRootPath() . $upload_path;
$filename = uniqid() . '.' . $file->extension();
$upload_filename = '/' . $upload_path . '/' . $filename;
return [$file->move($path, $filename), $file, $upload_filename];
}
}

131
app/service/Image.php Normal file
View File

@ -0,0 +1,131 @@
<?php
namespace app\service;
use think\Image as TImage;
use app\model\System;
class Image extends File
{
/**
* 对图片进行重置大小并对宽度大于max宽度的等比缩放为宽度为1920
* milo
* 2019-10-24修改
*/
public static function resize($src)
{
$max = 1920;
$realPath = app()->getRootPath() . 'public/' . ltrim($src,'/');
if(is_file($realPath)){
$img = TImage::open($realPath);
list($img_w,$img_h) = $img->size();
if($max > 0 && $img_w > $max){
$img->thumb($max, $max * ($img_h / $img_w))->save($realPath);
}
}
}
/**
* 添加水印
* milo
* 2018-01-17
*/
public static function mark($src)
{
$rootPath = app()->getRootPath();
if(!empty($src)){
$system = System::getSystem();
$realPath = $rootPath . 'public/' . ltrim($src, '/');
if(is_file($realPath)){
if($system['is_mark']){
$mark = $rootPath . ltrim($system['mark_img'], '/');
if(is_file($mark)){
$mark_position = $system['mark_position']??5;
$mark_opacity = $system['mark_opacity']??50;
$img = TImage::Open($realPath);
$img->water($mark,$mark_position,$mark_opacity)->save($realPath);
}
}
}
}
}
//获取水印位置键值对
public static function getMarkPosition()
{
return [
"1" => '上左',
"2" => '上中',
"3" => '上右',
"4" => '中左',
"5" => '正中',
"6" => '中右',
"7" => '下左',
"8" => '下中',
"9" => '下右'
];
}
/**
* 删除图片
* milo
* 2018-01-15
*/
public static function delImg($src)
{
if(!empty(trim($src))){
$realPath = app()->getRootPath() . 'public/' . ltrim($src, '/');
if (file_exists($realPath)) {
$info = pathinfo($realPath);
$source = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '*.' . $info['extension'];
foreach(glob($source) as $filename){
if(is_file($filename)){
unlink($filename);
}
}
clearstatcache();// 清除缓存
}
}
}
/**
* 获取缩略图
* milo
* 2019-10-24修改
* 避免跨平台出错,目录分隔符全部转换为'/'
* app()->getRuntimePath() = app()->getRootPath().'runtime/当前应用模块api/'
*/
public static function getThumb($src,$width=0,$height=0,$type = TImage::THUMB_CENTER)
{
if(empty($src)){
return '';
}
$rootPath = app()->getRootPath();
$realPath = $rootPath . 'public/' . ltrim($src, '/');
$realPath = str_replace('\\', '/', $realPath);
if(!file_exists($realPath)){
return '';
}
$info = pathinfo($src);
if($width <= 0 && $height <= 0){ //高宽都小于或等于0则返回原图片
return $src;
}
$image = TImage::open($realPath);
list($imageWidth, $imageHeight) = $image->size();
if($width <= 0){
$width = floor($height * ($imageWidth / $imageHeight));
}elseif($height <= 0){
$height = floor($width * ($imageHeight / $imageWidth));
}
if($width >= $imageWidth || $height >= $imageHeight){
return $src;
}
$thumbName = $info['dirname']. DIRECTORY_SEPARATOR .$info['filename'].'_'.$width.'_'.$height.'.'.$info['extension'];
$realThumbName = $rootPath . 'public/' . ltrim($thumbName, '/');
$realThumbName = str_replace('\\', '/', $realThumbName);
if(!file_exists($realThumbName)){
$image = TImage::open($realPath);
$image->thumb($width, $height, $type)->save($realThumbName);
}
return str_replace('\\', '/', $thumbName);
}
}

53
app/service/Tool.php Normal file
View File

@ -0,0 +1,53 @@
<?php
namespace app\service;
class Tool
{
//删除文件
public static function delFile($path)
{
if(!empty(trim($path))){
$realPath = app()->getRootPath() . ltrim($path, '/');
if (file_exists($realPath)) {
$info = pathinfo($realPath);
$source = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '*.' . $info['extension'];
foreach(glob($source) as $filename){
if(is_file($filename)){
unlink($filename);
}
}
clearstatcache();// 清除缓存
}
}
}
/**
* 删除目录下的所有文件和子目录
* 调用完毕后请用clearstatcache()清理缓存
*/
public static function removeByPath($path)
{
if(is_dir($path)) {
if($handle = @opendir($path)) {
while (($file = readdir($handle)) !== false){
if($file != '.' && $file != '..') {
$child = $path.'/'.$file;
is_dir($child) ? self::removeByPath($child) : @unlink($child);
}
}
}
closedir($handle);
} elseif (is_file($path)) {
@unlink($path);
} else {
return false;
}
return true;
}
//去除字符串空格
public static function trimSpace($str)
{
return str_replace(' ', '', trim($str));
}
}

16
app/validate/Article.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\validate;
use think\Validate;
class Article extends Validate
{
protected $rule = [
'title' => 'require',
'link' => 'url'
];
protected $message = [
'title.require' => '标题必须',
'link.url' => '请填写有效的网址'
];
}

View File

@ -0,0 +1,17 @@
<?php
namespace app\validate;
use think\Validate;
class AuthGroup extends Validate
{
protected $rule = [
'title' => 'require',
'status' => 'require|number',
];
protected $message = [
'title.require' => '角色名称不能为空',
'status.require' => '角色状态必须设置',
'status.number' => '角色状态参数值只能为数字类型',
];
}

19
app/validate/AuthRule.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace app\validate;
use think\Validate;
class AuthRule extends Validate
{
protected $rule = [
'title' => 'require',
'name' => 'require',
'status' =>'require|number',
];
protected $message = [
'title.require' => '名称必须',
'name.require'=> '标识必须',
'status.require'=> '显示状态必须传值',
'status.number'=> '显示状态传值只能为数字表示',
];
}

16
app/validate/Block.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\validate;
use think\Validate;
class Block extends Validate
{
protected $rule = [
'title' => 'require',
'keyword' => 'require',
];
protected $message = [
'title.require' => '名称必须',
'keyword.require' => '键值必须'
];
}

18
app/validate/Category.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace app\validate;
use think\Validate;
class Category extends Validate
{
protected $rule = [
'title' => 'require',
'model_id' => 'require|number|min:1',
];
protected $message = [
'title.require' => '栏目名称必须',
'model_id.require' => '栏目模型必须',
'model_id.number' => '栏目模型格式要正确',
'model_id.min' => '请选择正确的栏目模型'
];
}

19
app/validate/History.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace app\validate;
use think\Validate;
class History extends Validate
{
protected $rule = [
'title' => 'require|length:1,60',
'visible' => 'require|in:0,1',
];
protected $message = [
'title.require' => '标题不能为空',
'name.length' => '标题长度限制为60个字符以内',
'visible.require' => '历程状态必须设置',
'visible.in' => '状态参数错误',
];
}

View File

@ -0,0 +1,19 @@
<?php
namespace app\validate;
use think\Validate;
class HistoryInfo extends Validate
{
protected $rule = [
'title' => 'require|length:1,200',
'visible' => 'require|in:0,1',
];
protected $message = [
'title.require' => '标题不能为空',
'name.length' => '标题长度限制为200个字符以内',
'visible.require' => '历程事例状态必须设置',
'visible.in' => '状态参数错误',
];
}

16
app/validate/Link.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\validate;
use think\Validate;
class Link extends Validate
{
protected $rule = [
'title' => 'require',
'url' => 'url',
];
protected $message = [
'title.require' => '名称必须',
'url.url' => '请填写有效的网址,以http://或https://开头'
];
}

17
app/validate/Member.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace app\validate;
use think\Validate;
class Member extends Validate
{
protected $rule = [
'group_id' => 'require|number',
'username' => 'require',
];
protected $message = [
'group_id.require' => '所属角色不能为空!',
'group_id.number' => '用户角色信息数据格式不正确!',
'username.require' => '用户姓名不能为空!',
];
}

16
app/validate/Model.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\validate;
use think\Validate;
class Model extends Validate
{
protected $rule = [
'name' => 'require',
'manager' => 'require',
];
protected $message = [
'name.require' => '名称必须',
'manager.require' => '后台管理必须'
];
}

16
app/validate/Slide.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\validate;
use think\Validate;
class Slide extends Validate
{
protected $rule = [
'title' => 'require',
'url' => 'url',
];
protected $message = [
'title.require' => '标题必须',
'url.url' => '请填写有效的网址,以http://或https://开头'
];
}

60
app/validate/Upload.php Normal file
View File

@ -0,0 +1,60 @@
<?php
namespace app\validate;
use think\Validate;
use app\model\System;
use think\Lang;
class Upload extends Validate
{
protected $rule = [];
protected $message = [];
protected $system;
public function __construct()
{
$this->system = System::getSystem();
$this->lang = new Lang;
}
//验证图片上传
public function checkImage($image)
{
$ext = str_replace('', ',', $this->system['img_type']);
$size = $this->system['img_size'] * 1024 * 1024;
$this->rule = [
'image' => [
'fileExt' => $ext,
'fileSize' => (int)$size
]
];
return $this->check(['image' => $image]);
}
//验证视频上传
public function checkVideo($video)
{
$ext = str_replace('', ',', $this->system['video_type']);
$size = $this->system['video_size'] * 1024 * 1024;
$this->rule = [
'video' => [
'fileExt' => $ext,
'fileSize' => (int)$size
]
];
return $this->check(['video' => $video]);
}
//验证文件上传
public function checkFile($file)
{
$ext = str_replace('', ',', $this->system['file_type']);
$size = $this->system['file_size'] * 1024 * 1024;
$this->rule = [
'file' => [
'fileExt' => $ext,
'fileSize' => (int)$size
]
];
return $this->check(['file' => $file]);
}
}

17
app/widget/Crumbs.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace app\widget;
use app\model\Category;
use think\facade\View;
class Crumbs
{
public function index($categoryId)
{
$data = [
'crumbs' => Category::getCatesCrumbs($categoryId)
];
return View::assign($data)->fetch('public/crumbs');
}
}

49
app/widget/Menu.php Normal file
View File

@ -0,0 +1,49 @@
<?php
namespace app\widget;
use app\model\Category;
use think\facade\{Db,View, Cache};
class Menu
{
public function index($categoryId)
{
$menus = Cache::get('rules');
if(empty($menus)){
$menus = Category::getListForFrontMenu();
}
$currentFirstId = 0;
if (is_numeric($categoryId) && $categoryId > 0) {
$currentFirstId = Category::firstGradeById($categoryId);
}
//产品菜单
$product_children=Category::alias('c')
->leftJoin('model m', 'c.model_id=m.id')
->field('c.*, m.manager, m.template, m.name as modelName')
->where('c.parent_id', 5)
->order('c.sort','asc')
->select()
->toArray();
$data = [
'categoryId' => $categoryId,
'menus' => $menus,
'product_children' => $product_children?$product_children:[],
];
$this_menu= \app\model\Category::alias('c')
->leftJoin('model m', 'c.model_id=m.id')
->field('c.*, m.manager, m.name as modelName')
->when(3, function($query) {
$query->whereIn('c.id', []);
})
->order('sort','asc')
->select()
->toArray();
return View::assign($data)->fetch('public/menu');
}
}

16
app/widget/Slide.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace app\widget;
use think\facade\View;
use app\model\Slide as WSlide;
class Slide
{
public function index()
{
$data = [
'slides' => WSlide::getList(),
];
return View::assign($data)->fetch('public/slide');
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace app\widget\manager;
use app\model\{Category, AuthRule};
use think\facade\View;
class Crumbs
{
public function index()
{
$request = request();
$controller = strtolower($request->controller());
$action = strtolower($request->action());
$controller = str_replace('manager.', '', $controller);
$name = $controller . '/' . $action;
if($action == 'index'){
$rule = AuthRule::getByTwoName($name, $controller);
}else{
$rule = AuthRule::getByName($name);
}
$parent = [];
if(!empty($rule) && $rule['parent_id']){
$parent = AuthRule::getById($rule['parent_id']);
}
$cateCrumbs = [];
$isContent = false;
if($controller == 'content') {
$isContent = true;
$categoryId = $request->param('category_id', 0);
if (is_numeric($categoryId) && $categoryId > 0) {
$cateCrumbs = Category::getCatesCrumbs($categoryId);
}
}
$data = [
'rule' => $rule,
'parent' => $parent,
'isContent' => $isContent,
'cateCrumbs' => $cateCrumbs
];
return View::assign($data)->fetch('manager/widget/crumbs');
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace app\widget\manager;
use think\facade\{View, Cache};
use app\model\Category;
class Menu
{
/**
* 左侧菜单
* milo
* 2018-01-06
*/
public function left($categoryId = 0)
{
$auth = session('auth');
$authCates = array_filter(explode(',', $auth['cates']));
$rules = Cache::get('group_rules_'.$auth['groupId']);
$menuRules = $this->getMenuRules($rules);
$current = strtolower(request()->controller());
$current = str_replace('manager.', '', $current);
$currentAction = strtolower($current.'/'.request()->action());
// message 留言管理是否集成在内容管理中,后期开发中根据情况调整
if(in_array($current, ['article', 'product', 'page'], true)){
$current = 'content';
}
if($auth['groupId'] == 1) {
$menus = $this->getMenus(Category::getList(false));
} else {
$menus = $this->getMenus(Category::getList(true, $authCates));
}
$data = [
'rules' => $menuRules,
'categoryId' => $categoryId,
'menus' => $menus,
'current' => $current,
'currentAction' => $currentAction
];
return View::assign($data)->fetch('manager/widget/left');
}
/**
* 过滤出权限菜单
* @param $rules
* @return array
*/
private function getMenuRules($rules)
{
$menuRules = [];
if (!empty($rules)) {
foreach ($rules as $rule) {
$hasChildren = $rule['hasChildren'] ?? false;
if ($hasChildren) {
$rule['children'] = $this->getMenuRules($rule['children']);
if(count($rule['children']) > 0) {
$rule['status'] = 1;
}
}
if($rule['status'] > 0) {
$menuRules[] = $rule;
}
}
}
return $menuRules;
}
/**
* 内容栏目菜单
* @param $cates
* @param int $parent_id
* @return array
*/
private function getMenus($cates,$parentId=0)
{
$menus = [];
foreach($cates as $cate){
if($cate['parent_id'] == $parentId && $cate['state'] == 1){
$children = $this->getMenus($cates,$cate['id']);
if(!empty($children)){
$cate['children'] = $children;
}
if(!empty($cate['children']) || !empty($cate['manager'])){
$menus[] = $cate;
}
}
}
return $menus;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace app\widget\manager;
use think\facade\View;
class Upload
{
//视频
public function video($src = '', $append = '')
{
$data = [
'src' => $src,
'append' => $append
];
return View::assign($data)->fetch('manager/widget/video');
}
//图片layui自带上传控件,若同一页面内徐亚加载多层本上传控件则需要传不同的$append来区分控件ID
public function image($src = '', $append = '', $imgSize = 0, $thumb = 0)
{
$data = [
'src' => $src,
'append' => $append,
'imgSize' => $imgSize,
'thumb' => $thumb,
];
return View::assign($data)->fetch('manager/widget/image');
}
//上传文件,目前在文章中添加附件
public function files($files = [], $num = 10, $append = '')
{
if(!empty($files) && $files == 'null') {
$files = [];
}
$data = [
'files' => $files,
'append' => $append,
'num' => $num,
];
return View::assign($data)->fetch('manager/widget/files');
}
/**
* 水印图片上传
* milo
* 2018-01-13
*/
public function mark($src = '')
{
return View::assign(['src' => $src])->fetch('manager/widget/mark');
}
/**
* layui组图上传
* milo
*/
public function multi($imgs = [], $num = 10, $append = '', $imgSize = '')
{
if(!empty($imgs) && $imgs == 'null') {
$imgs = [];
}
$data = [
'imgs' => $imgs,
'append' => $append,
'imgSize' => $imgSize,
'num' => $num
];
return View::assign($data)->fetch('manager/widget/multi');
}
}

26
build.example.php Normal file
View File

@ -0,0 +1,26 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
/**
* php think build 自动生成应用的目录结构的定义示例
*/
return [
// 需要自动创建的文件
'__file__' => [],
// 需要自动创建的目录
'__dir__' => ['controller', 'model', 'view'],
// 需要自动创建的控制器
'controller' => ['Index'],
// 需要自动创建的模型
'model' => ['User'],
// 需要自动创建的模板
'view' => ['index/index'],
];

46
composer.json Normal file
View File

@ -0,0 +1,46 @@
{
"name": "topthink/think",
"description": "the new thinkphp framework",
"type": "project",
"keywords": [
"framework",
"thinkphp",
"ORM"
],
"homepage": "http://thinkphp.cn/",
"license": "Apache-2.0",
"authors": [
{
"name": "liu21st",
"email": "liu21st@gmail.com"
}
],
"require": {
"php": ">=7.1.0",
"topthink/framework": "^6.0.0",
"topthink/think-orm": "^2.0",
"topthink/think-view": "^1.0",
"topthink/think-image": "^1.0"
},
"require-dev": {
"symfony/var-dumper": "^4.2",
"topthink/think-trace":"^1.0"
},
"autoload": {
"psr-4": {
"app\\": "app"
},
"psr-0": {
"": "extend/"
}
},
"config": {
"preferred-install": "dist"
},
"scripts": {
"post-autoload-dump": [
"@php think service:discover",
"@php think vendor:publish"
]
}
}

1038
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

5
package-lock.json generated Normal file
View File

@ -0,0 +1,5 @@
{
"name": "cms",
"version": "1.0.0",
"lockfileVersion": 1
}

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "cms",
"version": "1.0.0",
"description": "本CMS基于ThinkPHP 6.0开发",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gitee.com/dxtc/cms.git"
},
"keywords": [],
"author": "",
"license": "ISC"
}

9
public/.htaccess Normal file
View File

@ -0,0 +1,9 @@
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^(.*)\.(gif|jpg|jpeg|png|swf|mp4)$ [NC]
RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L]
</IfModule>

24
public/index.php Normal file
View File

@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// [ 应用入口文件 ]
namespace think;
header("Access-Control-Allow-Origin:*");
header('Access-Control-Allow-Methods:POST');
header('Access-Control-Allow-Headers:x-requested-with, content-type');
require dirname(__DIR__) . '/vendor/autoload.php';
// 执行HTTP应用并响应
$http = (new App())->http;
$response = $http->run();
$response->send();
$http->end($response);

File diff suppressed because one or more lines are too long

3067
public/static/css/animate.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

5
public/static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

599
public/static/css/style.css Normal file
View File

@ -0,0 +1,599 @@
@charset "utf-8";
/* CSS Document */
/*公用代码*/
body,html{background:none repeat scroll 0 0;font:100% "Microsoft YaHei New","Microsoft Yahei","微软雅黑","Hiragino Sans GB","冬青黑体","Arial","Helvetica","SimHei","黑体","STXihei","华文细黑",sans-serif;}
body{overflow-x:hidden;color:#333;}
blockquote,body,button,dd,div,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;text-shadow:none;}
label input{vertical-align:middle;text-shadow:none;}
*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
a{-webkit-transition:all .5s;-moz-transition:all .5s;transition:all .5s;}
a:hover{ color: #578df3;}
:hover,a:active,a:focus,a:hover,a:link,a:visited{text-decoration:none;text-shadow:none;}
img{max-width:100%;border:0;}
i{ font-style: initial;}
table{border-collapse:collapse;}
ul li{list-style:none outside none;}
input,select,textarea{outline:medium none; resize: none;}
.f-l{float:left;}
.f-l,.f-r{display:inline-block;}
.f-r{float:right;}
.t-l{text-align:left;}
.t-c{text-align:center;}
.t-r{text-align:right;}
.top10{margin-top:10px;}
.top20{margin-top:20px;}
.top30,.top40{margin-top:30px;}
.top50{margin-top:50px;}
.top60{margin-top:60px;}
.top70{margin-top:70px;}
.top80{margin-top:80px;}
.bg-w{background:#fff;}
.w-90{ width: 94%; margin: auto;}
.w-100{width:100%; float: left;}
.w-1200{margin:auto;width:75rem;}
.w-1500{margin: auto; width: 1500px;}
.div-pc{ display: block;}
.div-phone{ display: none;}
/* 布局样式 */
.between-top{ display: flex; display: -webkit-flex; justify-content: space-between; -webkit-justify-content: space-between; }
.between-center{ display: flex; display: -webkit-flex; justify-content: space-between; align-items: center; -webkit-justify-content: space-between; -webkit-align-items: center; }
.between-bottom{ display: flex; display: -webkit-flex; justify-content: space-between; align-items: flex-end; -webkit-justify-content: space-between; -webkit-align-items: flex-end; }
.center-center{ display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-align: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; }
.around-center{ display: flex; display: -webkit-flex; justify-content: space-around; align-items: center; -webkit-justify-content: space-around; -webkit-align-items: center; }
.column-between{ display: flex; display: -webkit-flex; flex-direction: column; -webkit-flex-direction: column; justify-content: space-between; -webkit-justify-content: space-between; }
.column-around{ display: flex; display: -webkit-flex; flex-direction: column; -webkit-flex-direction: column; justify-content: space-around; -webkit-justify-content: space-around; }
/* 文字超出隐藏省略号 */
.text-one-hide{ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;}
.text-two-hide{ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;}
.text-three-hide{ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;}
/*nav*/
/**/
.nav ul li{ float: left; position: relative; margin-left: 4.6875rem; transition: all .6s;}
.nav ul li span a{ float: left; font-size: 1.125rem; line-height: 6.25rem; position: relative; text-decoration: none;}
.nav ul li span a::before{ content: ''; width: 0; height: 2px; position: absolute; left: 0; bottom: 0; background: #f54123; transition: all .6s; opacity: 0;}
/*二级控制*/
.nav ul li .nav-second{ width: auto; min-width: 5.625rem; position: absolute; left: 50%; top: 100%; background: #fff; opacity: 0; transform: translate(-50%,0); transition: all .6s;}
.nav ul li .nav-second a{ width: 100%; float: left; color: #333; text-align: center; height: 0; font-size: 0.875rem; white-space: nowrap;}
.nav ul li .nav-second a:hover,.nav ul li .nav-second a.active{ color: #f54123;}
/*三级级控制*/
.nav ul li .nav-second .nav-three{ width: 100%; position: relative; display: block; float: left;}
.nav ul li .nav-second .nav-three:hover p a{ background: #fff; color: #0c253b;}
.nav ul li .nav-second .nav-three div{ position: absolute; left: 100%; top: -10px; background: #f75c9a; padding: 10px 0; display: none;}
.nav ul li .nav-second .nav-three div::before{ content: ''; width: 10px; height: 50px; position: absolute; left: -10px; top: 0;}
.nav ul li .nav-second .nav-three div a{ display: block; white-space: nowrap;}
.nav ul li .nav-second .nav-three:hover div{ display: block;}
/*hover*/
.nav ul li:hover .nav-second{ padding: 0.625rem; opacity: 1;}
.nav ul li:hover .nav-second a{ height: 2rem; line-height: 2rem;}
.nav ul li:hover span a,.nav ul li.active span a{ color: #f54123 !important; font-weight: bold;}
.nav ul li:hover span a::before,.nav ul li.active span a::before{ opacity: 1; width: 100%;}
/*icon*/
.nav_btn{ width: 24px; float: right; position: relative; cursor: pointer; display: none;}
.nav_btn i{ display: block; width: 100%; height: 2px; float: left; background-color: #f54123; border-radius: 50px;
transition: all .5s ease 0s;
-webkit-transition: all .5s ease 0s;
-moz-transition: all .5s ease 0s;
}
.nav_btn i.bar-top{ margin-top: 0;}
.nav_btn i.bar-cen{ margin-top: 6px;}
.nav_btn i.bar-bom{ margin-top: 6px;}
.nav_btn.cur i.bar-cen{ opacity: 0;}
.nav_btn.cur i.bar-top{ -webkit-transform:rotate(45deg) translate(6px, 6px);transform:rotate(45deg) translate(6px, 6px);}
.nav_btn.cur i.bar-bom{ -webkit-transform: rotate(-45deg) translate(5.5px, -5px);transform: rotate(-45deg) translate(5.5px, -5px);}
/*隐藏*/
.overHide{ overflow: hidden;}
.all-center-box{ width: 100%; float: left; margin-top: 6.25rem;}
.head-box{ position: fixed; left: 0; top: 0; z-index: 99; background: #fff; transition: all .6s; padding-bottom: 1px; box-shadow: 0 0 10px rgba(0,0,0,0.1);}
.head-box .pull-left img{ height: 3.75rem;}
.head-two{ position: fixed; left: 0; top: 6.25rem; z-index: 98; background: rgba(0,0,0,0.4); display: none;}
.head-two ul{ display: flex;}
.head-two ul li{ width: 100%; float: left; text-align: center; padding: 1.875rem 10px;}
.head-two ul li i{ display: block; height: 8.125rem; overflow: hidden;}
.head-two ul li i img{ height: 100%; object-fit: cover;}
.head-two ul li p{ color: #fff; margin-top: 10px; font-size: 1rem; transition: all .6s;}
.head-two ul li:hover p{ color: #f54123;}
.banner-box{ height: auto;}
.banner-box .swiper-container{ height: 100%;}
.banner-box .swiper-container .swiper-slide{ background-position: center; background-size: cover; background-color: #ccc;}
.banner-box .swiper-container .swiper-slide .pull-left{ color: #fff;}
.banner-box .swiper-container .swiper-slide .pull-left p{ font-size: 4.375rem; transform: translate(3.125rem,0); opacity: 0; transition: all .6s;}
.banner-box .swiper-container .swiper-slide .pull-left i{ font-size: 1.25rem; line-height: 1.6; display: block; margin-top: 1.25rem; transform: translate(3.125rem,0); opacity: 0; transition: all .6s ease .1s;}
.banner-box .swiper-container .swiper-slide .w-1500.active .pull-left p{ opacity: 1; transform: translate(0,0);}
.banner-box .swiper-container .swiper-slide .w-1500.active .pull-left i{ opacity: 1; transform: translate(0,0);}
.banner-box .swiper-container .swiper-slide .w-1500.active .pull-left a{ opacity: 1; transform: translate(0,0);}
.banner-box .swiper-page{ width: 100%; position: absolute; left: 0; bottom: 4rem;}
.banner-box .swiper-container .swiper-pagination{ position: relative;}
.banner-box .swiper-container .swiper-pagination .swiper-pagination-bullet{ width: 0.75rem; height: 0.75rem; outline: none; margin: 0 0.3125rem; border-radius: 4px; background: #d8d8d8; transition: all .6s; opacity: 1;}
.banner-box .swiper-container .swiper-pagination .swiper-pagination-bullet.swiper-pagination-bullet-active{ width: 3.125rem; background: #f54123;}
.online{ position: fixed; left: 0; top: 50%; z-index: 99; margin-top: -3.125rem;}
.online img{ height: 5.0625rem; float: left;}
.home-box1 .top-box{ position: relative; overflow: hidden;}
.home-box1 .top-box::after{ content: ''; width: 40%; height: 100%; position: absolute; right: 0; bottom: 0; background: #0071ec;}
.home-box1 .top-box .pull-left{ width: 29%; line-height: 5.5rem; font-size: 1.25rem; color: #444; position: relative; z-index: 2;}
.home-box1 .top-box .pull-left span{ color: #f54123;}
.home-box1 .top-box .pull-right{ width: 71%; background: #0071ec; padding: 0 3.125rem; position: relative; z-index: 2;}
.home-box1 .top-box .pull-right .text{ width: 23.75rem; height: 5.5rem; float: left; background: none; border:none; font-size: 0.875rem; color: #fff;}
.home-box1 .top-box .pull-right .text::-webkit-input-placeholder{ color: rgba(255,255,255,0.8);}
.home-box1 .top-box .pull-right .btns{ width: 2.5rem; height: 5.5rem; float: left; background: url(../image/icon_1.png) no-repeat center; background-size: 1.25rem; border:none;}
.home-box1 .lower-box{ padding: 4.0625rem 0;}
.home-box1 .lower-box .pull-left{ width: 38%;}
.home-box1 .lower-box .pull-left .box1{ font-size: 1.875rem;}
.home-box1 .lower-box .pull-left .box2{ font-size: 14px; line-height: 1.5rem; color: #666; margin: 1.5625rem 0; text-align: justify;}
.home-box1 .lower-box .pull-right .center-center{ width: 20rem; height: 20rem; border: 1px solid #D5D5D5; float: left; border-radius: 100%; padding: 0 3.75rem;}
.home-box1 .lower-box .pull-right .center-center em img{ height: 32px;}
.home-box1 .lower-box .pull-right .center-center span{ font-size: 1.25rem; margin: 1rem 0 0;}
.home-box1 .lower-box .pull-right .center-center:nth-child(1) span{ font-size: 2.25rem;}
.home-box1 .lower-box .pull-right .center-center span i{ font-size: 3rem;}
.home-box1 .lower-box .pull-right .center-center p{ font-size: 12px; color: #888; text-align: center; height: 96px;}
.all-more{ border: 1px solid; padding: 0 0.75rem; line-height: 1.875rem; font-size: 12px; display: inline-block;}
.all-more i{ display: inline-block; padding-right: 1.875rem; background-position: right; background-repeat: no-repeat; background-size: 1rem;}
.all-more.orange{ color: #f54123;}
.all-more.orange i{ background-image: url(../image/icon_jt1.png);}
.all-more.white{ color: #fff;}
.all-more.white i{ background-image: url(../image/icon_jt2.png);}
.all-more.noBor{ color: #be0d27; padding: 0; border: none;}
.all-more.noBor i{ background-image: url(../image/icon_jt3.png); padding-right: 1.5625rem;}
.home-box2 ul li{ width: 25%; height: 600px; float: left; transition: all .6s; color: #fff; position: relative; overflow: hidden;}
.home-box2 ul li:nth-child(1){ background: #f54123;}
.home-box2 ul li:nth-child(2){ background: url(../image/ho2_bg2.jpg) no-repeat center; background-size: cover;}
.home-box2 ul li:nth-child(3){ background: url(../image/ho2_bg3.png) no-repeat right bottom #0071ec; background-size: 18.75rem;}
.home-box2 ul li .box-info1 .center-block{ width: 12.25rem;}
.home-box2 ul li .box-info2 .center-block{ width: 23.75rem;}
.home-box2 ul li .box-info1{ width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 2; font-size: 12px; padding: 0 3.25rem; transition: all .6s;}
.home-box2 ul li .box-info1 .box1{ text-align: center;}
.home-box2 ul li .box-info1 .box1 i img{ width: 2.5rem;}
.home-box2 ul li .box-info1 .box1 p{ margin-top: 0.75rem;}
.home-box2 ul li .box-info1 .box2{ padding: 30px 0;}
.home-box2 ul li .box-info1 .box3{ text-align: center;}
.home-box2 ul li .box-info1 .box3 img{ height: 2.125rem;}
.home-box2 ul li .box-info2{ width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 2; padding: 0 6.875rem; opacity: 0; transition: all .6s;}
.home-box2 ul li .box-info2 .box1 i{ font-size: 12px; display: block;}
.home-box2 ul li .box-info2 .box1 span{ display: block; font-size: 1.5rem; padding: 26px 0 15px;}
.home-box2 ul li .box-info2 .box1 p{ font-size: 0.875rem; text-align: justify;}
.home-box2 ul li .box-info2 .box2{ font-size: 0.875rem; margin: 29px 0 19px;}
.home-box2 ul li .box-info2 .box3 div{ float: left; text-align: center;}
.home-box2 ul li .box-info2 .box3 div+div{ margin-left: 3.75rem;}
.home-box2 ul li .box-info2 .box3 div i{ display: block; height: 28px;}
.home-box2 ul li .box-info2 .box3 div i img{ height: 28px;}
.home-box2 ul li .box-info2 .box3 div p{ display: block; font-size: 0.75rem; margin-top: 3px;}
.home-box2 ul li .box-info2 .box4{ margin-top: 28px;}
.home-box2 ul li.active{ width: 50%;}
.home-box2 ul li.active .box-info1{ opacity: 0;}
.home-box2 ul li.active .box-info2{ opacity: 1;}
.all-title1{}
.all-title1 .pull-left{ width: 23.75rem; border-top: 1px solid #be0d27; padding-top: 1.0625rem;}
.all-title1 .pull-left span{ font-size: 1.875rem; float: left; line-height: 2.5rem;}
.all-title1 .pull-left a{ width: 2.5rem; height: 2.5rem; float: right; background: url(../image/icon_jt2.png) no-repeat center #f54123; background-size: 1rem;}
.home-box3{ position: relative; padding: 4.0625rem 3.75rem 0 0;}
.home-box3::after{ content: ''; width: 75%; height: 94%; background: #F0F0F0; position: absolute; right: 0; top: 0;}
.home-box3 .center-block{ background: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.2); position: relative; z-index: 2; padding: 0 3.125rem 0.9375rem 6.875rem;}
.home-box3 .center-block .box-info1{ width: 68%; float: left; margin-top: 1rem;}
.home-box3 .center-block .box-info1 ul li{ width: 100%; float: left; border-top: 1px solid #eee; padding: 1.75rem 0;}
.home-box3 .center-block .box-info1 ul li:first-child{ border:none;}
.home-box3 .center-block .imgs{ width: 33%; height: 7.8125rem; float: left; overflow: hidden;}
.home-box3 .center-block .imgs img{ width: 100%; height: 100%; float: left; object-fit: cover; transition: all .6s;}
.home-box3 .center-block .info{ width: 67%; float: left; padding-left: 3.0625rem;}
.home-box3 .center-block .info .box1 i{ display: block; font-size: 12px; color: #666; margin-top: 0.375rem;}
.home-box3 .center-block .info .box1 span{ display: block; font-size: 1rem; color: #262626; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;}
.home-box3 .center-block .info .box1 p{ font-size: 12px; color: #4c4c4c; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; margin: 0.75rem 0;}
.home-box3 .center-block .info .all-more{ line-height: 1.1;}
.home-box3 .center-block .box-info2{ width: 28%; float: right; margin-top: 2.75rem;}
.home-box3 .center-block .box-info2 .imgs{ width: 100%; height: 9.6875rem;}
.home-box3 .center-block .box-info2 .info{ width: 100%; padding: 1.75rem 0 0;}
.home-box3 .center-block .box-info1 ul li:hover .imgs img,.home-box3 .center-block .box-info2:hover .imgs img{ transform: scale(1.1);}
.home-box4 .top-box{ padding: 2.5rem 6.875rem;}
.home-box4 .lower-box{ background: #34312C; color: #fff; position: relative; overflow: hidden;}
.home-box4 .lower-box .pull-left{ width: 78%; height: 28.125rem; background: url(../image/ho4_bg.jpg) no-repeat center; padding: 6.875rem 6.875rem 0;}
.home-box4 .lower-box .pull-left .center-block{ padding-right: 42%; display: none;}
.home-box4 .lower-box .pull-left .center-block .box1{ font-size: 1.5rem; font-weight: bold;}
.home-box4 .lower-box .pull-left .center-block .box2{ font-size: 0.75rem; margin: 0.9375rem 0; text-align: justify; min-height: 12.5rem;}
.home-box4 .lower-box .pull-right{ width: 22%; height: 100%; position: absolute; right: 0; top: 0;}
.home-box4 .lower-box .pull-right ul{ width: 100%;}
.home-box4 .lower-box .pull-right ul li{ width: 100%; float: left;}
.home-box4 .lower-box .pull-right ul li a{ width: 100%; float: left; line-height: 2.5rem; padding: 0 1.5625rem; color: #fff; font-size: 0.875rem; border-left: 2px solid #fff;}
.home-box4 .lower-box .pull-right ul li a:hover,.home-box4 .lower-box .pull-right ul li.active a{ color: #f54123; border-color: #f54123;}
.home-box4 .lower-box .swiper-pagination-bullet{ background: rgba(255,255,255,0.5); opacity: 1;}
.home-box4 .lower-box .swiper-pagination-bullet-active{ background: #f54123;}
.home-box4 .lower-box .swiper-pagination{ bottom: 0;}
.home-box5 .center-block{ background: url(../image/ho5_bg.png) no-repeat center; background-size: cover; height: 36.25rem; padding: 2.5rem 6.875rem;}
.home-box5 .center-block .box-info{ width: 230px; background: #fff; float: left; border-radius: 5px; box-shadow: 0 0 0.625rem rgba(0,0,0,0.1); position: relative; margin: 72px 0 0 280px;}
.home-box5 .center-block .box-info .info{ padding: 1.375rem 1rem 3.125rem;}
.home-box5 .center-block .box-info .info span{ font-size: 0.875rem; color: #f54123;}
.home-box5 .center-block .box-info .info p{ font-size: 12px; color: #7f7f7f; background-position: 0 3px; background-repeat: no-repeat; padding-left: 22px; margin-top: 10px;}
.home-box5 .center-block .box-info .info p.icon1{ background-image: url(../image/icon_4.png);}
.home-box5 .center-block .box-info .info p.icon2{ background-image: url(../image/icon_5.png);}
.home-box5 .center-block .box-info::before{ content: ''; width: 14px; height: 14px; background: url(../image/icon_3.png) no-repeat center; background-size: 100%; position: absolute; left: -44px; top: 50%; margin-top: -7px;}
.home-box5 .center-block .box-info::after{ content: ''; width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-right: 6px solid #fff; position: absolute; right: 100%; top: 50%; z-index: 2; margin-top: -6px;}
.home-box6{ background: #0071ec;}
.foot-box{ background: #111; color: #fff;}
.foot-box .top-box{ display: flex; padding: 1.875rem 2.5rem 3.125rem; letter-spacing: 2px;}
.foot-box .top-box ul{ float: left; font-size: 12px;}
.foot-box .top-box ul+ul{ margin-left: 3.125rem;}
.foot-box .top-box ul span{ display: block; font-size: 14px; white-space: nowrap;}
.foot-box .top-box ul li{ display: block; color: #999; margin-top: 1rem;}
.foot-box .top-box ul li img{ width: 70px;}
.foot-box .top-box ul li a{ color: #999;}
.foot-box .top-box ul li a:hover{ color: #fff;}
.foot-box .top-box ul:last-child li{ white-space: nowrap;}
.foot-box .lower-box{ padding: 24px 2.5rem; font-size: 14px;}
.all-title2{ text-align: center;}
.all-title2 span{ display: block; font-size: 2.5rem;}
.all-title2 p{ font-size: 12px; color: #999; display: inline-block; padding: 0 6.25rem; position: relative;}
.all-title2 p i{ display: inline-block; position: relative; z-index: 2; padding: 0 0.375rem; background: #fff;}
.all-title2 p::after{ content: ''; width: 100%; height: 1px; background: #999; position: absolute; left: 0; top: 50%;}
.about-box1{ padding: 2.5rem 0;}
.about-box1:nth-child(2){ padding-top: 5rem;}
.about-box1 .box-info{ padding-top: 3.75rem;}
.about-box1 .box-info .pull-left{ width: 48.4%; position: relative; padding-left: 9%;}
.about-box1 .box-info .pull-left::after{ content: ''; width: 100%; height: 48%; background: #f0f0f0; position: absolute; left: 0; bottom: 0;}
.about-box1 .box-info .pull-left img{ width: 100%; float: left; position: relative; z-index: 2;}
.about-box1 .box-info .pull-right{ width: 51.6%; padding-left: 3.25rem;}
.about-box1 .box-info .pull-right .box1{ font-size: 1.875rem;}
.about-box1 .box-info .pull-right .box2{ height: 350px; overflow: auto; font-size: 14px; line-height: 24px; margin-top: 1.875rem; text-align: justify; padding-right: 1.5rem;}
.about-box1 .box-info .pull-right .box2::-webkit-scrollbar{ width: 5px; background: #fff;}
.about-box1 .box-info .pull-right .box2::-webkit-scrollbar-thumb{ background: #eee;}
.about-box1 .box-info .pull-right .box2::-webkit-scrollbar-button:hover{ background-color: #ddd !important;}
.about-box1 .box-info .pull-right .box2::-webkit-scrollbar-button:active{ background-color: #d2d2d2 !important;}
.about-box1 .list-box1,.about-box1 .list-box2{ margin-top: 2rem;}
.list-box1 ul li{ width: 49.2%; float: left; margin-top: 2.1875rem; text-align: center; background: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.2);}
.list-box1 ul li:nth-child(2n){ float: right;}
.list-box1 ul li span{ width: 100%; float: left; height: 16.1875rem; overflow: hidden;}
.list-box1 ul li span img{ width: 100%; height: 100%; object-fit: cover; transition: all .6s;}
.list-box1 ul li p{ width: 100%; float: left; line-height: 40px; font-size: 1rem;}
.list-box1 ul li:hover span img{ transform: scale(1.1);}
.list-box2 ul{ margin: 0 -0.75rem;}
.list-box2 ul li{ width: 33.33%; float: left; padding: 0 0.75rem; margin-top: 1.25rem;}
.list-box2 ul li a{ width: 100%; float: left; background: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.2); text-align: center;}
.list-box2 ul li a span{ width: 100%; float: left; height: 19.6875rem; overflow: hidden;}
.list-box2 ul li a span img{ width: 100%; height: 100%; float: left; object-fit: cover; transition: all .6s;}
.list-box2 ul li a p{ width: 100%; height: 6.5625rem; float: left; display: flex; align-items: center; justify-content: center; padding: 0 1rem; font-size: 1rem;}
.list-box2 ul li a:hover{ background: #0071ec; color: rgba(255,255,255,0.85);}
.list-box2 ul li a:hover span img{ transform: scale(1.1);}
.page-menu{ margin-top: 3.125rem;}
.page-menu a{ line-height: 3rem; font-size: 1rem; min-width: 9.375rem; border: 1px solid #979797; text-align: center;}
.page-menu a+a{ border-left-width: 0;}
.page-menu a:hover,.page-menu a.active{ background: #0071ec; color: #fff;}
.product-box1{ padding: 5rem 0;}
.product-box1 .center-block{ margin-top: 2.5rem;}
.product-box1 .center-block ul{ margin: 0 -0.625rem;}
.product-box1 .center-block ul li{ width: 25%; float: left; padding: 0 0.625rem; margin-top: 1.25rem;}
.product-box1 .center-block ul li a{ width: 100%; float: left; position: relative; overflow: hidden; box-shadow: 0 0 10px rgba(0,0,0,0.1); background: #fff;}
.product-box1 .center-block ul li a .box-info1 .box1{ height: 12.5rem; overflow: hidden;}
.product-box1 .center-block ul li a .box-info1 .box1 img{ width: 100%; height: 100%; float: left; object-fit: cover;}
.product-box1 .center-block ul li a .box-info1 .box2{ padding: 0.875rem 0.875rem 0.9rem;}
.product-box1 .center-block ul li a .box-info1 .box2 span{ display: block; font-size: 1rem; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
.product-box1 .center-block ul li a .box-info1 .box2 p{ font-size: 12px; height: 32px; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; margin-top: 0.625rem;}
.product-box1 .center-block ul li a .box-info2{ width: 100%; height: 100%; position: absolute; left: 0; top: 0; background: rgba(0,113,236,0.8); color: #fff; padding: 0 14px; opacity: 0; transition: all .6s;}
.product-box1 .center-block ul li a .box-info2 span{ width: 100%; font-size: 1rem;}
.product-box1 .center-block ul li a .box-info2 p{ font-size: 12px; margin-top: 0.8rem;}
.product-box1 .center-block ul li a:hover .box-info2{ opacity: 1;}
.pager{ margin: 5rem 0 0;}
.pager li>a,.pager li>span{ border-radius: 2px !important; margin: 0 0.3125rem; padding: 0.35rem 0.65rem; color: #333; font-size: 12px;}
.pagination>.active>span{ background: #578DF3;}
.pagination>li:last-child>a, .pagination>li:last-child>span{ margin-right: 0;}
.page-info{ padding: 3.125rem 0;}
.page-info .box1{ font-size: 2.25rem; font-weight: bold;}
.page-info .box2{ margin-top: 1.875rem; font-size: 12px; color: #333;}
.page-info .box3{ font-size: 14px; margin-top: 1.875rem; line-height: 1.6;}
.service-box1{ padding: 5rem 0 3.75rem;}
.service-box1 .box-info{ margin-top: 1.25rem;}
.service-box1 .box-info ul{ margin: 0 -0.625rem;}
.service-box1 .box-info ul li{ float: left; padding: 0.625rem; position: relative;}
.service-box1 .box-info ul li img{ width: 100%; height: 100%; float: left; object-fit: cover; transition: all .6s;}
.service-box1 .box-info ul li a{ width: 100%; height: 100%; float: left; position: relative; overflow: hidden;}
.service-box1 .box-info ul li .center-block{ position: absolute; left: 2.25rem; bottom: 2.5rem; color: #fff;}
.service-box1 .box-info ul li .center-block strong{ display: block; font-size: 1.5rem; font-weight: bold;}
.service-box1 .box-info ul li .center-block p{ font-size: 0.875rem; margin: 0.875rem 0;}
.service-box1 .box-info ul li:hover img{ transform: scale(1.1);}
.service-box1 .box-info .pull-left{ width: 43.5%;}
.service-box1 .box-info .pull-right{ width: 56.5%; padding-left: 1.25rem;}
.service-box1 .box-info .pull-left ul li{ width: 100%;}
.service-box1 .box-info .pull-left ul li:nth-child(1){ height: 17.5rem;}
.service-box1 .box-info .pull-left ul li:nth-child(2){ height: 22.5rem;}
.service-box1 .box-info .pull-right ul li:nth-child(1){ width: 100%; height: 25.625rem;}
.service-box1 .box-info .pull-right ul li:nth-child(1) .center-block{ left: 3.6875rem; bottom: 50%; margin-bottom: -3.125rem;}
.service-box1 .box-info .pull-right ul li:nth-child(2){ width: 50%; height: 14.375rem;}
.service-box1 .box-info .pull-right ul li:nth-child(2) a{ background: #f54123;}
.service-box1 .box-info .pull-right ul li:nth-child(3){ width: 50%; height: 14.375rem;}
.service-box1 .box-info .pull-right ul li:nth-child(3) a{ background: #0071ec;}
.service-box2 .box-info{ padding: 3.4375rem 0 6.25rem;}
.service-box2 .box-info ul{ margin: 0 -0.625rem;}
.service-box2 .box-info ul li{ width: 16.66%; float: left; padding: 0 0.625rem; margin-top: 1.25rem;}
.service-box2 .box-info ul li a{ width: 100%; height: 13.4375rem; float: left; background: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.2); text-align: center; padding: 1.875rem 0 0;}
.service-box2 .box-info ul li a i{ display: block;}
.service-box2 .box-info ul li a i img{ height: 5.8125rem;}
.service-box2 .box-info ul li a span{ display: block; font-size: 1.5rem;}
.service-box2 .box-info ul li a p{ font-size: 12px; margin-top: 6px;}
.service-box2 .box-info ul li a:hover{ background: #4C85F9; color: #fff;}
.contact-box{ padding: 5rem 0 0;}
.contact-box .top-box{ padding: 1.5625rem 0 2.8125rem;}
.contact-box .top-box ul{ margin: 0 -0.75rem;}
.contact-box .top-box ul li{ width: 33.33%; float: left; padding: 0 0.75rem; margin-top: 1.25rem;}
.contact-box .top-box ul li .between-center{ width: 100%; height: 6.25rem; float: left; background: #fff; box-shadow: 0 0 10px rgba(0,0,0,0.1); padding: 0 1rem 0 1.875rem; position: relative;}
.contact-box .top-box ul li .between-center div{ width: 82%;}
.contact-box .top-box ul li .between-center div span{ font-size: 1.125rem;}
.contact-box .top-box ul li .between-center div p{ font-size: 0.875rem; margin-top: 0.5rem;}
.contact-box .top-box ul li .between-center .ewm{ width: 4.625rem; height: 4.625rem; position: absolute; right: 3.4375rem; top: 50%; margin-top: -2.3125rem;}
.contact-box .lower-box{ height: 47.5rem; background: #F2F1ED;}
.contact-box .lower-box img,.contact-box .lower-box label{ max-width: initial;}
.contact-map{ width: 230px; height: 255px; background: #fff; float: left; border-radius: 5px; box-shadow: 0 0 0.625rem rgba(0,0,0,0.1); position: relative; padding: 18px 0 0;}
.contact-map .imgs{ height: 132px; overflow: hidden;}
.contact-map .imgs img{ width: 100%; height: 100%; object-fit: cover;}
.contact-map .info{ padding:10px 0 0;}
.contact-map .info span{ font-size: 14px; color: #f54123;}
.contact-map .info p{ font-size: 12px; color: #7f7f7f; background-position: 0 3px; background-repeat: no-repeat; padding-left: 22px; margin-top: 10px;}
.contact-map .info p.icon1{ background-image: url(../image/icon_4.png);}
.contact-map .info p.icon2{ background-image: url(../image/icon_5.png);}
.xmcx_box .top-box{ background: #317dff; padding: 25px 20px 95px; text-align: center;}
.xmcx_box .lower-box{ position: relative; z-index: 2; padding: 0 30px; margin-top: -75px;}
.xmcx_box .lower-box .center-block{ background: #fff; border-radius: 10px; box-shadow: 0 5px 10px rgba(231,239,253,0.5); padding: 0 30px 30px; position: relative;}
.xmcx_box .lower-box .center-block p{ font-size: 20px; font-weight: bold; margin-top: 24px;}
.xmcx_box .lower-box .center-block input{ font-size: 14px; width: 100%; height: 20px; border: none; background: none; margin-top: 6px;}
.xmcx_box .lower-box .btns{ width: 100%; height: 45px; background: #317DFF; color: #fff; font-size: 20px; border-radius: 50px; margin: 50px 0 0; border:none;}
.xmjd-box .top-box{ background: #317dff; text-align: center; padding: 60px 30px 20px;}
.xmjd-box .lower-box{ padding: 5px 30px 30px;}
.xmjd-box .lower-box .box1{ font-size: 20px; font-weight: bold; margin-top: 17px;}
.xmjd-box .lower-box .box2{ font-size: 14px; color: #999; margin-top: 6px;}
.xmjd-box .lower-box .box3 ul{ margin: 0 -8px;}
.xmjd-box .lower-box .box3 ul li{ width: 33.33%; float: left; margin-top: 0.9375rem; text-align: center; padding: 0 8px;}
.xmjd-box .lower-box .box3 ul li span{ width: 100%; height: 120px; float: left; background: #EAF2FF; overflow: hidden;}
.xmjd-box .lower-box .box3 ul li p{ width: 100%; float: left; font-size: 14px; margin-top: 10px;}
.xmjd-box .lower-box .box3.style2 ul li span{ height: 80px;}
.xmjd-box .lower-box .box3.style2 ul li span img{ width: 100%; height: 100%; object-fit: cover;}
.xmjd-box .lower-box .box4{ background: #f7faff; padding: 15px; border-radius: 10px; margin-top: 15px; font-size: 14px;}
.xmjd-box .lower-box .box4 span{ display: block; color: #95A6C1;}
.xmjd-box .lower-box .box4 p{ margin-top: 6px; text-align: justify;}
.news-list{ padding: 5rem 0;}
.news-list .top-box{ padding: 2.1875rem 0;}
.news-list .top-box ul{ margin: 0 -0.6875rem;}
.news-list .top-box ul li{ width: 33.33%; float: left; padding: 0 0.6875rem; margin-top: 1.375rem;}
.news-list .top-box ul li a{ width: 100%; float: left; height: 16.875rem; position: relative; overflow: hidden; box-shadow: 0 0 10px rgba(0,0,0,0.2);}
.news-list .top-box ul li a img{ width: 100%; height: 100%; float: left; object-fit: cover; transition: all .6s;}
.news-list .top-box ul li a div{ width: 100%; position: absolute; left: 0; bottom: 0; color: #fff; background: rgba(0,0,0,0.2); padding: 0.9375rem; font-size: 12px;}
.news-list .top-box ul li a div span{ display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 1rem; margin-bottom: 0.375rem;}
.news-list .top-box ul li a:hover img{ transform: scale(1.1);}
.news-list .lower-box ul li{ width: 100%; float: left; border-bottom: 1px solid #EAEAEA; padding: 3rem 0;}
.news-list .lower-box ul li a{ width: 100%; float: left;}
.news-list .lower-box ul li .pull-left{ width: 33%; height: 14.6875rem; overflow: hidden;}
.news-list .lower-box ul li .pull-left img{ width: 100%; height: 100%; float: left; object-fit: cover; transition: all .6s;}
.news-list .lower-box ul li .pull-right{ width: 67%; padding:0 5.625rem 0 2.125rem;}
.news-list .lower-box ul li .pull-right span{ display: block; font-size: 1rem; font-weight: bold; margin-top: 0.3125rem;}
.news-list .lower-box ul li .pull-right p{ font-size: 12px; line-height: 1.5rem; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5; height: 7.5rem; margin: 0.9375rem 0 1.875rem; color: #222;}
.news-list .lower-box ul li .pull-right i{ font-size: 12px; color: #222;}
.news-list .lower-box ul li:hover .pull-left img{ transform: scale(1.1);}
.page-search{}
.page-search .between-center{ width: 500px;}
.page-search .between-center .layui-input{ width: 80%; font-size: 1rem; line-height: 3.125rem; height: 3.125rem;}
.page-search .between-center .layui-btn{ width: 20%; font-size: 1rem; margin-left: 10px; line-height: 3.125rem; height: 3.125rem;}
/* 小于等于多少高度的样式 */
@media screen and (max-height:880px){
}
@media screen and (max-height:600px){
}
/* 小于等于多少宽度的样式 */
@media screen and (max-width:1660px){
html,body{ font-size: 94%;}
.w-1500{ width: 94%;}
.home-box5 .center-block .box-info{ margin: 62px 0 0 265px;}
}
@media screen and (max-width:1440px){
html,body{ font-size: 80%;}
.w-1500{ width: 1200px;}
.home-box1 .lower-box .pull-right .center-center{ width: 22rem; height: 22rem;}
.home-box5 .center-block .box-info{ margin: 37px 0 0 230px;}
.home-box4 .lower-box .pull-left{ padding-top: 5rem;}
.home-box4 .lower-box .pull-left .center-block{ padding-right: 30%;}
}
@media screen and (max-width:1366px){
}
@media screen and (max-width:1200px){
.w-1200{ width: 94%;}
.w-1500{ width: 94%;}
}
@media screen and (max-width:1100px){
}
@media screen and (max-width:1024px){
html,body{ font-size: 70%;}
.div-pc{ display: none;}
.div-phone{ display: block;}
/*nav*/
.nav_btn{ display: block;}
.nav_btn.cur i{ background: #f54123;}
.nav{ width: 100%; position: absolute; right: 0; top: 0; background: rgba(255,255,255,0.9); padding: 10vh 0 10px; height: 100vh; transition: all .6s; transform: translate(100%,0); display: block;}
.nav ul li{ width: 100%; margin-left: 0;}
.nav ul li span{ width: 100%; float: left; text-align: center;}
.nav ul li span a{ display: inline-block; line-height: 35px; float: none; margin: auto; font-size: 14px; padding: 0; color: #333;}
.nav ul li span a::before{ display: none;}
.nav ul li span.active a::after{ content: ''; width: 13px; height: 97%; background: url(../image/icon_jt5.png) no-repeat center; background-size: 100%; position: absolute; right: -20px; top: 1px; pointer-events: none;}
.nav ul li span.active:hover a::after,.nav ul li.active span.active a::after{ background-image: url(../image/icon_jt5_h.png);}
.nav ul li .nav-second{ position: relative; top: 0; width: 100%; overflow: initial; display: block; float: left; background: none;}
.nav ul li .nav-second a{ min-width: 100%; margin: 0; font-size: 12px;}
.nav ul li:hover span a{ color: #f54123 !important;}
.nav ul li:hover span a::after{}
.nav ul li:hover .nav-second a{ height: 2.0625rem; line-height: 2.0625rem;}
.nav ul li:hover .nav-second{ padding: 5px 10px;}
.nav.active{ transform: translate(0,0);}
/*nav end*/
.head-box{ padding: 10px 0; position: fixed;}
.head-box .pull-left img{ height: 40px;}
.all-center-box{ margin-top: 60px;}
.online{ top: 25vh; margin-top: 0;}
.online img{ height: 3rem;}
.banner-box .swiper-container .swiper-slide .w-1500 .pull-left p{ font-size: 1.5rem;}
.banner-box .swiper-container .swiper-slide .w-1500 .pull-left i{ font-size: 0.75rem; line-height: 1.4; margin-top: 0.9375rem;}
.banner-box .swiper-page{ bottom: 1rem;}
.home-box1 .top-box .pull-left{ width: 100%; text-align: center; line-height: 4rem;}
.home-box1 .top-box::after{ width: 100%; height: 3.5rem; display: none;}
.home-box1 .top-box .pull-right{ width: 100%; padding: 0;}
.home-box1 .top-box .pull-right .text{ width: 85%; height: 3.5rem; padding-left: 6%;}
.home-box1 .top-box .pull-right .btns{ width: 15%; height: 3.5rem;}
.home-box1 .lower-box{ padding: 1.5rem 0 0;}
.home-box1 .lower-box .w-1200{ display: block;}
.home-box1 .lower-box .pull-left{ width: 100%;}
.home-box1 .lower-box .pull-left .box2{ margin: 1rem 0;}
.home-box1 .lower-box .pull-right{ width: 100%; margin-top: 0.5rem;}
.home-box1 .lower-box .pull-right .center-center{ width: 100%; height: auto; border-radius: 0; padding: 2rem; margin-top: 1rem;}
.home-box1 .lower-box .pull-right .center-center p{ height: auto;}
.home-box1 .lower-box .pull-right .center-center span{ margin: 1rem 0;}
.home-box2 ul li{ width: 100% !important; height: auto; margin-top: 1.5rem;}
.home-box2 ul li .box-info1{ display: none;}
.home-box2 ul li .box-info2{ position: relative; padding: 2rem 1.5rem; opacity: 1;}
.home-box2 ul li .box-info2 .box1 span{ padding: 16px 0 10px;}
.home-box2 ul li .box-info2 .box2{ margin: 16px 0 10px;}
.home-box2 ul li .box-info2 .box4{ margin-top: 18px;}
.home-box2 ul li .box-info1 .center-block{ width: 100%;}
.home-box2 ul li .box-info2 .center-block{ width: 100%;}
.home-box3{ padding: 1.5rem 1.5rem 0 0;}
.home-box3::after{ height: 96%;}
.home-box3 .center-block{ width: 100%; padding: 0 1.5rem 1rem;}
.home-box3 .center-block .box-info1,.home-box3 .center-block .box-info2{ width: 100%;}
.home-box3 .center-block .box-info1 ul li{ padding: 1rem 0;}
.home-box3 .center-block .imgs{ width: 35%; height: 9rem;}
.home-box3 .center-block .info{ width: 65%; padding-left: 1rem;}
.home-box3 .center-block .info .box1 i{ margin-top: 0.2rem;}
.home-box3 .center-block .box-info2{ margin: 0.5rem 0;}
.home-box3 .center-block .box-info2 .imgs{ height: 16rem;}
.home-box3 .center-block .box-info2 .info{ padding: 1rem 0 0;}
.all-title1 .pull-left{ width: 20rem;}
.all-title1 .pull-left span{ font-size: 1.7rem;}
.home-box4 .top-box{ padding: 2rem 1.5rem;}
.home-box4 .lower-box .pull-left{ width: 100%; padding: 1.5rem; height: auto;}
.home-box4 .lower-box .pull-left .center-block{ display: block !important; padding: 0;}
.home-box5 .center-block{ padding: 2rem 1.5rem 1.5rem; height: auto;}
.home-box5 .center-block .box-info{ margin: 1rem 0 0;}
.foot-box .top-box{ display: none;}
.foot-box .lower-box{ font-size: 12px; padding: 12px 0; text-align: center;}
.about-box1{ padding: 1rem 0;}
.about-box1:nth-child(2){ padding-top: 2rem;}
.about-box1 .box-info{ padding: 0;}
.about-box1 .box-info .pull-left{ width: 100%; padding: 0; height: 250px; overflow: hidden; margin-top: 1rem;}
.about-box1 .box-info .pull-right{ width: 100%; padding: 0; margin-top: 1.5rem;}
.about-box1 .box-info .pull-right .box2{ height: 200px; margin-top: 0.5rem;}
.list-box1 ul li{ width: 100%; margin-top: 1rem;}
.list-box1 ul li span{ height: 14rem;}
.about-box1 .list-box1,.about-box1 .list-box2{ margin-top: 1rem;}
.list-box2 ul li{ width: 100%;}
.list-box2 ul li a span{ height: 26rem;}
.product-box1{ padding: 2rem 0;}
.page-menu{ margin-top: 2rem; padding-left: 5px;}
.page-menu .between-center{ display: block; width: 100%;}
.page-menu a{ min-width: 25%; float: left; margin-top: -1px; margin-left: -1px; }
.page-menu a+a{ border-left-width: 1px;}
.product-box1 .center-block{ margin-top: 1rem;}
.product-box1 .center-block ul li{ width: 50%;}
.pager{ margin-top: 2rem;}
.page-info{ padding: 2rem 0;}
.page-info .box1{ font-size: 1.875rem;}
.page-info .box2,.page-info .box3{ margin-top: 1rem;}
.service-box1{ padding: 2rem 0;}
.service-box1 .box-info .pull-left,.service-box1 .box-info .pull-right{ width: 100%; padding: 0;}
.service-box1 .box-info ul li{ width: 100% !important; height: 18rem !important;}
.service-box1 .box-info ul li .center-block{ left: 1.5rem !important; bottom: 1.5rem !important; margin: auto !important;}
.service-box1 .box-info .pull-right ul li:nth-child(2),.service-box1 .box-info .pull-right ul li:nth-child(3){ width: 50% !important; height: 12rem !important;}
.service-box2 .box-info{ padding: 1rem 0 3rem;}
.service-box2 .box-info ul li{ width: 50%;}
.service-box2 .box-info ul li a{ padding-top: 1.5rem;}
.contact-box{ padding: 2rem 0 0;}
.contact-box .top-box{ padding: 0.5rem 0 2rem;}
.contact-box .top-box ul{ margin: auto;}
.contact-box .top-box ul li{ width: 100%; padding: 0;}
.contact-box .lower-box{ height: 370px;}
.all-title2 span{ font-size: 2rem;}
.all-title2 p{ margin-top: 0.2rem;}
.news-list{ padding: 2rem 0;}
.news-list .top-box{ padding: 1rem 0 0;}
.news-list .top-box ul{ margin: 0;}
.news-list .top-box ul li{ width: 100%; padding: 0; margin-top: 1rem;}
.news-list .top-box ul li a{ height: 20rem;}
.news-list .lower-box{ margin-top: 1rem;}
.news-list .lower-box ul li{ padding: 1rem 0;}
.news-list .lower-box ul li .pull-left{ width: 100%; height: 18rem;}
.news-list .lower-box ul li .pull-right{ width: 100%; padding: 1rem 0 0;}
.news-list .lower-box ul li .pull-right span{ font-size: 14px;}
.news-list .lower-box ul li .pull-right p{ height: auto; margin: 0.8rem 0;}
.page-search{}
.page-search .between-center{ width: 100%; padding: 0 5px;}
}
@media screen and (max-width:768px){
}
@media screen and (max-width:480px){
}
@media screen and (max-width:365px){
}

13
public/static/css/swiper.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Some files were not shown because too many files have changed in this diff Show More