Commit f42a7ac8 authored by 于飞's avatar 于飞

初始化项目1.0

parent 6c19f847

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

{
"directory": "public/assets/libs",
"ignoredDependencies": [
"es6-promise",
"file-saver",
"html2canvas",
"jspdf",
"jspdf-autotable",
"pdfmake"
]
}
[app]
debug = false
trace = false
[database]
hostname = 127.0.0.1
database = fastadmin
username = root
password = root
hostport = 3306
prefix = fa_
This diff is collapsed.
FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。
## 主要特性
* 基于`Auth`验证的权限管理系统
* 支持无限级父子级权限继承,父级的管理员可任意增删改子级管理员及权限设置
* 支持单管理员多角色
* 支持管理子级数据或个人数据
* 强大的一键生成功能
* 一键生成CRUD,包括控制器、模型、视图、JS、语言包、菜单、回收站等
* 一键压缩打包JS和CSS文件,一键CDN静态资源部署
* 一键生成控制器菜单和规则
* 一键生成API接口文档
* 完善的前端功能组件开发
* 基于`AdminLTE`二次开发
* 基于`Bootstrap`开发,自适应手机、平板、PC
* 基于`RequireJS`进行JS模块管理,按需加载
* 基于`Less`进行样式开发
* 强大的插件扩展功能,在线安装卸载升级插件
* 通用的会员模块和API模块
* 共用同一账号体系的Web端会员中心权限验证和API接口会员权限验证
* 二级域名部署支持,同时域名支持绑定到应用插件
* 多语言支持,服务端及客户端支持
* 支持大文件分片上传、剪切板粘贴上传、拖拽上传,进度条显示,图片上传前压缩
* 支持表格固定列、固定表头、跨页选择、Excel导出、模板渲染等功能
* 强大的第三方应用模块支持([CMS](https://www.fastadmin.net/store/cms.html)[博客](https://www.fastadmin.net/store/blog.html)[知识付费问答](https://www.fastadmin.net/store/ask.html)[在线投票系统](https://www.fastadmin.net/store/vote.html)[B2C商城](https://www.fastadmin.net/store/shopro.html)[B2B2C商城](https://www.fastadmin.net/store/wanlshop.html))
* 支持CMS、博客、知识付费问答无缝整合[Xunsearch全文搜索](https://www.fastadmin.net/store/xunsearch.html)
* 第三方小程序支持([CMS小程序](https://www.fastadmin.net/store/cms.html)[预订小程序](https://www.fastadmin.net/store/ball.html)[问答小程序](https://www.fastadmin.net/store/ask.html)[点餐小程序](https://www.fastadmin.net/store/unidrink.html)[B2C小程序](https://www.fastadmin.net/store/shopro.html)[B2B2C小程序](https://www.fastadmin.net/store/wanlshop.html)[博客小程序](https://www.fastadmin.net/store/blog.html))
* 整合第三方短信接口(阿里云、腾讯云短信)
* 无缝整合第三方云存储(七牛云、阿里云OSS、又拍云)功能,支持云储存分片上传
* 第三方富文本编辑器支持(Summernote、Kindeditor、百度编辑器)
* 第三方登录(QQ、微信、微博)整合
* 第三方支付(微信、支付宝)无缝整合,微信支持PC端扫码支付
* 丰富的插件应用市场
## 安装使用
https://doc.fastadmin.net
## 在线演示
https://demo.fastadmin.net
用户名:admin
密 码:123456
提 示:演示站数据无法进行修改,请下载源码安装体验全部功能
## 界面截图
![控制台](https://images.gitee.com/uploads/images/2020/0929/202947_8db2d281_10933.gif "控制台")
## 问题反馈
在使用中有任何问题,请使用以下联系方式联系我们
交流社区: https://ask.fastadmin.net
Github: https://github.com/karsonzhang/fastadmin
Gitee: https://gitee.com/karson/fastadmin
## 特别鸣谢
感谢以下的项目,排名不分先后
ThinkPHP:http://www.thinkphp.cn
AdminLTE:https://adminlte.io
Bootstrap:http://getbootstrap.com
jQuery:http://jquery.com
Bootstrap-table:https://github.com/wenzhixin/bootstrap-table
Nice-validator: https://validator.niceue.com
SelectPage: https://github.com/TerryZ/SelectPage
Layer: https://layuion.com/layer/
DropzoneJS: https://www.dropzonejs.com
## 版权信息
FastAdmin遵循Apache2开源协议发布,并提供免费使用。
本项目包含的第三方源码和二进制文件之版权信息另行标注。
版权所有Copyright © 2017-2024 by FastAdmin (https://www.fastadmin.net)
All rights reserved。
This diff is collapsed.
<?php
namespace addons\cms;
use addons\cms\library\FulltextSearch;
use addons\cms\library\Service;
use addons\cms\model\Archives;
use addons\cms\model\Modelx;
use app\common\library\Auth;
use app\common\library\Menu;
use think\Addons;
use think\Config;
use think\Db;
use think\Loader;
use think\Request;
/**
* CMS插件
*/
class Cms extends Addons
{
/**
* 插件安装方法
* @return bool
*/
public function install()
{
$menu = include ADDON_PATH . 'cms' . DS . 'data' . DS . 'menu.php';
Menu::create($menu);
//首次安装测试数据
if (version_compare(config('fastadmin.version'), '1.3.0', '<') && Db::name("cms_model")->count() == 0) {
$this->importTestData();
}
return true;
}
/**
* 导入测试数据
*/
protected function importTestData()
{
$sqlFile = ADDON_PATH . 'cms' . DS . 'testdata.sql';
if (is_file($sqlFile)) {
$lines = file($sqlFile);
$templine = '';
foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || $line == '' || substr($line, 0, 2) == '/*') {
continue;
}
$templine .= $line;
if (substr(trim($line), -1, 1) == ';') {
$templine = str_ireplace('__PREFIX__', config('database.prefix'), $templine);
$templine = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $templine);
try {
Db::getPdo()->exec($templine);
} catch (\Exception $e) {
//$e->getMessage();
}
$templine = '';
}
}
}
return true;
}
/**
* 插件卸载方法
* @return bool
*/
public function uninstall()
{
Menu::delete('cms');
return true;
}
/**
* 插件启用方法
*/
public function enable()
{
Menu::enable('cms');
$prefix = Config::get('database.prefix');
// 1.4.0表字段升级
$modelList = Modelx::whereRaw("FIND_IN_SET('price', `fields`)")->select();
foreach ($modelList as $index => $item) {
Db::startTrans();
try {
//更新表数据
Db::execute("UPDATE {$prefix}cms_archives a,{$prefix}{$item['table']} e SET a.price = e.price WHERE a.id = e.id");
//更新表结构
$field = \app\admin\model\cms\Fields::where('source', 'model')->where('name', 'price')->where('source_id', $item['id'])->find();
if ($field) {
$field->delete();
}
Db::commit();
} catch (\Exception $e) {
Db::rollback();
}
}
}
/**
* 插件禁用方法
*/
public function disable()
{
Menu::disable('cms');
}
/**
* 插件升级方法
*/
public function upgrade()
{
$menu = include ADDON_PATH . 'cms' . DS . 'data' . DS . 'menu.php';
Menu::upgrade('cms', $menu);
}
/**
* 应用初始化
*/
public function appInit()
{
$config = get_addon_config('cms');
$hashids_key_length = $config['hashids_key_length'] ?? 10;
// 自定义路由变量规则
\think\Route::pattern([
'diyname' => "/[a-zA-Z0-9\-_\x{4e00}-\x{9fa5}]+/u",
'id' => "\d+",
'eid' => "\w{{$hashids_key_length}}",
]);
//添加命名空间
if (!class_exists('\Hashids\Hashids')) {
Loader::addNamespace('Hashids', ADDON_PATH . 'cms' . DS . 'library' . DS . 'hashids' . DS);
}
$taglib = Config::get('template.taglib_pre_load');
Config::set('template.taglib_pre_load', ($taglib ? $taglib . ',' : '') . 'addons\\cms\\taglib\\Cms');
Config::set('cms', $config);
}
/**
* 控制器方法请求
*/
public function actionBegin()
{
$request = request();
//判断是否后台请求CMS相关页面
if ($request->module() === 'admin' && preg_match("/^cms(\.|\/)/i", $request->controller())) {
Service::checkPublishArchives();
}
}
/**
* 脚本替换
*/
public function viewFilter(&$content)
{
$request = \think\Request::instance();
$dispatch = $request->dispatch();
if (!$dispatch) {
return;
}
if ($request->module() || !isset($dispatch['method'][0]) || $dispatch['method'][0] != '\think\addons\Route') {
return;
}
$addon = $dispatch['var']['addon'] ?? $request->param('addon');
if ($addon != 'cms') {
return;
}
$style = '';
$script = '';
$result = preg_replace_callback("/<(script|style)\s(data\-render=\"(script|style)\")([\s\S]*?)>([\s\S]*?)<\/(script|style)>/i", function ($match) use (&$style, &$script) {
if (isset($match[1]) && in_array($match[1], ['style', 'script'])) {
${$match[1]} .= str_replace($match[2], '', $match[0]);
}
return '';
}, $content);
$content = preg_replace_callback('/^\s+(\{__STYLE__\}|\{__SCRIPT__\})\s+$/m', function ($matches) use ($style, $script) {
return $matches[1] == '{__STYLE__}' ? $style : $script;
}, $result ? $result : $content);
}
/**
* 会员中心边栏后
* @return mixed
* @throws \Exception
*/
public function userSidenavAfter()
{
$request = Request::instance();
$controllername = strtolower($request->controller());
$actionname = strtolower($request->action());
$config = get_addon_config('cms');
$sidenav = array_filter(explode(',', $config['usersidenav']));
if (!$sidenav) {
return '';
}
$user = Auth::instance()->getUser();
$data = [
'user' => $user,
'controllername' => $controllername,
'actionname' => $actionname,
'sidenav' => $sidenav
];
return $this->fetch('view/hook/user_sidenav_after', $data);
}
public function xunsearchConfigInit()
{
return FulltextSearch::config();
}
public function xunsearchIndexReset($project)
{
if (!$project['isaddon'] || $project['name'] != 'cms') {
return;
}
return FulltextSearch::reset();
}
}
### 插件协议
在使用FastAdmin付费插件前认真阅读FastAdmin插件使用协议
https://www.fastadmin.net/page/addon-agreement.html
### 交流专区
如果你在使用CMS内容管理系统有遇到什么问题,请到FastAdmin交流专区进行交流
https://ask.fastadmin.net/zone/cms.html
### 温馨提示
此插件为FastAdmin的商业产品,禁止分享、转售、复制CMS插件源码给他人使用,违者将追究法律责任
require.config({
paths: {
'jquery-colorpicker': '../addons/cms/js/jquery.colorpicker.min',
'jquery-autocomplete': '../addons/cms/js/jquery.autocomplete',
'jquery-tagsinput': '../addons/cms/js/jquery.tagsinput',
'clipboard': '../addons/cms/js/clipboard.min',
},
shim: {
'jquery-colorpicker': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'jquery-autocomplete': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'jquery-tagsinput': {
deps: ['jquery', 'jquery-autocomplete', 'css!../addons/cms/css/jquery.tagsinput.min.css'],
exports: '$.fn.extend'
}
}
});
if (Config.modulename === 'admin') {
require(['table'], function (Table) {
Fast.api.getCustomFields = function (fields, table) {
var result = [];
$.each(fields, function (i, j) {
if (j.type === 'editor') {
return true;
}
var param = {field: j.field, title: j.title, table: table, operate: (j.type === 'number' ? '=' : 'like'), formatter: Table.api.formatter.content, class: 'autocontent'};
//如果是图片,加上formatter
if (j.type === 'image' || j.type === 'images') {
param.events = Table.api.events.image;
param.formatter = Table.api.formatter.images;
} else if (j.type === 'file' || j.type === 'files') {
param.formatter = Table.api.formatter.files;
} else if (j.type === 'radio' || j.type === 'checkbox' || j.type === 'select' || j.type === 'selects') {
param.formatter = Table.api.formatter.label;
param.extend = j.content;
param.searchList = j.content;
} else {
param.formatter = Table.api.formatter.content;
param.classname = 'autocontent';
}
result.push(param);
});
return result;
};
});
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<?php
namespace addons\cms\controller;
use addons\cms\model\Collection;
use addons\cms\model\Fields;
use fast\Tree;
use think\Config;
use think\Db;
/**
* Ajax控制器
* Class Ajax
* @package addons\cms\controller
*/
class Ajax extends Base
{
protected $noNeedLogin = ["share", "selectpage"];
public function selectpage()
{
$id = $this->request->get("id/d", 0);
$fieldInfo = Fields::get($id);
if (!$fieldInfo) {
$this->error("未找到指定字段");
}
$setting = $fieldInfo['setting'];
if (!$setting || !isset($setting['table'])) {
$this->error("字段配置不正确");
}
//搜索关键词,客户端输入以空格分开,这里接收为数组
$word = (array)$this->request->request("q_word/a");
//当前页
$page = $this->request->request("pageNumber");
//分页大小
$pagesize = $this->request->request("pageSize");
//搜索条件
$andor = $this->request->request("andOr", "and", "strtoupper");
//排序方式
$orderby = (array)$this->request->request("orderBy/a");
//显示的字段
//$field = $this->request->request("showField");
$field = $setting['field'];
//主键
//$primarykey = $this->request->request("keyField");
$primaryKey = $setting['primarykey'];
//主键值
$primaryValue = $this->request->request("keyValue");
//搜索字段
//$searchField = (array)$this->request->request("searchField/a");
$searchField = [$field, $primaryKey];
//自定义搜索条件
$custom = (array)$this->request->request("custom/a");
$custom = isset($setting['conditions']) ? (array)json_decode($setting['conditions'], true) : [];
$admin_id = session('admin.id') ?: 0;
$user_id = $this->auth->id ?: 0;
$field = $field ?: 'name';
//表字段
$dbFields = Db::table($setting['table'])->getTableFields();
if (!in_array($field, $dbFields)) {
$this->error("不存在的字段:" . $field);
}
if (!in_array($primaryKey, $dbFields)) {
$this->error("不存在的字段:" . $primaryKey);
}
//如果是管理员需要移除user_id筛选,否则会导致管理员无法筛选列表信息
$admin = $this->request->request("admin/d");
if ($admin_id && $admin) {
unset($custom['user_id']);
}
//是否返回树形结构
$isTree = $this->request->request("isTree", 0);
$isHtml = $this->request->request("isHtml", 0);
if ($isTree) {
$word = [];
$pagesize = 99999;
}
$order = [];
foreach ($orderby as $k => $v) {
if (!in_array($v[0], $dbFields)) {
$this->error("不存在的字段:" . $v[0]);
}
$order[$v[0]] = $v[1];
}
//如果有primaryvalue,说明当前是初始化传值
if ($primaryValue !== null) {
$where = [$primaryKey => ['in', $primaryValue]];
$where = function ($query) use ($primaryValue) {
$query->where('id', 'in', $primaryValue);
};
$pagesize = 99999;
} else {
$where = function ($query) use ($word, $andor, $field, $searchField) {
$logic = $andor == 'AND' ? '&' : '|';
$searchField = is_array($searchField) ? implode($logic, $searchField) : $searchField;
$word = array_filter($word);
if ($word) {
foreach ($word as $k => $v) {
$query->where(str_replace(',', $logic, $searchField), "LIKE", "%{$v}%");
}
}
};
}
//严格字段判断
$searchFields = [];
foreach ($custom as $index => $item) {
$searchFields[] = is_array($item) && isset($item['field']) ? $item['field'] : $index;
}
if ($searchFields) {
$remainFields = array_diff($searchFields, $dbFields);
if ($remainFields) {
$this->error("不存在的字段:" . implode(',', $remainFields));
}
}
//自定义搜索条件
$customWhere = function ($query) use ($custom, $admin_id, $user_id) {
if ($custom && is_array($custom)) {
//替换暂位符
$search = ["{admin_id}", "{user_id}"];
$replace = [$admin_id, $user_id];
foreach ($custom as $k => $v) {
//判断值是否为JSON数组
if (is_string($v) && preg_match("/^\[(.*)\,(.*)\]$/", $v)) {
$v = (array)json_decode($v, true);
}
if (is_array($v)) {
$replaceMap = function ($value) use ($search, $replace) {
return str_replace($search, $replace, $value);
};
if (isset($v['field'])) {
$v['value'] = is_array($v['value']) ? array_map($replaceMap, $v['value']) : str_replace($search, $replace, $v['value']);
$query->where($v['field'], $v['operate'], $v['value']);
} else {
$query->where($k, trim($v[0]), is_array($v[1]) ? array_map($replaceMap, $v[1]) : str_replace($search, $replace, $v[1]));
}
} else {
$query->where($k, '=', str_replace($search, $replace, $v));
}
}
}
};
$list = [];
$total = Db::table($setting['table'])->where($where)->where($customWhere)->count();
if ($total > 0) {
$datalist = Db::table($setting['table'])
->where($where)
->where($customWhere)
->order($order)
->page($page, $pagesize)
->field($primaryKey . "," . $field . ($isTree ? ",pid" : ""))
->select();
foreach ($datalist as $index => &$item) {
unset($item['password'], $item['salt']);
$list[] = [
$primaryKey => $item[$primaryKey] ?? '',
$field => $item[$field] ?? '',
'pid' => $item['pid'] ?? 0
];
}
if ($isTree && !$primaryValue) {
$tree = Tree::instance();
$tree->init($list, 'pid');
$list = $tree->getTreeList($tree->getTreeArray(0), $field);
if (!$isHtml) {
foreach ($list as &$item) {
$item = str_replace('&nbsp;', ' ', $item);
}
unset($item);
}
}
}
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]);
}
/**
* 添加收藏
*/
public function collection()
{
if (!$this->auth->isLogin()) {
$this->error("请登录后操作", "index/user/login");
}
$type = $this->request->post("type");
$aid = $this->request->post("aid/d");
if (!in_array($type, ['archives', 'page', 'special', 'diyform'])) {
$this->error("参数不正确");
}
$model = call_user_func_array(['\\addons\\cms\\model\\' . ucfirst($type), "get"], [$aid]);
if (!$model) {
$this->error("未找到指定数据");
}
Db::startTrans();
try {
$collection = Collection::lock(true)->where(['type' => $type, 'aid' => $aid, 'user_id' => $this->auth->id])->find();
if ($collection) {
throw new \think\Exception("请勿重复收藏");
}
$title = $model->title;
$url = $model->fullurl;
$image = $model->image;
$data = [
'user_id' => $this->auth->id,
'type' => $type,
'aid' => $aid,
'title' => $title,
'url' => $url,
'image' => $image
];
Collection::create($data);
Db::commit();
} catch (\think\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (\Exception $e) {
Db::rollback();
$this->error("收藏失败");
}
$this->success("收藏成功");
}
/**
* 微信公众号内分享
*/
public function share()
{
$url = $this->request->request("url", "", "trim");
$config = get_addon_config('third');
if (!$config) {
$this->error("请在后台插件管理安装配置《第三方登录》插件");
}
$js_sdk = new \addons\cms\library\Jssdk();
$data = $js_sdk->getSignedPackage($url);
$this->success('', '', $data);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use addons\cms\model\Archives;
use addons\cms\model\Channel;
use addons\cms\model\Diydata;
use addons\cms\model\Fields;
use addons\cms\model\Modelx;
use addons\cms\model\Page;
use addons\cms\model\Special;
use think\Config;
use think\Db;
use think\Exception;
use think\exception\PDOException;
/**
* Api接口控制器
*
* 仅限用于数据迁移或内部接口,不建议用于对接外部API接口
* Class Api
* @package addons\cms\controller
*/
class Api extends Base
{
public function _initialize()
{
Config::set('default_return_type', 'json');
$apikey = $this->request->post('apikey');
$config = get_addon_config('cms');
if (!$config['apikey']) {
$this->error('请先在后台配置API密钥');
}
if ($config['apikey'] != $apikey) {
$this->error('密钥不正确');
}
parent::_initialize();
}
/**
* 文档数据写入接口
*/
public function index()
{
// API接口默认使用xss_clean进行全局过滤
$data = $this->request->post('', null, 'trim,xss_clean');
if (isset($data['user']) && $data['user']) {
$user = \app\common\model\User::where('nickname', $data['user'])->find();
if ($user) {
$data['user_id'] = $user->id;
}
}
//如果有传栏目名称
if (isset($data['channel']) && $data['channel']) {
$channel = Channel::where('name', $data['channel'])->find();
if (!$channel || $channel['status'] != 'normal') {
$this->error('栏目未找到');
}
$data['channel_id'] = $channel->id;
unset($data['channel']);
} else {
$channel_id = $this->request->request('channel_id');
$channel = Channel::get($channel_id);
if (!$channel || $channel['status'] != 'normal') {
$this->error('栏目未找到');
}
}
$model = Modelx::get($channel['model_id']);
if (!$model) {
$this->error('模型未找到');
}
$data['model_id'] = $model['id'];
$data['publishtime'] = time();
$data['weigh'] = 0;
Db::startTrans();
try {
//副表数据插入会在模型事件中完成
$archives = new \app\admin\model\cms\Archives;
$archives->allowField(true)->save($data);
Db::commit();
$data = [
'id' => $archives->id,
'url' => $archives->fullurl
];
} catch (PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
$this->success('新增成功', '', $data);
}
/**
* 读取文章数据
*/
public function archives()
{
$id = $this->request->request("id/d");
$archives = Archives::get($id, ['channel']);
if (!$archives || $archives['status'] != 'normal' || $archives['deletetime']) {
$this->error("文章未找到");
}
$channel = Channel::get($archives['channel_id']);
if (!$channel) {
$this->error("栏目未找到");
}
$model = Modelx::get($channel['model_id'], [], true);
if (!$model) {
$this->error("文章模型未找到");
}
$addon = db($model['table'])->where('id', $archives['id'])->find();
if ($addon) {
if ($model->fields) {
Service::appendTextAndList('model', $model->id, $addon);
}
$archives->setData($addon);
} else {
$this->error('文章副表数据未找到');
}
$content = $archives->content;
//移除分页数据
$content = str_replace("##pagebreak##", "<br>", $content);
$archives->content = $content;
Service::appendTextAndList('archives', 0, $archives);
$this->success(__('读取成功'), '', $archives->toArray());
}
/**
* 读取文章列表
*/
public function arclist()
{
$params = [];
$model = (int)$this->request->request('model');
$channel = (int)$this->request->request('channel');
$page = (int)$this->request->request('page');
$pagesize = (int)$this->request->request('pagesize');
$tags = $this->request->request('tags');
$flag = $this->request->request('flag');
$special = (int)$this->request->request('special');
$pagesize = $pagesize ?: 10;
if ($model) {
$params['model'] = $model;
}
if ($channel) {
$channelInfo = Channel::get($channel);
if (!$channelInfo || $channelInfo['status'] != 'normal') {
$channel = -1;
}
$params['channel'] = $channel;
}
$page = max(1, $page);
$params['limit'] = ($page - 1) * $pagesize . ',' . $pagesize;
if ($tags) {
$params['tags'] = $tags;
}
if ($flag) {
$params['flag'] = $flag;
}
if ($special) {
$params['special'] = $special;
}
$list = Archives::getArchivesList($params);
$list = collection($list)->toArray();
foreach ($list as $index => &$item) {
$item['url'] = $item['fullurl'];
unset($item['imglink'], $item['textlink'], $item['channellink'], $item['taglist'], $item['weigh'], $item['status'], $item['deletetime'], $item['memo'], $item['img']);
}
$this->success('读取成功', '', $list);
}
/**
* 获取栏目列表
*/
public function channel()
{
$channelList = Channel::where('status', 'normal')
->where('type', 'list')
->order('weigh DESC,id DESC')
->column('id,name');
Service::appendTextAndList('channel', 0, $channelList, true);
$this->success(__('读取成功'), '', $channelList);
}
/**
* 评论数据写入接口
*/
public function comment()
{
try {
$params = $this->request->post();
$params['status'] = $params['status'] ?? 'hidden';
$model = new \addons\cms\model\Comment();
$model->allowField(true)->save($params);
$archives = $params['type'] == 'archives' ? Archives::get($params['aid']) : ($params['type'] == 'special' ? Special::get($params['aid']) : Page::get($params['aid']));
//评论状态正常则增加统计
if ($params['status'] == 'normal') {
$archives->setInc('comments');
}
Db::commit();
} catch (Exception $e) {
$this->error($e->getMessage());
}
$this->success(__('评论成功'), '');
}
/**
* 自定义表单数据写入接口
*/
public function diyform()
{
$id = $this->request->request("diyform_id/d");
$diyform = \addons\cms\model\Diyform::get($id);
if (!$diyform || $diyform['status'] != 'normal') {
$this->error("自定义表单未找到");
}
//是否需要登录判断
if ($diyform['needlogin'] && !$this->auth->isLogin()) {
$this->error("请登录后再操作", "index/user/login");
}
$diydata = new Diydata([], $diyform);
$data = $this->request->request();
try {
$diydata->allowField(true)->save($data);
} catch (Exception $e) {
$this->error("数据提交失败");
}
$this->success("数据提交成功", $diyform['redirecturl'] ? $diyform['redirecturl'] : addon_url('cms/index/index'));
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\IntCode;
use addons\cms\library\Service;
use addons\cms\model\Archives as ArchivesModel;
use addons\cms\model\Channel;
use addons\cms\model\Fields;
use addons\cms\model\Modelx;
use addons\cms\model\SpiderLog;
use think\Config;
use think\Exception;
/**
* 文档控制器
* Class Archives
* @package addons\cms\controller
*/
class Archives extends Base
{
public function index()
{
$config = get_addon_config('cms');
$action = $this->request->post("action");
if ($action && $this->request->isPost()) {
return $this->$action();
}
$diyname = $this->request->param('diyname');
$eid = $this->request->param('eid');
if ($eid) {
$diyname = IntCode::decode($eid);
}
if ($diyname && !is_numeric($diyname)) {
$archives = ArchivesModel::with('channel')->where('diyname', $diyname)->find();
} else {
$id = $diyname ?: $this->request->param('id', '');
$archives = ArchivesModel::get($id, ['channel']);
}
if (!$archives || ($archives['status'] != 'normal' && (!$archives['user_id'] || $archives['user_id'] != $this->auth->id)) || $archives['deletetime']) {
$this->error(__('No specified article found'), null, '', 3, ['status' => '404 Not Found']);
}
if (!$this->auth->id && !$archives['isguest']) {
$this->error(__('Please login first'), 'index/user/login');
}
$channel = $archives->channel;
if (!$channel) {
$this->error(__('No specified channel found'));
}
$model = Modelx::get($channel['model_id'], [], true);
if (!$model) {
$this->error(__('No specified model found'));
}
$addon = db($model['table'])->where('id', $archives['id'])->find();
if ($addon) {
if ($model->fields) {
Service::appendTextAndList('model', $model->id, $addon);
}
$archives->setData($addon);
} else {
$this->error(__('No specified addon article found'));
}
// 判断是否跳转移动端
$this->checkredirect('archives', ['id' => $archives->id, 'model' => $model->id, 'diyname' => $archives->diyname, 'eid' => $archives->eid]);
SpiderLog::record('archives', $archives['id']);
// 追加主表自定义字段Text和List
Service::appendTextAndList('archives', 0, $archives);
// 追加栏目自定义字段Text和List
Service::appendTextAndList('channel', 0, $channel);
//PC支持内容分页
$page = (int)$this->request->request("page", 1);
$page = max(1, $page);
$contentArr = array_values(array_filter(explode("##pagebreak##", $archives->content)));
$content = $contentArr ? ($contentArr[$page - 1] ?? $contentArr[0]) : '';
$archives->content = $content . $archives->getPagerHTML($page, count($contentArr));
$archives->setInc("views", 1);
$this->view->assign("__ARCHIVES__", $archives);
$this->view->assign("__CHANNEL__", $channel);
$this->view->assign("__MODEL__", $model);
//统计作者文章数和评论数
if ($archives->user) {
$archives->user->archives = ArchivesModel::where('user_id', $archives->user_id)->where('status', 'normal')->cache(3600, null, 'cms')->count();
$archives->user->comments = \addons\cms\model\Comment::where('user_id', $archives->user_id)->where('status', 'normal')->cache(3600, null, 'cms')->count();
}
//设置TKD
Config::set('cms.title', isset($archives['seotitle']) && $archives['seotitle'] ? $archives['seotitle'] : $archives['title']);
Config::set('cms.keywords', $archives['keywords']);
Config::set('cms.description', $archives['description']);
Config::set('cms.image', isset($archives['image']) && $archives['image'] ? cdnurl($archives['image'], true) : '');
//是否跳转链接
if (isset($archives['outlink']) && $archives['outlink']) {
$this->redirect($archives['outlink']);
}
$template = preg_replace("/\.html\$/i", '', $channel['showtpl']);
if (!$template) {
$this->error('请检查栏目是否配置相应的模板');
}
return $this->view->fetch('/' . $template);
}
/**
* 赞与踩
*/
public function vote()
{
$id = (int)$this->request->post("id");
$type = trim($this->request->post("type", ""));
if (!$id || !$type) {
$this->error(__('Operation failed'));
}
$archives = ArchivesModel::get($id);
if (!$archives || ($archives['user_id'] != $this->auth->id && $archives['status'] != 'normal') || $archives['deletetime']) {
$this->error(__('No specified article found'));
}
$archives->where('id', $id)->setInc($type === 'like' ? 'likes' : 'dislikes', 1);
$archives = ArchivesModel::get($id);
$this->success(__('Operation completed'), null, ['likes' => $archives->likes, 'dislikes' => $archives->dislikes, 'likeratio' => $archives->likeratio]);
}
/**
* 下载次数
*/
public function download()
{
$id = (int)$this->request->post("id");
if (!$id) {
$this->error(__('Operation failed'));
}
$archives = ArchivesModel::get($id, ['model']);
if (!$archives || ($archives['user_id'] != $this->auth->id && $archives['status'] != 'normal') || $archives['deletetime']) {
$this->error(__('No specified article found'));
}
try {
$table = $archives->getRelation('model')->getData('table');
\think\Db::name($table)->where('id', $id)->setInc('downloads');
} catch (Exception $e) {
//
}
$this->success(__('Operation completed'), null);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use think\Controller;
use think\Db;
use think\Log;
/**
* CMS定时任务接口
*
* 以Crontab方式每分钟定时执行,且只可以Cli方式运行
* @internal
*/
class Autotask extends Controller
{
/**
* 初始化方法,最前且始终执行
*/
public function _initialize()
{
// 只可以以cli方式执行
if (!$this->request->isCli()) {
$this->error('Autotask script only work at client!');
}
parent::_initialize();
// 清除错误
error_reporting(0);
// 设置永不超时
set_time_limit(0);
}
/**
* 执行定时任务
*/
public function index()
{
Service::checkPublishArchives();
echo "done";
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\IntCode;
use addons\cms\library\Service;
use addons\cms\model\SpiderLog;
use think\Config;
use think\Hook;
use think\Request;
/**
* CMS控制器基类
*/
class Base extends \think\addons\Controller
{
// 初始化
public function __construct(Request $request = null)
{
parent::__construct($request);
$config = get_addon_config('cms');
// 设定主题模板目录
$this->view->engine->config('view_path', $this->view->engine->config('view_path') . $config['theme'] . DS);
// 加载自定义标签库
//$this->view->engine->config('taglib_pre_load', 'addons\cms\taglib\Cms');
// 默认渲染栏目为空
$this->view->assign('__CHANNEL__', null);
$this->view->assign('isWechat', strpos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false);
// 定义CMS首页的URL
Config::set('cms.indexurl', addon_url('cms/index/index', [], false));
// 定义分页类
Config::set('paginate.type', '\\addons\\cms\\library\\Bootstrap');
//判断站点状态
if (isset($config['openedsite']) && !in_array('pc', explode(',', $config['openedsite']))) {
if ($this->controller != 'order' && $this->action != 'epay') {
$this->error('站点已关闭');
}
}
//判断文档定时发布
if (isset($config['publishcheckmode']) && $config['publishcheckmode'] === 'index') {
Service::checkPublishArchives();
}
}
/**
* 是否加密ID处理
*/
protected function hashids($name = 'id')
{
$config = get_addon_config('cms');
$getValue = $this->request->get($name);
$postValue = $this->request->post($name);
if ($config['archiveshashids'] && ($getValue || $postValue)) {
if ($getValue) {
$getValue = (int)IntCode::decode($getValue);
$this->request->get([$name => $getValue]);
}
if ($postValue) {
$postValue = (int)IntCode::decode($postValue);
$this->request->post([$name => $postValue]);
}
$this->request->param('');
}
}
// 判断是否跳转移动H5
protected function checkredirect($type, $params = [])
{
$config = get_addon_config('cms');
//自动跳转H5
if (($config['autoredirectmobile'] ?? false) && ($config['mobileurl'] ?? '') && $this->request->isMobile()) {
$pageArr = [
'archives' => "/pages/article/detail",
'channel' => "/pages/article/article",
'archives_model_2' => "/pages/product/detail",
'channel_model_2' => "/pages/product/product",
'diyform/list' => "/pages/diyform/lists",
'diyform/show' => "/pages/diyform/detail",
'special' => "/pages/special/special",
'tag' => "/pages/tag/tag",
'page' => "/pages/page/detail",
'user' => "/pages/user/user",
];
$pageUrl = '';
if (isset($params['model'])) {
$pageUrl = $pageArr[$type . "_model_" . $params['model']] ?? '';
if ($type == 'archives') {
$params['id'] = $params['eid'];
unset($params['model'], $params['eid']);
}
}
$pageUrl = $pageUrl ?: ($pageArr[$type] ?? '');
$params = array_filter($params);
$this->redirect($config['mobileurl'] . "#" . $pageUrl . ($params ? '?' . http_build_query($params) : ''));
} else {
return;
}
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use addons\cms\model\Archives;
use addons\cms\model\Channel as ChannelModel;
use addons\cms\model\Fields;
use addons\cms\model\Modelx;
use addons\cms\model\SpiderLog;
use think\Cache;
use think\Config;
/**
* 栏目控制器
* Class Channel
* @package addons\cms\controller
*/
class Channel extends Base
{
public function index()
{
$config = get_addon_config('cms');
$diyname = $this->request->param('diyname');
if ($diyname && !is_numeric($diyname)) {
$channel = ChannelModel::getByDiyname($diyname);
} else {
$id = $diyname ?: $this->request->param('id', '');
$channel = ChannelModel::get($id);
}
if (!$channel || $channel['status'] != 'normal') {
$this->error(__('No specified channel found'), null, '', 3, ['status' => '404 Not Found']);
}
$filter = $this->request->get('filter/a', []);
$orderby = $this->request->get('orderby', '');
$orderway = $this->request->get('orderway', '');
$multiple = $this->request->get('multiple/d', 0);
$orderway = $orderway && in_array(strtolower($orderway), ['asc', 'desc']) ? $orderway : 'desc';
$params = [];
$filter = $this->request->get();
$filter = array_diff_key($filter, array_flip(['orderby', 'orderway', 'page', 'multiple']));
if (isset($filter['filter'])) {
$filter = array_merge($filter, $filter['filter']);
unset($filter['filter']);
}
if ($filter) {
$filter = array_filter($filter, 'strlen');
$params['filter'] = $filter;
$params = $filter;
}
if ($orderby) {
$params['orderby'] = $orderby;
}
if ($orderway) {
$params['orderway'] = $orderway;
}
if ($multiple) {
$params['multiple'] = $multiple;
}
if ($channel['type'] === 'link') {
$this->redirect($channel['outlink']);
}
//加载模型数据
$model = Modelx::get($channel['model_id']);
if (!$model) {
$this->error(__('No specified model found'));
}
// 判断是否跳转移动端
$this->checkredirect('channel', ['model' => $model->id, 'channel' => $channel->id]);
//默认排序字段
$orders = [
['name' => 'default', 'field' => 'weigh DESC,publishtime DESC', 'title' => __('Default')],
];
//合并主表筛选字段
$orders = array_merge($orders, $model->getOrderFields());
//获取过滤列表
list($filterList, $filter, $params, $fields, $multiValueFields, $fieldsList) = Service::getFilterList('model', $model['id'], $filter, $params, $multiple);
//获取排序列表
list($orderList, $orderby, $orderway) = Service::getOrderList($orderby, $orderway, $orders, $params, $fieldsList);
//获取过滤的条件和绑定参数
list($filterWhere, $filterBind) = Service::getFilterWhereBind($filter, $multiValueFields, $multiple);
$filterChannel = function ($query) use ($channel) {
$query->where(function ($query) use ($channel) {
if ($channel['listtype'] <= 2) {
$query->whereOr("channel_id", $channel['id']);
}
if ($channel['listtype'] == 1 || $channel['listtype'] == 3) {
$query->whereOr('channel_id', 'in', function ($query) use ($channel) {
$query->name("cms_channel")->where('parent_id', $channel['id'])->field("id");
});
}
if ($channel['listtype'] == 0 || $channel['listtype'] == 4) {
$childrenIds = \addons\cms\model\Channel::getChannelChildrenIds($channel['id'], false);
if ($childrenIds) {
$query->whereOr('channel_id', 'in', $childrenIds);
}
}
})
->whereOr("(`channel_ids`!='' AND FIND_IN_SET('{$channel['id']}', `channel_ids`))");
};
//模板名称
$template = ($this->request->isAjax() ? '/ajax/' : '/') . ($channel["{$channel['type']}tpl"] ?? '');
$template = preg_replace("/\.html\$/i", '', $template);
$pagelistParams = Service::getPagelistParams($template);
//分页大小
$pagesize = $pagelistParams['pagesize'] ?? $channel['pagesize'];
//过滤条件
$filterPagelist = function ($query) use ($pagelistParams) {
if (isset($pagelistParams['condition'])) {
$query->where($pagelistParams['condition']);
}
};
//分页模式
$simple = !($config['loadmode'] == 'paging' && $config['pagemode'] == 'full');
//缓存列表总数
if (!$simple && ($config['cachelistcount'] ?? false)) {
$simple = Archives::with(['channel', 'user'])->alias('a')
->where('a.status', 'normal')
->whereNull('a.deletetime')
->where($filterWhere)
->bind($filterBind)
->where($filterPagelist)
->where($filterChannel)
->where('model_id', $channel->model_id)
->join($model['table'] . ' n', 'a.id=n.id', 'LEFT')
->cache("cms-channel-list-" . $channel['id'] . '-' . md5(serialize($filter)), 3600, "cms") //总数缓存1小时
->count();
}
//加载列表数据
$pageList = Archives::with(['channel', 'user'])->alias('a')
->where('a.status', 'normal')
->whereNull('a.deletetime')
->where($filterWhere)
->bind($filterBind)
->where($filterPagelist)
->where($filterChannel)
->where('model_id', $channel->model_id)
->join($model['table'] . ' n', 'a.id=n.id', 'LEFT')
->field('a.*')
->field('id,content', true, config('database.prefix') . $model['table'], 'n')
->order($orderby, $orderway)
->paginate($pagesize, $simple);
Service::appendTextAndList('archives', 0, $pageList, true);
Service::appendTextAndList('model', $model->id, $pageList, true);
Service::appendTextAndList('channel', 0, $channel);
$pageList->appends(array_filter($params));
$this->view->assign("__FILTERLIST__", $filterList);
$this->view->assign("__ORDERLIST__", $orderList);
$this->view->assign("__PAGELIST__", $pageList);
$this->view->assign("__CHANNEL__", $channel);
SpiderLog::record('channel', $channel['id']);
//设置TKD
Config::set('cms.title', isset($channel['seotitle']) && $channel['seotitle'] ? $channel['seotitle'] : $channel['name']);
Config::set('cms.keywords', $channel['keywords']);
Config::set('cms.description', $channel['description']);
Config::set('cms.image', isset($channel['image']) && $channel['image'] ? cdnurl($channel['image'], true) : '');
//读取模板
if (!$template) {
$this->error('请检查栏目是否配置相应的模板');
}
if ($this->request->isAjax()) {
$this->success("", "", $this->view->fetch($template));
}
return $this->view->fetch($template);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\CommentException;
use addons\cms\model\Comment as CommentModel;
use think\addons\Controller;
use think\Exception;
/**
* 评论控制器
* Class Comment
* @package addons\cms\controller
*/
class Comment extends Base
{
protected $model = null;
public function _initialize()
{
parent::_initialize();
$type = $this->request->post("type");
if ($type == 'archives') {
//检测ID是否加密
$this->hashids('aid');
}
}
/**
* 发表评论
*/
public function post()
{
try {
$params = $this->request->post();
CommentModel::postComment($params);
} catch (CommentException $e) {
if ($e->getCode() == 1) {
$this->success($e->getMessage(), null, ['token' => $this->request->token()]);
} else {
$this->error($e->getMessage(), null, ['token' => $this->request->token()]);
}
} catch (Exception $e) {
$this->error($e->getMessage(), null, ['token' => $this->request->token()]);
}
$this->success(__('评论成功!'), null, ['token' => $this->request->token()]);
}
/**
* 取消评论订阅
*/
public function unsubscribe()
{
$id = (int)$this->request->param('id');
$key = $this->request->param('key');
$comment = CommentModel::get($id, 'user');
if (!$comment) {
$this->error("评论未找到");
}
if ($key !== md5($comment['id'] . $comment['user']['email'])) {
$this->error("无法进行该操作");
}
if (!$comment['subscribe']) {
$this->error("评论已经取消订阅,请勿重复操作");
}
$comment->subscribe = 0;
$comment->save();
$this->success('取消评论订阅成功');
}
}
This diff is collapsed.
<?php
namespace addons\cms\controller;
use addons\cms\model\Autolink;
use think\Config;
/**
* 跳转控制器
* Class Go
* @package addons\cms\controller
*/
class Go extends Base
{
protected $noNeedLogin = ['*'];
public function index()
{
$url = $this->request->get("url", "", 'trim,xss_clean');
$id = $this->request->get("id/d", "0");
if ($id) {
$autolink = Autolink::get($id);
if ($autolink) {
$autolink->setInc("views");
$this->redirect($autolink['url']);
}
}
Config::set('cms.title', '跳转提示');
return $this->view->fetch("/outlink", ['url' => $url]);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\VicDict;
/**
* 导入
* Class Import
* @package addons\cms\controller
*/
class Import extends Base
{
protected $noNeedLogin = ["*"];
protected $layout = 'default';
public function _initialize()
{
parent::_initialize();
if (!$this->request->isCli()) {
$this->error('只允许在终端进行操作!');
}
}
/**
* 导入词典
*/
public function dict()
{
define('_VIC_WORD_DICT_PATH_', ADDON_PATH . 'cms/data/dict.json');
$dict = new VicDict('json');
//添加词语词库 add(词语,词性) 可以是除保留字符(/,\ , \x ,\i),以外的utf-8编码的任何字符
$lines = file(ADDON_PATH . 'cms/data/dict.txt', FILE_IGNORE_NEW_LINES);
foreach ($lines as $index => $line) {
$lineArr = explode(' ', $line);
$dict->add($lineArr[0], 'n');
}
//保存词库
$dict->save();
echo "done";
}
}
<?php
namespace addons\cms\controller;
use addons\cms\model\SpiderLog;
use think\Config;
/**
* CMS首页控制器
* Class Index
* @package addons\cms\controller
*/
class Index extends Base
{
public function index()
{
// 判断是否跳转移动端
$this->checkredirect('index');
$config = get_addon_config('cms');
//设置TKD
Config::set('cms.title', $config['title'] ?: __('Home'));
Config::set('cms.keywords', $config['keywords']);
Config::set('cms.description', $config['description']);
Config::set('cms.image', cdnurl($config['sitelogo'], true));
//首页分页大小
$pagesize = $config['indexpagesize'] ?? 10;
//首页加载和分页模式
$simple = $config['indexloadmode'] == 'paging' && $config['indexpagemode'] == 'full' ? false : true;
$simple = $simple ? 'true' : \addons\cms\model\Archives::where('status', 'normal')->cache(true, null, 'cms')->count();
$archivesList = \addons\cms\model\Archives::getArchivesList(['cache' => false, 'paginate' => "{$pagesize},{$simple},page"]);
$this->view->assign("__PAGELIST__", $archivesList);
if ($this->request->isAjax()) {
$this->success("", "", $this->view->fetch('ajax/index'));
}
SpiderLog::record('index', 0);
return $this->view->fetch('/index');
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\OrderException;
use addons\cms\model\Archives;
use addons\epay\library\Service;
use Exception;
/**
* 订单控制器
* Class Order
* @package addons\cms\controller
*/
class Order extends Base
{
/**
* 创建订单并发起支付请求
*/
public function submit()
{
$config = get_addon_config('cms');
//是否需要登录后才可以支付
if ($config['ispaylogin'] && !$this->auth->isLogin()) {
$this->error("请登录后再进行操作!", "index/user/login");
}
$id = $this->request->request('id');
$paytype = $this->request->request('paytype');
$archives = Archives::get($id);
if (!$archives || ($archives['user_id'] != $this->auth->id && $archives['status'] != 'normal') || $archives['deletetime']) {
$this->error('未找到指的文档');
}
// 判断作者无需支付
if ($archives->user_id && $archives->user_id == $this->auth->id) {
$this->redirect($archives->url);
}
try {
$response = \addons\cms\library\Order::submit($id, $paytype ? $paytype : $config['defaultpaytype']);
} catch (OrderException $e) {
if ($e->getCode() == 1) {
$this->success($e->getMessage(), $archives->url);
} else {
$this->error($e->getMessage(), $archives->url);
}
} catch (Exception $e) {
$this->error($e->getMessage(), $archives->url);
}
return $response;
}
/**
* 企业支付通知和回调
*/
public function epay()
{
$type = $this->request->param('type');
$paytype = $this->request->param('paytype');
if ($type == 'notify') {
$pay = Service::checkNotify($paytype);
if (!$pay) {
return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']);
}
// 获取回调数据,V3和V2的回调接收不同
$data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
try {
//微信支付V3返回和V2不同
if (Service::isVersionV3() && $paytype === 'wechat') {
$data = $data['resource']['ciphertext'];
$data['total_fee'] = $data['amount']['total'];
}
//获取支付金额、订单号
$payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
$out_trade_no = $data['out_trade_no'];
\addons\cms\library\Order::settle($out_trade_no, $payamount);
} catch (Exception $e) {
\think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
}
//下面这句必须要执行,且在此之前不能有任何输出
if (Service::isVersionV3()) {
return $pay->success()->getBody()->getContents();
} else {
return $pay->success()->send();
}
} else {
$order = \addons\cms\model\Order::getByOrderid($this->request->param('orderid'));
if (!$order->archives) {
$this->error('未找到文档信息!');
}
$this->redirect($order->archives->url);
}
return;
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use addons\cms\model\Fields;
use addons\cms\model\Page as PageModel;
use addons\cms\model\SpiderLog;
use think\Config;
/**
* CMS单页控制器
* Class Page
* @package addons\cms\controller
*/
class Page extends Base
{
public function index()
{
$diyname = $this->request->param('diyname');
if ($diyname && !is_numeric($diyname)) {
$page = PageModel::getByDiyname($diyname);
} else {
$id = $diyname ?: $this->request->param('id', '');
$page = PageModel::get($id);
}
if (!$page || $page['status'] != 'normal') {
$this->error(__('No specified page found'), null, '', 3, ['status' => '404 Not Found']);
}
// 判断是否跳转移动端
$this->checkredirect('page', ['diyname' => $page->diyname]);
$page->setInc('views');
Service::appendTextAndList('page', 0, $page);
$this->view->assign("__PAGE__", $page);
$channel = \addons\cms\model\Channel::getChannelByLinktype('page', $page['id']);
$this->view->assign("__CHANNEL__", $channel);
SpiderLog::record('page', $page['id']);
//设置TKD
Config::set('cms.title', isset($page['seotitle']) && $page['seotitle'] ? $page['seotitle'] : $page['title']);
Config::set('cms.keywords', $page['keywords']);
Config::set('cms.description', $page['description']);
Config::set('cms.image', isset($page['image']) && $page['image'] ? cdnurl($page['image'], true) : '');
$template = preg_replace("/\.html\$/i", "", $page['showtpl'] ? $page['showtpl'] : 'page');
return $this->view->fetch('/' . $template);
}
/**
* 赞与踩
*/
public function vote()
{
$id = (int)$this->request->post("id");
$type = trim($this->request->post("type", ""));
if (!$id || !$type) {
$this->error(__('Operation failed'));
}
$page = \addons\cms\model\Page::get($id);
if (!$page) {
$this->error(__('No specified page found'));
}
$page->where('id', $id)->setInc($type === 'like' ? 'likes' : 'dislikes', 1);
$page = \addons\cms\model\Page::get($id);
$this->success(__('Operation completed'), null, ['likes' => $page->likes, 'dislikes' => $page->dislikes, 'likeratio' => $page->likeratio]);
}
}
This diff is collapsed.
<?php
namespace addons\cms\controller;
use think\Config;
use think\Response;
/**
* Sitemap控制器
* Class Sitemap
* @package addons\cms\controller
*/
class Sitemap extends Base
{
protected $noNeedLogin = ['*'];
protected $options = [
'item_key' => '',
'root_node' => 'urlset',
'item_node' => 'url',
'root_attr' => 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:mobile="http://www.baidu.com/schemas/sitemap-mobile/1/"'
];
//默认配置
protected $config = [
'pagesize' => 5000,
'cache' => 3600
];
public function _initialize()
{
parent::_initialize();
$config = get_addon_config('cms');
$this->config['pagesize'] = $config['sitemappagesize'] ?? 5000;
$this->config['cache'] = $config['sitemapcachelifetime'] ?? 3600;
$this->config['cache'] = intval($this->config['cache']) < 0 ? false : $this->config['cache'];
Config::set('default_return_type', 'xml');
}
/**
* Sitemap集合
*/
public function index()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$type = $this->request->param('type', '');
$type = str_replace('.xml', '', $type);
$type = $type === 'all' ? '' : $type;
$list = [];
$pagesizeStr = $pagesize != $this->config['pagesize'] ? "pagesize/{$pagesize}/" : '';
if (!$type || $type == 'channel') {
$path = "/addons/cms/sitemap/channels/{$pagesizeStr}page/[PAGE]";
$channelsList = \addons\cms\model\Channel::where('status', 'normal')->field('id,name,diyname,createtime')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $channelsList->lastPage();
foreach ($channelsList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'archives') {
$path = "/addons/cms/sitemap/archives/{$pagesizeStr}page/[PAGE]";
$archivesList = \addons\cms\model\Archives::with(['channel'])->where('status', 'normal')->field('id,channel_id,diyname,createtime,publishtime')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $archivesList->lastPage();
foreach ($archivesList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'tags') {
$path = "/addons/cms/sitemap/tags/{$pagesizeStr}page/[PAGE]";
$tagsList = \addons\cms\model\Tag::where('status', 'normal')->field('id,name')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $tagsList->lastPage();
foreach ($tagsList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'users') {
$path = "/addons/cms/sitemap/users/{$pagesizeStr}page/[PAGE]";
$usersList = \addons\cms\model\User::where('status', 'normal')->field('id')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $usersList->lastPage();
foreach ($usersList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'specials') {
$path = "/addons/cms/sitemap/specials/{$pagesizeStr}page/[PAGE]";
$usersList = \addons\cms\model\Special::where('status', 'normal')->field('id')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $usersList->lastPage();
foreach ($usersList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'pages') {
$path = "/addons/cms/sitemap/pages/{$pagesizeStr}page/[PAGE]";
$usersList = \addons\cms\model\Page::where('status', 'normal')->field('id')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $usersList->lastPage();
foreach ($usersList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
if (!$type || $type == 'diyforms') {
$path = "/addons/cms/sitemap/diyforms/{$pagesizeStr}page/[PAGE]";
$usersList = \addons\cms\model\Diyform::where('status', 'normal')->field('id')->paginate($pagesize, false, ['path' => $path]);
$lastPage = $usersList->lastPage();
foreach ($usersList->getUrlRange(1, $lastPage) as $index => $item) {
$list[] = ['loc' => url($item, '', 'xml', true)];
}
}
$this->options = [
'item_key' => '',
'root_node' => 'sitemapindex',
'item_node' => 'sitemap',
'root_attr' => ''
];
return $this->xml($list);
}
/**
* 栏目
*/
public function channels()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$archivesList = \addons\cms\model\Channel::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,name,diyname,createtime')->paginate($pagesize, true);
$list = [];
foreach ($archivesList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 文章
*/
public function archives()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$archivesList = \addons\cms\model\Archives::with(['channel'])->where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,channel_id,diyname,createtime')->paginate($pagesize, true);
$list = [];
foreach ($archivesList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.8
];
}
return $this->xml($list);
}
/**
* 标签
*/
public function tags()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$tagsList = \addons\cms\model\Tag::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,name')->paginate($pagesize, true);
$list = [];
foreach ($tagsList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 用户
*/
public function users()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$userList = \addons\cms\model\User::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id')->paginate($pagesize, true);
$list = [];
foreach ($userList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 专题
*/
public function specials()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$specialList = \addons\cms\model\Special::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,diyname,createtime')->paginate($pagesize, true);
$list = [];
foreach ($specialList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 单页
*/
public function pages()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$specialList = \addons\cms\model\Page::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,diyname,createtime')->paginate($pagesize, true);
$list = [];
foreach ($specialList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 自定义表单
*/
public function diyforms()
{
$pagesize = $this->request->param('pagesize/d', $this->config['pagesize']);
$specialList = \addons\cms\model\Diyform::where('status', 'normal')->cache($this->config['cache'], null, 'cms')->field('id,diyname,createtime')->paginate($pagesize, true);
$list = [];
foreach ($specialList as $index => $item) {
$list[] = [
'loc' => $item->fullurl,
'priority' => 0.6
];
}
return $this->xml($list);
}
/**
* 输出XML
*/
protected function xml($data = [])
{
foreach ($data as $index => &$item) {
$item['loc'] = htmlspecialchars($item['loc']);
}
return Response::create($data, 'xml', 200, [], $this->options);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use addons\cms\model\Archives;
use addons\cms\model\Fields;
use addons\cms\model\Special as SpecialModel;
use addons\cms\model\SpiderLog;
use addons\cms\model\Taggable;
use think\Config;
use think\Exception;
/**
* 专题控制器
* Class Special
* @package addons\cms\controller
*/
class Special extends Base
{
/**
* 专题页面
*/
public function index()
{
$config = get_addon_config('cms');
$diyname = $this->request->param('diyname');
if ($diyname && !is_numeric($diyname)) {
$special = SpecialModel::getByDiyname($diyname);
} else {
$id = $diyname ?: $this->request->param('id', '');
$special = SpecialModel::get($id);
}
if (!$special || $special['status'] != 'normal') {
$this->error(__('No specified special found'), null, '', 3, ['status' => '404 Not Found']);
}
// 判断是否跳转移动端
$this->checkredirect('special', ['diyname' => $special->diyname]);
$special->setInc("views", 1);
Service::appendTextAndList('special', 0, $special);
//模板名称
$special['template'] = $special['template'] ? $special['template'] : 'special.html';
$template = ($this->request->isAjax() ? '/ajax/' : '/') . $special["template"];
$template = preg_replace("/\.html\$/i", '', $template);
$pagelistParams = Service::getPagelistParams($template);
//分页大小
$pagesize = $pagelistParams['pagesize'] ?? 10;
//过滤条件
$filterPagelist = function ($query) use ($pagelistParams) {
if (isset($pagelistParams['condition'])) {
$query->where($pagelistParams['condition']);
}
};
$archivesList = \addons\cms\model\Archives::with(['channel'])
->where(function ($query) use ($special) {
//$query->whereRaw("(`special_ids`!='' AND FIND_IN_SET('{$special->id}', `special_ids`))");
//if ($special['tag_ids']) {
// $query->whereOr('id', 'in', function ($query) use ($special) {
// return $query->name("cms_taggable")->where("tag_id", 'in', $special['tag_ids'])->field("archives_id");
// });
//}
$tableName = (new Taggable)->getTable();
$archivesIds = Archives::whereRaw("(`special_ids`!='' AND FIND_IN_SET({$special->id}, `special_ids`))")
->whereOr("id IN (SELECT archives_id FROM {$tableName} WHERE tag_id IN (" . ($special->tag_ids ? $special->tag_ids : '0') . "))")
->cache(true, null, 'cms')
->column('id');
$archivesIds = array_filter(array_unique($archivesIds));
$query->where('id', 'in', $archivesIds);
})
->where($filterPagelist)
->where('status', 'normal')
->whereNull('deletetime')
->order('weigh DESC,publishtime DESC')
->paginate($pagesize, $config['pagemode'] == 'simple');
$this->view->assign("archivesList", $archivesList);
$this->view->assign("__PAGELIST__", $archivesList);
$this->view->assign("__SPECIAL__", $special);
$channel = \addons\cms\model\Channel::getChannelByLinktype('special', $special['id']);
$this->view->assign("__CHANNEL__", $channel);
SpiderLog::record('special', $special['id']);
//设置TKD
Config::set('cms.title', isset($special['seotitle']) && $special['seotitle'] ? $special['seotitle'] : $special['title']);
Config::set('cms.keywords', $special['keywords']);
Config::set('cms.description', $special['description']);
Config::set('cms.image', isset($special['image']) && $special['image'] ? cdnurl($special['image'], true) : '');
if ($this->request->isAjax()) {
$this->success("", "", $this->view->fetch($template));
}
return $this->view->fetch($template);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\library\Service;
use addons\cms\model\Archives;
use addons\cms\model\SpiderLog;
use addons\cms\model\Tag as TagModel;
use addons\cms\model\Taggable;
use think\Config;
/**
* 标签控制器
* Class Tag
* @package addons\cms\controller
*/
class Tag extends Base
{
public function index()
{
$config = get_addon_config('cms');
$tag = null;
$name = $this->request->param('name');
$diyname = $this->request->param('diyname');
$name = $name ? $name : $diyname;
if ($name && !is_numeric($name)) {
$tag = TagModel::getByName($name);
} else {
$id = $name ?: $this->request->param('id', '');
$tag = TagModel::get($id);
}
if (!$tag || $tag['status'] != 'normal') {
$this->error(__('No specified tags found'), null, '', 3, ['status' => '404 Not Found']);
}
// 判断是否跳转移动端
$this->checkredirect('tag', ['name' => $tag['name']]);
$filterList = [];
$orderList = [];
$orderby = $this->request->get('orderby', '');
$orderway = $this->request->get('orderway', '');
$orderway = $orderway && in_array(strtolower($orderway), ['asc', 'desc']) ? $orderway : 'desc';
$params = [];
if ($orderby) {
$params['orderby'] = $orderby;
}
if ($orderway) {
$params['orderway'] = $orderway;
}
//默认排序字段
$orders = [
['name' => 'default', 'field' => 'weigh', 'title' => __('Default')],
['name' => 'views', 'field' => 'views', 'title' => __('Views')],
['name' => 'id', 'field' => 'id', 'title' => __('Post date')],
];
//获取排序列表
list($orderList, $orderby, $orderway) = Service::getOrderList($orderby, $orderway, $orders, $params);
//模板名称
$template = ($this->request->isAjax() ? '/ajax' : '/') . 'tag';
$pagelistParams = Service::getPagelistParams($template);
//分页大小
$pagesize = $pagelistParams['pagesize'] ?? 10;
//过滤条件
$filterPagelist = function ($query) use ($pagelistParams) {
if (isset($pagelistParams['condition'])) {
$query->where($pagelistParams['condition']);
}
};
$simple = !($config['loadmode'] == 'paging' && $config['pagemode'] == 'full');
//缓存列表总数
if (!$simple && ($config['cachelistcount'] ?? false)) {
$simple = Archives::with(['channel'])
->where('status', 'normal')
->where('id', 'in', function ($query) use ($tag) {
return $query->name('cms_taggable')->where('tag_id', $tag['id'])->field('archives_id');
})
->where($filterPagelist)
->cache("cms-tag-list-" . $tag['id'], 3600, 'cms') //总数缓存1小时
->count();
}
$pageList = Archives::with(['channel'])
->where('status', 'normal')
->where('id', 'in', function ($query) use ($tag) {
return $query->name('cms_taggable')->where('tag_id', $tag['id'])->field('archives_id');
})
->where($filterPagelist)
->order($orderby, $orderway)
->paginate($pagesize, $simple);
$pageList->appends(array_filter($params));
$this->view->assign("__FILTERLIST__", $filterList);
$this->view->assign("__ORDERLIST__", $orderList);
$this->view->assign("__TAG__", $tag);
$this->view->assign("__TAGS__", $tag);
$this->view->assign("__PAGELIST__", $pageList);
if ($this->request->isAjax()) {
$this->success("", "", $this->view->fetch($template));
}
SpiderLog::record('tag', $tag['id']);
//设置TKD
Config::set('cms.title', isset($tag['seotitle']) && $tag['seotitle'] ? $tag['seotitle'] : $tag['name']);
Config::set('cms.keywords', $tag['keywords']);
Config::set('cms.description', $tag['description']);
Config::set('cms.image', isset($tag['image']) && $tag['image'] ? cdnurl($tag['image'], true) : '');
return $this->view->fetch($template);
}
}
<?php
namespace addons\cms\controller;
use addons\cms\model\Archives;
use addons\cms\model\Comment;
use addons\cms\model\SpiderLog;
use think\Config;
/**
* 会员个人主页控制器
* Class User
* @package addons\cms\controller
*/
class User extends Base
{
public function index()
{
$config = get_addon_config('cms');
if (!$config['userpage']) {
$this->error("会员主页功能已关闭");
}
$user_id = $this->request->param('id');
$user = \app\common\model\User::get($user_id);
if (!$user) {
$this->error("未找到指定会员", null, '', 3, ['status' => '404 Not Found']);
}
if ($user['status'] == 'hidden') {
$this->error("暂时无法浏览");
}
// 判断是否跳转移动端
$this->checkredirect('user', ['user_id' => $user->id]);
$pathArr = explode('/', $this->request->pathinfo());
$type = end($pathArr);
$type = is_numeric($type) || !in_array($type, ['archives', 'comment']) ? 'archives' : $type;
$pagesize = 10;
$page = $this->request->get('page/d', 1);
$page = max(1, $page);
$statistics = ['archives' => 0, 'comments' => 0];
//分页模式
$simple = !($config['loadmode'] == 'paging' && $config['pagemode'] == 'full');
if ($type == 'archives') {
$total = Archives::where('user_id', $user['id'])->where('status', 'normal')->count();
$archivesList = Archives::with(['user', 'channel'])
->where('user_id', $user['id'])
->where('status', 'normal')
->order('id', 'desc')
->paginate($pagesize, $simple, ['var_page' => 'page', 'fragment' => '']);
$this->view->assign('archivesList', $archivesList);
$this->view->assign('__PAGELIST__', $archivesList);
$statistics['archives'] = $total;
$statistics['comments'] = Comment::where('user_id', $user['id'])->cache(3600, null, 'cms')->where('status', 'normal')->count();
} else {
$total = Comment::where('user_id', $user['id'])->where('status', 'normal')->count();
$commentList = Comment::with(['user'])
->where('user_id', $user['id'])
->where('status', 'normal')
->order('id', 'desc')
->paginate($pagesize, $simple, ['var_page' => 'page', 'fragment' => '']);
$collection = $commentList->getCollection();
load_relation($collection, 'source');
$this->view->assign('commentList', $commentList);
$this->view->assign('__PAGELIST__', $commentList);
$statistics['archives'] = Archives::where('user_id', $user['id'])->cache(3600, null, 'cms')->where('status', 'normal')->count();
$statistics['comments'] = $total;
}
$title = $type == 'archives' ? '的文章' : '的评论';
Config::set('cms.title', $user['nickname'] . $title);
Config::set('cms.image', isset($user['avatar']) && $user['avatar'] ? cdnurl($user['avatar'], true) : '');
SpiderLog::record('user', $user['id']);
$this->view->assign('statistics', $statistics);
$this->view->assign('title', ($this->auth->id == $user['id'] ? '我' : 'TA') . $title);
$this->view->assign('page', $page);
$this->view->assign('type', $type);
$this->view->assign('__USER__', $user);
if ($this->request->isAjax()) {
$this->success("", "", $this->view->fetch('ajax/user'));
}
return $this->view->fetch("/user");
}
}
This diff is collapsed.
<?php
namespace addons\cms\controller\api;
use addons\cms\library\IntCode;
use app\common\controller\Api;
use app\common\library\Auth;
use think\Config;
use think\Lang;
use think\Request;
class Base extends Api
{
protected $noNeedLogin = [];
protected $noNeedRight = ['*'];
//设置返回的会员字段
protected $allowFields = ['id', 'username', 'nickname', 'vip', 'mobile', 'avatar', 'score', 'level', 'bio', 'balance', 'money', 'gender'];
public function _initialize()
{
if (isset($_SERVER['HTTP_ORIGIN'])) {
header('Access-Control-Expose-Headers: __token__');//跨域让客户端获取到
}
//跨域检测
check_cors_request();
if (!isset($_COOKIE['PHPSESSID'])) {
Config::set('session.id', $this->request->server("HTTP_SID"));
}
parent::_initialize();
$config = get_addon_config('cms');
Config::set('cms', $config);
Config::set('default_return_type', 'json');
Auth::instance()->setAllowFields($this->allowFields);
//判断站点状态
if (isset($config['openedsite']) && !in_array('uniapp', explode(',', $config['openedsite']))) {
$this->error('站点已关闭');
}
//这里手动载入语言包
Lang::load(ROOT_PATH . '/addons/cms/lang/zh-cn.php');
Lang::load(APP_PATH . '/index/lang/zh-cn/user.php');
}
/**
* 判断ID是否加密处理
*/
protected function hashids($name = 'id')
{
$config = get_addon_config('cms');
$getValue = $this->request->get($name);
$postValue = $this->request->post($name);
if ($config['archiveshashids'] && ($getValue || $postValue)) {
if ($getValue) {
$getValue = (int)IntCode::decode($getValue);
$this->request->get([$name => $getValue]);
}
if ($postValue) {
$postValue = (int)IntCode::decode($postValue);
$this->request->post([$name => $postValue]);
}
$this->request->param('');
}
}
}
<?php
namespace addons\cms\controller\api;
use addons\cms\library\IntCode;
use addons\cms\model\Collection as CollectionModel;
use addons\cms\model\Modelx;
use think\Db;
use think\Exception;
/**
* 会员收藏
*/
class Collection extends Base
{
protected $layout = 'default';
protected $noNeedLogin = [];
protected $noNeedRight = ['*'];
/**
* 我的收藏
*/
public function index()
{
$collection = new CollectionModel;
$model = null;
$type = (int)$this->request->param('type');
$q = $this->request->param('q');
$config = ['query' => []];
// 指定模型
if ($type) {
$model = Modelx::get($type);
if ($model) {
$collection->where('type', $type);
$config['query']['type'] = $type;
}
}
// 搜索关键字
if ($q) {
$collection->where('title|keywords|description', 'like', '%' . $q . '%');
$config['query']['q'] = $q;
}
$config = get_addon_config('cms');
$user_id = $this->auth->id;
$collectionList = $collection->where('user_id', $user_id)
->order('id', 'desc')
->paginate(10, null, $config);
foreach ($collectionList as $index => $item) {
if ($item['type'] == 'archives') {
$item->aid = isset($config['archiveshashids']) && $config['archiveshashids'] ? IntCode::encode($item->aid) : $item->aid;
}
}
$collectionList = $collectionList->toArray();
$this->success('获取成功', [
'collectionList' => $collectionList,
'model' => $model
]);
}
/**
* 添加收藏
*/
public function create()
{
$type = $this->request->post("type");
if (!in_array($type, ['archives', 'page', 'special', 'diyform'])) {
$this->error("参数不正确");
}
if ($type == 'archives') {
//检测ID是否加密
$this->hashids('aid');
}
$aid = $this->request->post("aid/d");
$model = call_user_func_array(['\\addons\\cms\\model\\' . ucfirst($type), "get"], [$aid]);
if (!$model) {
$this->error("未找到指定数据");
}
Db::startTrans();
try {
$collection = CollectionModel::lock(true)->where(['type' => $type, 'aid' => $aid, 'user_id' => $this->auth->id])->find();
if ($collection) {
throw new \think\Exception("请勿重复收藏");
}
$title = $model->title;
$url = $model->fullurl;
$image = $model->image;
$data = [
'user_id' => $this->auth->id,
'type' => $type,
'aid' => $aid,
'title' => $title,
'url' => $url,
'image' => $image
];
CollectionModel::create($data);
Db::commit();
} catch (\think\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (\Exception $e) {
Db::rollback();
$this->error("收藏失败");
}
$this->success("收藏成功");
}
/**
* 删除收藏
*/
public function delete()
{
$id = (int)$this->request->post('id/d');
if (!$id) {
$this->error("参数不正确");
}
$collection = \addons\cms\model\Collection::where('id', $id)->where('user_id', $this->auth->id)->find();
if (!$collection) {
$this->error("未找到指定的收藏");
}
Db::startTrans();
try {
$collection->delete();
Db::commit();
} catch (Exception $e) {
Db::rollback();
$this->error("移除收藏失败");
}
$this->success("移除收藏成功");
}
}
<?php
namespace addons\cms\controller\api;
use addons\cms\library\CommentException;
use think\Config;
use think\Exception;
/**
* 评论
*/
class Comment extends Base
{
protected $noNeedLogin = ['index'];
public function _initialize()
{
parent::_initialize();
$type = $this->request->post("type", "archives");
if ($type == 'archives') {
//检测ID是否加密
$this->hashids('aid');
}
}
/**
* 评论列表
*/
public function index()
{
$aid = (int)$this->request->param('aid');
$page = (int)$this->request->param('page');
Config::set('paginate.page', $page);
$commentList = \addons\cms\model\Comment::getCommentList(['aid' => $aid]);
$commentList = $commentList->getCollection();
foreach ($commentList as $index => $item) {
if ($item->user) {
$item->user->avatar = cdnurl($item->user->avatar, true);
$item->user->visible(explode(',', 'id,nickname,avatar'));
}
$item->hidden(['ip', 'useragent', 'deletetime', 'aid', 'subscribe', 'status', 'type', 'updatetime']);
}
$this->success('', ['commentList' => $commentList]);
}
/**
* 发表评论
*/
public function post()
{
try {
$params = $this->request->post();
$comment = \addons\cms\model\Comment::postComment($params);
$comment->user->visible(explode(',', 'id,nickname,avatar'));
$comment->user->avatar = cdnurl($comment->user->avatar, true);
} catch (CommentException $e) {
$this->success($e->getMessage(), ['__token__' => $this->request->token()]);
} catch (Exception $e) {
$this->error($e->getMessage(), ['__token__' => $this->request->token()]);
}
$this->success(__('评论成功'), ['comment' => $comment, '__token__' => $this->request->token()]);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
namespace addons\cms\controller\api;
/**
* 单页面
*/
class Page extends Base
{
protected $noNeedLogin = ['detail'];
/**
* 单页详情
*/
public function detail()
{
$name = $this->request->request("diyname");
$pageInfo = \addons\cms\model\Page::getByDiyname($name);
if (!$pageInfo || $pageInfo['status'] != 'normal') {
$this->error(__('单页未找到'));
}
unset($pageInfo['status'], $pageInfo['showtpl'], $pageInfo['parsetpl']);
$view = new \think\View();
$pageInfo['content'] = $view->fetch($pageInfo['content'], ["__PAGE__" => $pageInfo], [], [], true);
$this->success('', ['pageInfo' => $pageInfo->toArray()]);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
namespace addons\cms\controller\api;
use addons\cms\model\MoneyLog;
use addons\cms\model\ScoreLog;
/**
* 会员日志
*/
class TheLogs extends Base
{
protected $noNeedLogin = [];
/**
* 余额日志
*/
public function money()
{
$list = MoneyLog::where(['user_id' => $this->auth->id])
->order('id DESC')
->paginate(10);
$this->success('', $list);
}
/**
* 积分日志
*/
public function score()
{
$list = ScoreLog::where(['user_id' => $this->auth->id])
->order('id DESC')
->paginate(10);
$this->success('', $list);
}
}
This diff is collapsed.
This diff is collapsed.
请从以下地址下载更新词库:https://raw.githubusercontent.com/lizhichao/VicWord/master/Data/dict.txt
This diff is collapsed.
{"navbar":{"titleColor":"#ffffff","bgColor":{"background":"#374486"},"backIconColor":"#fff","backTextStyle":{"color":"#ffffff"},"titleSize":"35","isshow":true},"theme":{"color":"#ffffff","bgColor":"#374486"},"tabbar":{"color":"#999999","selectColor":"#000000","bgColor":"#ffffff","height":"100","borderTop":true,"iconSize":"40","midButton":false,"midButtonSize":"60","list":[{"image":"\/assets\/addons\/cms\/img\/tabbar\/home.png","selectedImage":"\/assets\/addons\/cms\/img\/tabbar\/home-hl.png","text":"首页","path":"\/pages\/index\/index","midButton":false,"count":0,"isDot":false,"badgeColor":"#ffffff","badgeBgColor":"#374486"},{"image":"\/assets\/addons\/cms\/img\/tabbar\/article.png","selectedImage":"\/assets\/addons\/cms\/img\/tabbar\/article-hl.png","text":"资讯","path":"\/pages\/article\/article?model=1","midButton":false,"count":0,"isDot":false,"badgeColor":"#ffffff","badgeBgColor":"#374486"},{"image":"\/assets\/addons\/cms\/img\/tabbar\/image.png","selectedImage":"\/assets\/addons\/cms\/img\/tabbar\/image-hl.png","text":"产品","path":"\/pages\/product\/product?model=2","midButton":false,"count":0,"isDot":false,"badgeColor":"#ffffff","badgeBgColor":"#374486"},{"image":"\/assets\/addons\/cms\/img\/tabbar\/my.png","selectedImage":"\/assets\/addons\/cms\/img\/tabbar\/my-hl.png","text":"我的","path":"\/pages\/index\/my","midButton":false,"count":0,"isDot":false,"badgeColor":"#ffffff","badgeBgColor":"#374486"}],"isshow":true}}
\ No newline at end of file
一行一个过滤词,第一行请不要修改
name = cms
title = CMS内容管理系统
intro = 基于ThinkPHP5的内容管理系统
author = FastAdmin
website = https://www.fastadmin.net
version = 2.0.5
state = 1
url = /addons/cms
license = extended
licenseto = 19686
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment