项目加入版本库

main
milo 2022-09-16 11:44:40 +08:00
commit cee79ce742
974 changed files with 130792 additions and 0 deletions

20
.env.bak Executable file
View File

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

11
.gitignore vendored Executable file
View File

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

32
LICENSE.txt Executable 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.

7
README.md Executable file
View File

@ -0,0 +1,7 @@
本CMS基于ThinkPHP 6.0.3开发
> 运行环境要求PHP7.1+。
> MySql版本使用的是5.7.21
> 富文本编辑器选择wangEditorv3.1.1 https://github.com/wangfupeng1988/wangEditor
> 上传插件选择filepond4.7.1 https://github.com/pqina/filepond
> 上传插件修改为使用layui组件库自带的

378
app/common.php Executable file
View File

@ -0,0 +1,378 @@
<?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;
}
}
if(!function_exists('getImgSrc')) {
function getImgSrc($item, $defaultImg)
{
$imgSrc = $defaultImg;
if(!empty($item['src']) && file_exists('.'.$item['src'])) {
$imgSrc = $item['src'];
}
return $imgSrc;
}
}

160
app/controller/Article.php Executable file
View File

@ -0,0 +1,160 @@
<?php
namespace app\controller;
use app\model\{Article as MArticle, Category};
class Article extends Base
{
//列表页
public function index()
{
$categoryId = input('param.category_id/d', 0);
if($categoryId <= 0){
return $this->error('错误页面');
}
$category = Category::getById($categoryId);
if(empty($category)){
return $this->error('错误页面');
}
$description = $category['description'] ? $category['description'] : $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
$this->data['category'] = $category;
$this->data['categoryId'] = $categoryId;
$this->templateAssign($category);
return $this->view($category['template_list'] ?? '');
}
//详情
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']);
$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->templateDetailAssign($article, $category);
return $this->view($category['template_detail'] ?? '');
}
// 列表数据绑定
private function templateAssign($category)
{
$template = strtolower($category['template_list'] ?? '');
$TopCId = Category::firstGradeById($category['id']);
if($TopCId == $category['id']) {
$topCategory = $category;
} else {
$topCategory = Category::getById($TopCId);
}
$categoryChildren = Category::getChildrenByParentId($topCategory['id']);
$this->data['topCategory'] = $topCategory;
$this->data['categoryChildren'] = $categoryChildren;
switch($template) {
case 'products' :
$this->assignProducts($topCategory, $category, $categoryChildren);
break;
case 'news_center' :
case 'news' :
$this->assignNews($topCategory, $category, $categoryChildren);
break;
default :
$this->data['items'] = MArticle::getListPageByCategory($category['id'], $category['number'] ? $category['number'] : 20);
}
}
// 详情数据绑定
private function templateDetailAssign($article, $category)
{
$template = strtolower($category['template_detail'] ?? '');
$TopCId = Category::firstGradeById($category['id']);
if($TopCId == $category['id']) {
$topCategory = $category;
} else {
$topCategory = Category::getById($TopCId);
}
$this->data['topCategory'] = $topCategory;
switch ($template) {
case 'product':
$this->assignDetailForProduct($article, $topCategory);
break;
default :
$this->data['prev'] = MArticle::getPrevArticleByIdAndCategories($article['id'], [$article['category_id']], true, $article['sort'], true);
$this->data['next'] = MArticle::getNextArticleByIdAndCategories($article['id'], [$article['category_id']], true, $article['sort'], true);
}
}
// 产品 - 展示当前分类和所有子类产品
private function assignProducts($topCategory, $category, $categoryChildren)
{
$keyword = input('param.keyword', '');
$cateIds[] = $category['id'];
if($topCategory['id'] == $category['id']) {
$children = $categoryChildren;
} else {
$children = Category::getChildrenByParentId($category['id']);
}
foreach ($children as $child) {
$cateIds[] = $child['id'];
}
$items = MArticle::getListPageByCategories($cateIds, $category['number'] ? $category['number'] : 20, $keyword);
$items->appends(['category_id'=>$category['id']]);
$this->data['items'] = $items;
$this->data['keyword'] = $keyword;
}
// 新闻
private function assignNews($topCategory, $category, $categoryChildren)
{
if($topCategory['id'] == $category['id']) {
// 新闻中心
$cateList = [];
$newsChildrenFlip = array_flip(Category::$CIdList['news_children']);
foreach ($categoryChildren as $cate) {
$num = 3;
if($cate['id'] == Category::$CIdList['news_children']['dynamics']) {
$num = 4;
}
$cate['items'] = MArticle::getLatestByCategory($cate['id'], $num, 1);
$cateList[$newsChildrenFlip[$cate['id']]] = $cate;
}
$this->data['cateList'] = $cateList;
} else {
// 新闻子栏目
$keyword = input('param.keyword', '');
$this->data['items'] = MArticle::getListPageByCategory($category['id'], $category['number'] ? $category['number'] : 20, $keyword);
$this->data['keyword'] = $keyword;
}
}
// 产品详情
private function assignDetailForProduct($article, $topCategory)
{
$cateIds[] = $article['category_id'];
$currentCateId = input('param.source', 0);
$categoryList = Category::getChildrenByParentId($topCategory['id']);
if($currentCateId == $topCategory['id']) {
foreach ($categoryList as $cate) {
$cateIds[] = $cate['id'];
}
}
$this->data['categoryChildren'] = $categoryList;
$this->data['prev'] = MArticle::getPrevArticleByIdAndCategories($article['id'], $cateIds, true, $article['sort'], true);
$this->data['next'] = MArticle::getNextArticleByIdAndCategories($article['id'], $cateIds, true, $article['sort'], true);
$this->data['currentCateId'] = $currentCateId;
}
}

52
app/controller/Base.php Executable file
View File

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

193
app/controller/BaseController.php Executable file
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);
}
}

48
app/controller/Error.php Executable file
View File

@ -0,0 +1,48 @@
<?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);
}
}

36
app/controller/Index.php Executable file
View File

@ -0,0 +1,36 @@
<?php
namespace app\controller;
use app\model\{Category, Block, Article, Slide};
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']);
$blocks = Block::getByCategoryId($categoryId);
$blocks = Block::analysisBlock($blocks);
$this->data['blocks'] = $blocks;
// 轮播图
$this->data['slides'] = Slide::getList();
// 营销网络栏目ID
$this->data['marketingCId'] = Category::$CIdList['marketing'];
// 关联产品分类
$productsCenterCId = Category::$CIdList['products'];
$this->data['productsCenter'] = Category::getById($productsCenterCId);
$this->data['products'] = Category::getChildrenByParentId($productsCenterCId);
// 关联新闻
$this->data['newsCenter'] = Category::getById(Category::$CIdList['news']);
$newsCIdList = [Category::$CIdList['news_children']['enterprise'], Category::$CIdList['news_children']['industry']];
$newsList = Category::getListByIds($newsCIdList);
foreach ($newsList as &$cate) {
$cate['items'] = Article::getLatestByCategory($cate['id'], 4, 1);
}
unset($cate);
$this->data['newsList'] = $newsList;
return $this->view();
}
}

