commit 1536e49dfe1b4e551fe8a612f2484a8d78f9474b Author: wangxinglong <2371974647@qq.com> Date: Fri Aug 6 18:50:55 2021 +0800 初始化 diff --git a/.env.bak b/.env.bak new file mode 100644 index 0000000..2eebf2b --- /dev/null +++ b/.env.bak @@ -0,0 +1,19 @@ +APP_DEBUG = true +APP_TRACE = true + +[APP] +DEFAULT_TIMEZONE = Asia/Shanghai + +[DATABASE] +TYPE = mysql +HOSTNAME = 211.149.245.223 +DATABASE = dev_bee_cms +USERNAME = dev_bee_cms +PASSWORD = dT7yH5fmd28JG6ER +HOSTPORT = 3306 +CHARSET = utf8mb4 +DEBUG = true +PREFIX = bee_ + +[LANG] +default_lang = zh-cn diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1dc246 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.env +/.idea +/.vscode +backup/data/* +*.log +runtime/* +storage/* +public/storage/* +.DS_Store +Test.php +nginx.htaccess +dump.rdb \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..df2334c --- /dev/null +++ b/LICENSE.txt @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..389e1b4 --- /dev/null +++ b/README.md @@ -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组件库自带的 \ No newline at end of file diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/app/common.php b/app/common.php new file mode 100644 index 0000000..66aecdd --- /dev/null +++ b/app/common.php @@ -0,0 +1,426 @@ + +// +---------------------------------------------------------------------- + +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('//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('//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('getTextareaText')) { + function getTextareaText($content) + { + $content = trim($content); + if (!empty($content)) { + $content = str_replace("\r\n", "\n", $content); + $content = str_replace("\r", "\n", $content); + } + return $content; + } +} + +if (!function_exists('getTextNlToList')) { + function getTextNlToList($content) + { + $list = []; + $content = getTextareaText($content); + if (!empty($content)) { + $list = explode("\n", $content); + } + return $list; + } +} +//验证手机 +if (!function_exists('is_tel')) { + function is_tel($mobile) + { + if (preg_match("/^1[3456789]\d{9}$/", $mobile)) { + return true; + } + return false; + } +} +if (!function_exists('tel_protect')) { + function tel_protect($mobile) + { + if (is_tel($mobile)) { + return substr($mobile, 0, 3) . "****" . substr($mobile, 7); + } + return $mobile; + } +} + +if (!function_exists('getExt')) { + function getExt($file) + { + if (strlen($file) > 0) { + $array = explode(".", $file); + return end($array); + } + return ''; + } +} diff --git a/app/controller/Article.php b/app/controller/Article.php new file mode 100644 index 0000000..56f5556 --- /dev/null +++ b/app/controller/Article.php @@ -0,0 +1,91 @@ +error('错误页面'); + } + $article = MArticle::getById($id); + if (empty($article)) { + return $this->error('无此文章'); + } + MArticle::updateById($id, ['views' => $article['views'] + 1]); + $category = Category::getById($article['category_id']); + $prev = MArticle::getPrevArticleByIdAndCategoryId($id, $article['category_id']); + $next = MArticle::getNextArticleByIdAndCategoryId($id, $article['category_id']); + + $keywords = $article['seo_keywords'] ? $article['seo_keywords'] : $article['title']; + $description = $article['seo_description'] ? $article['seo_description'] : $article['title']; + //$this->setSeo($category['title'], $category['title'], $category['title']); + $this->setSeo($article['title'] . "|" . $this->system['company_name'], $keywords, $description); + + $this->data['article'] = $article; + $this->data['category'] = $category; + $this->data['categoryId'] = $category['id']; + $this->data['prev'] = $prev; + $this->data['next'] = $next; + + + $banner = Slide::getList(); + View::assign("banner", $banner); + + return $this->view($category['template_detail'] ?? ''); + } + + //列表页 + public function index() + { + //动态设置当前分页驱动 + app('think\App')->bind(Paginator::class, Page::class); + + $categoryId = input('category_id/d', 0); + if ($categoryId <= 0) { + return $this->error('错误页面'); + } + $category = Category::getById($categoryId); + $page_size = 20; + if ($category['number']) $page_size = $category['number']; + + if ($this->request->param("page_size/d")) { + $page_size = $this->request->param("page_size/d"); + cookie("article_page_size", $this->request->param("page_size/d")); + } else { + if (cookie("?article_page_size")) $page_size = cookie("article_page_size"); + } + + if (empty($category)) { + return $this->error('错误页面'); + } + + $description = $category['description'] ? $category['description'] : $category['title']; + $keywords = $category['seo_keywords'] ? $category['seo_keywords'] : $category['title']; + //$this->setSeo($category['title'], $category['title'], $category['title']); + $this->setSeo($category['title'] . "-" . $this->system['company_name'], $keywords, $description); + + $this->data['items'] = MArticle::getListPageByCategory($categoryId, $page_size); + $this->data['category'] = $category; + $this->data['categoryId'] = $categoryId; + $this->data['page_size'] = $page_size; + $this->data['article_count'] = MArticle::getListCount($categoryId); + + + $banner = Slide::getList(); + View::assign("banner", $banner); + + return $this->view($category['template_list'] ?? ''); + } + + +} \ No newline at end of file diff --git a/app/controller/Base.php b/app/controller/Base.php new file mode 100644 index 0000000..e9c81eb --- /dev/null +++ b/app/controller/Base.php @@ -0,0 +1,37 @@ +system = System::getSystem(); + $this->data['system'] = $this->system; + } + + //设置SEO信息 + protected function setSeo($title, $keywords, $description) + { + $this->data['seoTitle'] = $title; + $this->data['seoKeywords'] = $keywords; + $this->data['seoDescription'] = $description; + } + + //模板 + protected function view($template = '') + { + return view($template)->assign($this->data); + } +} diff --git a/app/controller/BaseController.php b/app/controller/BaseController.php new file mode 100644 index 0000000..c24674a --- /dev/null +++ b/app/controller/BaseController.php @@ -0,0 +1,193 @@ +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); + } +} \ No newline at end of file diff --git a/app/controller/Error.php b/app/controller/Error.php new file mode 100644 index 0000000..181df05 --- /dev/null +++ b/app/controller/Error.php @@ -0,0 +1,49 @@ +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); + } +} \ No newline at end of file diff --git a/app/controller/Home.php b/app/controller/Home.php new file mode 100644 index 0000000..a10a2c0 --- /dev/null +++ b/app/controller/Home.php @@ -0,0 +1,31 @@ +data['categoryId'] = $categoryId; + $this->setSeo($this->system['seo_title'], $this->system['seo_keywords'], $this->system['seo_description']); + $this->data['blocks'] = Block::getByCategoryId($categoryId); + $this->category_id=$this->request->param("category_id/d"); + } + //关于我们 + public function aboutUs(){ + $Block=["key1"=>"","key2"=>""]; + $Block["key1"]=Block::getByKeyword(1,$this->category_id); + $Block["key2"]=Block::getByKeyword(2,$this->category_id); + dump($Block); + View::assign($Block); + return $this->view(); + } + +} \ No newline at end of file diff --git a/app/controller/Index.php b/app/controller/Index.php new file mode 100644 index 0000000..9e47e12 --- /dev/null +++ b/app/controller/Index.php @@ -0,0 +1,22 @@ +data['categoryId'] = $categoryId; + $this->setSeo($this->system['seo_title'], $this->system['seo_keywords'], $this->system['seo_description']); + $this->data['blocks'] = Block::getByCategoryId($categoryId); + View::assign("category", $category); + + return $this->view(); + } +} \ No newline at end of file diff --git a/app/controller/Page.php b/app/controller/Page.php new file mode 100644 index 0000000..a7b8d71 --- /dev/null +++ b/app/controller/Page.php @@ -0,0 +1,38 @@ +bind(Paginator::class, Layui::class); + + $categoryId = $this->request->param("category_id"); + $category = Category::getById($this->request->param("category_id")); + + if ($category) { + //$description = $category['description'] ? $category['description'] : $this->system['seo_description']; + $description = $category['description'] ? $category['description'] : $category['title']; + $keywords = $category['seo_keywords'] ? $category['seo_keywords'] : $category['title']; + //$this->setSeo($category['title'], $this->system['seo_keywords'], $description); + $this->setSeo($category['title'] . "-" . $this->system['company_name'], $keywords, $description); + } else { + return $this->error('错误页面'); + } + $childCategory = Category::getChildrenByParentId($categoryId); + + $this->data['categoryId'] = $categoryId; + $this->data['category'] = $category; + $this->data['childCategory'] = $childCategory; + $this->data['blocks'] = Block::getByCategoryId($categoryId); + return $this->view($category['template_detail']); + } + + +} \ No newline at end of file diff --git a/app/controller/api/Base.php b/app/controller/api/Base.php new file mode 100644 index 0000000..4a18c6a --- /dev/null +++ b/app/controller/api/Base.php @@ -0,0 +1,27 @@ +request->header(); + $this->token = isset($allHeader["wechattoken"]) ? $allHeader["wechattoken"] : ""; + $this->openid = isset($allHeader["openid"]) ? $allHeader["openid"] : ""; + $this->user = User::userTokenVerification($this->token, $this->openid); + } + +} \ No newline at end of file diff --git a/app/controller/api/Login.php b/app/controller/api/Login.php new file mode 100644 index 0000000..05ba6e3 --- /dev/null +++ b/app/controller/api/Login.php @@ -0,0 +1,86 @@ +request->param('code/s'); + $appId = $config["appId"];//appid + $appSecret = $config["appSecret"];//appsecret + $url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' . $appId . '&secret=' . $appSecret . '&js_code=' . $code . '&grant_type=authorization_code'; + $datas = json_decode(Tool::httpRequest($url, "get"), true); + //返回状态 + if (isset($datas["openid"])) { + return $this->json(0, "ok", $datas); + } + return $this->json(1, "null"); + } + + + /** + * 小程序用户登录 创建用户或更新用户信息 + */ + public function wechatMiniLogin() + { + $data = []; + $data['openid'] = $this->request->post('openid/s');//微信用户openid + $data['headimgurl'] = $this->request->post('avatarUrl/s');//微信头像 + $data['nickname'] = $this->request->post('nickName/s');//用户昵称 + + try { + validate(Vuser::class)->check($data); + } catch (ValidateException $e) { + return $this->json(1, "异常请求"); + } + + $user = User::getByOpenid($data['openid']); + $time = time(); + $token_close_time = $time + User::TokenCloseTime; + $data["login_ip"] = $this->request->ip(); + $data["last_login"] = $time; + $data["token_close_time"] = $token_close_time; + $data["token"] = md5($data["openid"] . $time . randomStr(1, 16)); + + Db::startTrans(); + try { + //如果没有注册过 就添加 + if (!empty($user)) { + User::create($data); + } else { + User::updateById($user['id'], $data); + } + //提交事务 + Db::commit(); + return $this->json(0, "ok", [ + "token" => $data["token"], + ]); + } catch (Exception $e) { + Db::rollback(); + return $this->json(2, $e->getMessage()); + } + + } + + +} \ No newline at end of file diff --git a/app/controller/manager/Article.php b/app/controller/manager/Article.php new file mode 100644 index 0000000..1db2b17 --- /dev/null +++ b/app/controller/manager/Article.php @@ -0,0 +1,244 @@ +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'); + $imgimgs = input('post.imgimgs'); + + $id = input('post.id/d'); + $article = MArticle::getById($id); + if (empty($article)) { + return $this->json(1, '该文章不存在!'); + } + if(!empty($img)){ + $item['src'] = $img; + } + if(!empty($imgimgs)){ + $item['imgs'] = json_encode($imgimgs); + } + + try { + validate(VArticle::class)->check($item); + $auth = session('auth'); + $item['update_time'] = time(); + $item['updated'] = $auth['userName']; + $content=$item['content']; + //替换图片alt + $preg = "//"; + $preg_replace_img = ''.$item['title'].''; + $content = preg_replace($preg,$preg_replace_img,$content); + $item['content'] = $content; + + 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'); + + $imgimgs = input('post.imgimgs'); + + if(!empty($img)){ + $item['src'] = $img; + } + if(!empty($imgimgs)){ + $item['imgs'] = $imgimgs; + } + try { + validate(VArticle::class)->check($item); + $content = $item['content'] ?? ''; + if(isset($item['content'])){ + unset($item['content']); + } + //替换图片alt + $preg = "//"; + $preg_replace_img = ''.$item['title'].''; + $content = preg_replace($preg,$preg_replace_img,$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(); + } + } +} diff --git a/app/controller/manager/Backup.php b/app/controller/manager/Backup.php new file mode 100644 index 0000000..dcb8965 --- /dev/null +++ b/app/controller/manager/Backup.php @@ -0,0 +1,153 @@ + 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, '非法请求'); + } + } +} \ No newline at end of file diff --git a/app/controller/manager/Base.php b/app/controller/manager/Base.php new file mode 100644 index 0000000..7e92e3b --- /dev/null +++ b/app/controller/manager/Base.php @@ -0,0 +1,53 @@ +middleware = [ +// 'csrf', + 'auth' => [ + 'except' => ['manager.login/index'] + ] + ]; + $auth = session('auth'); + $this->data['member'] = $auth; + if(session('?__token__')){ + $this->data['_token'] = session('__token__'); + }else{ + $this->data['_token'] = $this->request->buildToken(); + } + $this->data['groupId'] = $auth['groupId'] ?? 0; + } + + //变量赋值到模板 + protected function view() + { + return view()->assign($this->data); + } + + protected function error($msg = '', string $url = null, $data = '', int $wait = 3) + { + if (is_null($url)) { + $url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);'; + } elseif ($url) { + $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url); + } + $result = [ + 'code' => 0, + 'msg' => $msg, + 'data' => $data, + 'url' => $url, + 'wait' => $wait, + ]; + + return $this->redirect(url('manager.error/jump', $result)); + } +} \ No newline at end of file diff --git a/app/controller/manager/Category.php b/app/controller/manager/Category.php new file mode 100644 index 0000000..6cd5342 --- /dev/null +++ b/app/controller/manager/Category.php @@ -0,0 +1,314 @@ +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); + + + //如果是关于市场 就添加写入blocks内容 + if($item['parent_id']==MCategory::AboutMarketId){ + $blocks = [ + [ + "category_id"=>$category['id'], + "type"=>Block::BLOCK, + "keyword"=>'title', + "title"=>$category['title'], + "value"=>'让每一位养殖户依靠优质水产苗种走上致富的快车道,愿伟大事业,继往开来!(请修改)', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::TEXT, + "keyword"=>'content', + "title"=>'简介内容(无需修改)', + "value"=>'这里是内容 (请修改)', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::TEXT, + "keyword"=>'Marketpurpose', + "title"=>'内容1(请修改)', + "value"=>'这里是内容 (请修改)', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::TEXT, + "keyword"=>'Businessobjectives', + "title"=>'内容2(请修改)', + "value"=>'这里是内容 (请修改)', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::TEXT, + "keyword"=>'Marketvision', + "title"=>'内容3(请修改)', + "value"=>'这里是内容 (请修改)', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::IMG, + "keyword"=>'leftimg', + "title"=>'左图', + "width"=>'413', + "height"=>'246', + "value"=>'/storage/20210726/60fe7cdf7f0f8.jpg', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::IMG, + "keyword"=>'centerimg', + "title"=>'中图', + "width"=>'413', + "height"=>'246', + "value"=>'/storage/20210726/60fe7d0484182.jpg', + ], + [ + "category_id"=>$category['id'], + "type"=>Block::IMG, + "keyword"=>'rightimg', + "title"=>'右图', + "width"=>'413', + "height"=>'246', + "value"=>'/storage/20210726/60fe7d21aaa19.jpg', + ], + ]; + Block::create($blocks[0]); + Block::create($blocks[1]); + Block::create($blocks[2]); + Block::create($blocks[3]); + Block::create($blocks[4]); + Block::create($blocks[5]); + Block::create($blocks[6]); + Block::create($blocks[7]); + } + + + 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(); + } + } +} diff --git a/app/controller/manager/Content.php b/app/controller/manager/Content.php new file mode 100644 index 0000000..0d34494 --- /dev/null +++ b/app/controller/manager/Content.php @@ -0,0 +1,179 @@ +error('无此栏目'); + } + $list = Article::getList($categoryId, 20, $keyword, $param,$recommend_flag); + $this->data['list'] = $list; + $this->data['category'] = $category; + $this->data['keyword'] = $keyword; + $this->data['recommend_flag'] = $recommend_flag; + $this->data['param'] = $param; + + + return $this->view(); + } + + //做页面跳转 + public function index() + { + $items = Category::getList(); + if(!empty($items)){ + $items = Category::getCates($items); + } + + if(!empty($items)){ + $first = array_shift($items); + if(isset($first['children'])){ + $childrenFirst = array_shift($first['children']); + $url = url('manager.content/'.$childrenFirst['manager'],['category_id' => $childrenFirst['id']]); + }else{ + $url = url('manager.content/'.$first['manager'],['category_id' => $first['id']]); + } + if(!empty($url)){ + return $this->redirect($url); + } + }else{ + return $this->redirect(url('manager.category/add')); + } + } + //单页 + public function page() + { + if($this->request->isAjax()){ + $blocks = input('post.block/a'); //所有文本信息 + $texts = input('post.text/a'); //所有富文本信息 + $codes = input('post.code/a'); //所有代码信息 + $categoryId = input('post.category_id/d'); + $category = Category::getById($categoryId); + unset($_POST['block']); + unset($_POST['text']); + unset($_POST['file']); + unset($_POST['code']); + $imgs = []; //图片信息 + $videos = []; //视频信息 + $groups = []; //组图信息 + $groupIds = input('post.groupIds/a', []); + foreach($_POST as $key => $val){ + if(strpos($key, '_') !== FALSE){ + $keys = explode('_',$key); + if($keys[1] == 'img'){ //图片 + $imgs[$keys[2]] = $val; + }elseif($keys[1] == 'video'){ //视频 + $videos[$keys[2]][$keys[0]] = $val; + }elseif($keys[1] == 'group'){ //组图 + $groups[$keys[2]] = $val; + } + } + } + $data = []; + if(!empty($blocks)){ + foreach($blocks as $key => $block){ + $data[] = [ + 'id' => $key, + 'value' => $block + ]; + } + } + if(!empty($texts)){ + foreach($texts as $key => $text){ + $data[] = [ + 'id' => $key, + 'value' => $text + ]; + } + } + if(!empty($codes)){ + foreach($codes as $key => $code){ + $data[] = [ + 'id' => $key, + 'value' => $code + ]; + } + } + if(!empty($imgs)){ + foreach($imgs as $key => $img){ + $data[] = [ + 'id' => $key, + 'value' => $img + ]; + } + } + if(!empty($videos)){ + foreach($videos as $key => $video){ + $data[] = [ + 'id' => $key, + 'img' => $video['img'], + 'value' => $video['video'] + ]; + } + } + if(!empty($groupIds)){ + foreach($groupIds as $key => $groupId){ + $group = $groups[$groupId] ?? []; + $data[] = [ + 'id' => $groupId, + 'value' => json_encode($group) + ]; + } + } + $block = new Block; + $block->saveAll($data); + Log::write('content', 'page', "单页编辑,栏目ID:{$category['id']} ,标题:{$category['title']}"); + return $this->json(); + }else{ + $categoryId = input('param.category_id'); + $children = Category::getChildrenByParentId($categoryId); + if(empty($children)){ + $category = Category::getById($categoryId); + }else{ + $child = Category::getChildrenByParentId($children[0]['id']); + if(empty($child)){ + $category = $children[0]; + }else{ + $category = $child[0]; + } + } + if(empty($category)){ + return $this->redirect(url('manager.content/index')); + } + + $blocks = Block::getByCategoryId($categoryId); + + $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(); + } +} diff --git a/app/controller/manager/Desk.php b/app/controller/manager/Desk.php new file mode 100644 index 0000000..b23b0e8 --- /dev/null +++ b/app/controller/manager/Desk.php @@ -0,0 +1,105 @@ +error("大厅不存在"); + } + $keyword = input('param.keyword'); + $list = MDesk::getList(20, $keyword); + $this->data['hall'] = $hall; + $this->data['hall_id'] = $hallId; + $this->data['list'] = $list; + $this->data['keyword'] = $keyword; + return $this->view(); + } + + //删除 + public function del() + { + if ($this->request->isPost()) { + $id = input('post.id/d'); + if (is_numeric($id) && $id > 0) { + $item = MDesk::getById($id); + if (!empty($item)) { + MDesk::destroy($id); + return $this->json(); + } + return $this->json(3, '待删除信息不存在'); + } + return $this->json(2, '参数错误,请核对之后再操作!'); + } + return $this->json(1, '非法请求!'); + } + + + //编辑 + public function edit() + { + if ($this->request->isPost()) { + $item = input('post.item/a'); + $id = input('post.id/d'); + $desk = MDesk::getById($id); + if (empty($desk)) { + return $this->json(1, '该信息不存在!'); + } + $repeat = MDesk::editRepeat($desk['id'], $desk['hall_id'], $item['number']); + if (!empty($repeat)) { + return $this->json(1, '桌号不可重复!'); + } + try { + validate(VDesk::class)->check($item); + MDesk::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + } else { + $id = input('param.id'); + $desk = MDesk::getById($id); + $this->data['desk_type'] = MDesk::$desk_type; + $this->data['item'] = $desk; + return $this->view(); + } + } + + //添加 + public function add() + { + if ($this->request->isPost()) { + $item = input('post.item/a'); + $repeat = MDesk::addRepeat($item['hall_id'], $item['number']); + if (!empty($repeat)) { + return $this->json(1, '桌号不可重复!'); + } + try { + validate(VDesk::class)->check($item); + MDesk::create($item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + } else { + $this->data['hall_id'] = input('hall_id/d', 0); + $this->data['desk_type'] = MDesk::$desk_type; + $this->data['default_type'] = MDesk::$default_type; + return $this->view(); + } + } + +} diff --git a/app/controller/manager/Error.php b/app/controller/manager/Error.php new file mode 100644 index 0000000..8cdb0c6 --- /dev/null +++ b/app/controller/manager/Error.php @@ -0,0 +1,11 @@ +param(); + return view()->assign($param); + } +} diff --git a/app/controller/manager/File.php b/app/controller/manager/File.php new file mode 100644 index 0000000..1e1dd2d --- /dev/null +++ b/app/controller/manager/File.php @@ -0,0 +1,142 @@ +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(); + } +} diff --git a/app/controller/manager/Gift.php b/app/controller/manager/Gift.php new file mode 100644 index 0000000..87927ec --- /dev/null +++ b/app/controller/manager/Gift.php @@ -0,0 +1,150 @@ +data['list'] = $list; + $this->data['keyword'] = $keyword; + return $this->view(); + } + //删除 + public function del() + { + if ($this->request->isPost()) { + $id = input('post.id/d'); + if(is_numeric($id) && $id > 0) { + $item = MGift::getById($id); + if(!empty($item)){ + MGift::destroy($id); + 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 = MGift::getById($id); + if(empty($item)){ + return $this->json(3, '该文章信息不存在'); + } + if($sort == 'up'){ + $where = " sort > {$item['sort']} "; + $order = "sort asc"; + }else{ + $where = " sort < {$item['sort']} "; + $order = "sort desc"; + } + $forSortItems = MGift::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 MGift(); + $model->saveAll($updateData); + 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'); + $gift = MGift::getById($id); + if (empty($gift)) { + return $this->json(1, '该信息不存在!'); + } + if(!empty($img)){ + $item['img'] = $img; + } + try { + validate(VGift::class)->check($item); + $item['update_time'] = time(); + MGift::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + $id = input('param.id'); + $gift = MGift::getById($id); + $this->data['item'] = $gift; + return $this->view(); + } + } + + //添加 + public function add() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $img = input('post.img'); + + if(!empty($img)){ + $item['img'] = $img; + } + + try { + validate(VGift::class)->check($item); + MGift::create($item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + return $this->view(); + } + } +} diff --git a/app/controller/manager/Group.php b/app/controller/manager/Group.php new file mode 100644 index 0000000..af89259 --- /dev/null +++ b/app/controller/manager/Group.php @@ -0,0 +1,141 @@ +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(); + } +} diff --git a/app/controller/manager/Hall.php b/app/controller/manager/Hall.php new file mode 100644 index 0000000..39f1f53 --- /dev/null +++ b/app/controller/manager/Hall.php @@ -0,0 +1,167 @@ +data['list'] = $list; + $this->data['keyword'] = $keyword; + return $this->view(); + } + //删除 + public function del() + { + if ($this->request->isPost()) { + $id = input('post.id/d'); + if(is_numeric($id) && $id > 0) { + $item = MHall::getById($id); + if(!empty($item)){ + MHall::destroy($id); + 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 = MHall::getById($id); + if(empty($item)){ + return $this->json(3, '该文章信息不存在'); + } + if($sort == 'up'){ + $where = " sort > {$item['sort']} "; + $order = "sort asc"; + }else{ + $where = " sort < {$item['sort']} "; + $order = "sort desc"; + } + $forSortItems = MHall::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 MHall(); + $model->saveAll($updateData); + 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'); + $imgs = input('post.imgs/a'); + + + if(!empty($img)){ + $item['img'] = $img; + } + + if(!empty($imgs)){ + $item['imgs'] = json_encode($imgs); + } + + $id = input('post.id/d'); + $gift = MHall::getById($id); + if (empty($gift)) { + return $this->json(1, '该信息不存在!'); + } + + try { + validate(VHall::class)->check($item); + $item['update_time'] = time(); + MHall::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + $id = input('param.id'); + $gift = MHall::getById($id); + $this->data['item'] = $gift; + $this->data['hall_layout'] = HallLayout::getAll(); + return $this->view(); + } + } + + //添加 + public function add() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $img = input('post.img'); + $imgs = input('post.imgs/a'); + + + + if(!empty($img)){ + $item['img'] = $img; + } + if(!empty($imgs)){ + $item['imgs'] = $imgs; + } + try { + validate(VHall::class)->check($item); + MHall::create($item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + $this->data['hall_layout'] = HallLayout::getAll(); + return $this->view(); + } + } +} diff --git a/app/controller/manager/HallLayout.php b/app/controller/manager/HallLayout.php new file mode 100644 index 0000000..c91aaeb --- /dev/null +++ b/app/controller/manager/HallLayout.php @@ -0,0 +1,153 @@ +data['list'] = $list; + $this->data['keyword'] = $keyword; + return $this->view(); + } + //删除 + public function del() + { + if ($this->request->isPost()) { + $id = input('post.id/d'); + if(is_numeric($id) && $id > 0) { + $item = MHallLayout::getById($id); + if(!empty($item)){ + MHallLayout::destroy($id); + 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 = MHallLayout::getById($id); + if(empty($item)){ + return $this->json(3, '该文章信息不存在'); + } + if($sort == 'up'){ + $where = " sort > {$item['sort']} "; + $order = "sort asc"; + }else{ + $where = " sort < {$item['sort']} "; + $order = "sort desc"; + } + $forSortItems = MHallLayout::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 MHallLayout(); + $model->saveAll($updateData); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->json(1, '非法请求!'); + } + + //编辑 + public function edit() + { + if($this->request->isPost()){ + + $item = input('post.item/a'); + $imglayout = input('post.img'); + + if(!empty($imglayout)){ + $item['layout_img'] = $imglayout; + } + + $id = input('post.id/d'); + $gift = MHallLayout::getById($id); + if (empty($gift)) { + return $this->json(1, '该信息不存在!'); + } + + try { + validate(VHallLayout::class)->check($item); + $item['update_time'] = time(); + MHallLayout::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + $id = input('param.id'); + $gift = MHallLayout::getById($id); + $this->data['item'] = $gift; + return $this->view(); + } + } + + //添加 + public function add() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + + $imglayout = input('post.img'); + + if(!empty($imglayout)){ + $item['layout_img'] = $imglayout; + } + try { + validate(VHallLayout::class)->check($item); + MHallLayout::create($item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + }else{ + return $this->view(); + } + } +} diff --git a/app/controller/manager/History.php b/app/controller/manager/History.php new file mode 100644 index 0000000..7968c48 --- /dev/null +++ b/app/controller/manager/History.php @@ -0,0 +1,345 @@ +isPost()) { + $params = input('post.item/a', []); + $params = arrayHtmlFilter($params); + try { + validate(VHistory::class)->check($params); + $data = [ + 'title' => $params['title'], + 'visible' => $params['visible'], + 'category_id' => $params['category_id'], + ]; + $newItem = MHistory::create($data); + MLog::write('history', 'add', '新增发展历程,ID:'.$newItem->id); + } catch (ValidateException $e) { + return $this->json(1, $e->getError()); + } + return $this->json(); + } else { + $categoryId = input('param.category_id/d', 0); + $category = MCategory::getById($categoryId); + $this->data['category'] = $category; + return $this->view(); + } + } + + public function edit() + { + $id = input('param.id/d', 0); + $item = MHistory::getById($id); + if(count($item) == 0) { + return $this->json(1, '该历程信息不存在'); + } + if(request()->isPost()) { + $params = input('post.item/a', []); + $params = arrayHtmlFilter($params); + try { + validate(VHistory::class)->check($params); + $data = [ + 'title' => $params['title'], + 'visible' => $params['visible'], + ]; + MHistory::updateById($id, $data); + MLog::write('history', 'edit', '修改发展历程,ID:'.$id); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + return $this->json(); + } else { + $this->data['item'] = $item; + return $this->view(); + } + } + + public function sort() + { + if(request()->isPost()) { + $id = input('post.id/d'); + $sort = input('post.sort'); + $num = input('post.num/d', 1); + if($num <= 0){ + $num = 1; + } + if(!in_array($sort, ['up', 'down'], true)){ + return $this->json(2, '参数错误'); + } + $item = MHistory::getById($id); + if(empty($item)){ + return $this->json(3, '该历程信息不存在'); + } + if($sort == 'up'){ + $where = "category_id='{$item['category_id']}' and sort < {$item['sort']}"; + $order = "sort desc"; + }else{ + $where = "category_id='{$item['category_id']}' and sort > {$item['sort']}"; + $order = "sort asc"; + } + $forSortItems = MHistory::getListByWhereAndOrder($where, $order, $num); + if(!empty($forSortItems)){ + $updateData = []; + $forSortCount = count($forSortItems); + for($i = 0; $i < $forSortCount; $i++){ + if($i == 0){ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $item['sort'] + ]; + }else{ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + } + } + $updateData[] = [ + 'id' => $item['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + if(!empty($updateData)){ + $model = new MHistory(); + $model->saveAll($updateData); + $sortStr = $sort == 'up' ? '上移' : '下调'; + MLog::write('history', 'sort', "发展历程排序,ID:{$id} ,{$sortStr}了{$num}位"); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->json(1, '无此操作'); + } + + // 删除历程和历程相关的事例 + public function del() + { + if(request()->isPost()) { + $historyId = input('param.id/d', 0); + $item = MHistory::getById($historyId); + if(count($item) == 0) { + return $this->json(2, '该历程信息不存在'); + } + Db::startTrans(); + try { + MHistory::destroy($historyId); + $hasInfo = MHistoryInfo::countByHistoryId($historyId); + if($hasInfo > 0) { + MHistoryInfo::delByHistoryId($historyId); + } + MLog::write('history','del', '删除历程,ID:'.$historyId); + Db::commit(); + } catch (\Exception $e) { + Db::rollback(); + return $this->json(3, '删除失败,'.$e->getMessage()); + } + return $this->json(); + } + return $this->json(1, '无此操作'); + } + + + public function info() + { + $historyId = input('param.history_id/d', 0); + $history = MHistory::getById($historyId); + $infoItems = []; + $categoryId = $history['category_id'] ?? 0; + if(count($history) > 0) { + $infoItems = MHistoryInfo::getByHistoryId($historyId); + } + $this->data['history'] = $history; + $this->data['categoryId'] = $categoryId; + $this->data['items'] = $infoItems; + return $this->view(); + } + + // 新增发展历程详情 + public function addInfo() + { + $historyId = input('param.history_id/d', 0); + $history = MHistory::getById($historyId); + if(count($history) == 0) { + return $this->json(1, '该历程信息不存在'); + } + if(request()->isPost()) { + $params = input('post.item/a', []); + $params = arrayHtmlFilter($params); + $imgs = input('post.img/a'); + if (!empty($imgs) && is_array($imgs)) { + $imgs = json_encode($imgs); + } else { + $imgs = ''; + } + try { + validate(VHistoryInfo::class)->check($params); + $data = [ + 'title' => $params['title'], + 'visible' => $params['visible'], + 'history_id' => $historyId, + 'imgs' => $imgs, + ]; + $newItem = MHistoryInfo::create($data); + MLog::write('history', 'addInfo', '新增发展历程事例,ID:'.$newItem->id); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + return $this->json(); + } else { + $imgSize = ''; + $category = MCategory::getById($history['category_id']); + if(count($category) > 0 && $category['img_width'] && $category['img_height']){ + $imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素'; + } + + $this->data['historyId'] = $historyId; + $this->data['history'] = $history; + $this->data['imgSize'] = $imgSize; + return $this->view(); + } + } + + // 编辑发展历程详情 + public function editInfo() + { + $id = input('param.id/d', 0); + $item = MHistoryInfo::getById($id); + if(count($item) == 0) { + return $this->json(1, '该历程事例信息不存在'); + } + + if(request()->isPost()) { + $params = input('post.item/a', []); + $params = arrayHtmlFilter($params); + $imgs = input('post.img/a'); + if (!empty($imgs) && is_array($imgs)) { + $imgs = json_encode($imgs); + } else { + $imgs = ''; + } + try { + validate(VHistoryInfo::class)->check($params); + $data = [ + 'title' => $params['title'], + 'visible' => $params['visible'], + 'imgs' => $imgs, + ]; + MHistoryInfo::updateById($id, $data); + MLog::write('history', 'editInfo', '修改发展历程事例,ID:'.$id); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + return $this->json(); + } else { + $history = MHistory::getById($item['history_id']); + $imgSize = ''; + if(count($history) > 0) { + $category = MCategory::getById($history['category_id']); + if(count($category) > 0 && $category['img_width'] && $category['img_height']){ + $imgSize = $category['img_width'] . '像素 X ' . $category['img_height'] . '像素'; + } + } + + $this->data['item'] = $item; + $this->data['imgSize'] = $imgSize; + return $this->view(); + } + } + + public function sortInfo() + { + if(request()->isPost()) { + $id = input('post.id/d'); + $sort = input('post.sort'); + $num = input('post.num/d', 1); + if($num <= 0){ + $num = 1; + } + if(!in_array($sort, ['up', 'down'], true)){ + return $this->json(2, '参数错误'); + } + $item = MHistoryInfo::getById($id); + if(empty($item)){ + return $this->json(3, '该历程事例信息不存在'); + } + if($sort == 'up'){ + $where = "history_id='{$item['history_id']}' and sort < {$item['sort']}"; + $order = "sort desc"; + }else{ + $where = "history_id='{$item['history_id']}' and sort > {$item['sort']}"; + $order = "sort asc"; + } + $forSortItems = MHistoryInfo::getListByWhereAndOrder($where, $order, $num); + if(!empty($forSortItems)){ + $updateData = []; + $forSortCount = count($forSortItems); + for($i = 0; $i < $forSortCount; $i++){ + if($i == 0){ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $item['sort'] + ]; + }else{ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + } + } + $updateData[] = [ + 'id' => $item['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + if(!empty($updateData)){ + $model = new MHistoryInfo(); + $model->saveAll($updateData); + $sortStr = $sort == 'up' ? '上移' : '下调'; + MLog::write('history', 'sortInfo', "发展历程事例排序,ID:{$id} ,{$sortStr}了{$num}位"); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->json(1, '无此操作'); + } + + public function delInfo() + { + if(request()->isPost()) { + $infoIds = []; + $ids = input('post.ids', []); + $id = input('post.id', 0); + if(!empty($ids)) { + if(is_array($ids)) { + $infoIds = $ids; + } else { + $infoIds = explode(',', $ids); + } + } elseif($id > 0) { + $infoIds[] = $id; + } + if(count($infoIds) > 0) { + MHistoryInfo::destroy($infoIds); + MLog::write('history','delInfo', '删除历程事例,IDs:'.implode(',', $infoIds)); + return $this->json(); + } + return $this->json(2, '参数错误'); + } + return $this->json(1, '无此操作'); + } +} \ No newline at end of file diff --git a/app/controller/manager/Index.php b/app/controller/manager/Index.php new file mode 100644 index 0000000..9a33dd7 --- /dev/null +++ b/app/controller/manager/Index.php @@ -0,0 +1,11 @@ +redirect(url('manager.safe/index')); + } +} diff --git a/app/controller/manager/InvitationTemplateClass.php b/app/controller/manager/InvitationTemplateClass.php new file mode 100644 index 0000000..222ba7d --- /dev/null +++ b/app/controller/manager/InvitationTemplateClass.php @@ -0,0 +1,159 @@ +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 = MInvitationTemplateClass::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 = MInvitationTemplateClass::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 MInvitationTemplateClass(); + $model->saveAll($updateData); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->json(1, '非法请求!'); + } + + /** + * 删除 + */ + public function del() + { + if ($this->request->isAjax()) { + $id = input('post.id/d'); + $item = MInvitationTemplateClass::getById($id); + if(empty($item)){ + return $this->json(1, '信息不存在'); + } + $children = MInvitationTemplateClass::getListByParentId($id); + if(!empty($children)){ + return $this->json(2, '当前权限有下级权限,不可删除'); + } + MInvitationTemplateClass::destroy($id); + return $this->json(); + } + return $this->json(1, '非法请求!'); + } + + /** + * 修改 + */ + public function edit() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $id = input('post.id'); + $InvitationTemplateClass = MInvitationTemplateClass::getById($id); + if(empty($InvitationTemplateClass)){ + return $this->json(1, '信息不存在'); + } + try { + validate(VMInvitationTemplateClass::class)->check($item); + MInvitationTemplateClass::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(3, $e->getError()); + } + } + $id = input('param.id/d'); + $InvitationTemplateClass = MInvitationTemplateClass::getById($id); + if(empty($InvitationTemplateClass)){ + return $this->json(1,'无此信息,请核对之后再操作!'); + }else{ + $this->data['item'] = $InvitationTemplateClass; + if($InvitationTemplateClass['parent_id'] > 0){ + $parent = MInvitationTemplateClass::getById($InvitationTemplateClass['parent_id']); + $this->data['parent'] = $parent; + } + return $this->view(); + } + } + + /** + * 添加 + */ + public function add() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + try { + validate(VMInvitationTemplateClass::class)->check($item); + + MInvitationTemplateClass::create($item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + } + $parentId = input('param.parent_id/d',0); + if($parentId > 0){ + $parent = MInvitationTemplateClass::getById($parentId); + $this->data['parent'] = $parent; + } + $this->data['parentId'] = $parentId; + return $this->view(); + } + + /** + * 列表(全部) + */ + public function index() + { + $list = MInvitationTemplateClass::getListTree(); + $this->data['items'] = $list; + return $this->view(); + } +} \ No newline at end of file diff --git a/app/controller/manager/Link.php b/app/controller/manager/Link.php new file mode 100644 index 0000000..4fcc969 --- /dev/null +++ b/app/controller/manager/Link.php @@ -0,0 +1,177 @@ +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(); + } +} diff --git a/app/controller/manager/Login.php b/app/controller/manager/Login.php new file mode 100644 index 0000000..17084e0 --- /dev/null +++ b/app/controller/manager/Login.php @@ -0,0 +1,75 @@ +isPost()){ + $username = trim(input('param.username')); + $password = trim(input('param.password')); + $loginUrl = url('manager.login/index'); + if(empty($username) || empty($password)){ + session('loginError','用户名和密码不能为空'); + return $this->redirect($loginUrl); + } + + $member = Member::getByUserName($username); + if(empty($member)){ + session('loginError','用户名错误'); + return $this->redirect($loginUrl); + } + if($member['password'] != md5($password)){ + session('loginError','用户密码错误'); + return $this->redirect($loginUrl); + + } + $rulesList = AuthRule::userRolesList($member['group_id']); + $rulesIdStr = ''; + if (!empty($rulesList)) { + $rulesId = $rulesList['allRulesId']; + $rulesIdStr = implode(',', $rulesId); + } + + $authSession = [ + 'userId' => $member['id'], + 'userName' => $member['username'], + 'groupId' => $member['group_id'], + 'rules' => $rulesIdStr, + 'cates' => $member['cates'] + ]; + + //记录最后登陆时间 + $ip = request()->ip(); + $time = time(); + Member::updateById($member['id'], [ + 'login_time' => $time, + 'login_ip' => $ip + ]); + LoginLog::create([ + 'member_id' => $member['id'], + 'name' => $member['username'], + 'ip' => $ip, + 'create_time' => $time + ]); + session('auth', $authSession); + return redirect(url('manager.index/index')); + } + + $viewData = []; + if(session('?loginError')) { + $viewData['error'] = session('loginError'); + } + session('loginError', null); + return view()->assign($viewData); + } +} diff --git a/app/controller/manager/Logout.php b/app/controller/manager/Logout.php new file mode 100644 index 0000000..6c7b25f --- /dev/null +++ b/app/controller/manager/Logout.php @@ -0,0 +1,13 @@ +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(); + } +} \ No newline at end of file diff --git a/app/controller/manager/Model.php b/app/controller/manager/Model.php new file mode 100644 index 0000000..3a112f3 --- /dev/null +++ b/app/controller/manager/Model.php @@ -0,0 +1,184 @@ +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, '非法请求!'); + } +} \ No newline at end of file diff --git a/app/controller/manager/Page.php b/app/controller/manager/Page.php new file mode 100644 index 0000000..276bb69 --- /dev/null +++ b/app/controller/manager/Page.php @@ -0,0 +1,471 @@ +request->isPost()){ + $item = input('post.item/a'); + $categoryId = input('post.category_id/d'); + $id = input('post.id/d'); + $item['keyword'] = Tool::trimSpace($item['keyword']); + try{ + validate(VBlock::class)->check($item); + if(empty($item['value'])){ + return $this->json(2, '内容不可为空!'); + } + $block = Block::getByKeyword($item['keyword'], $categoryId); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(3, '键值已存在,请更改键值'); + } + Block::updateById($id, $item); + Log::write('page', 'code', "单页代码编辑,ID:{$id}, 键值:{$item['keyword']}"); + }else{ + if($categoryId <= 0){ + return $this->json(4, '栏目参数错误!'); + } + if(!empty($block)){ + return $this->json(3, '键值已存在,请更改键值'); + } + $item['category_id'] = $categoryId; + $item['type'] = Block::CODE; + $block = Block::create($item); + Log::write('page', 'code', "单页代码新增,ID:{$block->id}, 键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此代码块!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + $this->data['categoryId'] = $categoryId; + return $this->view(); + } + } + //排序 + public function sort() + { + if($this->request->isPost()){ + $id = input('post.id/d'); + $sort = input('post.sort'); + $num = input('post.num/d', 1); + if($num <= 0){ + $num = 1; + } + if(!in_array($sort, ['up', 'down'], true)){ + return $this->json(2, '参数错误'); + } + $item = Block::getById($id); + if(empty($item)){ + return $this->json(3, '无此块信息'); + } + if($sort == 'up'){ + $where = "category_id='{$item['category_id']}' and sort < {$item['sort']}"; + $order = "sort desc"; + }else{ + $where = "category_id='{$item['category_id']}' and sort > {$item['sort']}"; + $order = "sort asc"; + } + $forSortItems = Block::getListByWhereAndOrder($where, $order, $num); + if(!empty($forSortItems)){ + $updateData = []; + $forSortCount = count($forSortItems); + for($i = 0; $i < $forSortCount; $i++){ + if($i == 0){ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $item['sort'] + ]; + }else{ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + } + } + $updateData[] = [ + 'id' => $item['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + if(!empty($updateData)){ + $model = new Block(); + $model->saveAll($updateData); + $sortStr = $sort == 'up' ? '上移' : '下调'; + Log::write('page', 'sort', "单页区块排序,ID:{$id} ,键值:{$item['keyword']},{$sortStr}了{$num}位"); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->error('无此操作'); + } + + //删除 + public function del() + { + if ($this->request->isAjax()) { + $id = input('post.id/d'); + $item = Block::getById($id); + if(!empty($item)){ + Block::destroy($id); + Log::write('page', 'del', "单页区块删除,ID:{$id} ,键值:{$item['keyword']}"); + return $this->json(); + } + return $this->json(1, 'fail'); + } + return $this->error('无此操作'); + } + //图片 + public function img() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $img = trim(input('post.img')); + $categoryId = input('post.category_id/d'); + if (!empty($img) && $img == 'null') { + $img = ''; + } + $id = input('post.id/d'); + $item['keyword'] = Tool::trimSpace($item['keyword']); + try{ + validate(VBlock::class)->check($item); + $block = Block::getByKeyword($item['keyword'], $categoryId); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(4, '键值已存在,请更改键值'); + } + if(!empty($img)){ + $item['value'] = $img; + } + Block::updateById($id, $item); + Log::write('page', 'img', "单页图片编辑,ID:{$id} ,键值:{$item['keyword']}"); + }else{ + if(!empty($block)){ + return $this->json(4, '键值已存在,请更改键值'); + } + if($categoryId <= 0){ + return $this->json(2, '栏目参数错误!!'); + } + if(empty($img)){ + return $this->json(3, '图片不可为空'); + } + $item['value'] = $img; + $item['type'] = Block::IMG; + $item['category_id'] = $categoryId; + $block = Block::create($item); + Log::write('page', 'img', "单页图片新增,ID:{$block->id} ,键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此图片!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + if(isset($item) && $item['width'] && $item['height']){ + $imgSize = $item['width'].'px X '.$item['height'].'px'; + }else{ + $imgSize = ''; + } + $this->data['categoryId'] = $categoryId; + $this->data['imgSize'] = $imgSize; + $this->data['groupId'] = session('auth.groupId'); + return $this->view(); + } + } + //文字块 + public function block() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $categoryId = input('post.category_id/d'); + $id = input('post.id/d'); + if(isset($item['keyword'])){ + $item['keyword'] = Tool::trimSpace($item['keyword']); + } + try{ + validate(VBlock::class)->check($item); + if(empty($item['value'])){ + return $this->json(1, '内容不可为空!'); + } + $block = Block::getByKeyword($item['keyword'], $categoryId); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(4, '键值已存在,请更改键值'); + } + Block::updateById($id, $item); + Log::write('page', 'block', "单页文字块编辑,ID:{$id} ,键值:{$item['keyword']}"); + }else{ + if($categoryId <= 0){ + return $this->json(2, '栏目参数错误!'); + } + if(!empty($block)){ + return $this->json(4, '键值已存在,请更改键值'); + } + $item['category_id'] = $categoryId; + $block = Block::create($item); + Log::write('page', 'block', "单页文字块新增,ID:{$block->id} ,键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此文字块!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + $this->data['categoryId'] = $categoryId; + return $this->view(); + } + } + //富文本内容 + public function text() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $categoryId = input('post.category_id/d'); + $item['keyword'] = Tool::trimSpace($item['keyword']); + try{ + validate(VBlock::class)->check($item); + if(empty($item['value'])){ + return $this->json(1, '内容不可为空!'); + } + $block = Block::getByKeyword($item['keyword'], $categoryId); + $id = input('post.id/d'); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(4, '键值已存在,请更改'); + } + Block::updateById($id, $item); + Log::write('page', 'text', "单页富文本编辑,ID:{$id} ,键值:{$item['keyword']}"); + }else{ + if($categoryId <= 0){ + return $this->json(2, '栏目参数错误!'); + } + if(!empty($block)){ + return $this->json(4, '键值已存在,请更改键值'); + } + $item['category_id'] = $categoryId; + $item['type'] = Block::TEXT; + $block = Block::create($item); + Log::write('page', 'text', "单页富文本新增,ID:{$block->id} ,键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此富文本!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + $this->data['categoryId'] = $categoryId; + return $this->view(); + } + } + //组图 + public function group() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + + $imgs = input('post.img/a'); + //halt($item); + $categoryId = input('post.category_id/d'); + if (!empty($imgs) && is_array($imgs)) { + $item['value'] = json_encode($imgs); + } else { + $item['value'] = ''; + } + $item['keyword'] = Tool::trimSpace($item['keyword']); + try{ + validate(VBlock::class)->check($item); + $block = Block::getByKeyword($item['keyword'], $categoryId); + $id = input('post.id/d'); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(4, '键值已存在,请更改'); + } + Block::updateById($id, $item); + Log::write('page', 'group', "单页组图编辑,ID:{$id} ,键值:{$item['keyword']}"); + }else{ + if($categoryId <= 0){ + return $this->json(2, '栏目参数错误!'); + } + if(!empty($block)){ + return $this->json(4, '键值已存在,请更改键值'); + } + $item['category_id'] = $categoryId; + $item['type'] = Block::GROUP; + $block = Block::create($item); + Log::write('page', 'group', "单页组图新增,ID:{$block->id} ,键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此组图!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + $this->data['categoryId'] = $categoryId; + if(isset($item) && $item['width'] && $item['height']){ + $imgSize = $item['width'].'px X '.$item['height'].'px'; + }else{ + $imgSize = ''; + } + $this->data['imgSize'] = $imgSize; + $this->data['groupId'] = session('auth.groupId'); + return $this->view(); + } + } + //视频 + public function video() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $img = trim(input('post.img')); + $video = trim(input('post.video')); + $categoryId = input('post.category_id/d'); + $item['keyword'] = Tool::trimSpace($item['keyword']); + try{ + validate(VBlock::class)->check($item); + $block = Block::getByKeyword($item['keyword'], $categoryId); + $id = input('post.id/d'); + if($id){ + if(!empty($block) && $block['id'] != $id){ + return $this->json(4, '键值已存在,请更改'); + } + if(!empty($img)){ + $item['img'] = $img; + } + if(!empty($video)){ + $item['value'] = $video; + } + Block::updateById($id, $item); + Log::write('page', 'video', "单页视频编辑,ID:{$id} ,键值:{$item['keyword']}"); + }else{ + if($categoryId <= 0){ + return $this->json(2, '栏目参数错误!'); + } + if(!empty($block)){ + return $this->json(3, '键值已存在,请更改键值'); + } + if(empty($video)){ + return $this->json(3, '视频不可为空'); + } + $item['category_id'] = $categoryId; + $item['type'] = Block::VIDEO; + $item['value'] = $video; + $item['img'] = $img; + $block = Block::create($item); + Log::write('page', 'video', "单页视频新增,ID:{$block->id} ,键值:{$item['keyword']}"); + } + return $this->json(); + } catch (ValidateException $e){ + return $this->json(1, $e->getError()); + } + }else{ + $id = input('param.id/d'); + if($id <= 0){ //添加 + $categoryId = input('param.category_id/d'); + $category = Category::getById($categoryId); + if(empty($category)){ + $url = url('manager.content/index')->__toString(); + return $this->error('无此栏目', $url); + } + }else{ //修改 + $item = Block::getById($id); + if(empty($item)){ + return $this->error('无此视频!'); + } + $categoryId = $item['category_id']; + $this->data['item'] = $item; + } + $this->data['categoryId'] = $categoryId; + if(isset($item) && $item['width'] && $item['height']){ + $imgSize = $item['width'].'px X '.$item['height'].'px'; + }else{ + $imgSize = ''; + } + $this->data['imgSize'] = $imgSize; + $this->data['groupId'] = session('auth.groupId'); + return $this->view(); + } + } +} \ No newline at end of file diff --git a/app/controller/manager/Rule.php b/app/controller/manager/Rule.php new file mode 100644 index 0000000..8b9d81b --- /dev/null +++ b/app/controller/manager/Rule.php @@ -0,0 +1,180 @@ +request->isAjax()) { + $id = input('post.id'); + $sort = input('post.sort'); + $num = input('post.num/d', 1); + if($num <= 0){ + $num = 1; + } + if(!in_array($sort, ['up', 'down'], true)){ + return $this->json(2, '参数错误'); + } + $item = AuthRule::getById($id); + if(empty($item)){ + return $this->json(3, '权限不存在'); + } + if($sort == 'up'){ + $where = "parent_id = {$item['parent_id']} and sort < {$item['sort']}"; + $order = "sort desc"; + }else{ + $where = "parent_id = {$item['parent_id']} and sort > {$item['sort']}"; + $order = "sort asc"; + } + $forSortItems = AuthRule::getListByWhereAndOrder($where, $order, $num); + if(!empty($forSortItems)){ + $updateData = []; + $forSortCount = count($forSortItems); + for($i = 0; $i < $forSortCount; $i++){ + if($i == 0){ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $item['sort'] + ]; + }else{ + $updateData[] = [ + 'id' => $forSortItems[$i]['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + } + } + $updateData[] = [ + 'id' => $item['id'], + 'sort' => $forSortItems[$i - 1]['sort'] + ]; + if(!empty($updateData)){ + $model = new AuthRule(); + $model->saveAll($updateData); + $sortStr = $sort == 'up' ? '上移' : '下调'; + Log::write('rule', 'sort', "权限排序,ID:{$id} ,标题:{$item['title']},{$sortStr}了{$num}位"); + return $this->json(); + } + } + return $this->json(4, '无须调整排序!'); + } + return $this->json(1, '非法请求!'); + } + + /** + * 权限删除 + */ + public function del() + { + if ($this->request->isAjax()) { + $id = input('post.id/d'); + $item = AuthRule::getById($id); + if(empty($item)){ + return $this->json(1, '无此权限'); + } + $children = AuthRule::getListByParentId($id); + if(!empty($children)){ + return $this->json(2, '当前权限有下级权限,不可删除'); + } + AuthRule::destroy($id); + AuthGroup::resetGroupRulesCache(); + Log::write('rule', 'del', "权限删除,ID:{$id}, 标题:{$item['title']}"); + return $this->json(); + } + return $this->json(1, '非法请求!'); + } + + /** + * 权限修改 + */ + public function edit() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + $id = input('post.id'); + $rule = AuthRule::getById($id); + if(empty($rule)){ + return $this->json(1, '请选择正确的权限'); + } + $rule2 = AuthRule::getByName($item['name']); + if(!empty($rule2) && $rule2['id'] != $id){ + return $this->json(2, '已存在相同权限['.$item['name'].']'); + } + try { + validate(VAuthRule::class)->check($item); + AuthRule::updateById($id, $item); + AuthGroup::resetGroupRulesCache(); + Log::write('rule', 'edit', "权限编辑,ID:{$id}, 标题:{$item['title']}"); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(3, $e->getError()); + } + } + $id = input('param.id/d'); + $rule = AuthRule::getById($id); + if(empty($rule)){ + return $this->json(1,'无此权限信息,请核对之后再操作!'); + }else{ + $this->data['item'] = $rule; + if($rule['parent_id'] > 0){ + $parent = AuthRule::getById($rule['parent_id']); + $this->data['parent'] = $parent; + } + return $this->view(); + } + } + + /** + * 权限添加 + */ + public function add() + { + if($this->request->isPost()){ + $item = input('post.item/a'); + try { + validate(VAuthRule::class)->check($item); + $rule = AuthRule::getByName($item['name']); + if(!empty($rule)){ + return $this->json(1, '已存在相同权限'); + } + $rule = AuthRule::create($item); + //基本权限的话需要重置所有已有角色权限缓存 + if ($item['is_base'] > 0) { + AuthGroup::resetGroupRulesCache(); + } else { + AuthGroup::resetGroupRulesCache(1); + } + Log::write('rule', 'add', "权限新增,ID:{$rule->id}, 标题:{$item['title']}"); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + } + $parentId = input('param.parent_id/d',0); + if($parentId > 0){ + $parent = AuthRule::getById($parentId); + $this->data['parent'] = $parent; + } + $this->data['parentId'] = $parentId; + return $this->view(); + } + + /** + * 权限列表(全部) + */ + public function index() + { + $list = AuthRule::getListTree(); + $this->data['items'] = $list; + return $this->view(); + } +} \ No newline at end of file diff --git a/app/controller/manager/Safe.php b/app/controller/manager/Safe.php new file mode 100644 index 0000000..c8f15a1 --- /dev/null +++ b/app/controller/manager/Safe.php @@ -0,0 +1,63 @@ +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(); + } + } +} \ No newline at end of file diff --git a/app/controller/manager/Slide.php b/app/controller/manager/Slide.php new file mode 100644 index 0000000..b5321a6 --- /dev/null +++ b/app/controller/manager/Slide.php @@ -0,0 +1,191 @@ +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(); + } +} diff --git a/app/controller/manager/Store.php b/app/controller/manager/Store.php new file mode 100644 index 0000000..064d9d8 --- /dev/null +++ b/app/controller/manager/Store.php @@ -0,0 +1,178 @@ +data['list'] = $list; + $this->data['keyword'] = $keyword; + $this->data['param'] = $param; + return $this->view(); + } + + //删除 + 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 = MStore::getById($id); + if (empty($item)) { + return $this->json(3, '该信息不存在'); + } + if ($sort == 'up') { + $where = "sort > {$item['sort']}"; + $order = "sort asc"; + } else { + $where = "sort < {$item['sort']}"; + $order = "sort desc"; + } + $forSortItems = MStore::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 MStore(); + $model->saveAll($updateData); + 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'); + $imgimgs = input('post.imgimgs'); + + $id = input('post.id/d'); + $article = MStore::getById($id); + if (empty($article)) { + return $this->json(1, '该门店不存在!'); + } + if (!empty($img)) { + $item['src'] = $img; + } + if (!empty($imgimgs)) { + $item['imgs'] = json_encode($imgimgs); + } + + try { + MStore::updateById($id, $item); + return $this->json(); + } catch (ValidateException $e) { + return $this->json(2, $e->getError()); + } + } else { + $id = input('param.id'); + $article = MStore::getById($id); + $category = Category::getById(MArticle::storeId); + 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'); + + $imgimgs = input('post.imgimgs'); + if (!empty($img)) { + $item['src'] = $img; + } + if (!empty($imgimgs)) { + $item['imgs'] = json_encode($imgimgs); + } + try { + validate(VStore::class)->check($item); + MStore::create($item); + 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(); + } + } +} diff --git a/app/controller/manager/System.php b/app/controller/manager/System.php new file mode 100644 index 0000000..db7b7cb --- /dev/null +++ b/app/controller/manager/System.php @@ -0,0 +1,78 @@ +request->isPost()) { + $item = input('post.item/a'); + $img = input('post.img'); + $imgwechat_img = input('post.imgwechat_img'); + $resume = input('post.fileresume'); + $clause = input('post.fileclause'); + $system = MSystem::getSystem(); + if (empty($system)) { + if (!empty($img)) { + $item['mark_img'] = $img; + } + if (!empty($imgwechat_img)) { + $item['wechat_img'] = $imgwechat_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; + } + if (!empty($resume)){ + $item['resume'] = $resume; + } + if (!empty($clause)){ + $item['clause'] = $clause; + } + if (!empty($imgwechat_img)) { + $item['wechat_img'] = $imgwechat_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(); + } +} diff --git a/app/controller/manager/Upload.php b/app/controller/manager/Upload.php new file mode 100644 index 0000000..7e4aaf5 --- /dev/null +++ b/app/controller/manager/Upload.php @@ -0,0 +1,139 @@ +isCompress = $system['compress']??true; + } + $this->validate = new VUpload(); + $this->uploadPath = Config::get('filesystem.disks.local.url'); + if(is_writable(app()->getRootPath() . 'public' . $this->uploadPath)){ + $this->uploadPathIsWritable = 1; + } + } + + //视频上传 + public function video() + { + if(!$this->uploadPathIsWritable){ + return $this->json(1, '上传文件夹需要写入权限'); + } + $video = request()->file('video'); + if($this->validate->checkVideo($video)){ + $src = Filesystem::disk('video')->putFile(date('Ymd'), $video, 'uniqid'); + $src = $this->uploadPath . '/' . $src; + $return['src'] = $src; + File::add($video, $src, 'video'); //加入上传文件表 + return $this->json(0, 'ok', $return); + }else{ + $errorMsg = Lang::get($this->validate->getError()); + return $this->json(1, $errorMsg); + } + } + + //文件上传(通用) + public function file() + { + $file = request()->file('file'); + if($this->validate->checkFile($file)){ + try{ + if(!$this->uploadPathIsWritable){ + throw new \Exception('上传文件夹需要写入权限'); + } + $src = Filesystem::putFile(date('Ymd'), $file, 'uniqid'); + $src = $this->uploadPath . '/' . $src; + $return['src'] = $src; + $return['name'] = $file->getOriginalName(); + File::add($file, $src, 'file'); //加入上传文件表 + } catch (\Exception $e) { + return $this->json(1, $e->getMessage()); + } + return $this->json(0,'ok',$return); + }else{ + $errorMsg = Lang::get($this->validate->getError()); + return $this->json(1, $errorMsg); + } + } + + //图片上传(通用) + public function image() + { + $image = request()->file('image'); + if($this->validate->checkImage($image)){ + try{ + if(!$this->uploadPathIsWritable){ + throw new \Exception('上传文件夹需要写入权限'); + } + $src = Filesystem::putFile(date('Ymd'), $image, 'uniqid'); + $src = $this->uploadPath . '/' . $src; + $suffix = strtolower($image->getOriginalExtension()); + if($suffix == 'gif'){ + $return['thumb_src'] = $src; //TODO获取GIF缩略图 + }else{ + $return['thumb_src'] = Image::getThumb($src, 100, 100, TImage::THUMB_SCALING); //上传返回缩略图宽度为100 + } + $return['src'] = $src; + if($this->isCompress){ + Image::resize($src); + } + File::add($image, $src); //加入上传文件表 + } catch (\Exception $e) { + return $this->json(1, $e->getMessage()); + } + return $this->json(0, 'ok', $return); + }else{ + $errorMsg = Lang::get($this->validate->getError()); + return $this->json(1, $errorMsg); + } + } + + //富文本编辑器商城图片 + public function wangImage() + { + + $imageArr = request()->file('wang_img'); // 该方式,前端js上传方法中字段名称必须以数组形式传参 如 wang_img[] = 值 + $errno = 0; + $data = []; + if(!$this->uploadPathIsWritable){ + $errno = 1; + $data[] = '上传文件夹需要写入权限'; + }else{ + foreach ($imageArr as $image) { + if($this->validate->checkImage($image)){ + $src = Filesystem::putFile(date('Ymd'), $image, 'uniqid'); + $src = $this->uploadPath . '/' . $src; + $data[] = $src; + if($this->isCompress){ + Image::resize($src); + } + File::add($image, $src); //加入上传文件表 + }else{ + $errno = 1; + $data = []; + $data[] = Lang::get($this->validate->getError()); + break; + } + } + } + + $return['errno'] = $errno; + $return['data'] = $data; + return json($return); + } +} \ No newline at end of file diff --git a/app/controller/manager/Wechat.php b/app/controller/manager/Wechat.php new file mode 100644 index 0000000..1bdb2f6 --- /dev/null +++ b/app/controller/manager/Wechat.php @@ -0,0 +1,27 @@ + [ + ], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [ + ], +]; diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 0000000..9994670 --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,10 @@ +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('无操作权限') ; + } + + } +} \ No newline at end of file diff --git a/app/middleware/Csrf.php b/app/middleware/Csrf.php new file mode 100644 index 0000000..054aec7 --- /dev/null +++ b/app/middleware/Csrf.php @@ -0,0 +1,55 @@ +isPost()){ + $check = $request->checkToken('__token__'); + if(false === $check) { + return $this->csrfError($request); + } + } + return $next($request); + } + + protected function csrfError($request, $msg = '非法请求, 用户身份认证失败!') + { + if($request->isAjax()) { + return json(['code' => 401, 'msg' => $msg], 200); + } else { + $referer = $_SERVER['HTTP_REFERER'] ?? null; + if (empty($referer)) { + $url = '/'; + } else { + $domain = $request->domain(); + $urlInfo = parse_url($referer); + $scheme = $urlInfo['scheme'] ?? ''; + $requestSrc = ''; + if (!empty($scheme)) { + $requestSrc = $scheme.'://'.($urlInfo['host'] ?? ''); + } + if($domain != $requestSrc) { + $url = '/'; + } else { + $url = 'javascript:history.back(-1);'; + } + } + $errorData = [ + 'code'=> 401, + 'msg' => $msg, + 'data' => [], + 'wait' => 5, + 'url' => $url + ]; + return view('error/400', $errorData); + // 返回401视图 response type has html、json、jsonp、xml、file、view、redirect + } + } +} \ No newline at end of file diff --git a/app/middleware/Token.php b/app/middleware/Token.php new file mode 100644 index 0000000..11ab1e7 --- /dev/null +++ b/app/middleware/Token.php @@ -0,0 +1,46 @@ + -1, + 'msg' => "未登录或登录过期", + 'time' => time(), + ]; + $allHeader = request()->header(); + $token = isset($allHeader["token"]) ? $allHeader["token"] : ""; + $userId = isset($allHeader["userid"]) ? (int)$allHeader["userid"] : 0; + $wechatToken = isset($allHeader["wechattoken"]) ? $allHeader["wechattoken"] : ""; + $openid = isset($allHeader["openid"]) ? $allHeader["openid"] : ""; + //先验证是否有小程序登录信息 + if ($wechatToken != "" && $openid != "") { + $wechatUserId = WeixinAccountMini::userTokenVerification($wechatToken, $openid); + //微信小程序登录过期或未登录 + if ($wechatUserId <= 0) { + $result["msg"] = "小程序登录已过期或未登录"; + return json($result); + } + } + + //验证平台账号是否登录 + if ($token != "" || $userId > 0) { + $IndexUserId = User::userTokenVerification($token, $userId); + if ($IndexUserId <= 0) { + $result["msg"] = "原账号登录已过期或未登录" /*. $token . "_" . $userId*/ + ; + return json($result); + } + return $next($request); + } + return json($result); + + } +} \ No newline at end of file diff --git a/app/model/Article.php b/app/model/Article.php new file mode 100644 index 0000000..b6a9165 --- /dev/null +++ b/app/model/Article.php @@ -0,0 +1,243 @@ +limit($limit) + ->select() + ->toArray(); + } + + //获取栏目下最新记录 + public static function getLatestByCategory($categoryId, $limit = 5) + { + if (empty($categoryId)) { + return []; + } + if ($limit <= 0) { + $limit = 5; + } + return self::where('category_id', $categoryId) + ->order('create_time', 'desc') + ->limit($limit) + ->select() + ->toArray(); + } + + //根据文章ID和栏目ID获取下一篇文章 + public static function getNextArticleByIdAndCategoryId($id, $categoryId) + { + return self::where('id', '<', $id) + ->where('category_id', $categoryId) + ->where('status', 1) + ->order('sort desc') + ->findOrEmpty() + ->toArray(); + } + + //根据文章ID和栏目ID获取上一篇文章 + public static function getPrevArticleByIdAndCategoryId($id, $categoryId) + { + return self::where('id', '>', $id) + ->where('category_id', $categoryId) + ->where('status', 1) + ->order('sort asc') + ->findOrEmpty() + ->toArray(); + } + + //根据栏目ID获取文章列表 + public static function getListByCategory($categoryId, $limit = 10) + { + return self::where('category_id', $categoryId) + ->where('status', 1) + ->order("sort desc") + ->limit($limit) + ->select() + ->toArray(); + } + + //根据栏目ID获取文章列表 + public static function getListByCategoryTop($categoryId, $limit = 10) + { + $where = [ + ["category_id", "=", $categoryId], + ["status", "=", 1], + ["top", "=", 1], + ]; + return self::where($where) + ->order("sort desc") + ->limit($limit) + ->select() + ->toArray(); + } + + public static function getNewsAllList($pageSize) + { + $where = [ + ["category_id", "in", self::newsChildrenIds] + ]; + return self::where($where) + ->order("sort desc") + ->paginate($pageSize, false); + } + + //根据栏目ID获取文章分页列表 + public static function getListPageByCategory($categoryId, $per = 20, $keyword = '') + { + $where = [ + ['category_id', '=', $categoryId], + ['status', '=', 1], + ]; + $param['category_id'] = $categoryId; + if ($keyword != '') { + $where[] = ['title', 'like', '%' . $keyword . '%']; + $param['keyword'] = $keyword; + } + $paginate = [ + 'list_rows' => $per, + 'query' => $param + ]; + return self::where($where) + ->order("sort desc") + ->paginate($paginate, false); + } + + //根据栏目ID获取文章分页列表 + public static function getListCount($categoryId) + { + $where = [ + ['category_id', '=', $categoryId], + ['status', '=', 1], + ]; + $param['category_id'] = $categoryId; + + return self::where($where) + ->order("sort desc") + ->count(); + } + + public static function onAfterInsert($article) + { + $article->sort = $article->id; + $article->create_time = $article->update_time = time(); + $auth = session('auth'); + $article->created = $article->updated = $auth['userName']; + $article->save(); + } + + /** + * 获取文章列表 + * @param $categoryId 分类ID + * @param int $per 每页数量 + * @param string $keyword 关键词 + * @param array $param 文章类型:置顶、热门、推荐 ['top','hot','recommend'] + * @param int $status 文章状态,-1表示不限制 + * @return \think\Paginator + * @throws \think\db\exception\DbException + */ + public static function getList($categoryId, $per = 20, $keyword = '', $param = [], $recommend_flag = '') + { + $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 (!empty($recommend_flag)) { + $whereMap[] = ['recommend_flag', '=', $recommend_flag]; + $pageParam['recommend_flag'] = $recommend_flag; + } + if (is_array($param) && count($param) > 0) { + $pageParam['param'] = $param; + foreach ($param as $vo) { + if (in_array($vo, ['top', 'hot', 'recommend'], true)) { + $whereMap[] = ["{$vo}", '=', 1]; + } + } + } + $paginate = [ + 'list_rows' => $per, + 'query' => $pageParam + ]; + return self::when(count($whereMap) > 0, function ($query) use ($whereMap) { + $query->where($whereMap); + }) + ->order("sort desc") + ->paginate($paginate, false); + } + + //获取文章涉及到的图片 + public static function getFilesInUse() + { + $items = self::select()->toArray(); + $data = []; + foreach ($items as $item) { + $src = trim($item['src']); + if (!empty($src)) { + $key = getKeyByPath($src); + $data[$key] = $src; + } + $imgs = getImageUrlFromText($item['content']); + if (!empty($imgs)) { + $data = array_merge($data, $imgs); + } + $videos = getVideoUrlFromText($item['content']); + if (!empty($videos)) { + $data = array_merge($data, $videos); + } + } + return $data; + } + + + //获取文章 + public static function getFinancingArticle($category_id = 0, $recommend_flag = '', $limit = 2) + { + $where = [ + ["category_id", "=", $category_id], + ["hot", "=", 1], + ["status", "=", "1"], + ]; + if (!empty($recommend_flag)) { + $where[] = ["recommend_flag", "=", $recommend_flag]; + } + return self::where($where)->limit($limit)->order("sort desc")->select()->toArray(); + } + + public static function getTopArticle($categoryId, $limit = 1) + { + $where = [ + ["top", "=", 1], + ["status", "=", "1"], + ]; + if (is_array($categoryId)) { + $where[] = ["category_id", "in", $categoryId]; + } else { + $where[] = ["category_id", "=", $categoryId]; + } + return self::where($where)->limit($limit)->order("sort desc")->select()->toArray(); + } + + public function setImgsAttr($value) + { + return json_encode($value); + } + +// ----------页面函数 + +} diff --git a/app/model/AuthGroup.php b/app/model/AuthGroup.php new file mode 100644 index 0000000..c69324f --- /dev/null +++ b/app/model/AuthGroup.php @@ -0,0 +1,54 @@ + $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); + } + } + } +} diff --git a/app/model/AuthRule.php b/app/model/AuthRule.php new file mode 100644 index 0000000..ad1e875 --- /dev/null +++ b/app/model/AuthRule.php @@ -0,0 +1,271 @@ +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; + } + +} diff --git a/app/model/Base.php b/app/model/Base.php new file mode 100644 index 0000000..250434a --- /dev/null +++ b/app/model/Base.php @@ -0,0 +1,41 @@ +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(); + } +} \ No newline at end of file diff --git a/app/model/Block.php b/app/model/Block.php new file mode 100644 index 0000000..3b9fbaa --- /dev/null +++ b/app/model/Block.php @@ -0,0 +1,113 @@ + '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; + } +} diff --git a/app/model/Category.php b/app/model/Category.php new file mode 100644 index 0000000..83ad6dd --- /dev/null +++ b/app/model/Category.php @@ -0,0 +1,306 @@ +findOrEmpty()->toArray(); + } + + //根据上级ID和语言获取下级栏目 + public static function getChildrenByParentId($parentId) + { + if ($parentId <= 0) { + return []; + } + $category = self::getById($parentId); + if (empty($category)) { + return []; + } + return self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.template, m.name as modelName') + ->where('c.parent_id', $parentId) + ->order('c.sort', 'asc') + ->select() + ->toArray(); + } + + //重写方法 + public static function getById($categoryId) + { + return self::alias('c') + ->leftJoin('model m', 'c.model_id = m.id') + ->where('c.id', $categoryId) + ->field('c.*, m.template') + ->findOrEmpty() + ->toArray(); + } + + //查看是否有下级栏目 + public static function hasChildren($categoryId) + { + if (is_array($categoryId)) { + $count = self::where('parent_id', 'in', $categoryId)->count(); + } else { + $count = self::where(['parent_id' => $categoryId])->count(); + } + return $count ? true : false; + } + + //获取前台菜单 + public static function getListForFrontMenu() + { + $items = self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.template') + ->where('c.state', 1) + ->order('is_index desc, sort asc') + ->select() + ->toArray(); + return self::getCates($items); + } + + /** + * 获取栏目 + * @param bool $limit 是否限制查询 + * @param array $cates 需要限制查询的栏目IDs + */ + public static function getList($limit = false, $cates = []) + { + if ($limit && empty($cates)) { + return []; + } + return self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.name as modelName') + ->when($limit, function ($query) use ($cates) { + $query->whereIn('c.id', $cates); + }) + ->order('sort', 'asc') + ->select() + ->toArray(); + } + + //获取栏目分级列表 + public static function getListTree($isMenu = false) + { + if ($isMenu) { + $items = self::where('c.state', 1)->order('sort', 'asc')->select()->toArray(); + } else { + $items = self::order('sort', 'asc')->select()->toArray(); + } + return self::getCates($items); + } + + //获取递归栏目 + public static function getCates($cates, $parentId = 0) + { + $menus = []; + foreach ($cates as $cate) { + if ($cate['parent_id'] == $parentId) { + $children = self::getCates($cates, $cate['id']); + if (!empty($children)) { + $cate['children'] = $children; + } + $menus[] = $cate; + } + } + return $menus; + } + + public static function onAfterInsert($category) + { + $category->sort = $category->id; + $category->save(); + } + + //递归获取栏目名称面包屑 + public static function getCatesCrumbs($currentId = 0) + { + $crumbs = []; + $category = self::getById($currentId); + if ($category) { + if ($category['parent_id'] != 0) { + $categoryIds = explode(',', trim($category['path'], ',')); + $categories = self::where('id', 'in', $categoryIds)->column('*', 'id'); + foreach ($categoryIds as $id) { + if (isset($categories[$id])) { + $crumbs[] = $categories[$id]['title']; + } + } + } + $crumbs[] = $category['title']; + } + return $crumbs; + } + + //获取栏目中涉及到的文件 + public static function getFilesInUse() + { + $items = self::select()->toArray(); + $data = []; + foreach ($items as $item) { + $src = trim($item['src']); + if (!empty($src)) { + $key = getKeyByPath($src); + $data[$key] = $src; + } + } + return $data; + } + + //当前分类的最高级分类Id + public static function firstGradeById($id) + { + $res = 0; + $item = self::getById($id); + if ($item) { + $res = $id; + if ($item['parent_id'] > 0) { + $items = self::select()->toArray(); + $first = self::getFirstGrade($items, $item['parent_id']); + if (!empty($first)) { + $res = $first['id']; + } + } + } + return $res; + } + + public static function getFirstGrade($items, $parentId) + { + $data = []; + foreach ($items as $key => $item) { + if ($item['id'] == $parentId) { + if ($item['parent_id'] > 0) { + unset($items[$key]); + $parent = self::getFirstGrade($items, $item['parent_id']); + if (!empty($parent)) { + $data = $parent; + } else { + $data = $item; + } + } else { + $data = $item; + } + } + } + return $data; + } + + public static function getFooterMenu() + { + $items = self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.template') + ->where('c.state', 1) + ->where('c.id', "in", self::footer_menu_ids) + ->whereOr('c.parent_id', "in", self::footer_menu_ids) + ->order('is_index desc, sort asc') + ->select() + ->toArray(); + return self::getCates($items); + } + + public static function getChildrenIds($parentId) + { + return self::where("parent_id", $parentId)->column("id"); + } + + //获取当前位置 + public static function getPosition($categoryId, $isIndex = true) + { + $position = ""; + $getFirstGrade = self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.template, m.name as modelName') + ->where("c.id", $categoryId) + ->find() + ->toArray(); + + if (!$getFirstGrade) return $position; + + $position = '' . $getFirstGrade["title"] . " " . $position; + if (!in_array($getFirstGrade["parent_id"], [0, 1])) { + $position = (self::getPosition($getFirstGrade["parent_id"], false) . $position); + } + return ($isIndex ? "首页" : "") . $position; + + } + + public static function getProductNewsChildrenIds() + { + return self::where("parent_id","in",[ + self::NewsId, + self::ProductCategoryId, + ])->column("id"); + } +// ----------web ------- + //关于市场 + public static function getAboutMarket() + { + $ids = self::where("parent_id", self::AboutMarketId)->column("id"); + return self::alias('c') + ->leftJoin('model m', 'c.model_id=m.id') + ->field('c.*, m.manager, m.template, m.name as modelName') + ->where('c.id', "in", $ids) + ->order('c.sort', 'asc') + ->select() + ->toArray(); + } + + //产品展示 + public static function getProduct() + { + 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', "=", self::ProductCategoryId) + ->order('c.sort', 'asc') + ->select() + ->toArray(); + } + + //水产供求 + public static function getAquaticSupplyAndDemand() + { + 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', "=", self::AquaticSupplyAndDemandId) + ->order('c.sort', 'asc') + ->select() + ->toArray(); + } + + //新闻 市场动态 + public static function getNews() + { + 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', "=", self::NewsId) + ->order('c.sort', 'asc') + ->select() + ->toArray(); + } +} diff --git a/app/model/Desk.php b/app/model/Desk.php new file mode 100644 index 0000000..4e16c0b --- /dev/null +++ b/app/model/Desk.php @@ -0,0 +1,92 @@ +"单人", + "2"=>"双人", + "3"=>"3人", + "4"=>"4人", + "5"=>"5人", + "6"=>"6人", + "7"=>"7人", + "8"=>"8人", + "9"=>"9人", + "10"=>"10人", + "12"=>"12人", + ]; + static $default_type = "12"; + + + + + + + + + + + + + + + + /** + * 获取文章列表 + * @param int $per 每页数量 + * @param string $keyword 关键词 + * @return \think\Paginator + * @throws \think\db\exception\DbException + */ + public static function getList( $per = 20, $keyword = '') + { + $whereMap = []; + $pageParam = []; + + if (!empty($keyword)) { + $whereMap[] = ['title', 'like', '%' . $keyword . '%']; + $pageParam['keyword'] = $keyword; + } + + $paginate = [ + 'list_rows' => $per, + 'query' => $pageParam + ]; + return self::when(count($whereMap) > 0, function ($query) use ($whereMap) { + $query->where($whereMap); + }) + ->order("number asc") + ->paginate($paginate, false); + } + + + public static function editRepeat($desk_id,$hall_id,$number) + { + $where=[ + ["id","<>",$desk_id], + ["hall_id","=",$hall_id], + ["number","=",$number], + ]; + return self::where($where) + ->findOrEmpty() + ->toArray(); + } + public static function addRepeat($hall_id,$number) + { + $where=[ + ["hall_id","=",$hall_id], + ["number","=",$number], + ]; + return self::where($where) + ->findOrEmpty() + ->toArray(); + } + + +} diff --git a/app/model/File.php b/app/model/File.php new file mode 100644 index 0000000..132e363 --- /dev/null +++ b/app/model/File.php @@ -0,0 +1,93 @@ + '图片', + '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(); + } +} diff --git a/app/model/Gift.php b/app/model/Gift.php new file mode 100644 index 0000000..67f19cc --- /dev/null +++ b/app/model/Gift.php @@ -0,0 +1,48 @@ +sort = $item->id; + $item->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( $per = 20, $keyword = '') + { + $whereMap = []; + $pageParam = []; + + if (!empty($keyword)) { + $whereMap[] = ['title', 'like', '%' . $keyword . '%']; + $pageParam['keyword'] = $keyword; + } + + $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); + } +// ----------页面函数 + +} diff --git a/app/model/Hall.php b/app/model/Hall.php new file mode 100644 index 0000000..7912397 --- /dev/null +++ b/app/model/Hall.php @@ -0,0 +1,51 @@ +sort = $item->id; + $item->save(); + } + + + + /** + * 获取列表 + * @param int $per 每页数量 + * @param string $keyword 关键词 + * @return \think\Paginator + * @throws \think\db\exception\DbException + */ + public static function getList( $per = 20, $keyword = '') + { + $whereMap = []; + $pageParam = []; + + if (!empty($keyword)) { + $whereMap[] = ['a.title', 'like', '%' . $keyword . '%']; + $pageParam['keyword'] = $keyword; + } + + $paginate = [ + 'list_rows' => $per, + 'query' => $pageParam + ]; + return self::alias("a")->join("hall_layout b","a.layout_id = b.id")->when(count($whereMap) > 0, function ($query) use ($whereMap) { + $query->where($whereMap); + }) + ->order("a.sort desc") + ->field('a.*,b.layout_img,b.title as layout_title') + ->paginate($paginate, false); + } + + public function setImgsAttr($name){ + return json_encode($name); + } + +} diff --git a/app/model/HallLayout.php b/app/model/HallLayout.php new file mode 100644 index 0000000..5752ead --- /dev/null +++ b/app/model/HallLayout.php @@ -0,0 +1,47 @@ +sort = $item->id; + $item->save(); + } + + /** + * 获取列表 + * @param int $per 每页数量 + * @param string $keyword 关键词 + * @return \think\Paginator + * @throws \think\db\exception\DbException + */ + public static function getList( $per = 20, $keyword = '') + { + $whereMap = []; + $pageParam = []; + + if (!empty($keyword)) { + $whereMap[] = ['title', 'like', '%' . $keyword . '%']; + $pageParam['keyword'] = $keyword; + } + + $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 getAll(){ + return self::select()->toArray(); + } +} diff --git a/app/model/History.php b/app/model/History.php new file mode 100644 index 0000000..681f5c8 --- /dev/null +++ b/app/model/History.php @@ -0,0 +1,45 @@ +sort = $item->id; + $item->save(); + } + + public static function getPaginateList($categoryId, $per = 20, $isSample = false) + { + $paginate = [ + 'list_rows' => $per + ]; + $items = self::where('category_id', $categoryId)->order('sort', 'asc')->paginate($paginate, $isSample); + if(!$items->isEmpty()) { + $ids = $items->column('id'); + $infoList = HistoryInfo::getByHistoryIds($ids); + foreach ($items as $k => $item) { + $items[$k]['info'] = $infoList[$item['id']] ?? []; + } + } + return $items; + } + + public static function getByCategoryId($categoryId, $onlyVisible = false) + { + $items = self::where('category_id', $categoryId) + ->when($onlyVisible, function($query){ + $query->where('visible', 1); + }) + ->order('sort', 'asc') + ->select(); + if(!$items->isEmpty()) { + $ids = $items->column('id'); + $infoList = HistoryInfo::getByHistoryIds($ids, $onlyVisible); + foreach ($items as $k => $item) { + $items[$k]['info'] = $infoList[$item['id']] ?? []; + } + } + return $items->toArray(); + } +} \ No newline at end of file diff --git a/app/model/HistoryInfo.php b/app/model/HistoryInfo.php new file mode 100644 index 0000000..dac20a7 --- /dev/null +++ b/app/model/HistoryInfo.php @@ -0,0 +1,52 @@ +sort = $item->id; + $item->save(); + } + + public static function getByHistoryIds($historyIds = [], $onlyVisible = false) + { + if(!is_array($historyIds) || count($historyIds) == 0) { + return []; + } + $list = self::whereIn('history_id', $historyIds) + ->when($onlyVisible, function ($query) { + $query->where('visible', 1); + }) + ->order(['history_id'=>'asc','sort'=>'asc']) + ->select() + ->toArray(); + $data = []; + foreach ($list as $item) { + $item['img_list'] = []; + if(!empty($item['imgs'])) { + $item['img_list'] = array_filter(explode(',', $item['imgs'])); + } + $data[$item['history_id']][] = $item; + } + return $data; + } + + public static function countByHistoryId($historyId) + { + return self::where('history_id', $historyId)->count(); + } + + public static function delByHistoryId($historyId) + { + return self::where('history_id', $historyId)->delete(); + } + + public static function getByHistoryId($historyId) + { + if($historyId <= 0) { + return []; + } + return self::where('history_id', $historyId)->order(['sort'=>'asc'])->select()->toArray(); + } +} \ No newline at end of file diff --git a/app/model/InvitationTemplateClass.php b/app/model/InvitationTemplateClass.php new file mode 100644 index 0000000..c489743 --- /dev/null +++ b/app/model/InvitationTemplateClass.php @@ -0,0 +1,141 @@ +order('sort', 'asc')->select()->toArray(); + }else{ + return self::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 onAfterInsert($rule) + { + $rule->sort = $rule->id; + $rule->save(); + } + + + /** + * 分组排序(不拆分为子集) + * + * @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; + } + + //根据上级ID获取下级列表 + public static function getListByParentId($parentId) + { + return self::where('parent_id', $parentId) + ->order('sort', 'asc') + ->select() + ->toArray(); + } + +} diff --git a/app/model/Link.php b/app/model/Link.php new file mode 100644 index 0000000..ab83ac0 --- /dev/null +++ b/app/model/Link.php @@ -0,0 +1,49 @@ +delete(); + } + + //获取友情链接 + public static function getList() + { + return self::order('sort desc') + ->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; + } + public static function getListNew($limit = 5){ + return self::order('sort desc') + ->limit($limit) + ->select() + ->toArray(); + } + public static function getListPage($limit = 5){ + return self::order("sort desc") + ->paginate($limit, false); + } +} diff --git a/app/model/Log.php b/app/model/Log.php new file mode 100644 index 0000000..7b8cbb1 --- /dev/null +++ b/app/model/Log.php @@ -0,0 +1,20 @@ + $auth['userId'], + 'name' => $auth['userName'], + 'ip' => request()->ip(), + 'create_time' => time(), + 'controller' => $controller, + 'action' => $action, + 'content' => $content + ]); + } +} \ No newline at end of file diff --git a/app/model/LoginLog.php b/app/model/LoginLog.php new file mode 100644 index 0000000..d120603 --- /dev/null +++ b/app/model/LoginLog.php @@ -0,0 +1,6 @@ +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); + } +} \ No newline at end of file diff --git a/app/model/Model.php b/app/model/Model.php new file mode 100644 index 0000000..7284e32 --- /dev/null +++ b/app/model/Model.php @@ -0,0 +1,18 @@ +select() + ->toArray(); + } + public static function onAfterInsert($model) + { + $model->sort = $model->id; + $model->save(); + } +} \ No newline at end of file diff --git a/app/model/Slide.php b/app/model/Slide.php new file mode 100644 index 0000000..b7cba5a --- /dev/null +++ b/app/model/Slide.php @@ -0,0 +1,43 @@ +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; + } +} diff --git a/app/model/Store.php b/app/model/Store.php new file mode 100644 index 0000000..5b52a7f --- /dev/null +++ b/app/model/Store.php @@ -0,0 +1,61 @@ + $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 onAfterInsert($article) + { + $article->sort = $article->id; + $article->create_time = time(); + $article->save(); + } + + + public static function getWebList() + { + $keyword = input("keyword/s"); + return self::when(!empty($keyword), function ($query) use ($keyword) { + $query->where("title|address", "like", "%" . $keyword . "%"); + }) + ->order("sort desc") + ->select() + ->withAttr("imgs", function ($name) { + $imgs = json_decode($name, true); + if (!empty($imgs)) { + $imgs = array_values($imgs); + return $imgs; + } + return []; + }) + ->toArray(); + } +} diff --git a/app/model/System.php b/app/model/System.php new file mode 100644 index 0000000..0c179c8 --- /dev/null +++ b/app/model/System.php @@ -0,0 +1,54 @@ + $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(); + } +} diff --git a/app/model/User.php b/app/model/User.php new file mode 100644 index 0000000..90af15a --- /dev/null +++ b/app/model/User.php @@ -0,0 +1,68 @@ +findOrEmpty()->toArray(); + } + + //更新用户信息 或添加用户信息 + public static function userLogin($data) + { + if (!empty($data['openid'])) { + $wechatUser = self::getByOpenid($data['openid']); + self::startTrans(); + try { + $time = time(); + if ($wechatUser) { + //更新用户微信信息 + $wechatUserId = $wechatUser['id']; + $data["token"] = md5($data["openid"] . $time . randomStr(1, 16)); + $data["token_close_time"] = $time + 86400 * 3; + $data["created_at"] = date('Y-m-d H:i:s', $time); + $data["login_ip"] =request()->ip(); + $data["last_login"] = date('Y-m-d H:i:s', $time); + self::where(["id" => ["=", $wechatUserId]])->update($data); + } else { + //新增用户信息 + $data["token"] = md5($data["openid"] . $time . randomStr(1, 16)); + $data["token_close_time"] = $time + (86400 * 3); + $data["created_at"] = date('Y-m-d H:i:s', $time); + $data["login_ip"] = request()->ip(); + $data["last_login"] = date('Y-m-d H:i:s', $time); + $data["username"] = "";//所属用户 + + self::insertGetId($data); + } + //提交事务 + self::commit(); + return json(["state" => "ok", "message" => "登录成功", "token" => $data["token"]]); + } catch (Exception $e) { + self::rollback(); + return json(["state" => "fail", "message" => "登录失败500"]); + } + } else { + return json(["state" => "fail"]); + } + } + + //验证当前用户登录状态 + static function userTokenVerification(string $token, string $openid) + { + $user = self::where([["openid", "=", $openid], ["token", "=", $token]])->field("id,token,token_close_time")->findOrEmpty(); + if ($user->isEmpty()) { + return []; + } + if (!$user["token"] || !($user["token_close_time"]) || $user["token_close_time"] < time()) { + return []; + } + return $user; + } +} diff --git a/app/service/File.php b/app/service/File.php new file mode 100644 index 0000000..4845cee --- /dev/null +++ b/app/service/File.php @@ -0,0 +1,17 @@ +getRootPath() . $upload_path; + $filename = uniqid() . '.' . $file->extension(); + $upload_filename = '/' . $upload_path . '/' . $filename; + return [$file->move($path, $filename), $file, $upload_filename]; + } +} \ No newline at end of file diff --git a/app/service/Image.php b/app/service/Image.php new file mode 100644 index 0000000..30e0161 --- /dev/null +++ b/app/service/Image.php @@ -0,0 +1,153 @@ +getRootPath() . 'public/' . ltrim($src, '/'); + if (is_file($realPath)) { + $img = TImage::open($realPath); + list($img_w, $img_h) = $img->size(); + if ($max > 0 && $img_w > $max) { + $img->thumb($max, $max * ($img_h / $img_w))->save($realPath); + } + } + } + +// public static function webResize($src, $width = 1920, $height = 500) +// { +// +// $realPath = app()->getRootPath() . 'public/' . ltrim($src, '/'); +// if (is_file($realPath)) { +// $img = TImage::open($realPath); +// list($img_w, $img_h) = $img->size(); +// if ($width > 0 && $img_w > $width) { +// $img->thumb($width, $width * ($img_h / $img_w))->save($realPath); +// } +// $ext = explode(".", $src); +// return $ext[0] . "_" . $width . "_" . $height . ".".$ext[1]; +// } +// return $src; +// } + + + /** + * 添加水印 + * milo + * 2018-01-17 + */ + public static function mark($src) + { + $rootPath = app()->getRootPath(); + if (!empty($src)) { + $system = System::getSystem(); + $realPath = $rootPath . 'public/' . ltrim($src, '/'); + if (is_file($realPath)) { + if ($system['is_mark']) { + $mark = $rootPath . ltrim($system['mark_img'], '/'); + if (is_file($mark)) { + $mark_position = $system['mark_position'] ?? 5; + $mark_opacity = $system['mark_opacity'] ?? 50; + $img = TImage::Open($realPath); + $img->water($mark, $mark_position, $mark_opacity)->save($realPath); + } + } + } + } + } + + //获取水印位置键值对 + public static function getMarkPosition() + { + return [ + "1" => '上左', + "2" => '上中', + "3" => '上右', + "4" => '中左', + "5" => '正中', + "6" => '中右', + "7" => '下左', + "8" => '下中', + "9" => '下右' + ]; + } + + /** + * 删除图片 + * milo + * 2018-01-15 + */ + public static function delImg($src) + { + if (!empty(trim($src))) { + $realPath = app()->getRootPath() . 'public/' . ltrim($src, '/'); + if (file_exists($realPath)) { + $info = pathinfo($realPath); + $source = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '*.' . $info['extension']; + foreach (glob($source) as $filename) { + if (is_file($filename)) { + unlink($filename); + } + } + clearstatcache();// 清除缓存 + } + + } + } + + /** + * 获取缩略图 + * milo + * 2019-10-24修改 + * 避免跨平台出错,目录分隔符全部转换为'/' + * app()->getRuntimePath() = app()->getRootPath().'runtime/当前应用模块(api)/' + */ + public static function getThumb($src, $width = 0, $height = 0, $type = TImage::THUMB_CENTER) + { + if (empty($src)) { + return ''; + } + $rootPath = app()->getRootPath(); + $realPath = $rootPath . 'public/' . ltrim($src, '/'); + $realPath = str_replace('\\', '/', $realPath); + if (!file_exists($realPath)) { + return ''; + } + $info = pathinfo($src); + if ($width <= 0 && $height <= 0) { //高宽都小于或等于0,则返回原图片 + return $src; + } + + $image = TImage::open($realPath); + list($imageWidth, $imageHeight) = $image->size(); + if ($width <= 0) { + $width = floor($height * ($imageWidth / $imageHeight)); + } elseif ($height <= 0) { + $height = floor($width * ($imageHeight / $imageWidth)); + } +// if ($width >= $imageWidth || $height >= $imageHeight) { +// return $src; +// } + + $thumbName = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '_' . $width . '_' . $height . '.' . $info['extension']; + $realThumbName = $rootPath . 'public/' . ltrim($thumbName, '/'); + $realThumbName = str_replace('\\', '/', $realThumbName); + if (!file_exists($realThumbName)) { + $image = TImage::open($realPath); + $image->thumb($width, $height, $type)->save($realThumbName); + } + + return str_replace('\\', '/', $thumbName); + } +} diff --git a/app/service/Layui.php b/app/service/Layui.php new file mode 100644 index 0000000..b53cfc6 --- /dev/null +++ b/app/service/Layui.php @@ -0,0 +1,202 @@ +currentPage() <= 1) { +// return ('
  • 上一页
  • '.$this->getDisabledTextWrapper($text,"prev")); + return ('
    '); + } + + $url = $this->url( + $this->currentPage() - 1 + ); + +// return ($this->getPageLinkWrapper($url, "上一页" ,"") .$this->getPageLinkWrapper($url, $text ,"prev")); + return ($this->getPageLinkWrapper($url, "" ,"prev")); + } + + /** + * 下一页按钮 + * @param string $text + * @return string + */ + protected function getNextButton(string $text = '>'): string + { + if (!$this->hasMore) { +// return ($this->getDisabledTextWrapper($text,"next").'
  • 下一页
  • '); + return ('
    '); + } + + $url = $this->url($this->currentPage() + 1); + + return ($this->getPageLinkWrapper($url, "",'next')) ; + } + + /** + * 页码按钮 + * @return string + */ + protected function getLinks(): string + { + if ($this->simple) { + return ''; + } + + $block = [ + 'first' => null, + 'slider' => null, + 'last' => null, + ]; + + $side = 3; + $window = $side * 2; + + if ($this->lastPage < $window + 6) { + $block['first'] = $this->getUrlRange(1, $this->lastPage); + } elseif ($this->currentPage <= $window) { + $block['first'] = $this->getUrlRange(1, $window + 2); + $block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage); + } elseif ($this->currentPage > ($this->lastPage - $window)) { + $block['first'] = $this->getUrlRange(1, 2); + $block['last'] = $this->getUrlRange($this->lastPage - ($window + 2), $this->lastPage); + } else { + $block['first'] = $this->getUrlRange(1, 2); + $block['slider'] = $this->getUrlRange($this->currentPage - $side, $this->currentPage + $side); + $block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage); + } + + $html = ''; + + if (is_array($block['first'])) { + $html .= $this->getUrlLinks($block['first']); + } + + if (is_array($block['slider'])) { + $html .= $this->getDots(); + $html .= $this->getUrlLinks($block['slider']); + } + + if (is_array($block['last'])) { + $html .= $this->getDots(); + $html .= $this->getUrlLinks($block['last']); + } + + return $html; + } + + /** + * 渲染分页html + * @return mixed + */ + public function render($linkStr='') + { + $this->linkStr=$linkStr; + if ($this->hasPages()) { + if ($this->simple) { + return sprintf( + '
      %s %s
    ', + $this->getPreviousButton(), + $this->getNextButton() + ); + } else { + return sprintf( + '
      %s %s %s
    ', + $this->getPreviousButton(), + $this->getLinks(), + $this->getNextButton() + ); + } + } + } + + /** + * 生成一个可点击的按钮 + * + * @param string $url + * @param string $page + * @return string + */ + protected function getAvailablePageWrapper(string $url, string $page,$class=""): string + { + return '
  • ' . $page . '
  • '; + } + + /** + * 生成一个禁用的按钮 + * + * @param string $text + * @return string + */ + protected function getDisabledTextWrapper(string $text,$class=""): string + { + return '
  • ' . $text . '
  • '; + } + + /** + * 生成一个激活的按钮 + * + * @param string $text + * @return string + */ + protected function getActivePageWrapper(string $text,$class=""): string + { +// return '
  • ' . $text . '
  • '; + return '
  • ' . $text . '
  • '; + } + + /** + * 生成省略号按钮 + * + * @return string + */ + protected function getDots(): string + { + return $this->getDisabledTextWrapper('...'); + } + + /** + * 批量生成页码按钮. + * + * @param array $urls + * @return string + */ + protected function getUrlLinks(array $urls): string + { + $html = ''; + + foreach ($urls as $page => $url) { + $html .= $this->getPageLinkWrapper($url, $page); + } + + return $html; + } + + /** + * 生成普通页码按钮 + * + * @param string $url + * @param string $page + * @return string + */ + protected function getPageLinkWrapper(string $url, string $page ,$class=""): string + { + if ($this->currentPage() == $page) { + return $this->getActivePageWrapper($page,'cur'); + } + + return $this->getAvailablePageWrapper($url, $page,$class); + } +} diff --git a/app/service/Page.php b/app/service/Page.php new file mode 100644 index 0000000..4088d6c --- /dev/null +++ b/app/service/Page.php @@ -0,0 +1,202 @@ +currentPage() <= 1) { +// return ('
  • 上一页
  • '.$this->getDisabledTextWrapper($text,"prev")); + return ('
    '); + } + + $url = $this->url( + $this->currentPage() - 1 + ); + +// return ($this->getPageLinkWrapper($url, "上一页" ,"") .$this->getPageLinkWrapper($url, $text ,"prev")); + return ($this->getPageLinkWrapper($url, "" ,"prve")); + } + + /** + * 下一页按钮 + * @param string $text + * @return string + */ + protected function getNextButton(string $text = '>'): string + { + if (!$this->hasMore) { +// return ($this->getDisabledTextWrapper($text,"next").'
  • 下一页
  • '); + return ('
    '); + } + + $url = $this->url($this->currentPage() + 1); + + return ($this->getPageLinkWrapper($url, "",'next')) ; + } + + /** + * 页码按钮 + * @return string + */ + protected function getLinks(): string + { + if ($this->simple) { + return ''; + } + + $block = [ + 'first' => null, + 'slider' => null, + 'last' => null, + ]; + + $side = 3; + $window = $side * 2; + + if ($this->lastPage < $window + 6) { + $block['first'] = $this->getUrlRange(1, $this->lastPage); + } elseif ($this->currentPage <= $window) { + $block['first'] = $this->getUrlRange(1, $window + 2); + $block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage); + } elseif ($this->currentPage > ($this->lastPage - $window)) { + $block['first'] = $this->getUrlRange(1, 2); + $block['last'] = $this->getUrlRange($this->lastPage - ($window + 2), $this->lastPage); + } else { + $block['first'] = $this->getUrlRange(1, 2); + $block['slider'] = $this->getUrlRange($this->currentPage - $side, $this->currentPage + $side); + $block['last'] = $this->getUrlRange($this->lastPage - 1, $this->lastPage); + } + + $html = ''; + + if (is_array($block['first'])) { + $html .= $this->getUrlLinks($block['first']); + } + + if (is_array($block['slider'])) { + $html .= $this->getDots(); + $html .= $this->getUrlLinks($block['slider']); + } + + if (is_array($block['last'])) { + $html .= $this->getDots(); + $html .= $this->getUrlLinks($block['last']); + } + + return $html; + } + + /** + * 渲染分页html + * @return mixed + */ + public function render($linkStr='') + { + $this->linkStr=$linkStr; + if ($this->hasPages()) { + if ($this->simple) { + return sprintf( + '
    %s %s
    ', + $this->getPreviousButton(), + $this->getNextButton() + ); + } else { + return sprintf( + '
    %s %s %s
    ', + $this->getPreviousButton(), + $this->getLinks(), + $this->getNextButton() + ); + } + } + } + + /** + * 生成一个可点击的按钮 + * + * @param string $url + * @param string $page + * @return string + */ + protected function getAvailablePageWrapper(string $url, string $page,$class=""): string + { + return '
  • ' . $page . '
  • '; + } + + /** + * 生成一个禁用的按钮 + * + * @param string $text + * @return string + */ + protected function getDisabledTextWrapper(string $text,$class=""): string + { + return '
  • ' . $text . '
  • '; + } + + /** + * 生成一个激活的按钮 + * + * @param string $text + * @return string + */ + protected function getActivePageWrapper(string $text,$class=""): string + { +// return '
  • ' . $text . '
  • '; + return '
  • ' . $text . '
  • '; + } + + /** + * 生成省略号按钮 + * + * @return string + */ + protected function getDots(): string + { + return $this->getDisabledTextWrapper('...'); + } + + /** + * 批量生成页码按钮. + * + * @param array $urls + * @return string + */ + protected function getUrlLinks(array $urls): string + { + $html = ''; + + foreach ($urls as $page => $url) { + $html .= $this->getPageLinkWrapper($url, $page); + } + + return $html; + } + + /** + * 生成普通页码按钮 + * + * @param string $url + * @param string $page + * @return string + */ + protected function getPageLinkWrapper(string $url, string $page ,$class=""): string + { + if ($this->currentPage() == $page) { + return $this->getActivePageWrapper($page,'cur'); + } + + return $this->getAvailablePageWrapper($url, $page,$class); + } +} diff --git a/app/service/Tool.php b/app/service/Tool.php new file mode 100644 index 0000000..b7c6b8d --- /dev/null +++ b/app/service/Tool.php @@ -0,0 +1,53 @@ +getRootPath() . ltrim($path, '/'); + if (file_exists($realPath)) { + $info = pathinfo($realPath); + $source = $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '*.' . $info['extension']; + foreach(glob($source) as $filename){ + if(is_file($filename)){ + unlink($filename); + } + } + clearstatcache();// 清除缓存 + } + } + } + + /** + * 删除目录下的所有文件和子目录 + * 调用完毕后请用clearstatcache()清理缓存 + */ + public static function removeByPath($path) + { + if(is_dir($path)) { + if($handle = @opendir($path)) { + while (($file = readdir($handle)) !== false){ + if($file != '.' && $file != '..') { + $child = $path.'/'.$file; + is_dir($child) ? self::removeByPath($child) : @unlink($child); + } + } + } + closedir($handle); + } elseif (is_file($path)) { + @unlink($path); + } else { + return false; + } + return true; + } + + //去除字符串空格 + public static function trimSpace($str) + { + return str_replace(' ', '', trim($str)); + } +} diff --git a/app/service/WechatMiniPay.php b/app/service/WechatMiniPay.php new file mode 100644 index 0000000..3bf3fc6 --- /dev/null +++ b/app/service/WechatMiniPay.php @@ -0,0 +1,121 @@ +WechatMiniPayConfig = config('wechat'); + } + + /** + * 微信小程序支付 + * @static + * @access public + * @param $order_number 订单号 + * @param $open_id 用户openid + * @param $total_fee 支付金额 + * @param $body 支付抬头 + * @param $attach 附加数据 + */ + public function dopay(string $order_number = "", + string $open_id = "", + float $total_fee = 0, + string $body = "充值", + string $attach = "充值" , + string $notify_url = "" + ) + { + if (!$order_number || !$open_id || !$total_fee || !$body || !$attach) { + return ["state" => "fail"]; + } +// 开始组建支付数据数组 + $data['param'] = []; + $data['param']['appid'] = $this->WechatMiniPayConfig["appId"]; + $data['param']['mch_id'] = $this->WechatMiniPayConfig["mchId"]; + $data['param']['nonce_str'] = randomStr(0, 16); + $data['param']['body'] = $body; + $data['param']['out_trade_no'] = $order_number;//商户下的唯一订单号 +// $data['param']['total_fee'] = $total_fee * 100; // 单位:分 + $data['param']['total_fee'] = 1; // 单位:分 + $data['param']['spbill_create_ip'] = request()->ip(); + $data['param']['notify_url'] = $notify_url; + $data['param']['trade_type'] = 'JSAPI';//支付方式 NATIVE表示二维码支付 +// $data['param']['product_id'] = $order["commodity_id"];//商品id 非必填 + $data['param']['attach'] = $attach;//附加数据 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。 + $data['param']['openid'] = $open_id;//用户openid + $data['param']['sign'] = wechatSign($data['param'], $this->WechatMiniPayConfig["mchKey"]); //key为商户平台设置的密钥key + + $pay_data = array_to_xml($data['param']); + + //请求支付 JSAPI 不会直接吊起支付请求 返回prepay_id是微信生成的预支付会话标识,用于后续接口调用中使用 + $result_data2 = Tool::httpRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", "post", $pay_data); + + $result_data = xmlToArray($result_data2); + + + //如果返回数据验证成功 + if (isset($result_data["prepay_id"]) && isset($result_data["result_code"]) && $result_data["return_code"] == "SUCCESS" && $result_data["result_code"] == "SUCCESS") { + $js_data = []; + $js_data["appId"] = $this->WechatMiniPayConfig["appId"]; + $js_data["timeStamp"] = (string)time(); + $js_data["nonceStr"] = $data['param']['nonce_str']; + $js_data["package"] = "prepay_id=" . $result_data["prepay_id"]; + $js_data["signType"] = "MD5"; + $js_data["paySign"] = wechatSign($js_data, $this->WechatMiniPayConfig["mchKey"]);; + return ["state" => "ok", "data" => $js_data]; + } else { + return (["state" => "fail", + "message" => "fail:" . + (isset($result_data["err_code_des"]) + ? + $result_data["err_code_des"] + : + '错误' + )]); + } + } + + /** + * 微信支付查询 + * @param $order_number 订单号 + */ + public function wechatQueryOrder($order_number = "") + { + if (empty($order_number)) { + return ["state" => "fail", "message" => "fail"]; + } + $data['param'] = []; + $data['param']['appid'] = $this->WechatMiniPayConfig["appId"]; + $data['param']['mch_id'] = $this->WechatMiniPayConfig["mchId"]; + $data['param']['nonce_str'] = randomStr(0, 16); + $data['param']['out_trade_no'] = $order_number;//商户下的唯一订单号 + $data['param']['sign'] = wechatSign($data['param'], $this->WechatMiniPayConfig["mchKey"]); //key为商户平台设置的密钥key + $xml = array_to_xml($data['param']); + $wechat_data = Tool::httpRequest("https://api.mch.weixin.qq.com/pay/orderquery", "post", $xml); + + $wechat_data = xmlToArray($wechat_data); + + if ($wechat_data["return_code"] == "SUCCESS") {// 通信标识 + + if ($wechat_data["result_code"] == "SUCCESS") {//业务标识 订单不存在或者微信服务器错误 + + if ($wechat_data["trade_state"] == "SUCCESS") {//如果支付成功 + + return array("state" => "ok", "queryData" => $wechat_data); + } + } + } + return array("state" => "fail"); + } + + +} \ No newline at end of file diff --git a/app/validate/Article.php b/app/validate/Article.php new file mode 100644 index 0000000..0fb6b0f --- /dev/null +++ b/app/validate/Article.php @@ -0,0 +1,16 @@ + 'require', + 'link' => 'url' + ]; + protected $message = [ + 'title.require' => '标题必须', + 'link.url' => '请填写有效的网址' + ]; +} \ No newline at end of file diff --git a/app/validate/AuthGroup.php b/app/validate/AuthGroup.php new file mode 100644 index 0000000..5a76315 --- /dev/null +++ b/app/validate/AuthGroup.php @@ -0,0 +1,17 @@ + 'require', + 'status' => 'require|number', + ]; + protected $message = [ + 'title.require' => '角色名称不能为空', + 'status.require' => '角色状态必须设置', + 'status.number' => '角色状态参数值只能为数字类型', + ]; +} \ No newline at end of file diff --git a/app/validate/AuthRule.php b/app/validate/AuthRule.php new file mode 100644 index 0000000..805afe7 --- /dev/null +++ b/app/validate/AuthRule.php @@ -0,0 +1,19 @@ + 'require', + 'name' => 'require', + 'status' =>'require|number', + ]; + protected $message = [ + 'title.require' => '名称必须', + 'name.require'=> '标识必须', + 'status.require'=> '显示状态必须传值', + 'status.number'=> '显示状态传值只能为数字表示', + ]; +} \ No newline at end of file diff --git a/app/validate/Block.php b/app/validate/Block.php new file mode 100644 index 0000000..7714738 --- /dev/null +++ b/app/validate/Block.php @@ -0,0 +1,16 @@ + 'require', + 'keyword' => 'require', + ]; + protected $message = [ + 'title.require' => '名称必须', + 'keyword.require' => '键值必须' + ]; +} \ No newline at end of file diff --git a/app/validate/Category.php b/app/validate/Category.php new file mode 100644 index 0000000..b3a1966 --- /dev/null +++ b/app/validate/Category.php @@ -0,0 +1,18 @@ + 'require', + 'model_id' => 'require|number|min:1', + ]; + protected $message = [ + 'title.require' => '栏目名称必须', + 'model_id.require' => '栏目模型必须', + 'model_id.number' => '栏目模型格式要正确', + 'model_id.min' => '请选择正确的栏目模型' + ]; +} \ No newline at end of file diff --git a/app/validate/Desk.php b/app/validate/Desk.php new file mode 100644 index 0000000..070f8f9 --- /dev/null +++ b/app/validate/Desk.php @@ -0,0 +1,15 @@ + 'require|integer|>:0', + 'number|乘坐人数' => 'require|integer|>:0', + 'type|类型' => 'require|integer|>:0', + ]; + protected $message = [ + ]; +} \ No newline at end of file diff --git a/app/validate/Gift.php b/app/validate/Gift.php new file mode 100644 index 0000000..0431977 --- /dev/null +++ b/app/validate/Gift.php @@ -0,0 +1,18 @@ + 'require', + 'img|图片' => 'require', + 'price|价格' => 'require|float|>:0', + 'inventory|库存' => 'require|integer|>:0' + ]; + protected $message = [ + 'title.require' => '标题必须', + 'img.require' => '图片必填' + ]; +} \ No newline at end of file diff --git a/app/validate/Hall.php b/app/validate/Hall.php new file mode 100644 index 0000000..6dd3ccf --- /dev/null +++ b/app/validate/Hall.php @@ -0,0 +1,17 @@ + 'require|length:1,255', + 'img|封面图片' => 'require', + 'imgs|组图' => 'require', + 'layout_id|布局' => 'require|integer|>:0', + ]; + protected $message = [ + 'title.require' => '标题必须', + ]; +} \ No newline at end of file diff --git a/app/validate/HallLayout.php b/app/validate/HallLayout.php new file mode 100644 index 0000000..dd047ed --- /dev/null +++ b/app/validate/HallLayout.php @@ -0,0 +1,15 @@ + 'require|length:1,255', + 'layout_img|布局图片' => 'require', + ]; + protected $message = [ + 'title.require' => '标题必须', + ]; +} \ No newline at end of file diff --git a/app/validate/History.php b/app/validate/History.php new file mode 100644 index 0000000..d7a05b8 --- /dev/null +++ b/app/validate/History.php @@ -0,0 +1,19 @@ + 'require|length:1,60', + 'visible' => 'require|in:0,1', + ]; + protected $message = [ + 'title.require' => '标题不能为空', + 'name.length' => '标题长度限制为60个字符以内', + 'visible.require' => '历程状态必须设置', + 'visible.in' => '状态参数错误', + ]; + +} \ No newline at end of file diff --git a/app/validate/HistoryInfo.php b/app/validate/HistoryInfo.php new file mode 100644 index 0000000..970f7e8 --- /dev/null +++ b/app/validate/HistoryInfo.php @@ -0,0 +1,19 @@ + 'require|length:1,200', + 'visible' => 'require|in:0,1', + ]; + protected $message = [ + 'title.require' => '标题不能为空', + 'name.length' => '标题长度限制为200个字符以内', + 'visible.require' => '历程事例状态必须设置', + 'visible.in' => '状态参数错误', + ]; + +} \ No newline at end of file diff --git a/app/validate/InvitationTemplateClass.php b/app/validate/InvitationTemplateClass.php new file mode 100644 index 0000000..b35f528 --- /dev/null +++ b/app/validate/InvitationTemplateClass.php @@ -0,0 +1,14 @@ + 'require', + ]; + protected $message = [ + 'title.require' => '名称必须', + ]; +} \ No newline at end of file diff --git a/app/validate/Link.php b/app/validate/Link.php new file mode 100644 index 0000000..4a78ce1 --- /dev/null +++ b/app/validate/Link.php @@ -0,0 +1,16 @@ + 'require', + 'url' => 'url', + ]; + protected $message = [ + 'title.require' => '名称必须', + 'url.url' => '请填写有效的网址,以http://或https://开头' + ]; +} \ No newline at end of file diff --git a/app/validate/Member.php b/app/validate/Member.php new file mode 100644 index 0000000..d3e7dc5 --- /dev/null +++ b/app/validate/Member.php @@ -0,0 +1,17 @@ + 'require|number', + 'username' => 'require', + ]; + protected $message = [ + 'group_id.require' => '所属角色不能为空!', + 'group_id.number' => '用户角色信息数据格式不正确!', + 'username.require' => '用户姓名不能为空!', + ]; +} \ No newline at end of file diff --git a/app/validate/Message.php b/app/validate/Message.php new file mode 100644 index 0000000..ad986c2 --- /dev/null +++ b/app/validate/Message.php @@ -0,0 +1,29 @@ + 'require|length:1,64', + 'tel|联系电话' => 'require|checkTel', + 'email|邮箱' => 'email', + 'content|留言内容' => 'length:1,120' + ]; + protected $message = [ + 'username.require' => '联系人不能为空', + 'tel' => '联系方式错误', + 'content.require' => '问题描述不能为空', + + ]; + // 自定义验证规则 + protected function checkTel($value, $rule, $data=[]) + { + if(preg_match("/^1[345789]\d{9}$/", $value)){ + return true ; + } + return false; + } + +} \ No newline at end of file diff --git a/app/validate/Model.php b/app/validate/Model.php new file mode 100644 index 0000000..d5d4be0 --- /dev/null +++ b/app/validate/Model.php @@ -0,0 +1,16 @@ + 'require', + 'manager' => 'require', + ]; + protected $message = [ + 'name.require' => '名称必须', + 'manager.require' => '后台管理必须' + ]; +} \ No newline at end of file diff --git a/app/validate/Slide.php b/app/validate/Slide.php new file mode 100644 index 0000000..8a5b0fa --- /dev/null +++ b/app/validate/Slide.php @@ -0,0 +1,16 @@ + 'require', + 'url' => 'url', + ]; + protected $message = [ + 'title.require' => '标题必须', + 'url.url' => '请填写有效的网址,以http://或https://开头' + ]; +} \ No newline at end of file diff --git a/app/validate/Store.php b/app/validate/Store.php new file mode 100644 index 0000000..c03cebb --- /dev/null +++ b/app/validate/Store.php @@ -0,0 +1,14 @@ + 'require', + ]; + protected $message = [ + 'title.require' => '标题必须', + ]; +} \ No newline at end of file diff --git a/app/validate/Upload.php b/app/validate/Upload.php new file mode 100644 index 0000000..b24601e --- /dev/null +++ b/app/validate/Upload.php @@ -0,0 +1,74 @@ +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]); + } + + //pdf上传 + public function checkPdf($pdf) + { + + $size = 3 * 1024 * 1024;//3M + $this->rule = [ + 'pdf' => [ + 'fileExt' => "pdf", + 'fileSize' => (int)$size + ] + ]; + return $this->check(['pdf' => $pdf]); + } + + //验证视频上传 + 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]); + } +} \ No newline at end of file diff --git a/app/validate/User.php b/app/validate/User.php new file mode 100644 index 0000000..b805102 --- /dev/null +++ b/app/validate/User.php @@ -0,0 +1,16 @@ + 'require', + 'headimgurl' => 'require', + 'nickname' => 'require', + ]; + protected $message = []; + +} \ No newline at end of file diff --git a/app/widget/Common.php b/app/widget/Common.php new file mode 100644 index 0000000..818f5cb --- /dev/null +++ b/app/widget/Common.php @@ -0,0 +1,18 @@ +data)->fetch('widget/common/'.$template); + } + + +} \ No newline at end of file diff --git a/app/widget/Crumbs.php b/app/widget/Crumbs.php new file mode 100644 index 0000000..45577ab --- /dev/null +++ b/app/widget/Crumbs.php @@ -0,0 +1,17 @@ + Category::getCatesCrumbs($categoryId) + ]; + return View::assign($data)->fetch('public/crumbs'); + } + +} \ No newline at end of file diff --git a/app/widget/Menu.php b/app/widget/Menu.php new file mode 100644 index 0000000..be2ebbb --- /dev/null +++ b/app/widget/Menu.php @@ -0,0 +1,22 @@ + $categoryId, + 'menus' => $menus, + ]; + return View::assign($data)->fetch('public/menu'); + } +} \ No newline at end of file diff --git a/app/widget/Slide.php b/app/widget/Slide.php new file mode 100644 index 0000000..77b2eee --- /dev/null +++ b/app/widget/Slide.php @@ -0,0 +1,16 @@ + WSlide::getList(), + ]; + return View::assign($data)->fetch('public/slide'); + } +} \ No newline at end of file diff --git a/app/widget/manager/Crumbs.php b/app/widget/manager/Crumbs.php new file mode 100644 index 0000000..91e2791 --- /dev/null +++ b/app/widget/manager/Crumbs.php @@ -0,0 +1,43 @@ +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'); + } +} \ No newline at end of file diff --git a/app/widget/manager/Menu.php b/app/widget/manager/Menu.php new file mode 100644 index 0000000..7b9fde6 --- /dev/null +++ b/app/widget/manager/Menu.php @@ -0,0 +1,90 @@ +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['admin_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; + } +} diff --git a/app/widget/manager/Upload.php b/app/widget/manager/Upload.php new file mode 100644 index 0000000..4eb6e6d --- /dev/null +++ b/app/widget/manager/Upload.php @@ -0,0 +1,71 @@ + $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($src = '', $num = 10, $append = '') + { +// if(!empty($files) && $files == 'null') { +// $files = []; +// } + $data = [ + 'src' => $src, + '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'); + } +} diff --git a/build.example.php b/build.example.php new file mode 100644 index 0000000..ab5c8ff --- /dev/null +++ b/build.example.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- + +/** + * php think build 自动生成应用的目录结构的定义示例 + */ +return [ + // 需要自动创建的文件 + '__file__' => [], + // 需要自动创建的目录 + '__dir__' => ['controller', 'model', 'view'], + // 需要自动创建的控制器 + 'controller' => ['Index'], + // 需要自动创建的模型 + 'model' => ['User'], + // 需要自动创建的模板 + 'view' => ['index/index'], +]; diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c0e9cb0 --- /dev/null +++ b/composer.json @@ -0,0 +1,48 @@ +{ + "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", + "alibabacloud/client": "^1.5", + "phpoffice/phpspreadsheet": "^1.18" + }, + "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" + ] + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..787a51a --- /dev/null +++ b/composer.lock @@ -0,0 +1,2379 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "cc46256f2ffa4d59691ddfb4b2797d4e", + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "reference": "eee4fc81296531e6aafba4c2bbccfc5adab1676e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.0|^5.0|^6.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.x" + }, + "time": "2019-01-01T23:59:15+00:00" + }, + { + "name": "alibabacloud/client", + "version": "1.5.31", + "source": { + "type": "git", + "url": "https://github.com/aliyun/openapi-sdk-php-client.git", + "reference": "19224d92fe27ab8ef501d77d4891e7660bc023c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/openapi-sdk-php-client/zipball/19224d92fe27ab8ef501d77d4891e7660bc023c1", + "reference": "19224d92fe27ab8ef501d77d4891e7660bc023c1", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.2", + "clagiordano/weblibs-configmanager": "^1.0", + "danielstjules/stringy": "^3.1", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" + }, + "require-dev": { + "composer/composer": "^1.8", + "drupal/coder": "^8.3", + "ext-dom": "*", + "ext-pcre": "*", + "ext-sockets": "*", + "ext-spl": "*", + "league/climate": "^3.2.4", + "mikey179/vfsstream": "^1.6", + "monolog/monolog": "^1.24", + "phpunit/phpunit": "^5.7.27|^6.1", + "psr/cache": "^1.0", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "psr-4": { + "AlibabaCloud\\Client\\": "src" + }, + "files": [ + "src/Functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Alibaba Cloud Client for PHP - Use Alibaba Cloud in your PHP project", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibaba", + "alibabacloud", + "aliyun", + "client", + "cloud", + "library", + "sdk", + "tool" + ], + "support": { + "issues": "https://github.com/aliyun/openapi-sdk-php-client/issues", + "source": "https://github.com/aliyun/openapi-sdk-php-client" + }, + "time": "2021-05-13T06:26:38+00:00" + }, + { + "name": "clagiordano/weblibs-configmanager", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/clagiordano/weblibs-configmanager.git", + "reference": "8ff8bf195d0cbab9fe2ad3199c70920261300834" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clagiordano/weblibs-configmanager/zipball/8ff8bf195d0cbab9fe2ad3199c70920261300834", + "reference": "8ff8bf195d0cbab9fe2ad3199c70920261300834", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4", + "symfony/yaml": "^2.8" + }, + "require-dev": { + "clagiordano/phpunit-result-printer": "^1", + "php-coveralls/php-coveralls": "^1.1", + "phpunit/phpunit": "^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "clagiordano\\weblibs\\configmanager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Claudio Giordano", + "email": "claudio.giordano@autistici.org", + "role": "Developer" + } + ], + "description": "weblibs-configmanager is a tool library for easily read and access to php config array file and direct read/write configuration file / object", + "keywords": [ + "clagiordano", + "configuration", + "manager", + "tool", + "weblibs" + ], + "support": { + "issues": "https://github.com/clagiordano/weblibs-configmanager/issues", + "source": "https://github.com/clagiordano/weblibs-configmanager/tree/v1.4.0" + }, + "time": "2021-05-27T17:48:44+00:00" + }, + { + "name": "danielstjules/stringy", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "reference": "df24ab62d2d8213bbbe88cc36fc35a4503b4bd7e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stringy\\": "src/" + }, + "files": [ + "src/Create.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "description": "A string manipulation library with multibyte support", + "homepage": "https://github.com/danielstjules/Stringy", + "keywords": [ + "UTF", + "helpers", + "manipulation", + "methods", + "multibyte", + "string", + "utf-8", + "utility", + "utils" + ], + "support": { + "issues": "https://github.com/danielstjules/Stringy/issues", + "source": "https://github.com/danielstjules/Stringy" + }, + "time": "2017-06-12T01:10:27+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.13.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/master" + }, + "time": "2020-06-29T00:56:53+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7008573787b430c1c1f650e3722d9bba59967628" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", + "reference": "7008573787b430c1c1f650e3722d9bba59967628", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.7 || ^2.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.3-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://github.com/alexeyshockov", + "type": "github" + }, + { + "url": "https://github.com/gmponos", + "type": "github" + } + ], + "time": "2021-03-23T11:33:13+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.1" + }, + "time": "2021-03-07T09:25:29+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.2" + }, + "time": "2021-04-26T09:17:50+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.70", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "585824702f534f8d3cf7fab7225e8466cc4b7493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/585824702f534f8d3cf7fab7225e8466cc4b7493", + "reference": "585824702f534f8d3cf7fab7225e8466cc4b7493", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/phpspec": "^3.4 || ^4.0 || ^5.0 || ^6.0", + "phpunit/phpunit": "^5.7.26" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2020-07-26T07:20:36+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "time": "2020-07-25T15:56:04+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58", + "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58", + "shasum": "" + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": ">= 7.1", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "guzzlehttp/guzzle": ">= 6.3", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": ">= 7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/master" + }, + "funding": [ + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2020-05-30T13:11:16+00:00" + }, + { + "name": "markbaker/complex", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "6f724d7e04606fd8adaa4e3bb381c3e9db09c946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/6f724d7e04606fd8adaa4e3bb381c3e9db09c946", + "reference": "6f724d7e04606fd8adaa4e3bb381c3e9db09c946", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + }, + "files": [ + "classes/src/functions/abs.php", + "classes/src/functions/acos.php", + "classes/src/functions/acosh.php", + "classes/src/functions/acot.php", + "classes/src/functions/acoth.php", + "classes/src/functions/acsc.php", + "classes/src/functions/acsch.php", + "classes/src/functions/argument.php", + "classes/src/functions/asec.php", + "classes/src/functions/asech.php", + "classes/src/functions/asin.php", + "classes/src/functions/asinh.php", + "classes/src/functions/atan.php", + "classes/src/functions/atanh.php", + "classes/src/functions/conjugate.php", + "classes/src/functions/cos.php", + "classes/src/functions/cosh.php", + "classes/src/functions/cot.php", + "classes/src/functions/coth.php", + "classes/src/functions/csc.php", + "classes/src/functions/csch.php", + "classes/src/functions/exp.php", + "classes/src/functions/inverse.php", + "classes/src/functions/ln.php", + "classes/src/functions/log2.php", + "classes/src/functions/log10.php", + "classes/src/functions/negative.php", + "classes/src/functions/pow.php", + "classes/src/functions/rho.php", + "classes/src/functions/sec.php", + "classes/src/functions/sech.php", + "classes/src/functions/sin.php", + "classes/src/functions/sinh.php", + "classes/src/functions/sqrt.php", + "classes/src/functions/tan.php", + "classes/src/functions/tanh.php", + "classes/src/functions/theta.php", + "classes/src/operations/add.php", + "classes/src/operations/subtract.php", + "classes/src/operations/multiply.php", + "classes/src/operations/divideby.php", + "classes/src/operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/2.0.3" + }, + "time": "2021-06-02T09:44:11+00:00" + }, + { + "name": "markbaker/matrix", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "174395a901b5ba0925f1d790fa91bab531074b61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/174395a901b5ba0925f1d790fa91bab531074b61", + "reference": "174395a901b5ba0925f1d790fa91bab531074b61", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/php-compatibility": "^9.0", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + }, + "files": [ + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.3" + }, + "time": "2021-05-25T15:42:17+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" + }, + "time": "2021-06-14T00:11:39+00:00" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.3", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "b942d263c641ddb5190929ff840c68f78713e937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/b942d263c641ddb5190929ff840c68f78713e937", + "reference": "b942d263c641ddb5190929ff840c68f78713e937", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.3" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2021-07-05T08:18:36+00:00" + }, + { + "name": "opis/closure", + "version": "3.5.5", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "dec9fc5ecfca93f45cd6121f8e6f14457dff372c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/dec9fc5ecfca93f45cd6121f8e6f14457dff372c", + "reference": "dec9fc5ecfca93f45cd6121f8e6f14457dff372c", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "time": "2020-06-17T14:59:55+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.18.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "418cd304e8e6b417ea79c3b29126a25dc4b1170c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/418cd304e8e6b417ea79c3b29126a25dc4b1170c", + "reference": "418cd304e8e6b417ea79c3b29126a25dc4b1170c", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.13", + "maennchen/zipstream-php": "^2.1", + "markbaker/complex": "^2.0", + "markbaker/matrix": "^2.0", + "php": "^7.2 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "dompdf/dompdf": "^1.0", + "friendsofphp/php-cs-fixer": "^2.18", + "jpgraph/jpgraph": "^4.0", + "mpdf/mpdf": "^8.0", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^0.12.82", + "phpstan/phpstan-phpunit": "^0.12.18", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5", + "tecnickcom/tcpdf": "^6.3" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)", + "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.18.0" + }, + "time": "2021-05-31T18:21:15+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", + "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v2.8.52", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "02c1859112aa779d9ab394ae4f3381911d84052b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b", + "reference": "02c1859112aa779d9ab394ae4f3381911d84052b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v2.8.52" + }, + "time": "2018-11-11T11:18:13+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.0.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "b4046fb21e6163ba23a792b694162693dbe71b4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/b4046fb21e6163ba23a792b694162693dbe71b4b", + "reference": "b4046fb21e6163ba23a792b694162693dbe71b4b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "opis/closure": "^3.1", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "time": "2020-06-26T16:03:10+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.4", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/c28d37743bda4a0455286ca85b17b5791d626e10", + "reference": "c28d37743bda4a0455286ca85b17b5791d626e10", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "time": "2019-11-08T08:01:10+00:00" + }, + { + "name": "topthink/think-image", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-image.git", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-image/zipball/8586cf47f117481c6d415b20f7dedf62e79d5512", + "reference": "8586cf47f117481c6d415b20f7dedf62e79d5512", + "shasum": "" + }, + "require": { + "ext-gd": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "topthink/framework": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP5 Image Package", + "time": "2016-09-29T06:05:43+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.33", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "35ca511a1e4d671b39f7afb4c887703c16ef6957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/35ca511a1e4d671b39f7afb4c887703c16ef6957", + "reference": "35ca511a1e4d671b39f7afb4c887703c16ef6957", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "time": "2020-06-22T14:57:28+00:00" + }, + { + "name": "topthink/think-template", + "version": "v2.0.7", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-template.git", + "reference": "e98bdbb4a4c94b442f17dfceba81e0134d4fbd19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-template/zipball/e98bdbb4a4c94b442f17dfceba81e0134d4fbd19", + "reference": "e98bdbb4a4c94b442f17dfceba81e0134d4fbd19", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the php template engine", + "time": "2019-09-20T15:31:04+00:00" + }, + { + "name": "topthink/think-view", + "version": "v1.0.14", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-view.git", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp template driver", + "time": "2019-11-06T11:40:13+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-php72", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "639447d008615574653fb3bc60d1986d7172eaae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae", + "reference": "639447d008615574653fb3bc60d1986d7172eaae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.18.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-14T12:35:20+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "2125805a1a4e57f2340bc566c3013ca94d2722dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2125805a1a4e57f2340bc566c3013ca94d2722dc", + "reference": "2125805a1a4e57f2340bc566c3013ca94d2722dc", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-06-24T13:34:53+00:00" + }, + { + "name": "topthink/think-trace", + "version": "v1.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "d8da2e39df268ab8775013de699f0c3012e51318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/d8da2e39df268ab8775013de699f0c3012e51318", + "reference": "d8da2e39df268ab8775013de699f0c3012e51318", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "time": "2020-03-18T07:59:53+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.0" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..5397ebd --- /dev/null +++ b/config/app.php @@ -0,0 +1,40 @@ + 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, +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..800f0fc --- /dev/null +++ b/config/cache.php @@ -0,0 +1,30 @@ + Env::get('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 0000000..061c755 --- /dev/null +++ b/config/console.php @@ -0,0 +1,9 @@ + [ + ], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..ec465d9 --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,18 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..c9d1d37 --- /dev/null +++ b/config/database.php @@ -0,0 +1,63 @@ + 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', '211.149.245.223'), + // 数据库名 + 'database' => Env::get('database.database', 'qingjian_mini'), + // 用户名 + 'username' => Env::get('database.username', 'qingjian_mini'), + // 密码 + 'password' => Env::get('database.password', 'nsW22s6Pbnys5mxZ'), + // 端口 + 'hostport' => Env::get('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => Env::get('database.charset', 'utf8'), + // 数据库表前缀 + 'prefix' => Env::get('database.prefix', 'bee_'), + + // 数据库部署方式: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, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/extra/wechat.php b/config/extra/wechat.php new file mode 100644 index 0000000..3b79f5b --- /dev/null +++ b/config/extra/wechat.php @@ -0,0 +1,14 @@ + 'wxd88620c3f33f789a',//桔子 小程序 + 'appSecret' => 'b5b18862a5e605a2c2f861dada83abbd',//桔子 小程序 + 'mchId' => '1501627331',//桔子 商户号 + 'mchKey' => '9f7b7ae1ed2342d2fe1f517fb0ea5ed0',//商户号key //桔子 + 'notify_url' => '', + +// 'appId' => 'wxa02e44170bc722cd',//大向天诚 小程序 +// 'appSecret' => '062e5cf65bcbfddc2ffd9b9867fadb99',//大向天诚 小程序 + +// 'mchId' => '1605090111',//大向天诚 商户号 +// 'mchKey' => '1803d40793e61fadc1a71db146cd1f00',//商户号key //大向天诚 +); \ No newline at end of file diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..38e8c81 --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,52 @@ + Env::get('filesystem.driver', 'local'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + 'video' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + 'audio' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + 'backup' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage/backup', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage/backup', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..9d4ff9e --- /dev/null +++ b/config/lang.php @@ -0,0 +1,27 @@ + 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, +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..b35b7a8 --- /dev/null +++ b/config/log.php @@ -0,0 +1,46 @@ + 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, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..d90e1ee --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,12 @@ + [ + 'auth' => app\middleware\Auth::class, + 'csrf' => app\middleware\Csrf::class, + 'token' => app\middleware\Token::class, + ], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..d12c54d --- /dev/null +++ b/config/route.php @@ -0,0 +1,51 @@ + '/', + // 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', +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..6828f26 --- /dev/null +++ b/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间(秒) + 'expire' => 3600 * 2, + // 前缀 + 'prefix' => '', +]; diff --git a/config/trace.php b/config/trace.php new file mode 100644 index 0000000..0fd4b4c --- /dev/null +++ b/config/trace.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..046744d --- /dev/null +++ b/config/view.php @@ -0,0 +1,34 @@ + 'Think', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', + 'tpl_replace_string' => [ + '__STATIC__' => '/static', + '__MANAGER__' => '/static/manager', + '__COMMON__' => '/static/common', + '__JS__' => '/static/js', + '__CSS__' => '/static/css', + '__IMG__' => '/static/images', + '__IMAGE__' => '/static/image', + ], +]; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1107f52 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "cms", + "version": "1.0.0", + "lockfileVersion": 1 +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8907467 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "cms", + "version": "1.0.0", + "description": "本CMS基于ThinkPHP 6.0开发", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://gitee.com/dxtc/cms.git" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..37495b3 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,9 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_URI} !^(.*)\.(gif|jpg|jpeg|png|swf|mp4)$ [NC] + RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] + \ No newline at end of file diff --git a/public/.htaccess.bak b/public/.htaccess.bak new file mode 100644 index 0000000..37495b3 --- /dev/null +++ b/public/.htaccess.bak @@ -0,0 +1,9 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_URI} !^(.*)\.(gif|jpg|jpeg|png|swf|mp4)$ [NC] + RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] + \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..4124ea5 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..be9884e --- /dev/null +++ b/public/index.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +header("Access-Control-Allow-Origin:*"); +header('Access-Control-Allow-Methods:POST'); +header('Access-Control-Allow-Headers:x-requested-with, content-type'); +require dirname(__DIR__) . '/vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; +$response = $http->run(); +$response->send(); +$http->end($response); \ No newline at end of file diff --git a/public/static/common/jquery-3.4.1.min.js b/public/static/common/jquery-3.4.1.min.js new file mode 100644 index 0000000..409c3f4 --- /dev/null +++ b/public/static/common/jquery-3.4.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0