42
app/controller/Message.php Executable file
View File

@ -0,0 +1,42 @@
<?php
namespace app\controller;
use app\model\Message as MMessage;
use app\validate\Message as VMessage;
use think\exception\ValidateException;
/**
* 留言
* Class Message
* @package app\controller
*/
class Message extends Base
{
// 新增留言
public function add()
{
if(request()->isPost()) {
$msgData = [
'company_name' => trim(input('post.company_name', '')),
'name' => trim(input('post.name', '')),
'phone' => trim(input('post.phone', '')),
'email' => trim(input('post.email', '')),
'content' => trim(input('post.content', '')),
];
// 安全过滤
$msgData = array_map('strip_tags', $msgData);
try {
validate(VMessage::class)->check($msgData);
$msgData['ip'] = request()->ip();
$msgData['create_time'] = time();
MMessage::create($msgData);
return $this->json();
} catch (ValidateException $e) {
return $this->json(2, $e->getError());
}
} else {
return $this->json(1, '非法请求');
}
}
}

145
app/controller/Page.php Executable file
View File

@ -0,0 +1,145 @@
<?php
namespace app\controller;
use app\model\{Achievement, AchievementInfo, Category, Block, Article, History, Model};
class Page extends Base
{
// 默认单页页面
public function index($categoryId)
{
$category = Category::getById($categoryId);
if ($category) {
$description = $category['description'] ? $category['description'] : $this->system['seo_description'];
$this->setSeo($category['title'], $this->system['seo_keywords'], $description);
} else {
return $this->error('页面错误');
}
$this->data['categoryId'] = $categoryId;
$this->data['category'] = $category;
$this->data['blocks'] = Block::getByCategoryId($categoryId);
$this->templateDetailAssign($category);
return $this->view($category['template_detail']);
}
private function templateDetailAssign($category)
{
$template = $category['template_detail'] ?? '';
$TopCId = Category::firstGradeById($category['id']);
if($TopCId == $category['id']) {
$topCategory = $category;
} else {
$topCategory = Category::getById($TopCId);
}
$childCategory = Category::getChildrenByParentId($topCategory['id']);
$this->data['topCategory'] = $topCategory;
$this->data['childCategory'] = $childCategory;
switch ($template) {
case 'about' :
$this->assignAbout($childCategory);
break;
case 'service' :
$this->assignService($childCategory);
break;
case 'marketing' :
$this->assignMarketing($childCategory);
break;
case 'contact' :
$this->assignContact($childCategory);
break;
default :
$this->data['blocks'] = Block::getByCategoryId($category['id']);
}
}
// 获取单页栏目IDs
private function getBlockCateIds($categoryItems)
{
$blockCateIds = [];
foreach ($categoryItems as $cate) {
if($cate['model_id'] == Model::PAGE) {
$blockCateIds[] = $cate['id'];
}
}
return $blockCateIds;
}
// 走进超宇
private function assignAbout($childCategory)
{
$honorTopCId = Category::$CIdList['honors_manage'] ?? 0;
$historyCId = Category::$CIdList['history_manage'] ?? 0;
$historyCate = Category::getById($historyCId);
$honors = [];
$blocks = [];
$blockCateIds = $this->getBlockCateIds($childCategory);
if($honorTopCId) {
$honors = Category::getChildrenByParentId($honorTopCId);
foreach ($honors as &$honor) {
$honor['items'] = Article::getListByCategoryIds([$honor['id']], $honor['number'] ? $honor['number'] : 20, '', [], 1);
}
unset($honor);
}
$blockList = Block::getByCategoryIds($blockCateIds);
$aboutChildrenFlip = array_flip(Category::$CIdList['about_children']);
foreach ($childCategory as $cate) {
$blocks[$aboutChildrenFlip[$cate['id']]] = $blockList[$cate['id']] ?? [];
}
$this->data['blocks'] = $blocks;
$this->data['honors'] = $honors;
$this->data['historyList'] = array_reverse(History::getByCategoryId($historyCId, true, $historyCate['number'] ?? -1));
}
// 品质与服务
private function assignService($childCategory)
{
$blocks = [];
$blockCateIds = $this->getBlockCateIds($childCategory);
$blockList = Block::getByCategoryIds($blockCateIds);
$serviceChildrenFlip = array_flip(Category::$CIdList['service_children']);
foreach ($childCategory as $cate) {
$blocks[$serviceChildrenFlip[$cate['id']]] = $blockList[$cate['id']] ?? [];
}
$this->data['blocks'] = $blocks;
}
// 营销网络
private function assignMarketing($childCategory)
{
$blocks = [];
$blockCateIds = $this->getBlockCateIds($childCategory);
$blockList = Block::getByCategoryIds($blockCateIds);
$marketingChildrenFlip = array_flip(Category::$CIdList['marketing_children']);
foreach ($childCategory as $cate) {
$blocks[$marketingChildrenFlip[$cate['id']]] = $blockList[$cate['id']] ?? [];
}
$achievementCate = Category::getById(Category::$CIdList['achievement_manage']);
$achievementList = [];
if ($achievementCate) {
$achievementList = Achievement::getListByCategoryId($achievementCate['id'], $achievementCate['number'] ? $achievementCate['number'] : 10, true);
}
$this->data['blocks'] = $blocks;
$this->data['achievementList'] = $achievementList;
}
// 联系我们
private function assignContact($childCategory)
{
$blocks = [];
$blockCateIds = $this->getBlockCateIds($childCategory);
$blockList = Block::getByCategoryIds($blockCateIds);
$contactChildrenFlip = array_flip(Category::$CIdList['contact_children']);
foreach ($childCategory as $cate) {
$blocks[$contactChildrenFlip[$cate['id']]] = $blockList[$cate['id']] ?? [];
}
$jobsCate = Category::getById(Category::$CIdList['jobs_manage']);
$jobList = Article::getLatestByCategory($jobsCate['id'], $jobsCate['number'] ? $jobsCate['number'] : 10, 1);
$this->data['blocks'] = $blocks;
$this->data['jobList'] = $jobList;
}
}

View File

@ -0,0 +1,338 @@
<?php
namespace app\controller\manager;
use app\model\{AchievementInfo, Category, Achievement as MAchievement, Log};
use app\validate\Achievement as VAchievement;
use think\facade\Db;
/**
* 业绩管理
* Class Achievement
* @package app\controller\manager
*/
class Achievement extends Base
{
protected $validate;
public function initialize()
{
parent::initialize();
$this->validate = new VAchievement();
}
/****************************
* 业绩
****************************/
public function add()
{
$categoryId = input('param.category_id/d', 0);
$category = Category::getById($categoryId);
if(empty($category)) {
return $this->json(1, '无此栏目信息');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
if($this->validate->checkAchievement($params)) {
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
'category_id' => $categoryId,
'summary' => $params['summary'] ?? '',
'description' => $params['description'] ?? '',
'create_time' => time(),
];
$newItem = MAchievement::create($data);
Log::write('achievement', 'add', '新增业绩ID:'.$newItem->id);
} else {
return $this->json(2, $this->validate->getError());
}
return $this->json();
} else {
$this->data['category'] = $category;
return $this->view();
}
}
public function edit()
{
$id = input('param.id/d', 0);
$item = MAchievement::getById($id);
if(count($item) == 0) {
return $this->json(1, '该业绩信息不存在');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
if($this->validate->checkAchievement($params)) {
$data = [
'title' => $params['title'],
'visible' => $params['visible'],
'summary' => $params['summary'] ?? '',
'description' => $params['description'] ?? '',
];
MAchievement::updateById($item['id'] ,$data);
Log::write('achievement', 'add', '修改业绩ID:'.$item['id']);
} else {
return $this->json(2, $this->validate->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 = MAchievement::getById($id);
if(empty($item)){
return $this->json(3, '该业绩信息不存在');
}
if($sort == 'up'){ // sort 变大
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}else{ // sort 变小
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}
$forSortItems = MAchievement::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 MAchievement();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('achievement', 'sort', "业绩排序ID{$id} {$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '无此操作');
}
public function del()
{
if(request()->isPost()) {
$id = input('param.id/d', 0);
$item = MAchievement::getById($id);
if(count($item) == 0) {
return $this->json(2, '该业绩信息不存在');
}
Db::startTrans();
try {
MAchievement::destroy($id);
$hasInfo = AchievementInfo::hasByAchievementId($id);
if($hasInfo > 0) {
AchievementInfo::delByAchievementId($id);
}
Log::write('achievement','del', '删除业绩ID:'.$id);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return $this->json(3, '删除失败,'.$e->getMessage());
}
return $this->json();
}
return $this->json(1, '无此操作');
}
/****************************
* 业绩详情
****************************/
public function info()
{
$achievementId = input('param.achievement_id/d', 0);
$achievement = MAchievement::getById($achievementId);
$infoItems = [];
$categoryId = $achievement['category_id'] ?? 0;
if($achievement) {
$infoItems = AchievementInfo::getByAchievementId($achievementId);
}
$this->data['achievement'] = $achievement;
$this->data['categoryId'] = $categoryId;
$this->data['items'] = $infoItems;
return $this->view();
}
public function infoAdd()
{
$achievementId = input('param.achievement_id/d', 0);
$achievement = MAchievement::getById($achievementId);
if(empty($achievement)) {
return $this->json(2, '无此业绩信息');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
if($this->validate->checkAchievementInfo($params)) {
$data = [
'achievement_id' => $achievementId,
'title' => $params['title'],
'order_company' => $params['order_company'],
'goods_model' => $params['goods_model'],
'goods_amount' => $params['goods_amount'],
'visible' => $params['visible'],
'owner' => $params['owner'] ?? '',
'owner_tel' => $params['owner_tel'] ?? '',
'owner_email' => $params['owner_email'] ?? '',
'create_time' => time(),
];
$newItem = AchievementInfo::create($data);
Log::write('achievement', 'infoAdd', '新增业绩项目ID:'.$newItem->id);
} else {
return $this->json(2, $this->validate->getError());
}
return $this->json();
} else {
$this->data['achievementId'] = $achievementId;
$this->data['achievement'] = $achievement;
return $this->view();
}
}
public function infoEdit()
{
$id = input('param.id/d', 0);
$item = AchievementInfo::getById($id);
if(count($item) == 0) {
return $this->json(1, '该业务项目不存在');
}
if(request()->isPost()) {
$params = input('post.item/a', []);
$params = arrayHtmlFilter($params);
if($this->validate->checkAchievementInfo($params)) {
$data = [
'title' => $params['title'],
'order_company' => $params['order_company'],
'goods_model' => $params['goods_model'],
'goods_amount' => $params['goods_amount'],
'visible' => $params['visible'],
'owner' => $params['owner'] ?? '',
'owner_tel' => $params['owner_tel'] ?? '',
'owner_email' => $params['owner_email'] ?? '',
];
AchievementInfo::updateById($id, $data);
Log::write('achievement', 'infoEdit', '修改业绩项目ID:'.$id);
} else {
return $this->json(2, $this->validate->getError());
}
return $this->json();
} else {
$this->data['item'] = $item;
return $this->view();
}
}
public function infoSort()
{
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 = AchievementInfo::getById($id);
if(empty($item)){
return $this->json(3, '该业绩项目信息不存在');
}
if($sort == 'up'){
$where = "achievement_id='{$item['achievement_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}else{
$where = "achievement_id='{$item['achievement_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}
$forSortItems = AchievementInfo::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 AchievementInfo();
$model->saveAll($updateData);
$sortStr = $sort == 'up' ? '上移' : '下调';
Log::write('achievement', 'infoSort', "业绩项目排序ID{$id} {$sortStr}{$num}");
return $this->json();
}
}
return $this->json(4, '无须调整排序!');
}
return $this->json(1, '无此操作');
}
public function infoDel()
{
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) {
AchievementInfo::destroy($infoIds);
Log::write('achievement','infoDel', '删除业绩项目IDs:'.implode(',', $infoIds));
return $this->json();
}
return $this->json(2, '参数错误');
}
return $this->json(1, '无此操作');
}
}

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();
}
}
}

153
app/controller/manager/Backup.php Executable file
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, '非法请求');
}
}
}

54
app/controller/manager/Base.php Executable file
View File

@ -0,0 +1,54 @@
<?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']
]
];
$this->setCsrfToken();
$auth = session('auth');
$this->data['member'] = $auth;
$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));
}
protected function setCsrfToken()
{
$this->data['_token'] = session('_token') ?? '';
}
}

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,190 @@
<?php
namespace app\controller\manager;
use app\model\{Category, Article, Block, Log, History, Achievement};
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] ?? [];
$group = array_values($group);
$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();
}
// 主要业绩
public function achievement()
{
$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'] = Achievement::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);
}
}

142
app/controller/manager/File.php Executable file
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();
}
}

141
app/controller/manager/Group.php Executable file
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'){ // sort 变大
$where = "category_id='{$item['category_id']}' and sort > {$item['sort']}";
$order = "sort asc";
}else{ // sort 变小
$where = "category_id='{$item['category_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}
$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 = '425像素 X 280像素';
$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 = '425像素 X 280像素';
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 asc";
}else{
$where = "history_id='{$item['history_id']}' and sort < {$item['sort']}";
$order = "sort desc";
}
$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'));
}
}

177
app/controller/manager/Link.php Executable file
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,78 @@
<?php
namespace app\controller\manager;
use app\model\{Member, AuthRule, LoginLog};
use app\controller\BaseController;
class Login extends BaseController
{
protected $middleware = ['csrf'];
/**
* 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);
$viewData['_token'] = $this->request->csrfToken;
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'));
}
}

181
app/controller/manager/Member.php Executable file
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,32 @@
<?php
namespace app\controller\manager;
use app\model\Message as MMessage;
/**
* 留言
* Class Message
* @package app\controller\manager
*/
class Message extends Base
{
// 留言消息
public function index()
{
$keyword = trim(input('param.keyword', ''));
$this->data['list'] = MMessage::getPaginateList(20, $keyword, false);
$this->data['keyword'] = $keyword;
return $this->view();
}
public function del()
{
$id = input('param.id/d', 0);
$msg = MMessage::getById($id);
if(count($msg) == 0) {
return $this->json(1, '该消息不存在');
}
MMessage::destroy($id);
return $this->json();
}
}

184
app/controller/manager/Model.php Executable file
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, '非法请求!');
}
}

462
app/controller/manager/Page.php Executable file
View File

@ -0,0 +1,462 @@
<?php
namespace app\controller\manager;
use app\model\{Category, Block, Log};
use app\validate\Block as VBlock;
use think\exception\ValidateException;
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');
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 delblock()
{
if ($this->request->isAjax()) {
$id = input('post.id/d');
$item = Block::getById($id);
if(!empty($item)){
Block::destroy($id);
Log::write('page', 'delblock', "单页区块删除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');
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');
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');
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)) {
$imgs = array_values($imgs);
$item['value'] = json_encode($imgs);
} else {
$item['value'] = '';
}
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');
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();
}
}
}

181
app/controller/manager/Rule.php Executable file
View File

@ -0,0 +1,181 @@
<?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);
AuthGroup::resetGroupRulesCache();
$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();
}
}

63
app/controller/manager/Safe.php Executable file
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();
}
}
}

191
app/controller/manager/Slide.php Executable file
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();
}
}

141
app/controller/manager/Upload.php Executable file
View File

@ -0,0 +1,141 @@
<?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()
{
ini_set("memory_limit",-1);
set_time_limit(30); // 默认执行时长限制30秒
$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() . 'wwwroot' . $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 . '/videos/' . $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,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 . '/videos/' . $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 Executable file
View File

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

12
app/middleware.php Executable file
View File

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

65
app/middleware/Auth.php Executable 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('无操作权限') ;
}
}
}

79
app/middleware/Csrf.php Executable file
View File

@ -0,0 +1,79 @@
<?php
namespace app\middleware;
use Closure;
/**
* CSRF校验
*/
class Csrf
{
public function handle($request, Closure $next)
{
$csrfToken = session('_token');
if (empty($csrfToken)) {
$csrfToken = randomStr(1, 32);
session('_token', $csrfToken);
}
$paramToken = input('param._token', '');
if (!empty($paramToken)) {
if ($paramToken != $csrfToken) {
return $this->csrfError($request);
}
} elseif($request->isPost() || $request->isAjax()) {
if (empty($paramToken) || $paramToken != $csrfToken) {
return $this->csrfError($request);
}
//HTTP_REFERER 认证
$referer = $_SERVER['HTTP_REFERER'] ?? null;
if(!empty($referer)) {
$domain = $request->domain();
$urlInfo = parse_url($referer);
$scheme = $urlInfo['scheme'] ?? '';
$requestSrc = '';
if (!empty($scheme)) {
$requestSrc = $scheme.'://'.($urlInfo['host'] ?? '');
}
if($domain != $requestSrc) {
return $this->csrfError($request);
}
}
}
$request->csrfToken = $csrfToken;
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
}
}
}

56
app/model/Achievement.php Executable file
View File

@ -0,0 +1,56 @@
<?php
namespace app\model;
/**
* 业绩管理
* Class Achievement
* @package app\model
*/
class Achievement extends Base
{
public static function onAfterInsert($achievement)
{
$achievement->sort = $achievement->id;
$achievement->save();
}
public static function getPaginateList($categoryId, $per = 20, $isSample = false , $onlyVisible = false, $order = [])
{
$paginate = [
'list_rows' => $per
];
if(empty($order)) {
$order = ['sort'=>'desc'];
}
return self::where('category_id', $categoryId)
->when($onlyVisible, function ($query) {
$query->where('visible', 1);
})
->order($order)
->paginate($paginate, $isSample);
}
public static function getListByCategoryId($categoryId, $per = 20, $onlyVisible = false, $order = [])
{
if(empty($order)) {
$order = ['sort'=>'desc'];
}
$items = self::where('category_id', $categoryId)
->when($onlyVisible, function ($query) {
$query->where('visible', 1);
})
->order($order)
->limit($per)
->column('*', 'id');
if(count($items) > 0) {
$ids = array_keys($items);
$infoList = AchievementInfo::getGroupByAchievementIds($ids, $onlyVisible);
foreach ($items as &$item) {
$item['infos'] = $infoList[$item['id']] ?? [];
}
unset($item);
}
return array_values($items);
}
}

96
app/model/AchievementInfo.php Executable file
View File

@ -0,0 +1,96 @@
<?php
namespace app\model;
/**
* 业绩详情
* Class AchievementInfo
* @package app\model
*/
class AchievementInfo extends Base
{
public static function onAfterInsert($achievementInfo)
{
$achievementInfo->sort = $achievementInfo->id;
$achievementInfo->save();
}
/**
* 根据业绩ID查询是否有关联的详情记录
* @param int $achievementId
* @return bool
*/
public static function hasByAchievementId($achievementId)
{
$resp = false;
$count = self::where('achievement_id', $achievementId)->count();
if($count) {
$resp = true;
}
return $resp;
}
/**
* 删除业绩相关的详情记录
* @param $achievementId
* @return bool
*/
public static function delByAchievementId($achievementId)
{
return self::where('achievement_id', $achievementId)->delete();
}
/**
* 获取业绩相关的详情记录
* @param int $achievementId
* @param bool $onlyVisible
* @param array $order
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getByAchievementId($achievementId, $onlyVisible = false, $order = [])
{
if(empty($order)) {
$order = ['sort'=>'desc'];
}
return self::where('achievement_id', $achievementId)
->when($onlyVisible, function ($query) {
$query->where('visible', 1);
})
->order($order)
->select()
->toArray();
}
/**
* 查询业绩相关的项目并以业绩ID进行分组返回
* @param array $achievementIds
* @param bool $onlyVisible
* @param array $order
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getGroupByAchievementIds($achievementIds, $onlyVisible = false, $order = [])
{
$data = [];
if(empty($order)) {
$order = ['sort'=>'desc'];
}
$items = self::whereIn('achievement_id', $achievementIds)
->when($onlyVisible, function ($query) {
$query->where('visible', 1);
})
->order($order)
->select()
->toArray();
if(count($items) > 0) {
foreach ($items as $item) {
$data[$item['achievement_id']][] = $item;
}
}
return $data;
}
}

267
app/model/Article.php Executable file
View File

@ -0,0 +1,267 @@
<?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, $status = -1, $order = [])
{
if(empty($categoryId)){
return [];
}
$whereMap = [];
if($limit <= 0){
$limit = 5;
}
if(is_numeric($status) && $status != -1){
$whereMap[] = ['status', '=', $status];
}
if(empty($order)) {
$order = ['create_time' => 'desc'];
}
return self::where('category_id', $categoryId)
->where($whereMap)
->order($order)
->limit($limit)
->select()
->toArray();
}
/**
* 根据文章ID和栏目ID获取下一篇文章
* @param int $id 当前文章ID
* @param array $categoryIds 当前文章栏目IDs
* @param bool $orderSort 是否以“sort”字段排序
* @param int $currentSort 当前文章的排序号
* @param bool $sortDesc 是否以sort字段倒叙排列
* @return array
*/
public static function getNextArticleByIdAndCategories($id, $categoryIds, $orderSort = false, $currentSort = 0, $sortDesc = false)
{
$whereMap = [];
if($orderSort && $currentSort > 0) {
if($sortDesc) {
$whereMap[] = ['sort', '<', $currentSort];
$order = ['sort'=> 'desc'];
} else {
$whereMap[] = ['sort', '>', $currentSort];
$order = ['sort'=> 'asc'];
}
} else {
$whereMap[] = ['id', '>', $id];
$order = ['id'=> 'asc'];
}
return self::where($whereMap)
->whereIn('category_id', $categoryIds)
->where('status', 1)
->order($order)
->findOrEmpty()
->toArray();
}
/**
* 根据文章ID和栏目ID获取上一篇文章
* @param int $id 当前文章ID
* @param array $categoryIds 当前文章栏目IDs
* @param bool $orderSort 是否以“sort”字段排序
* @param int $currentSort 当前文章的排序号
* @param bool $sortDesc 是否以sort字段倒叙排列
* @return array
*/
public static function getPrevArticleByIdAndCategories($id, $categoryIds, $orderSort = false, $currentSort = 0, $sortDesc = false)
{
$whereMap = [];
if($orderSort && $currentSort > 0) {
if($sortDesc) {
$whereMap[] = ['sort', '>', $currentSort];
$order = ['sort'=> 'asc'];
} else {
$whereMap[] = ['sort', '<', $currentSort];
$order = ['sort'=> 'desc'];
}
} else {
$whereMap[] = ['id', '<', $id];
$order = ['id'=> 'desc'];
}
return self::where($whereMap)
->whereIn('category_id', $categoryIds)
->where('status', 1)
->order($order)
->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);
}
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];
}
}
}
if(is_numeric($status) && $status != -1){
$whereMap[] = ['status', '=', $status];
$pageParam['status'] = $status;
}
$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;
}
// 查询栏目下的文章
public static function getListByCategoryIds($categoryIds, $per = 20, $keyword = '', $param = [], $status = -1, $order = [])
{
$whereMap = [];
if(is_array($categoryIds) && count($categoryIds) > 0) {
$whereMap[] = ['category_id', 'in', $categoryIds];
}
if(!empty($keyword)){
$whereMap[] = ['title', 'like', '%'.$keyword.'%'];
}
if (is_array($param) && count($param) > 0) {
foreach ($param as $vo) {
if(in_array($vo, ['top','hot','recommend'], true)) {
$whereMap[] = ["{$vo}", '=', 1];
}
}
}
if(is_numeric($status) && $status != -1){
$whereMap[] = ['status', '=', $status];
}
if(empty($order)) {
$order = ['sort'=>'desc'];
}
return self::when(count($whereMap) > 0, function($query) use ($whereMap) {
$query->where($whereMap);
})
->order($order)
->limit($per)
->select()
->toArray();
}
//根据栏目IDs获取文章分页列表
public static function getListPageByCategories($categoryIds, $per = 20, $keyword = '', $order = [])
{
$param = [];
$where = [
['category_id', 'in', $categoryIds],
['status', '=', 1],
];
if($keyword!=''){
$where[] = ['title', 'like', '%'.$keyword.'%'];
$param['keyword'] = $keyword;
}
$paginate = [
'list_rows' => $per,
'query' => $param
];
if(empty($order)) {
$order = ['sort'=>'desc'];
}
return self::where($where)
->order($order)
->paginate($paginate,false);
}
}

54
app/model/AuthGroup.php Executable 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 Executable 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;
}
}

47
app/model/Base.php Executable file
View File

@ -0,0 +1,47 @@
<?php
namespace app\model;
use think\Model;
class Base extends Model
{
protected $autoWriteTimestamp = false;
//根据Id列表获取列表
public static function getListByIds($ids, $order = [])
{
if(count($ids) == 0 || empty($ids)) {
return [];
}
if(empty($order)) {
$order = ['id'=>'asc'];
}
return self::where('id', 'in', $ids)
->order($order)
->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();
}
}

165
app/model/Block.php Executable file
View File

@ -0,0 +1,165 @@
<?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;
}
// 解析单页块元素内容,把JSON化的内容转为数组格式
public static function analysisBlock(array $items)
{
$arrayToJsonTypes = [4];
if(count($items) > 0) {
foreach ($items as &$item) {
if(in_array($item['type'], $arrayToJsonTypes)) {
$item['value'] = empty($item['value']) ? [] : json_decode($item['value'], true);
}
}
unset($item);
}
return $items;
}
// 按块元素的栏目分类和关键字进行分组
public static function convertGroupByCategory(array $items)
{
$data = [];
foreach($items as $item){
$data[$item['category_id']][$item['keyword']] = $item;
}
return $data;
}
// 按块元素的关键字进行分组
public static function convertGroupByKeyword(array $items)
{
$data = [];
foreach($items as $item){
$data[$item['keyword']] = $item;
}
return $data;
}
//根据栏目ID获取块列表
public static function getByCategoryIds($categoryIds)
{
if(!is_array($categoryIds) || empty($categoryIds)){
return [];
}
$items = self::whereIn('category_id', $categoryIds)
->order('category_id', 'asc')
->order('sort', 'asc')
->select()
->toArray();
if(empty($items)){
return [];
}
return self::convertGroupByCategory($items);
}
}

251
app/model/Category.php Executable file
View File

@ -0,0 +1,251 @@
<?php
namespace app\model;
class Category extends Base
{
public static $CIdList = [
'about' => 1, // 走进超宇
'about_children' => [
'company' => 3, // 企业简介
'honor' => 8, // 资质荣誉
'structure' => 9, // 组织架构
'history' => 10, // 发展历程
'video' => 11, // 企业视频
],
'honors_manage' => 26, // 荣誉资质管理
'history_manage' => 29, // 发展历程管理
'products' => 2, // 产品中心
'service' => 5, // 品质与服务
'service_children' => [
'before' => 12, // 售前服务
'in_progress' => 13, // 售中服务
'after' => 14, // 售后服务
],
'marketing' => 15, // 营销网络(主)
'marketing_children' => [
'network' => 16, // 营销网络
'achievement' => 17, // 主要业绩
],
'achievement_manage' => 34, // 主要业绩管理
'news' => 18, // 新闻动态
'news_children' => [
'enterprise' => 20, // 企业新闻
'industry' => 21, // 行业资讯
'dynamics' => 22, // 最新动态
],
'contact' => 19, // 联系我们
'contact_children' => [
'information' => 23, // 联系方式
'jobs' => 24, // 行业资讯
'message' => 25, // 在线留言
],
'jobs_manage' => 33, // 招聘管理
];
//获取首页栏目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)
->where('c.is_menu', 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){
$crumbs[] = $category;
}else{
$categoryIds = explode(',', trim($category['path'], ','));
$categories = self::alias('c')
->leftJoin('model m', 'c.model_id = m.id')
->where('c.id', 'in', $categoryIds)
->column('c.*,m.template', 'c.id');
foreach($categoryIds as $id){
if(isset($categories[$id])){
$crumbs[] = $categories[$id];
}
}
$crumbs[] = $category;
}
}
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;
}
//根据栏目ID获取面包屑列表
public static function getListForCrumbs($categoryId)
{
$categories = [];
$category = self::getById($categoryId);
if(!empty($category)){
$categories[] = $category;
if($category['parent_id'] != 0 ){
$parents = self::getListForCrumbs($category['parent_id']);
if(!empty($parents)){
$categories = array_merge($categories, $parents);
}
}
}
return $categories;
}
}

93
app/model/File.php Executable 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();
}
}

53
app/model/History.php Executable file
View File

@ -0,0 +1,53 @@
<?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,
'query' => [
'category_id' => $categoryId
]
];
$items = self::where('category_id', $categoryId)->order('sort', 'desc')->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, $defaultNum = -1)
{
$items = self::where('category_id', $categoryId)
->when($onlyVisible, function($query){
$query->where('visible', 1);
})
->order('sort', 'desc')
->select();
if(!$items->isEmpty()) {
$ids = $items->column('id');
$infoList = [];
if ($defaultNum != 0) {
$infoList = HistoryInfo::getByHistoryIds($ids, $onlyVisible);
}
foreach ($items as $k => $item) {
$infos = $infoList[$item['id']] ?? [];
$infoData = $defaultNum > 0 ? array_slice($infos, 0, $defaultNum, false) : $infos;
$items[$k]['info'] = $infoData;
}
}
return $items->toArray();
}
}

52
app/model/HistoryInfo.php Executable 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'=>'desc','sort'=>'desc'])
->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'=>'desc'])->select()->toArray();
}
}

39
app/model/Link.php Executable 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 Executable 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 Executable file
View File

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

57
app/model/Member.php Executable 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);
}
}

27
app/model/Message.php Executable file
View File

@ -0,0 +1,27 @@
<?php
namespace app\model;
class Message extends Base
{
// 获取留言列表
public static function getPaginateList($per = 20, $keyword = '', $isSimple = false)
{
$paginate = [
'list_rows' => $per,
'query' => [
'keyword' => $keyword,
]
];
return self::when(!empty($keyword), function ($query) use ($keyword) {
$map = [
['company_name', 'like', '%'.$keyword.'%'],
['name', 'like', '%'.$keyword.'%'],
['phone', 'like', '%'.$keyword.'%'],
['email', 'like', '%'.$keyword.'%'],
];
$query->whereOr($map);
})
->order('create_time', 'desc')
->paginate($paginate, $isSimple);
}
}

21
app/model/Model.php Executable file
View File

@ -0,0 +1,21 @@
<?php
namespace app\model;
class Model extends Base
{
const ARTICLE = 31;
const PAGE = 33;
//获取模型列表
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 Executable 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 Executable 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();
}
}

5
app/provider.php Executable file
View File

@ -0,0 +1,5 @@
<?php
// 全局容器对象绑定文件
return [
'think\Paginator' => 'tool\CustomPageHelper'
];

17
app/service/File.php Executable 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 Executable 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() . 'wwwroot/' . 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 . 'wwwroot/' . 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() . 'wwwroot/' . 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 . 'wwwroot/' . 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 . 'wwwroot/' . 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);
}
}

47
app/service/Tool.php Executable file
View File

@ -0,0 +1,47 @@
<?php
namespace app\service;
class Tool
{
//删除文件
public static function delFile($path,$isImg = 0)
{
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;
}
}

62
app/validate/Achievement.php Executable file
View File

@ -0,0 +1,62 @@
<?php
namespace app\validate;
use think\Validate;
class Achievement extends Validate
{
protected $achievementRule = [
'title' => 'require|length:1,60',
'visible' => 'require|in:0,1',
];
protected $achievementMessage = [
'title.require' => '业绩标题不能为空',
'name.length' => '业绩标题长度限制为60个字符以内',
'visible.require' => '业绩状态必须设置',
'visible.in' => '业绩状态参数错误',
];
protected $achievementInfoRule = [
'title' => 'require|length:1,60',
'order_company' => 'require|length:1,100',
'goods_model' => 'require|length:1,300',
'goods_amount' => 'require|length:1,500',
'visible' => 'require|in:0,1',
];
protected $achievementInfoMessage = [
'title.require' => '业绩项目名称不能为空',
'name.length' => '业绩项目名称长度限制为60个字符以内',
'order_company.require' => '订货单位不能为空',
'order_company.length' => '订货单位长度限制为100个字符以内',
'goods_model.require' => '货物名称及型号规格不能为空',
'goods_model.length' => '货物名称及型号规格长度限制为300个字符以内',
'goods_amount.require' => '订货数量不能为空',
'goods_amount.length' => '订货数量长度限制为500个字符以内',
'visible.require' => '业绩项目状态必须设置',
'visible.in' => '业绩项目状态参数错误',
];
/**
* 校验业绩数据
* @param array $data
* @return bool
*/
public function checkAchievement(array $data)
{
$this->rule = $this->achievementRule;
$this->message = $this->achievementMessage;
return $this->check($data);
}
/**
* 校验业绩详情数据
* @param array $data
* @return bool
*/
public function checkAchievementInfo(array $data)
{
$this->rule = $this->achievementInfoRule;
$this->message = $this->achievementInfoMessage;
return $this->check($data);
}
}

16
app/validate/Article.php Executable 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' => '请填写有效的网址'
];
}

17
app/validate/AuthGroup.php Executable file
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 Executable 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 Executable 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 Executable 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 Executable 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' => '状态参数错误',
];
}

19
app/validate/HistoryInfo.php Executable file
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 Executable 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 Executable 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' => '用户姓名不能为空!',
];
}

27
app/validate/Message.php Executable file
View File

@ -0,0 +1,27 @@
<?php
namespace app\validate;
use think\Validate;
class Message extends Validate
{
protected $rule = [
'company_name' => 'requireWithout:name|length:2,100',
'name' => 'requireWithout:company_name|length:2,50',
'content' => 'require|length:4,500',
'phone' => 'requireWithout:email|mobile',
'email' => 'requireWithout:phone|email',
];
protected $message = [
'company_name.requireWithout' => '公司名称和联系人署名至少需要填写一个',
'company_name.length' => '公司名称长度限制为2~100个字符',
'name.requireWithout' => '公司名称和联系人署名至少需要填写一个',
'name.length' => '联系人署名长度限制为2~50个字符',
'phone.requireWithout' => '联系电话和邮箱至少需要填写一个',
'phone.mobile' => '请输入正确的联系电话',
'email.requireWithout' => '联系电话和邮箱至少需要填写一个',
'email.email' => '请输入正确的邮箱',
'content.require' => '咨询事项不能为空',
'content.length' => '咨询事项长度限制为4~500个字符',
];
}

16
app/validate/Model.php Executable 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 Executable 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 Executable 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]);
}
}

18
app/widget/Crumbs.php Executable file
View File

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

23
app/widget/Footer.php Executable file
View File

@ -0,0 +1,23 @@
<?php
namespace app\widget;
use app\model\Category;
use app\model\System;
use think\facade\{View,Cache};
class Footer
{
public function index()
{
$menus = Cache::get('front_menus');
if (empty($menus)){
$menus = Category::getListForFrontMenu();
Cache::set('front_menus', $menus, 3600 * 12);
}
$data = [
'system' => System::getSystem(),
'footerMenus' => $menus,
];
return View::assign($data)->fetch('public/footer');
}
}

28
app/widget/Menu.php Executable file
View File

@ -0,0 +1,28 @@
<?php
namespace app\widget;
use think\facade\{View, Cache};
use app\model\Category;
class Menu
{
public function index($categoryId)
{
$menus = Cache::get('front_menus');
$menus = null;
if(empty($menus)){
$menus = Category::getListForFrontMenu();
Cache::set('front_menus', $menus, 3600 * 12);
}
$currentFirstId = 0;
if (is_numeric($categoryId) && $categoryId > 0) {
$currentFirstId = Category::firstGradeById($categoryId);
}
$data = [
'categoryId' => $categoryId,
'menus' => $menus,
'currentFirstId' => $currentFirstId,
];
return View::assign($data)->fetch('public/menu');
}
}

16
app/widget/Slide.php Executable 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');
}
}

42
app/widget/manager/Crumbs.php Executable file
View File

@ -0,0 +1,42 @@
<?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');
}
}

90
app/widget/manager/Menu.php Executable file
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;
}
}

71
app/widget/manager/Upload.php Executable file
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 Executable 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 Executable 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 Executable file

File diff suppressed because it is too large Load Diff

41
config/app.php Executable file
View File

@ -0,0 +1,41 @@
<?php
use think\facade\Env;
return [
// 应用地址
'app_host' => Env::get('app.host', ''),
// 应用的命名空间
'app_namespace' => '',
// 是否启用路由
'with_route' => true,
// 是否启用事件
'with_event' => true,
// 自动多应用模式
'auto_multi_app' => true,
// 应用映射(自动多应用模式有效)
'app_map' => [],
// 域名绑定(自动多应用模式有效)
'domain_bind' => [],
// 禁止URL访问的应用列表自动多应用模式有效
'deny_app_list' => [],
// 默认应用
'default_app' => 'index',
// 默认时区
'default_timezone' => 'Asia/Shanghai',
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
/*
'http_exception_template' => [
400 => '',
500 => app()->getThinkPath() . 'tpl/think_exception.tpl',
],
*/
// 错误显示信息,非调试模式有效
'error_message' => '页面错误!请稍后再试~',
// 显示错误信息
'show_error_msg' => true,
'app_debug' => true,
];

30
config/cache.php Executable file
View File

@ -0,0 +1,30 @@
<?php
use think\facade\Env;
// +----------------------------------------------------------------------
// | 缓存设置
// +----------------------------------------------------------------------
return [
// 默认缓存驱动
'default' => Env::get('cache.driver', 'file'),
// 缓存连接方式配置
'stores' => [
'file' => [
// 驱动方式
'type' => 'File',
// 缓存保存目录
'path' => '',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
// 缓存标签前缀
'tag_prefix' => 'tag:',
// 序列化机制 例如 ['serialize', 'unserialize']
'serialize' => [],
],
// 更多的缓存连接
],
];

9
config/console.php Executable file
View File

@ -0,0 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | 控制台配置
// +----------------------------------------------------------------------
return [
// 指令定义
'commands' => [
],
];

18
config/cookie.php Executable file
View File

@ -0,0 +1,18 @@
<?php
// +----------------------------------------------------------------------
// | Cookie设置
// +----------------------------------------------------------------------
return [
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => '',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => false,
// 是否使用 setcookie
'setcookie' => true,
];

63
config/database.php Executable file
View File

@ -0,0 +1,63 @@
<?php
use think\facade\Env;
return [
// 默认使用的数据库连接配置
'default' => Env::get('database.driver', 'mysql'),
// 自定义时间查询规则
'time_query_rule' => [],
// 自动写入时间戳字段
// true为自动识别类型 false关闭
// 字符串则明确指定时间字段类型 支持 int timestamp datetime date
'auto_timestamp' => true,
// 时间字段取出后的默认时间格式
'datetime_format' => 'Y-m-d H:i:s',
// 数据库连接配置信息
'connections' => [
'mysql' => [
// 数据库类型
'type' => Env::get('database.type', 'mysql'),
// 服务器地址
'hostname' => Env::get('database.hostname', '127.0.0.1'),
// 数据库名
'database' => Env::get('database.database', ''),
// 用户名
'username' => Env::get('database.username', 'root'),
// 密码
'password' => Env::get('database.password', ''),
// 端口
'hostport' => Env::get('database.hostport', '3306'),
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => Env::get('database.charset', 'utf8'),
// 数据库表前缀
'prefix' => Env::get('database.prefix', ''),
// 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'deploy' => 0,
// 数据库读写是否分离 主从式有效
'rw_separate' => false,
// 读写分离后 主服务器数量
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
// 是否严格检查字段是否存在
'fields_strict' => true,
// 是否需要断线重连
'break_reconnect' => false,
// 监听SQL
'trigger_sql' => true,
// 开启字段缓存
'fields_cache' => false,
// 字段缓存路径
'schema_cache_path' => app()->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR,
],
// 更多的数据库配置信息
],
];

42
config/filesystem.php Executable file
View File

@ -0,0 +1,42 @@
<?php
use think\facade\Env;
return [
// 默认磁盘
'default' => Env::get('filesystem.driver', 'local'),
// 磁盘列表
'disks' => [
'local' => [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'wwwroot/storage',
// 磁盘路径对应的外部URL路径
'url' => '/storage',
// 可见性
'visibility' => 'public',
],
'video' => [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'wwwroot/storage/videos',
// 磁盘路径对应的外部URL路径
'url' => '/storage/videos',
// 可见性
'visibility' => 'public',
],
'backup' => [
// 磁盘类型
'type' => 'local',
// 磁盘路径
'root' => app()->getRootPath() . 'wwwroot/storage/backup',
// 磁盘路径对应的外部URL路径
'url' => '/storage/backup',
// 可见性
'visibility' => 'public',
],
// 更多的磁盘配置信息
],
];

27
config/lang.php Executable file
View File

@ -0,0 +1,27 @@
<?php
// +----------------------------------------------------------------------
// | 多语言设置
// +----------------------------------------------------------------------
use think\facade\Env;
return [
// 默认语言
'default_lang' => Env::get('lang.default_lang', 'zh-cn'),
// 允许的语言列表
'allow_lang_list' => ['zh-cn'],
// 多语言自动侦测变量名
'detect_var' => 'lang',
// 是否使用Cookie记录
'use_cookie' => true,
// 多语言cookie变量
'cookie_var' => 'think_lang',
// 扩展语言包
'extend_list' => [],
// Accept-Language转义为对应语言包名称
'accept_language' => [
'zh-hans-cn' => 'zh-cn',
],
// 是否支持语言分组
'allow_group' => false,
];

46
config/log.php Executable file
View File

@ -0,0 +1,46 @@
<?php
use think\facade\Env;
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
return [
// 默认日志记录通道
'default' => Env::get('log.channel', 'file'),
// 日志记录级别
'level' => [],
// 日志类型记录的通道 ['error'=>'email',...]
'type_channel' => [],
// 关闭全局日志写入
'close' => false,
// 全局日志处理 支持闭包
'processor' => null,
// 日志通道列表
'channels' => [
'file' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => '',
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => [],
// 最大日志文件数量
'max_files' => 0,
// 使用JSON格式记录
'json' => false,
// 日志处理
'processor' => null,
// 关闭通道日志写入
'close' => false,
// 日志输出格式化
'format' => '[%s][%s] %s',
// 是否实时写入
'realtime_write' => false,
],
// 其它日志通道配置
],
];

11
config/middleware.php Executable file
View File

@ -0,0 +1,11 @@
<?php
// 中间件配置
return [
// 别名或分组
'alias' => [
'auth' => app\middleware\Auth::class,
'csrf' => app\middleware\Csrf::class,
],
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
'priority' => [],
];

51
config/route.php Executable file
View File

@ -0,0 +1,51 @@
<?php
// +----------------------------------------------------------------------
// | 路由设置
// +----------------------------------------------------------------------
return [
// pathinfo分隔符
'pathinfo_depr' => '/',
// URL伪静态后缀
'url_html_suffix' => 'html',
// URL普通方式参数 用于自动生成
'url_common_param' => true,
// 是否开启路由延迟解析
'url_lazy_route' => false,
// 是否强制使用路由
'url_route_must' => false,
// 合并路由规则
'route_rule_merge' => false,
// 路由是否完全匹配
'route_complete_match' => false,
// 是否开启路由缓存
'route_check_cache' => false,
// 路由缓存连接参数
'route_cache_option' => [],
// 路由缓存Key
'route_check_cache_key' => '',
// 访问控制器层名称
'controller_layer' => 'controller',
// 空控制器名
'empty_controller' => 'Error',
// 是否使用控制器后缀
'controller_suffix' => false,
// 默认的路由变量规则
'default_route_pattern' => '[\w\.]+',
// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
'request_cache' => false,
// 请求缓存有效期
'request_cache_expire' => null,
// 全局请求缓存排除规则
'request_cache_except' => [],
// 默认控制器名
'default_controller' => 'Index',
// 默认操作名
'default_action' => 'index',
// 操作方法后缀
'action_suffix' => '',
// 默认JSONP格式返回的处理方法
'default_jsonp_handler' => 'jsonpReturn',
// 默认JSONP处理方法
'var_jsonp_handler' => 'callback',
];

19
config/session.php Executable file
View File

@ -0,0 +1,19 @@
<?php
// +----------------------------------------------------------------------
// | 会话设置
// +----------------------------------------------------------------------
return [
// session name
'name' => 'PHPSESSID',
// SESSION_ID的提交变量,解决flash上传跨域
'var_session_id' => '',
// 驱动方式 支持file cache
'type' => 'file',
// 存储连接标识 当type使用cache的时候有效
'store' => null,
// 过期时间(秒)
'expire' => 3600 * 2,
// 前缀
'prefix' => '',
];

10
config/trace.php Executable file
View File

@ -0,0 +1,10 @@
<?php
// +----------------------------------------------------------------------
// | Trace设置 开启调试模式后有效
// +----------------------------------------------------------------------
return [
// 内置Html和Console两种方式 支持扩展
'type' => 'Html',
// 读取的日志通道名
'channel' => '',
];

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