diff --git a/.gitignore b/.gitignore index 1962050f52dac6888412967374d70fe6356bdc17..3d20590a5e5e3464af9e24b33b94fc9f5a682b0f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /thinkphp/ /vendor/ /runtime/* -/addons/* /application/admin/command/Install/*.lock /public/assets/libs/ /public/assets/addons/* diff --git a/addons/cms/Cms.php b/addons/cms/Cms.php new file mode 100644 index 0000000000000000000000000000000000000000..7ddcb0cd6bca75e18578e0919c61e1c49e240269 --- /dev/null +++ b/addons/cms/Cms.php @@ -0,0 +1,162 @@ + 'cms', + 'title' => 'CMS管理', + 'sublist' => [ + [ + 'name' => 'cms/archives', + 'title' => '内容管理', + 'icon' => 'fa fa-file-text-o', + 'sublist' => [ + ['name' => 'cms/archives/index', 'title' => '查看'], + ['name' => 'cms/archives/content', 'title' => '副表'], + ['name' => 'cms/archives/add', 'title' => '添加'], + ['name' => 'cms/archives/edit', 'title' => '修改'], + ['name' => 'cms/archives/del', 'title' => '删除'], + ['name' => 'cms/archives/multi', 'title' => '批量更新'], + ] + ], + [ + 'name' => 'cms/channel', + 'title' => '栏目管理', + 'icon' => 'fa fa-list', + 'sublist' => [ + ['name' => 'cms/channel/index', 'title' => '查看'], + ['name' => 'cms/channel/add', 'title' => '添加'], + ['name' => 'cms/channel/edit', 'title' => '修改'], + ['name' => 'cms/channel/del', 'title' => '删除'], + ['name' => 'cms/channel/multi', 'title' => '批量更新'], + ] + ], + [ + 'name' => 'cms/modelx', + 'title' => '模型管理', + 'icon' => 'fa fa-th', + 'sublist' => [ + ['name' => 'cms/modelx/index', 'title' => '查看'], + ['name' => 'cms/modelx/add', 'title' => '添加'], + ['name' => 'cms/modelx/edit', 'title' => '修改'], + ['name' => 'cms/modelx/del', 'title' => '删除'], + ['name' => 'cms/modelx/multi', 'title' => '批量更新'], + [ + 'name' => 'cms/fields', + 'title' => '字段管理', + 'icon' => 'fa fa-fields', + 'ismenu' => 0, + 'sublist' => [ + ['name' => 'cms/fields/index', 'title' => '查看'], + ['name' => 'cms/fields/add', 'title' => '添加'], + ['name' => 'cms/fields/edit', 'title' => '修改'], + ['name' => 'cms/fields/del', 'title' => '删除'], + ['name' => 'cms/fields/multi', 'title' => '批量更新'], + ] + ] + ] + ], + [ + 'name' => 'cms/tags', + 'title' => '标签管理', + 'icon' => 'fa fa-tags', + 'sublist' => [ + ['name' => 'cms/tags/index', 'title' => '查看'], + ['name' => 'cms/tags/add', 'title' => '添加'], + ['name' => 'cms/tags/edit', 'title' => '修改'], + ['name' => 'cms/tags/del', 'title' => '删除'], + ['name' => 'cms/tags/multi', 'title' => '批量更新'], + ] + ], + [ + 'name' => 'cms/block', + 'title' => '区块管理', + 'icon' => 'fa fa-th-large', + 'sublist' => [ + ['name' => 'cms/block/index', 'title' => '查看'], + ['name' => 'cms/block/add', 'title' => '添加'], + ['name' => 'cms/block/edit', 'title' => '修改'], + ['name' => 'cms/block/del', 'title' => '删除'], + ['name' => 'cms/block/multi', 'title' => '批量更新'], + ] + ], + [ + 'name' => 'cms/page', + 'title' => '单页管理', + 'icon' => 'fa fa-file', + 'sublist' => [ + ['name' => 'cms/page/index', 'title' => '查看'], + ['name' => 'cms/page/add', 'title' => '添加'], + ['name' => 'cms/page/edit', 'title' => '修改'], + ['name' => 'cms/page/del', 'title' => '删除'], + ['name' => 'cms/page/multi', 'title' => '批量更新'], + ] + ], + [ + 'name' => 'cms/comment', + 'title' => '评论管理', + 'icon' => 'fa fa-comment', + 'sublist' => [ + ['name' => 'cms/comment/index', 'title' => '查看'], + ['name' => 'cms/comment/add', 'title' => '添加'], + ['name' => 'cms/comment/edit', 'title' => '修改'], + ['name' => 'cms/comment/del', 'title' => '删除'], + ['name' => 'cms/comment/multi', 'title' => '批量更新'], + ] + ] + ] + ] + ]; + Menu::create($menu); + return true; + } + + /** + * 插件卸载方法 + * @return bool + */ + public function uninstall() + { + Menu::delete('cms'); + return true; + } + + /** + * 插件启用方法 + */ + public function enable() + { + Menu::enable('cms'); + } + + /** + * 插件禁用方法 + */ + public function disable() + { + Menu::disable('cms'); + } + + public function addonAfterUpgrade() + { + + } + +} diff --git a/addons/cms/application/admin/controller/cms/Ajax.php b/addons/cms/application/admin/controller/cms/Ajax.php new file mode 100644 index 0000000000000000000000000000000000000000..f937fa15315eea9681aaaf3c35c113bf28ddcf0f --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Ajax.php @@ -0,0 +1,59 @@ +request->request("keyValue"); + if (!$keyValue) { + $name = $this->request->request("name"); + if ($name) { + $files[] = ['name' => $name . '.html']; + } + //设置过滤方法 + $this->request->filter(['strip_tags']); + $config = get_addon_config('cms'); + $themeDir = ADDON_PATH . 'cms' . DS . 'view' . DS . $config['theme'] . DS; + $dh = opendir($themeDir); + while (false !== ($filename = readdir($dh))) { + if ($filename == '.' || $filename == '..') + continue; + $files[] = ['name' => $filename]; + } + } else { + $files[] = ['name' => $keyValue]; + } + return $result = ['total' => count($files), 'list' => $files]; + } + +} diff --git a/addons/cms/application/admin/controller/cms/Archives.php b/addons/cms/application/admin/controller/cms/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..7c27d9044332e57f2949827faaf63e406404288e --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Archives.php @@ -0,0 +1,360 @@ +model = model('Archives'); + + $channelList = []; + $disabledIds = []; + $all = collection(Channel::order("weigh desc,id desc")->select())->toArray(); + foreach ($all as $k => $v) { + $state = ['opened' => true]; + if ($v['type'] != 'list') { + $disabledIds[] = $v['id']; + } + if ($v['type'] == 'link') { + $state['checkbox_disabled'] = true; + } + $channelList[] = [ + 'id' => $v['id'], + 'parent' => $v['parent_id'] ? $v['parent_id'] : '#', + 'text' => __($v['name']), + 'type' => $v['type'], + 'state' => $state + ]; + } + $tree = Tree::instance()->init($all, 'parent_id'); + $channelOptions = $tree->getTree(0, "", '', $disabledIds); + $this->view->assign('channelOptions', $channelOptions); + $this->assignconfig('channelList', $channelList); + + $this->view->assign("flagList", $this->model->getFlagList()); + $this->view->assign("statusList", $this->model->getStatusList()); + } + + /** + * 查看 + */ + public function index() + { + //设置过滤方法 + $this->request->filter(['strip_tags']); + if ($this->request->isAjax()) { + $this->relationSearch = TRUE; + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + $total = $this->model + ->with('Channel') + ->where($where) + ->order($sort, $order) + ->count(); + + $list = $this->model + ->with('Channel') + ->where($where) + ->order($sort, $order) + ->limit($offset, $limit) + ->select(); + + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + + $modelList = \app\admin\model\Modelx::all(); + $this->view->assign('modelList', $modelList); + return $this->view->fetch(); + } + + /** + * 副表内容 + */ + public function content($model_id = null) + { + $model = \app\admin\model\Modelx::get($model_id); + if (!$model) { + $this->error('未找到对应模型'); + } + $fieldsList = \app\admin\model\Fields::where('model_id', $model['id'])->where('type', '<>', 'text')->select(); + + //设置过滤方法 + $this->request->filter(['strip_tags']); + if ($this->request->isAjax()) { + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + $fields = []; + foreach ($fieldsList as $index => $item) { + $fields[] = "addon." . $item['name']; + } + $table = $this->model->getTable(); + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + $sort = 'main.id'; + $total = Db::table($table) + ->alias('main') + ->join('cms_channel channel', 'channel.id=main.channel_id', 'LEFT') + ->join($model['table'] . ' addon', 'addon.id=main.id', 'LEFT') + ->field('main.id,main.channel_id,main.title,channel.name as channel_name,addon.id as aid' . ($fields ? ',' . implode(',', $fields) : '')) + ->where($where) + ->order($sort, $order) + ->count(); + + $list = Db::table($table) + ->alias('main') + ->join('cms_channel channel', 'channel.id=main.channel_id', 'LEFT') + ->join($model['table'] . ' addon', 'addon.id=main.id', 'LEFT') + ->field('main.id,main.channel_id,main.title,channel.name as channel_name,addon.id as aid' . ($fields ? ',' . implode(',', $fields) : '')) + ->where($where) + ->order($sort, $order) + ->limit($offset, $limit) + ->select(); + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + $fields = []; + foreach ($fieldsList as $index => $item) { + $fields[] = ['field' => $item['name'], 'title' => $item['title'], 'type' => $item['type'], 'content' => $item['content_list']]; + } + $this->assignconfig('fields', $fields); + $this->view->assign('fieldsList', $fieldsList); + $this->view->assign('model', $model); + $this->assignconfig('model_id', $model_id); + return $this->view->fetch(); + } + + /** + * 编辑 + * + * @param mixed $ids + */ + public function edit($ids = NULL) + { + $row = $this->model->get($ids); + if (!$row) + $this->error(__('No Results were found')); + $adminIds = $this->getDataLimitAdminIds(); + if (is_array($adminIds)) { + if (!in_array($row[$this->dataLimitField], $adminIds)) { + $this->error(__('You have no permission')); + } + } + if ($this->request->isPost()) { + return parent::edit($ids); + } + $channel = Channel::get($row['channel_id']); + if (!$channel) { + $this->error(__('No specified channel found')); + } + $model = \app\admin\model\Modelx::get($channel['model_id']); + if (!$model) { + $this->error(__('No specified model found')); + } + $addon = db($model['table'])->where('id', $row['id'])->find(); + if ($addon) { + $row = array_merge($row->toArray(), $addon); + } + + $all = collection(Channel::order("weigh desc,id desc")->select())->toArray(); + foreach ($all as $k => $v) { + if ($v['type'] != 'list' || $v['model_id'] != $channel['model_id']) { + $disabledIds[] = $v['id']; + } + } + $tree = Tree::instance()->init($all, 'parent_id'); + $channelOptions = $tree->getTree(0, "", $row['channel_id'], $disabledIds); + $this->view->assign('channelOptions', $channelOptions); + $this->view->assign("row", $row); + return $this->view->fetch(); + } + + /** + * 删除 + * @param mixed $ids + */ + public function del($ids = "") + { + \app\admin\model\Archives::event('after_delete', function ($row) { + Channel::where('id', $row['channel_id'])->where('items', '>', 0)->setDec('items'); + }); + return parent::del($ids); + } + + /** + * 还原 + * @param mixed $ids + */ + public function restore($ids = "") + { + $pk = $this->model->getPk(); + $adminIds = $this->getDataLimitAdminIds(); + if (is_array($adminIds)) { + $this->model->where($this->dataLimitField, 'in', $adminIds); + } + if ($ids) { + $this->model->where($pk, 'in', $ids); + } + $archivesChannelIds = $this->model->onlyTrashed()->column('id,channel_id'); + $archivesChannelIds = array_filter($archivesChannelIds); + $this->model->where('id', 'in', array_keys($archivesChannelIds)); + $count = $this->model->restore('1=1'); + if ($count) { + $channelNums = array_count_values($archivesChannelIds); + foreach ($channelNums as $k => $v) { + Channel::where('id', $k)->setInc('items', $v); + } + $this->success(); + } + $this->error(__('No rows were updated')); + + } + + /** + * 移动 + */ + public function move($ids = "") + { + if ($ids) { + $channel_id = $this->request->post('channel_id'); + $pk = $this->model->getPk(); + $adminIds = $this->getDataLimitAdminIds(); + if (is_array($adminIds)) { + $this->model->where($this->dataLimitField, 'in', $adminIds); + } + $this->model->where($pk, 'in', $ids); + $channel = Channel::get($channel_id); + if ($channel && $channel['type'] === 'list') { + $channelNums = \app\admin\model\Archives:: + with('channel') + ->where('archives.' . $pk, 'in', $ids) + ->where('channel_id', '<>', $channel['id']) + ->field('channel_id,COUNT(*) AS nums') + ->group('channel_id') + ->select(); + $result = $this->model + ->where('model_id', '=', $channel['model_id']) + ->where('channel_id', '<>', $channel['id']) + ->update(['channel_id' => $channel_id]); + if ($result) { + $count = 0; + foreach ($channelNums as $k => $v) { + if ($v['channel']) { + Channel::where('id', $v['channel_id'])->where('items', '>', 0)->setDec('items', min($v['channel']['items'], $v['nums'])); + } + $count += $v['nums']; + } + Channel::where('id', $channel_id)->setInc('items', $count); + $this->success(); + } else { + $this->error(__('No rows were updated')); + } + } else { + $this->error(__('No rows were updated')); + } + $this->error(__('Parameter %s can not be empty', 'ids')); + } + } + + /** + * 获取栏目列表 + * @internal + */ + public function get_channel_fields() + { + $this->view->engine->layout(false); + $channel_id = $this->request->post('channel_id'); + $archives_id = $this->request->post('archives_id'); + $channel = Channel::get($channel_id, 'model'); + if ($channel && $channel['type'] === 'list') { + + $values = []; + if ($archives_id) { + $values = db($channel['model']['table'])->where('id', $archives_id)->find(); + } + + $fields = \app\admin\model\Fields::where('model_id', $channel['model_id']) + ->order('weigh desc,id desc') + ->select(); + foreach ($fields as $k => $v) { + $v->value = isset($values[$v['name']]) ? $values[$v['name']] : ''; + $v->rule = str_replace(',', '; ', $v->rule); + if (in_array($v->type, ['checkbox', 'lists', 'images'])) { + $checked = ''; + if ($v['minimum'] && $v['maximum']) + $checked = "{$v['minimum']}~{$v['maximum']}"; + else if ($v['minimum']) + $checked = "{$v['minimum']}~"; + else if ($v['maximum']) + $checked = "~{$v['maximum']}"; + if ($checked) + $v->rule .= (';checked(' . $checked . ')'); + } + if (in_array($v->type, ['checkbox', 'radio']) && stripos($v->rule, 'required') !== false) { + $v->rule = str_replace('required', 'checked', $v->rule); + } + if (in_array($v->type, ['selects'])) { + $v->extend .= (' ' . 'data-max-options="' . $v['maximum'] . '"'); + } + } + + $this->view->assign('fields', $fields); + $this->view->assign('values', $values); + $this->success('', null, ['html' => $this->view->fetch('fields')]); + } else { + $this->error(__('Please select channel')); + } + $this->error(__('Parameter %s can not be empty', 'ids')); + } + + /** + * 检测元素是否可用 + * @internal + */ + public function check_element_available() + { + $id = $this->request->request('id'); + $name = $this->request->request('name'); + $value = $this->request->request('value'); + $name = substr($name, 4, -1); + if (!$name) { + $this->error(__('Parameter %s can not be empty', 'name')); + } + if ($id) { + $this->model->where('id', '<>', $id); + } + $exist = $this->model->where($name, $value)->find(); + if ($exist) { + $this->error(__('The data already exist')); + } else { + $this->success(); + } + } + +} diff --git a/addons/cms/application/admin/controller/cms/Block.php b/addons/cms/application/admin/controller/cms/Block.php new file mode 100644 index 0000000000000000000000000000000000000000..800ac737fa933015cafffdc506afc8b63225fb6f --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Block.php @@ -0,0 +1,55 @@ +model = model('Block'); + $this->view->assign("statusList", $this->model->getStatusList()); + } + + public function selectpage_type() + { + $list = []; + $word = (array)$this->request->request("q_word/a"); + $field = $this->request->request('showField'); + $keyValue = $this->request->request('keyValue'); + if (!$keyValue) { + if (array_filter($word)) { + foreach ($word as $k => $v) { + $list[] = ['id' => $v, $field => $v]; + } + } + $typeArr = \app\admin\model\Block::column('type'); + $typeArr = array_unique($typeArr); + foreach ($typeArr as $index => $item) { + $list[] = ['id' => $item, $field => $item]; + } + } else { + $list[] = ['id' => $keyValue, $field => $keyValue]; + } + return json(['total' => count($list), 'list' => $list]); + } + + public function import() + { + return parent::import(); + } + +} diff --git a/addons/cms/application/admin/controller/cms/Channel.php b/addons/cms/application/admin/controller/cms/Channel.php new file mode 100644 index 0000000000000000000000000000000000000000..50c08e27bf274f0389d479b76303d081818da4f2 --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Channel.php @@ -0,0 +1,174 @@ +request->filter(['strip_tags']); + $this->model = model('Channel'); + + $tree = Tree::instance(); + $tree->init(collection($this->model->order('weigh desc,id desc')->select())->toArray(), 'parent_id'); + $this->channelList = $tree->getTreeList($tree->getTreeArray(0), 'name'); + $this->modelList = \app\admin\model\Modelx::order('id asc')->select(); + + $this->view->assign("modelList", $this->modelList); + $this->view->assign("channelList", $this->channelList); + $this->view->assign("typeList", ChannelModel::getTypeList()); + $this->view->assign("statusList", ChannelModel::getStatusList()); + } + + /** + * 查看 + */ + public function index() + { + + if ($this->request->isAjax()) { + $search = $this->request->request("search"); + //构造父类select列表选项数据 + $list = []; + if ($search) { + foreach ($this->channelList as $k => $v) { + if (stripos($v['name'], $search) !== false || stripos($v['nickname'], $search) !== false) { + $list[] = $v; + } + } + } else { + $list = $this->channelList; + } + $modelNameArr = []; + foreach ($this->modelList as $k => $v) { + $modelNameArr[$v['id']] = $v['name']; + } + foreach ($list as $k => &$v) { + $v['model_name'] = $v['model_id'] && isset($modelNameArr[$v['model_id']]) ? $modelNameArr[$v['model_id']] : __('None'); + } + $total = count($list); + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + return $this->view->fetch(); + } + + /** + * 添加 + */ + public function add() + { + if ($this->request->isPost()) { + $params = $this->request->post("row/a"); + if ($params) { + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $params[$this->dataLimitField] = $this->auth->id; + } + try { + //是否采用模型验证 + if ($this->modelValidate) { + $name = basename(str_replace('\\', '/', get_class($this->model))); + $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : true) : $this->modelValidate; + $this->model->validate($validate); + } + $nameArr = array_filter(explode("\n", str_replace("\r\n", "\n", $params['name']))); + if (count($nameArr) > 1) { + foreach ($nameArr as $index => $item) { + $itemArr = array_filter(explode('|', $item)); + $params['name'] = $itemArr[0]; + $params['diyname'] = isset($itemArr[1]) ? $itemArr[1] : ''; + $result = $this->model->allowField(true)->isUpdate(false)->data($params)->save(); + } + } else { + $result = $this->model->allowField(true)->save($params); + } + if ($result !== false) { + $this->success(); + } else { + $this->error($this->model->getError()); + } + } catch (\think\exception\PDOException $e) { + $this->error($e->getMessage()); + } + } + $this->error(__('Parameter %s can not be empty', '')); + } + return $this->view->fetch(); + } + + /** + * Selectpage搜索 + * + * @internal + */ + public function selectpage() + { + return parent::selectpage(); + } + + /** + * 检测元素是否可用 + * @internal + */ + public function check_element_available() + { + $id = $this->request->request('id'); + $name = $this->request->request('name'); + $value = $this->request->request('value'); + $name = substr($name, 4, -1); + if (!$name) { + $this->error(__('Parameter %s can not be empty', 'name')); + } + if ($name == 'diyname') { + if ($id) { + $this->model->where('id', '<>', $id); + } + $exist = $this->model->where($name, $value)->find(); + if ($exist) { + $this->error(__('The data already exist')); + } else { + $this->success(); + } + } else if ($name == 'name') { + $nameArr = array_filter(explode("\n", str_replace("\r\n", "\n", $value))); + if (count($nameArr) > 1) { + foreach ($nameArr as $index => $item) { + $itemArr = array_filter(explode('|', $item)); + if (!isset($itemArr[1])) { + $this->error('格式:分类名称|自定义名称'); + } + $exist = \app\admin\model\Channel::getByDiyname($itemArr[1]); + if ($exist) { + $this->error('自定义名称[' . $itemArr[1] . ']已经存在'); + } + } + $this->success(); + } else { + $this->success(); + } + } + } + +} diff --git a/addons/cms/application/admin/controller/cms/Comment.php b/addons/cms/application/admin/controller/cms/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..a8042439a585bac0cc1dae0ff3f42435e0b2b4f3 --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Comment.php @@ -0,0 +1,67 @@ +model = model('Comment'); + $this->view->assign("typeList", $this->model->getTypeList()); + $this->view->assign("statusList", $this->model->getStatusList()); + } + + /** + * 查看 + */ + public function index() + { + $this->relationSearch = true; + //设置过滤方法 + $this->request->filter(['strip_tags']); + if ($this->request->isAjax()) + { + //如果发送的来源是Selectpage,则转发到Selectpage + if ($this->request->request('keyField')) + { + return $this->selectpage(); + } + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + $total = $this->model + ->with('archives') + ->where($where) + ->order($sort, $order) + ->count(); + + $list = $this->model + ->with('archives') + ->where($where) + ->order($sort, $order) + ->limit($offset, $limit) + ->select(); + + $list = collection($list)->toArray(); + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + return $this->view->fetch(); + } +} diff --git a/addons/cms/application/admin/controller/cms/Fields.php b/addons/cms/application/admin/controller/cms/Fields.php new file mode 100644 index 0000000000000000000000000000000000000000..8b9126dd7b0bdeb18580a5512401a8b5e3beafbe --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Fields.php @@ -0,0 +1,90 @@ +model = model('Fields'); + $this->view->assign("statusList", $this->model->getStatusList()); + $this->view->assign('typeList', Config::getTypeList()); + $this->view->assign('regexList', Config::getRegexList()); + } + + /** + * 查看 + */ + public function index() + { + $model_id = $this->request->param('model_id'); + //设置过滤方法 + $this->request->filter(['strip_tags']); + if ($this->request->isAjax()) { + list($where, $sort, $order, $offset, $limit) = $this->buildparams(); + $total = $this->model + ->where('model_id', $model_id) + ->where($where) + ->order($sort, $order) + ->count(); + + $list = $this->model + ->where('model_id', $model_id) + ->where($where) + ->order($sort, $order) + ->limit($offset, $limit) + ->select(); + + $result = array("total" => $total, "rows" => $list); + + return json($result); + } + $this->assignconfig('model_id', $model_id); + return $this->view->fetch(); + } + + /** + * 规则列表 + * @internal + */ + public function rulelist() + { + //主键 + $primarykey = $this->request->request("keyField"); + //主键值 + $primaryvalue = $this->request->request("keyValue"); + + $regexList = Config::getRegexList(); + $list = []; + foreach ($regexList as $k => $v) { + if ($primaryvalue !== null) { + if ($primaryvalue == $k) { + $list[] = ['id' => $k, 'name' => $v]; + } + } else { + $list[] = ['id' => $k, 'name' => $v]; + } + } + return json(['list' => $list]); + } + +} diff --git a/addons/cms/application/admin/controller/cms/Modelx.php b/addons/cms/application/admin/controller/cms/Modelx.php new file mode 100644 index 0000000000000000000000000000000000000000..7005bdcd59ccc6745a2a37e22a9f8575d44cd272 --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Modelx.php @@ -0,0 +1,26 @@ +model = model('Modelx'); + } + +} diff --git a/addons/cms/application/admin/controller/cms/Page.php b/addons/cms/application/admin/controller/cms/Page.php new file mode 100644 index 0000000000000000000000000000000000000000..8aef1b669a5387ddc38d835c4e86839ceb6ae662 --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Page.php @@ -0,0 +1,56 @@ +model = model('Page'); + $this->view->assign("flagList", $this->model->getFlagList()); + $this->view->assign("statusList", $this->model->getStatusList()); + } + + /** + * 动态下拉选择类型 + * @internal + */ + public function selectpage_type() + { + $list = []; + $word = (array)$this->request->request("q_word/a"); + $field = $this->request->request('showField'); + $keyValue = $this->request->request('keyValue'); + if (!$keyValue) { + if (array_filter($word)) { + foreach ($word as $k => $v) { + $list[] = ['id' => $v, $field => $v]; + } + } + $typeArr = \app\admin\model\Page::column('type'); + $typeArr = array_unique($typeArr); + foreach ($typeArr as $index => $item) { + $list[] = ['id' => $item, $field => $item]; + } + } else { + $list[] = ['id' => $keyValue, $field => $keyValue]; + } + return json(['total' => count($list), 'list' => $list]); + } + +} diff --git a/addons/cms/application/admin/controller/cms/Tags.php b/addons/cms/application/admin/controller/cms/Tags.php new file mode 100644 index 0000000000000000000000000000000000000000..07077ba30217a8a25756738ff58b7858e820db2c --- /dev/null +++ b/addons/cms/application/admin/controller/cms/Tags.php @@ -0,0 +1,46 @@ +model = model('Tags'); + } + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个方法 + * 因此在当前控制器中可不用编写增删改查的代码,如果需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + public function selectpage() + { + $response = parent::selectpage(); + $word = (array)$this->request->request("q_word/a"); + if (array_filter($word)) { + $result = $response->getData(); + foreach ($word as $k => $v) { + array_unshift($result['list'], ['id' => $v, 'name' => $v]); + $result['total']++; + } + $response->data($result); + } + return $response; + } + +} diff --git a/addons/cms/application/admin/lang/zh-cn/cms/archives.php b/addons/cms/application/admin/lang/zh-cn/cms/archives.php new file mode 100644 index 0000000000000000000000000000000000000000..0662fad55f690633dba4ca0c9ba547710122179d --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/archives.php @@ -0,0 +1,41 @@ + '栏目', + 'Channel_id' => '栏目ID', + 'Channel_name' => '栏目名称', + 'Channel list' => '栏目列表', + 'Addon list' => '副表列表', + 'Model' => '模型', + 'Model_id' => '模型ID', + 'Title' => '文章标题', + 'Flag' => '标志', + 'Image' => '缩略图', + 'Keywords' => '关键字', + 'Description' => '描述', + 'Tags' => 'TAG', + 'Weigh' => '权重', + 'Views' => '浏览', + 'Comments' => '评论', + 'Likes' => '点赞', + 'Dislikes' => '点踩', + 'Diyname' => '自定义URL', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'Deletetime' => '删除时间', + 'Recycle bin' => '回收站', + 'Restore' => '还原', + 'Restore all' => '还原全部', + 'Destroy' => '销毁', + 'Destroy all' => '清空回收站', + 'Nothing need restore' => '没有需要还原的数据', + 'Move tips' => '只能将数据移动到相同模型的栏目下,不同模型的数据移动将被忽略', + 'Are you sure you want to truncate?' => '确认清空回收站?', + 'Can not be digital' => '不能为数字', + 'Please select channel' => '请选择分类', + 'The data already exist' => '已经存在', + 'Status' => '状态', + 'Array key' => '键', + 'Array value' => '值', + 'Publish' => '发布' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/block.php b/addons/cms/application/admin/lang/zh-cn/cms/block.php new file mode 100644 index 0000000000000000000000000000000000000000..b97f34d6174ce07c470b5678dd92ba9b93687b67 --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/block.php @@ -0,0 +1,13 @@ + '类型', + 'Name' => '名称', + 'Title' => '标题', + 'Image' => '图片', + 'Url' => '链接', + 'Content' => '内容', + 'Createtime' => '添加时间', + 'Updatetime' => '更新时间', + 'Status' => '状态' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/channel.php b/addons/cms/application/admin/lang/zh-cn/cms/channel.php new file mode 100644 index 0000000000000000000000000000000000000000..288f5d97ab16f266f72a8c5e5bbedbd53acaacae --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/channel.php @@ -0,0 +1,29 @@ + '类型', + 'Model_id' => '模型ID', + 'Model_name' => '模型名称', + 'Parent_id' => '父ID', + 'Parent_ids' => '父ID集合', + 'Child_ids' => '子ID集合', + 'Name' => '名称', + 'Image' => '图片', + 'Keywords' => '关键字', + 'Description' => '描述', + 'Diyname' => '自定义名称', + 'Outlink' => '外部链接', + 'Items' => '文章数量', + 'Weigh' => '权重', + 'Channeltpl' => '栏目页模板', + 'Listtpl' => '列表页模板', + 'Showtpl' => '详情页模板', + 'Pagesize' => '分页大小', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'The data already exist' => '已经存在', + 'Status' => '状态', + 'Channel' => '栏目', + 'List' => '列表', + 'Link' => '外部链接' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/comment.php b/addons/cms/application/admin/lang/zh-cn/cms/comment.php new file mode 100644 index 0000000000000000000000000000000000000000..6b48b392967a51f64663e24a1fddee9de5a78a1b --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/comment.php @@ -0,0 +1,19 @@ + 'ID', + 'Type' => '类型', + 'Archives' => '文档', + 'Page' => '单页', + 'Aid' => '关联ID', + 'Pid' => '父ID', + 'User_id' => '会员ID', + 'Content' => '内容', + 'Comments' => '评论数', + 'Ip' => 'IP', + 'Useragent' => 'User Agent', + 'Subscribe' => '订阅', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'Status' => '状态' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/fields.php b/addons/cms/application/admin/lang/zh-cn/cms/fields.php new file mode 100644 index 0000000000000000000000000000000000000000..8d8d562bf11257a69171ee54ebdfac31ecf23135 --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/fields.php @@ -0,0 +1,43 @@ + '模型ID', + 'Name' => '名称', + 'Type' => '类型', + 'Title' => '标题', + 'Content' => '条目列表', + 'Rule' => '验证规则', + 'Validate Msg' => '错误消息', + 'Validate Ok' => '成功消息', + 'Validate Tip' => '提示消息', + 'Extend' => '扩展信息', + 'Weigh' => '排序', + 'Setting' => '字段设置', + 'Length' => '字段长度', + 'Decimals' => '小数点长度', + 'Minimum' => '最少选择', + 'Maximum' => '最大选择', + 'Defaultvalue' => '默认值', + 'Isfilter' => '是否列表筛选', + 'String' => '字符', + 'Text' => '文本', + 'Editor' => '编辑器', + 'Number' => '数字', + 'Date' => '日期', + 'Time' => '时间', + 'Datetime' => '日期时间', + 'Image' => '图片', + 'Images' => '图片(多)', + 'File' => '文件', + 'Files' => '文件(多)', + 'Select' => '列表', + 'Selects' => '列表(多选)', + 'Checkbox' => '复选', + 'Radio' => '单选', + 'Array' => '数组', + 'Array key' => '键名', + 'Array value' => '键值', + 'Createtime' => '添加时间', + 'Updatetime' => '更新时间', + 'Status' => '状态' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/modelx.php b/addons/cms/application/admin/lang/zh-cn/cms/modelx.php new file mode 100644 index 0000000000000000000000000000000000000000..0a46902733d26d413e65ae758ebc4942446c3921 --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/modelx.php @@ -0,0 +1,15 @@ + '模型名称', + 'Table' => '表名', + 'Fields' => '字段列表', + 'Channeltpl' => '栏目页模板', + 'Listtpl' => '列表页模板', + 'Showtpl' => '详情页模板', + 'Main list' => '主表列表', + 'Addon list' => '副表列表', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'Setting' => '配置' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/page.php b/addons/cms/application/admin/lang/zh-cn/cms/page.php new file mode 100644 index 0000000000000000000000000000000000000000..44154bb493766711b2538a7a5239d73e90cd55af --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/page.php @@ -0,0 +1,22 @@ + 'ID', + 'Category_id' => '分类ID', + 'Type' => '类型', + 'Title' => '标题', + 'Keywords' => '关键字', + 'Description' => '描述', + 'Flag' => '标志', + 'Image' => '图片', + 'Content' => '内容', + 'Icon' => '图标', + 'Views' => '点击', + 'Comments' => '评论', + 'Diyname' => '自定义', + 'Showtpl' => '视图模板', + 'Createtime' => '创建时间', + 'Updatetime' => '更新时间', + 'Weigh' => '权重', + 'Status' => '状态' +]; diff --git a/addons/cms/application/admin/lang/zh-cn/cms/tags.php b/addons/cms/application/admin/lang/zh-cn/cms/tags.php new file mode 100644 index 0000000000000000000000000000000000000000..68e086b85b34d896cd61380ac0c4d9221b12f776 --- /dev/null +++ b/addons/cms/application/admin/lang/zh-cn/cms/tags.php @@ -0,0 +1,7 @@ + '标签名称', + 'Archives' => '文档ID集合', + 'Nums' => '文档数量' +]; diff --git a/addons/cms/application/admin/model/Archives.php b/addons/cms/application/admin/model/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..9d86aa88031fc80a93739676039f54ffe686354f --- /dev/null +++ b/addons/cms/application/admin/model/Archives.php @@ -0,0 +1,138 @@ + $data['id'], ':diyname' => $diyname, ':channel' => $data['channel_id']]); + } + + protected static function init() + { + self::afterInsert(function ($row) { + $pk = $row->getPk(); + $channel = Channel::get($row['channel_id']); + $row->getQuery()->where($pk, $row[$pk])->update(['model_id' => $channel ? $channel['model_id'] : 0, 'weigh' => $row[$pk]]); + Channel::where('id', $row['channel_id'])->setInc('items'); + }); + self::beforeWrite(function ($row) { + //在更新之前对数组进行处理 + foreach ($row->getData() as $k => $value) { + if (is_array($value) && isset($value['field'])) { + $value = json_encode(Config::getArrayData($value), JSON_UNESCAPED_UNICODE); + } else { + $value = is_array($value) ? implode(',', $value) : $value; + } + $row->$k = $value; + } + }); + self::afterWrite(function ($row) { + if (isset($row['channel_id'])) { + //在更新成功后刷新副表、TAGS表数据、栏目表 + $channel = Channel::get($row->channel_id); + if ($channel) { + $model = Modelx::get($channel['model_id']); + if ($model && isset($row['content'])) { + $values = array_intersect_key($row->getData(), array_flip($model->fields)); + $values['id'] = $row['id']; + $values['content'] = $row['content']; + db($model['table'])->insert($values, TRUE); + } + } + } + if (isset($row['tags'])) { + $tags = array_filter(explode(',', $row['tags'])); + if ($tags) { + $tagslist = Tags::where('name', 'in', $tags)->select(); + foreach ($tagslist as $k => $v) { + $archives = explode(',', $v['archives']); + if (!in_array($row['id'], $archives)) { + $archives[] = $row['id']; + $v->archives = implode(',', $archives); + $v->nums++; + $v->save(); + } + $tags = array_diff($tags, [$v['name']]); + } + $list = []; + foreach ($tags as $k => $v) { + $list[] = ['name' => $v, 'archives' => $row['id'], 'nums' => 1]; + } + if ($list) { + model('Tags')->saveAll($list); + } + } + } + }); + } + + public function getFlagList() + { + return ['hot' => __('Hot'), 'new' => __('New'), 'recommend' => __('Recommend')]; + } + + public function getStatusList() + { + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; + } + + public function getFlagTextAttr($value, $data) + { + $value = $value ? $value : $data['flag']; + $valueArr = $value ? explode(',', $value) : []; + $list = $this->getFlagList(); + return implode(',', array_intersect_key($list, array_flip($valueArr))); + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + public function getPublishtimeTextAttr($value, $data) + { + $value = $value ? $value : $data['publishtime']; + return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; + } + + protected function setPublishtimeAttr($value) + { + return $value && !is_numeric($value) ? strtotime($value) : $value; + } + + public function channel() + { + return $this->belongsTo('Channel', 'channel_id', '', [], 'LEFT')->setEagerlyType(0); + } + +} diff --git a/addons/cms/application/admin/model/Block.php b/addons/cms/application/admin/model/Block.php new file mode 100644 index 0000000000000000000000000000000000000000..77172df00f07113d3f5bafe5c0ac7da6bb4652e6 --- /dev/null +++ b/addons/cms/application/admin/model/Block.php @@ -0,0 +1,34 @@ + __('Normal'), 'hidden' => __('Hidden')]; + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + +} diff --git a/addons/cms/application/admin/model/Channel.php b/addons/cms/application/admin/model/Channel.php new file mode 100644 index 0000000000000000000000000000000000000000..96afae7361f45b39397c693dee280cfebaaa8522 --- /dev/null +++ b/addons/cms/application/admin/model/Channel.php @@ -0,0 +1,97 @@ + $data['id'], ':diyname' => $diyname]); + } + + protected static function init() + { + self::afterInsert(function ($row) { + //创建时自动添加权重值 + $pk = $row->getPk(); + $row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]); + }); + self::afterDelete(function ($row) { + //删除时,删除子节点,同时将所有相关文档移入回收站 + static $tree; + if (!$tree) { + $tree = \fast\Tree::instance(); + $tree->init(collection(Channel::order('weigh desc,id desc')->field('id,parent_id,name,type,diyname,status')->select())->toArray(), 'parent_id'); + } + $childIds = $tree->getChildrenIds($row['id']); + if ($childIds) { + Channel::destroy(function ($query) use ($childIds) { + $query->where('id', 'in', $childIds); + }); + } + $childIds[] = $row['id']; + db('cms_archives')->where('channel_id', 'in', $childIds)->update(['deletetime' => time()]); + }); + self::afterWrite(function ($row) { + $changed = $row->getChangedData(); + //隐藏时判断是否有子节点,有则隐藏 + if (isset($changed['status']) && $changed['status'] == 'hidden') { + static $tree; + if (!$tree) { + $tree = \fast\Tree::instance(); + $tree->init(collection(Channel::order('weigh desc,id desc')->field('id,parent_id,name,type,diyname,status')->select())->toArray(), 'parent_id'); + } + $childIds = $tree->getChildrenIds($row['id']); + db('cms_channel')->where('id', 'in', $childIds)->update(['status' => 'hidden']); + } + }); + } + + public static function getTypeList() + { + return ['channel' => __('Channel'), 'list' => __('List'), 'link' => __('Link')]; + } + + public static function getStatusList() + { + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; + } + + public function getTypeTextAttr($value, $data) + { + $value = $value ? $value : $data['type']; + $list = $this->getTypeList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + public function model() + { + return $this->belongsTo('Modelx', 'model_id')->setEagerlyType(0); + } + +} diff --git a/addons/cms/application/admin/model/Comment.php b/addons/cms/application/admin/model/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..77ea8be3cea001d8fc0f622cd623808341a1e5cb --- /dev/null +++ b/addons/cms/application/admin/model/Comment.php @@ -0,0 +1,58 @@ + __('Archives'), 'page' => __('Page')]; + } + + public function getStatusList() + { + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; + } + + + public function getTypeTextAttr($value, $data) + { + $value = $value ? $value : $data['type']; + $list = $this->getTypeList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + + public function archives() + { + return $this->belongsTo('Archives', 'aid', '', [], 'LEFT')->setEagerlyType(0); + } + +} diff --git a/addons/cms/application/admin/model/Fields.php b/addons/cms/application/admin/model/Fields.php new file mode 100644 index 0000000000000000000000000000000000000000..a1738eb806eb454b40db1ae8cf8447dc281fedee --- /dev/null +++ b/addons/cms/application/admin/model/Fields.php @@ -0,0 +1,134 @@ +error = $error; + } + + protected static function init() + { + $beforeUpdateCallback = function ($row) { + + }; + + $afterInsertCallback = function ($row) { + //为了避免引起更新的事件回调,这里采用直接执行SQL的写法 + $row->query($row->fetchSql(true)->update(['id' => $row['id'], 'weigh' => $row['id']])); + $model = Modelx::get($row['model_id']); + if ($model) { + $sql = Alter::instance() + ->setTable($model['table']) + ->setName($row['name']) + ->setLength($row['length']) + ->setContent($row['content']) + ->setDecimals($row['decimals']) + ->setDefaultvalue($row['defaultvalue']) + ->setComment($row['title']) + ->setType($row['type']) + ->getAddSql(); + try { + db()->query($sql); + $fields = Fields::where('model_id', $model['id'])->field('name')->column('name'); + $model->fields = implode(',', $fields); + $model->save(); + } catch (PDOException $e) { + $row->getQuery()->where('id', $row->id)->delete(); + throw new Exception($e->getMessage()); + } + } + }; + $afterUpdateCallback = function ($row) { + $model = Modelx::get($row['model_id']); + if ($model) { + $alter = Alter::instance(); + if (isset($row['oldname']) && $row['oldname'] != $row['name']) { + $alter->setOldname($row['oldname']); + } + $sql = $alter + ->setTable($model['table']) + ->setName($row['name']) + ->setLength($row['length']) + ->setContent($row['content']) + ->setDecimals($row['decimals']) + ->setDefaultvalue($row['defaultvalue']) + ->setComment($row['title']) + ->setType($row['type']) + ->getModifySql(); + db()->query($sql); + $fields = Fields::where('model_id', $model['id'])->field('name')->column('name'); + $model->fields = implode(',', $fields); + $model->save(); + } + }; + + self::beforeInsert($beforeUpdateCallback); + self::beforeUpdate($beforeUpdateCallback); + + self::afterInsert($afterInsertCallback); + self::afterUpdate($afterUpdateCallback); + + self::afterDelete(function ($row) { + $model = Modelx::get($row['model_id']); + if ($model) { + $sql = Alter::instance() + ->setTable($model['table']) + ->setName($row['name']) + ->getDropSql(); + try { + db()->query($sql); + } catch (PDOException $e) { + + } + } + }); + } + + public function getContentListAttr($value, $data) + { + return in_array($data['type'], self::$listField) ? Config::decode($data['content']) : $data['content']; + } + + public function getStatusList() + { + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + public function model() + { + return $this->belongsTo('Modelx', 'model_id')->setEagerlyType(0); + } + +} diff --git a/addons/cms/application/admin/model/Modelx.php b/addons/cms/application/admin/model/Modelx.php new file mode 100644 index 0000000000000000000000000000000000000000..6a4bb45834a2e53bab4722bf53ea5a0745ed3e62 --- /dev/null +++ b/addons/cms/application/admin/model/Modelx.php @@ -0,0 +1,36 @@ +query($sql); + }); + } + + public function getFieldsAttr($value, $data) + { + return is_array($value) ? $value : ($value ? explode(',', $value) : []); + } + +} diff --git a/addons/cms/application/admin/model/Page.php b/addons/cms/application/admin/model/Page.php new file mode 100644 index 0000000000000000000000000000000000000000..d2aca16fc047742cc652eee1676f6c6c1a805a13 --- /dev/null +++ b/addons/cms/application/admin/model/Page.php @@ -0,0 +1,61 @@ +save(['weigh' => $row['id']]); + }); + } + + public function getUrlAttr($value, $data) + { + return addon_url('cms/page/index', [':diyname' => $data['diyname']]); + } + + public function getStatusList() + { + return ['normal' => __('Normal'), 'hidden' => __('Hidden')]; + } + + public function getStatusTextAttr($value, $data) + { + $value = $value ? $value : $data['status']; + $list = $this->getStatusList(); + return isset($list[$value]) ? $list[$value] : ''; + } + + public function getFlagList() + { + return ['hot' => __('Hot'), 'index' => __('Index'), 'recommend' => __('Recommend')]; + } + + public function getFlagTextAttr($value, $data) + { + $value = $value ? $value : $data['flag']; + $valueArr = explode(',', $value); + $list = $this->getFlagList(); + return implode(',', array_intersect_key($list, array_flip($valueArr))); + } + +} diff --git a/addons/cms/application/admin/model/Tags.php b/addons/cms/application/admin/model/Tags.php new file mode 100644 index 0000000000000000000000000000000000000000..688ae4acaec7c2e5e7a055ed530b9934b00c81f8 --- /dev/null +++ b/addons/cms/application/admin/model/Tags.php @@ -0,0 +1,27 @@ + $data['name']]); + } + +} diff --git a/addons/cms/application/admin/validate/Archives.php b/addons/cms/application/admin/validate/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..8f8cebc2ecde66a24e9547cafa2ae1526075630a --- /dev/null +++ b/addons/cms/application/admin/validate/Archives.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Block.php b/addons/cms/application/admin/validate/Block.php new file mode 100644 index 0000000000000000000000000000000000000000..eb60cd580486d082ec2b480da15acda079450a79 --- /dev/null +++ b/addons/cms/application/admin/validate/Block.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Channel.php b/addons/cms/application/admin/validate/Channel.php new file mode 100644 index 0000000000000000000000000000000000000000..7df3d4440ce37b39dd1e39dc38b66a863451aefc --- /dev/null +++ b/addons/cms/application/admin/validate/Channel.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Comment.php b/addons/cms/application/admin/validate/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..ffddfd0916f36f753e57dbf9bf7ca4130a76f6c1 --- /dev/null +++ b/addons/cms/application/admin/validate/Comment.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Fields.php b/addons/cms/application/admin/validate/Fields.php new file mode 100644 index 0000000000000000000000000000000000000000..34941a5b95b6ddda2e157b24624dc7bd9b98ec44 --- /dev/null +++ b/addons/cms/application/admin/validate/Fields.php @@ -0,0 +1,49 @@ + 'require|unique:fields,model_id^name', + 'title|管理员' => 'require', + 'model_id|模型ID' => 'require|integer', + 'status|状态' => 'require|in:normal,hidden', + ]; + + /** + * 提示消息 + */ + protected $message = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => [ + 'name', 'title', 'model_id', 'status' + ], + 'edit' => [ + 'name', 'title', 'model_id', 'status' + ], + ]; + + public function __construct(array $rules = array(), $message = array(), $field = array()) + { + //如果是编辑模式,则排除下主键 + $ids = request()->param("ids"); + if ($ids) + { + $this->rule['name|名称'] .= ",{$ids}"; + } + parent::__construct($rules, $message, $field); + } + +} diff --git a/addons/cms/application/admin/validate/Modelx.php b/addons/cms/application/admin/validate/Modelx.php new file mode 100644 index 0000000000000000000000000000000000000000..8b96be187cf531dafca7e1b84f8c0145b1bf9ba9 --- /dev/null +++ b/addons/cms/application/admin/validate/Modelx.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Page.php b/addons/cms/application/admin/validate/Page.php new file mode 100644 index 0000000000000000000000000000000000000000..4eb69a6abc746785ebe1ee6d07c9e64d2cce082d --- /dev/null +++ b/addons/cms/application/admin/validate/Page.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/validate/Tags.php b/addons/cms/application/admin/validate/Tags.php new file mode 100644 index 0000000000000000000000000000000000000000..cc9f954fddb29c0c4ca2713b4b5ecebba0b34065 --- /dev/null +++ b/addons/cms/application/admin/validate/Tags.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/addons/cms/application/admin/view/cms/archives/add.html b/addons/cms/application/admin/view/cms/archives/add.html new file mode 100644 index 0000000000000000000000000000000000000000..371aa04e8717f40b08ad8bb3ef0b8f7f2eb4e0e4 --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/add.html @@ -0,0 +1,192 @@ +
+
+
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+ + +
+ +
+
    +
    +
    +
    + +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +
    相关信息
    +
    +
    +
    +
    +
    + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    状态
    +
    +
    +
    +
    +
    + +
    + + + +
    +
    +
    + +
    +
    + {foreach name="statusList" item="vo"} + + {/foreach} +
    +
    +
    +
    + +
    +
    + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/addons/cms/application/admin/view/cms/archives/content.html b/addons/cms/application/admin/view/cms/archives/content.html new file mode 100644 index 0000000000000000000000000000000000000000..3b402ee4f123a63842861feb3696b4c1b3363174 --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/content.html @@ -0,0 +1,21 @@ +
    + {:build_heading()} + +
    +
    +
    +
    +
    + {:build_toolbar('refresh,edit,del')} +
    + +
    +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/addons/cms/application/admin/view/cms/archives/edit.html b/addons/cms/application/admin/view/cms/archives/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..83cd966e4bb211c9d1d172797ac589ba4e9225a4 --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/edit.html @@ -0,0 +1,201 @@ +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    + +
    +
    + +
    + + +
    + +
    +
      +
      +
      +
      + +
      + +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      +
      +
      + +
      + +
      + +
      +
      +
      +
      +
      相关信息
      +
      +
      +
      +
      +
      + +
      +
      + + + +
      +
      +
      +
      + +
      +
      + + + +
      +
      +
      +
      + +
      +
      + + + +
      +
      +
      +
      + +
      +
      + + +
      +
      +
      +
      + +
      +
      + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      状态
      +
      +
      +
      +
      +
      + +
      + + + +
      +
      +
      + +
      +
      + {foreach name="statusList" item="vo"} + + {/foreach} +
      +
      +
      +
      + +
      +
      + + + + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      \ No newline at end of file diff --git a/addons/cms/application/admin/view/cms/archives/fields.html b/addons/cms/application/admin/view/cms/archives/fields.html new file mode 100644 index 0000000000000000000000000000000000000000..7fbbac61bff00fd34a74014c9478dcb6d05f128e --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/fields.html @@ -0,0 +1,96 @@ +{foreach $fields as $item} + +
      +
      {$item.title}
      +
      + {switch $item.type} + {case string} + + {/case} + {case value="text" break="0"}{/case} + {case editor} + + {/case} + {case array} + {php}$arrList=isset($values[$item['name']])?(array)json_decode($item['value'],true):$item['content_list'];{/php} +
      +
      + {:__('Array key')} + {:__('Array value')} +
      + + {foreach $arrList as $key => $vo} +
      + + + + +
      + {/foreach} +
      {:__('Append')}
      +
      + {/case} + {case date} + + {/case} + {case time} + + {/case} + {case datetime} + + {/case} + {case number} + + {/case} + {case checkbox} + {foreach name="item.content_list" item="vo"} + + {/foreach} + {/case} + {case radio} + {foreach name="item.content_list" item="vo"} + + {/foreach} + {/case} + {case value="select" break="0"}{/case} + {case value="selects"} + + {/case} + {case value="image" break="0"}{/case} + {case value="images"} +
      + +
      + + +
      + +
      + + {/case} + {case value="file" break="0"}{/case} + {case value="files"} +
      + +
      + + +
      + +
      + {/case} + {case bool} + + + {/case} + {case custom} + {$item.content} + {/case} + {/switch} +
      +
      +{/foreach} \ No newline at end of file diff --git a/addons/cms/application/admin/view/cms/archives/index.html b/addons/cms/application/admin/view/cms/archives/index.html new file mode 100644 index 0000000000000000000000000000000000000000..47eb8d9acca04912b0a8b9a93eaa848e3c08af33 --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/index.html @@ -0,0 +1,91 @@ + +
      + +
      +
      + {:build_heading()} +
      +
      +
      +
      + {:build_toolbar('refresh,add,del',['add'=>[url('cms.archives/add'), 'btn btn-success btn-addtabs', 'fa fa-plus', __('Add'), __('Add')]])} + {:__('Move')} + + {:__('Recycle bin')} + + + +
      + +
      +
      +
      + +
      +
      +
      +
      + diff --git a/addons/cms/application/admin/view/cms/archives/recyclebin.html b/addons/cms/application/admin/view/cms/archives/recyclebin.html new file mode 100644 index 0000000000000000000000000000000000000000..ab39d45a1b57e667bbb479f9f50be5eb5f8067c1 --- /dev/null +++ b/addons/cms/application/admin/view/cms/archives/recyclebin.html @@ -0,0 +1,23 @@ +
      + {:build_heading()} + +
      +
      +
      + +
      + +
      +
      +
      diff --git a/addons/cms/application/admin/view/cms/block/add.html b/addons/cms/application/admin/view/cms/block/add.html new file mode 100644 index 0000000000000000000000000000000000000000..c56d17293d95a4cf783a13a8a2eeac04541c7d7c --- /dev/null +++ b/addons/cms/application/admin/view/cms/block/add.html @@ -0,0 +1,66 @@ +
      + +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      + +
      +
      +
      + +
      +
      + +
      + + +
      + +
      +
        +
        +
        +
        + +
        + +
        +
        +
        + +
        + +
        +
        +
        + +
        + +
        + {foreach name="statusList" item="vo"} + + {/foreach} +
        + +
        +
        + +
        diff --git a/addons/cms/application/admin/view/cms/block/edit.html b/addons/cms/application/admin/view/cms/block/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..ac4196b29c6e62f0d42ed0f804ca3260f12d08e8 --- /dev/null +++ b/addons/cms/application/admin/view/cms/block/edit.html @@ -0,0 +1,66 @@ +
        + +
        + +
        + +
        +
        +
        + +
        + +
        +
        +
        + +
        + +
        +
        +
        + +
        +
        + +
        + + +
        + +
        +
          +
          +
          +
          + +
          + +
          +
          +
          + +
          + +
          +
          +
          + +
          + +
          + {foreach name="statusList" item="vo"} + + {/foreach} +
          + +
          +
          + +
          diff --git a/addons/cms/application/admin/view/cms/block/index.html b/addons/cms/application/admin/view/cms/block/index.html new file mode 100644 index 0000000000000000000000000000000000000000..2206b204f6cb8dad66fc34ed01f6b14b5bdf8da4 --- /dev/null +++ b/addons/cms/application/admin/view/cms/block/index.html @@ -0,0 +1,28 @@ +
          + {:build_heading()} + +
          +
          +
          +
          +
          + {:build_toolbar('refresh,add,edit,del')} + +
          + +
          +
          +
          + +
          +
          +
          diff --git a/addons/cms/application/admin/view/cms/channel/add.html b/addons/cms/application/admin/view/cms/channel/add.html new file mode 100644 index 0000000000000000000000000000000000000000..4d1bfaa38a66ca321543edf847653936199f31b2 --- /dev/null +++ b/addons/cms/application/admin/view/cms/channel/add.html @@ -0,0 +1,130 @@ +
          + +
          + +
          + +
          + {foreach name="typeList" item="vo"} + + {/foreach} +
          +
          +
          + + 栏目: 栏目类型下不可以发布文章,但可以添加子栏目、列表、链接
          + 列表: 列表类型下可以发布文章,但不能添加子栏目
          + 链接: 链接类型下不可以发布文章和子级栏目
          +
          +
          +
          +
          +
          + +
          + +
          +
          +
          + +
          + +
          +
          +
          + +
          + +
          +
          +
          + +
          +
          + +
          + + +
          + +
          +
            +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            + +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            + {foreach name="statusList" item="vo"} + + {/foreach} +
            + +
            +
            + +
            diff --git a/addons/cms/application/admin/view/cms/channel/edit.html b/addons/cms/application/admin/view/cms/channel/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..73abf8989ec951892cab611139747c15c55dd160 --- /dev/null +++ b/addons/cms/application/admin/view/cms/channel/edit.html @@ -0,0 +1,136 @@ +
            + +
            + +
            + +
            + {foreach name="typeList" item="vo"} + + {/foreach} +
            +
            +
            + + 栏目: 栏目类型下不可以发布文章,但可以添加子栏目、列表、链接
            + 列表: 列表类型下可以发布文章,但不能添加子栏目
            + 链接: 链接类型下不可以发布文章和子级栏目
            +
            +
            +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            + +
            +
            +
            + +
            +
            + +
            + + +
            + +
            +
              +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              + {foreach name="statusList" item="vo"} + + {/foreach} +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/channel/index.html b/addons/cms/application/admin/view/cms/channel/index.html new file mode 100644 index 0000000000000000000000000000000000000000..1466c35e5f95ccfb093bd7b973216dcdf6874e8d --- /dev/null +++ b/addons/cms/application/admin/view/cms/channel/index.html @@ -0,0 +1,28 @@ +
              + {:build_heading()} + +
              +
              +
              +
              +
              + {:build_toolbar('refresh,add,edit,del')} + +
              + +
              +
              +
              + +
              +
              +
              diff --git a/addons/cms/application/admin/view/cms/comment/add.html b/addons/cms/application/admin/view/cms/comment/add.html new file mode 100644 index 0000000000000000000000000000000000000000..9a7118b0c808ab86c2940b4598fd23a1f693b737 --- /dev/null +++ b/addons/cms/application/admin/view/cms/comment/add.html @@ -0,0 +1,82 @@ +
              + +
              + +
              + + + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + {:build_radios('row[subscribe]', [1=>'是', 0=>'否'])} +
              +
              +
              + +
              + +
              + {foreach name="statusList" item="vo"} + + {/foreach} +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/comment/edit.html b/addons/cms/application/admin/view/cms/comment/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..3f12aad98b95d475fa7a950268577d9da554194f --- /dev/null +++ b/addons/cms/application/admin/view/cms/comment/edit.html @@ -0,0 +1,82 @@ +
              + +
              + +
              + + + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + {:build_radios('row[subscribe]', [1=>'是', 0=>'否'], $row['subscribe'])} +
              +
              +
              + +
              + +
              + {foreach name="statusList" item="vo"} + + {/foreach} +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/comment/index.html b/addons/cms/application/admin/view/cms/comment/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e33e5f01ee5fcfaf422857982a487c84105454c5 --- /dev/null +++ b/addons/cms/application/admin/view/cms/comment/index.html @@ -0,0 +1,32 @@ +
              + {:build_heading()} + +
              + +
              +
              diff --git a/addons/cms/application/admin/view/cms/fields/add.html b/addons/cms/application/admin/view/cms/fields/add.html new file mode 100644 index 0000000000000000000000000000000000000000..fde627395825dc4341e0ce3d87dc8ed69e52b8a3 --- /dev/null +++ b/addons/cms/application/admin/view/cms/fields/add.html @@ -0,0 +1,122 @@ +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              + + + +
              + +
              + +
              +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              + +
              + +
              + +
              +
              +
              + +
              + +
              + {foreach name="statusList" item="vo"} + + {/foreach} +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/fields/edit.html b/addons/cms/application/admin/view/cms/fields/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..de46ee5e67afe2a2aa75742764ca86c6d78d27c2 --- /dev/null +++ b/addons/cms/application/admin/view/cms/fields/edit.html @@ -0,0 +1,121 @@ +
              + + +
              + +
              + +
              +
              +
              + +
              + +
              +
              + + + +
              + +
              + +
              +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              + +
              + +
              + +
              +
              +
              + +
              + +
              + {foreach name="statusList" item="vo"} + + {/foreach} +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/fields/index.html b/addons/cms/application/admin/view/cms/fields/index.html new file mode 100644 index 0000000000000000000000000000000000000000..d042f87a17c2b7316b301fed5a58ce41577c0a78 --- /dev/null +++ b/addons/cms/application/admin/view/cms/fields/index.html @@ -0,0 +1,28 @@ +
              + {:build_heading()} + +
              +
              +
              +
              + + +
              +
              +
              + +
              +
              +
              diff --git a/addons/cms/application/admin/view/cms/modelx/add.html b/addons/cms/application/admin/view/cms/modelx/add.html new file mode 100644 index 0000000000000000000000000000000000000000..33c1c82b3d0dce6b9aaa4151132af01cfc3929cb --- /dev/null +++ b/addons/cms/application/admin/view/cms/modelx/add.html @@ -0,0 +1,40 @@ +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/modelx/edit.html b/addons/cms/application/admin/view/cms/modelx/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..3f53885054dc6def6fffd7b4ca6522b7fad7eb84 --- /dev/null +++ b/addons/cms/application/admin/view/cms/modelx/edit.html @@ -0,0 +1,40 @@ +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              + +
              diff --git a/addons/cms/application/admin/view/cms/modelx/index.html b/addons/cms/application/admin/view/cms/modelx/index.html new file mode 100644 index 0000000000000000000000000000000000000000..543991629fae405a0bd8f9b6e2b238f68e9bc5dd --- /dev/null +++ b/addons/cms/application/admin/view/cms/modelx/index.html @@ -0,0 +1,24 @@ +
              + {:build_heading()} + +
              +
              +
              +
              +
              + {:build_toolbar('refresh,add,edit,del')} +
              + +
              +
              +
              + +
              +
              +
              diff --git a/addons/cms/application/admin/view/cms/modelx/tpl.html b/addons/cms/application/admin/view/cms/modelx/tpl.html new file mode 100644 index 0000000000000000000000000000000000000000..7b49a6b46083cee3b9e151feb9ad33ddacb94237 --- /dev/null +++ b/addons/cms/application/admin/view/cms/modelx/tpl.html @@ -0,0 +1,66 @@ + + + \ No newline at end of file diff --git a/addons/cms/application/admin/view/cms/page/add.html b/addons/cms/application/admin/view/cms/page/add.html new file mode 100644 index 0000000000000000000000000000000000000000..48adf679a207ff5381d9f2574bac06ac59961685 --- /dev/null +++ b/addons/cms/application/admin/view/cms/page/add.html @@ -0,0 +1,96 @@ +
              + +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + +
              +
              +
              + +
              + + + +
              +
              +
              + +
              +
              + +
              + + +
              + +
              +
                +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                + {foreach name="statusList" item="vo"} + + {/foreach} +
                + +
                +
                + +
                diff --git a/addons/cms/application/admin/view/cms/page/edit.html b/addons/cms/application/admin/view/cms/page/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..63fd1ed72a41201279cc2e85f21d1344d80b9f16 --- /dev/null +++ b/addons/cms/application/admin/view/cms/page/edit.html @@ -0,0 +1,107 @@ +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + +
                +
                +
                + +
                + + + +
                +
                +
                + +
                +
                + +
                + + +
                + +
                +
                  +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  + {foreach name="statusList" item="vo"} + + {/foreach} +
                  + +
                  +
                  + +
                  diff --git a/addons/cms/application/admin/view/cms/page/index.html b/addons/cms/application/admin/view/cms/page/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c968a2213a9e14b9df01e3561186835b19134cba --- /dev/null +++ b/addons/cms/application/admin/view/cms/page/index.html @@ -0,0 +1,28 @@ +
                  + {:build_heading()} + +
                  +
                  +
                  +
                  +
                  + {:build_toolbar('refresh,add,edit,del')} + +
                  + +
                  +
                  +
                  + +
                  +
                  +
                  diff --git a/addons/cms/application/admin/view/cms/tags/add.html b/addons/cms/application/admin/view/cms/tags/add.html new file mode 100644 index 0000000000000000000000000000000000000000..5b6a2fac1c8c6ca820c1c0b298a1df11b3ec1380 --- /dev/null +++ b/addons/cms/application/admin/view/cms/tags/add.html @@ -0,0 +1,28 @@ +
                  + +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  + +
                  diff --git a/addons/cms/application/admin/view/cms/tags/edit.html b/addons/cms/application/admin/view/cms/tags/edit.html new file mode 100644 index 0000000000000000000000000000000000000000..97ff20cf6a2dab879145e80797efec6540017f70 --- /dev/null +++ b/addons/cms/application/admin/view/cms/tags/edit.html @@ -0,0 +1,28 @@ +
                  + +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  +
                  + +
                  diff --git a/addons/cms/application/admin/view/cms/tags/index.html b/addons/cms/application/admin/view/cms/tags/index.html new file mode 100644 index 0000000000000000000000000000000000000000..a0379d73a704555938c81261fa16db7a95dbe27b --- /dev/null +++ b/addons/cms/application/admin/view/cms/tags/index.html @@ -0,0 +1,21 @@ +
                  + {:build_heading()} + +
                  +
                  +
                  +
                  +
                  + {:build_toolbar('refresh,delete')} +
                  + +
                  +
                  +
                  + +
                  +
                  +
                  diff --git a/addons/cms/assets/css/common.css b/addons/cms/assets/css/common.css new file mode 100644 index 0000000000000000000000000000000000000000..8556a7eff30c8fd2f5098474d812759e7ffd3c7c --- /dev/null +++ b/addons/cms/assets/css/common.css @@ -0,0 +1,1286 @@ +@import url("../../../css/bootstrap.min.css"); +@import url("../../../libs/font-awesome/css/font-awesome.min.css"); +html, +body { + height: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 400; + overflow-x: hidden; + overflow-y: auto; + padding-top: 40px; + background: #f4f6f8; + font-size: 14px; + color: #616161; +} +.wow { + visibility: hidden; +} +.dropdown:hover > .dropdown-menu { + display: block; + margin-top: 0; +} +.dropdown-submenu { + position: relative; +} +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 3px 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-border-radius: 3px 0 3px 3px; + -moz-background-clip: padding; + border-radius: 3px 0 3px 3px; + background-clip: padding-box; +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} +.dropdown-submenu:hover > a:after { + border-left-color: #fff; +} +.dropdown-submenu > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #ccc; + margin-top: 5px; + margin-right: -10px; +} +.dropdown-submenu.pull-left { + float: none; +} +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 3px 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-border-radius: 3px 0 3px 3px; + -moz-background-clip: padding; + border-radius: 3px 0 3px 3px; + background-clip: padding-box; +} +.navbar { + border: none; +} +.navbar-nav .form-search.focused { + position: relative; +} +.navbar-nav .form-search.focused input { + position: absolute; + top: 0; + right: 0; + width: 250px; +} +.navbar-nav li > a { + font-size: 13px; +} +.navbar-nav li > a h5 { + overflow: hidden; + text-overflow: ellipsis; +} +.navbar-nav > li > a { + font-size: 14px; +} +@media (max-width: 769px) { + ul.dropdown-menu { + position: relative; + width: 100%; + background: #222; + } + ul.dropdown-menu .open > a, + ul.dropdown-menu .open > a:hover, + ul.dropdown-menu .open > a:focus { + background: none; + color: #9d9d9d; + } + ul.dropdown-menu > .dropdown-menu { + position: relative; + width: 100%; + margin: 0; + } + .navbar-nav .form-search { + padding: 0 10px; + } + .navbar-nav .open .dropdown-menu { + position: relative; + width: 100%; + margin: 0; + left: 0; + } + .dropdown-submenu > a:after { + display: none; + } +} +.navbar-brand { + padding: 5px 5px; +} +.toast-top-center { + top: 50px; +} +#toast-container > div { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +/*修复nice-validator和summernote的编辑框冲突*/ +.nice-validator .note-editor .note-editing-area .note-editable { + display: inherit; +} +/*预览区域*/ +.plupload-preview { + padding: 10px; + margin-bottom: 0; +} +.plupload-preview li { + margin-bottom: 10px; +} +.plupload-preview .thumbnail { + margin-bottom: 10px; +} +.plupload-preview a { + display: block; +} +.plupload-preview a:first-child { + height: 90px; +} +.plupload-preview a img { + height: 80px; + object-fit: cover; +} +#floatbtn { + width: 50px; + height: auto; + position: fixed; + top: auto; + right: 50%; + bottom: 10px; + left: auto; + z-index: 80; + margin-right: -620px; +} +#floatbtn.fixed { + position: absolute; + bottom: 279px; + right: 50%; +} +#floatbtn a { + position: relative; + z-index: 90; + display: block; + margin-top: 4px; + width: 50px; + height: 50px; + line-height: 50px; + text-align: center; + font-size: 20px; + color: #d5d5d5; + background-color: #fff; + border: 1px solid #eee; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#floatbtn a.hover:hover { + -webkit-transition: background-color 200ms ease-out; + -moz-transition: background-color 200ms ease-out; + -o-transition: background-color 200ms ease-out; + transition: background-color 200ms ease-out; +} +#floatbtn a.hover:hover:before { + content: ""; + position: absolute; + z-index: 100; + display: block; + width: 100%; + height: 100%; + padding: 10px; + font-size: 14px; + line-height: 15px; + color: #fff; + text-align: center; + background-color: #17bb9c; + -webkit-pointer-events: none; + -moz-pointer-events: none; + pointer-events: none; +} +#floatbtn a.hover:hover i { + display: none; +} +#floatbtn a.hover:hover#fb-tipoff:before { + content: "\7206\6599\6295\7a3f"; + font-weight: 400; +} +#floatbtn a.hover:hover#feedback:before { + content: "\53d1\8868\8bc4\8bba"; +} +#floatbtn a.hover:hover#back-to-top:before { + content: "\56de\5230\9876\90e8"; +} +#floatbtn a#fb-qrcode:hover #fb-qrcode-wrapper { + display: block; +} +#floatbtn .iconfont { + display: inline-block; + font: normal normal normal 14px/1 iconfont; + font-size: inherit; +} +#fb-qrcode-wrapper { + position: absolute; + right: 59px; + top: -55px; + z-index: 120; + display: none; + width: 190px; + height: 212px; + background-color: #fff; + border: 1px solid #eee; +} +#fb-qrcode-wrapper:after { + content: ""; + position: absolute; + right: -6px; + top: 73px; + display: block; + width: 0; + height: 0; + border-left: 6px solid #d5d5d5; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; +} +#fb-qrcode-wrapper .qrcode { + margin-top: 20px; + line-height: 1; +} +#fb-qrcode-wrapper .qrcode img { + width: 128px; + height: 128px; +} +#fb-qrcode-wrapper p { + font-size: 12px; + line-height: 20px; + color: #999; +} +#fb-qrcode-wrapper p em { + color: #dd3067; +} +.text-primary, +.text-primary:hover { + color: #2c3e50; +} +.text-success, +.text-success:hover { + color: #18bc9c; +} +.text-danger, +.text-danger:hover { + color: #e74c3c; +} +.text-warning, +.text-warning:hover { + color: #f39c12; +} +.text-info, +.text-info:hover { + color: #3498db; +} +.well { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.responsive-container { + position: relative; + width: 100%; + border: 1px solid #f8f8f8; +} +footer { + padding: 30px 0; +} +@media (min-width: 979px) { + ul.nav li.dropdown:hover > ul.dropdown-menu { + display: block; + } +} +.main { + background: #fff; + padding: 15px; + min-height: 500px; +} +.main h3 { + margin: 0; + margin-bottom: 10px; + height: 35px; + line-height: 35px; +} +.main h3 label { + display: inline-block; + font-size: 14px; + font-weight: 400; + vertical-align: middle; +} +.main > row { + margin-top: 15px; +} +.main label { + font-weight: 400; +} +.main .fixed-table-container thead th .th-inner { + font-weight: 500; +} +.main table a:not(.btn), +.main .table a:not(.btn) { + text-decoration: none; +} +.nav-sidebar li.active a { + text-decoration: none; + background-color: #ecf0f1; +} +.navbar-toggle .icon-bar { + width: 18px; +} +.footer-inner { + padding: 2em 0; +} +.footer-inner .copyright { + margin-bottom: 20px !important; + line-height: 1.5; +} +.footer-inner .footer-logo { + margin-bottom: 20px; +} +.footer-inner .footer-logo a { + padding: 15px 15px; + background: rgba(0, 0, 0, 0.07); + font-size: 40px; + font-weight: 700; +} +.footer-inner .footer-logo a:hover, +.footer-inner .footer-logo a:focus { + text-decoration: none; +} +.footer-inner h3 { + font-weight: 400; + margin-bottom: 20px; +} +.footer-inner p { + font-weight: 40; +} +.footer-inner p:last-child { + margin-bottom: 0; +} +.footer-inner .links { + padding: 0; + margin: 0 0 20px 0; +} +.footer-inner .links li { + list-style: none; + padding: 5px 0; +} +.footer-inner .links li a:hover { + text-decoration: none; +} +.footer-inner .footer-social { + text-align: right; + margin-top: 0; +} +.footer-inner .footer-social a { + margin-right: 15px; + margin-bottom: 10px; + font-size: 20px; +} +.footer-inner .footer-social a:hover { + text-decoration: none; +} +#footer { + border-top: 1px solid #ddd; + margin-top: 50px; + padding-top: 20px; +} +.article-section { + background: #fff; + padding: 15px; + margin-bottom: 20px; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); +} +.article-list-main .article-item .content { + margin-top: 15px; + color: #919191; +} +.article-list-main .media { + color: #919191; +} +.article-list-main .media .media-body { + padding-left: 10px; + line-height: 25px; +} +.article-list-main .media img { + -webkit-border-radius: 6px; + -webkit-background-clip: padding-box; + -moz-border-radius: 6px; + -moz-background-clip: padding; + border-radius: 6px; + background-clip: padding-box; + width: 220px; +} +.article-list-main .article-tag { + display: block; + clear: both; + margin-top: 20px; + padding-top: 15px; + border-top: 1px solid #efefef; +} +.article-list-main .article-tag .pull-left { + height: 34px; + line-height: 34px; + color: #919191; +} +.article-list-main .article-tag .pull-left a { + color: #919191; +} +.article-list-main .pager { + margin: 40px 0 20px 0; +} +@media (max-width: 767px) { + .article-list-main .media img { + width: 140px; + } +} +.article-metas { + overflow: hidden; + margin-bottom: 10px; +} +.article-metas .date { + height: 45px; + width: 45px; + margin-top: 10px; + text-align: center; + color: #c1c1c1; + border: 1px solid #c1c1c1; + -webkit-border-radius: 50%; + -webkit-background-clip: padding-box; + -moz-border-radius: 50%; + -moz-background-clip: padding; + border-radius: 50%; + background-clip: padding-box; +} +.article-metas .date .day { + margin-top: 2px; + font-size: 16px; + line-height: 1.2; +} +.article-metas .date .month { + font-size: 12px; +} +.article-metas .metas-body { + padding-left: 60px; +} +.article-metas .metas-body p { + margin-bottom: 0; + margin-top: 0px; + font-size: 12px; +} +.article-metas .metas-body .title { + margin: 5px 0 0 0; + line-height: 36px; +} +.article-metas .metas-body .title a { + color: #616161; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-metas .metas-body .title a:hover { + color: #46c37b; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-metas .metas-body .sns { + color: #e1e1e1; + margin: 0px auto; +} +.article-metas .metas-body .sns span { + margin-right: 10px; +} +.article-metas .metas-body .sns span i { + margin-right: 5px; +} +@media (max-width: 1199px) { + .article-metas .metas-body .title { + font-size: 20px; + line-height: 30px; + } +} +@media (max-width: 767px) { + .article-metas .metas-body .title { + font-size: 16px; + line-height: 20px; + } +} +.article-text p { + line-height: 30px; + margin: 20px auto 30px auto; +} +@media (max-width: 767px) { + .article-text p { + margin: 10px auto 20px auto; + } +} +.article-text img { + margin: 10px auto; + display: block; + max-width: 100%; + height: auto; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; +} +.product-action-btn { + color: #999; +} +.product-action-btn .bdshare-button-style0-16 .bds_more { + float: none; + padding: 0; + height: inherit; + line-height: inherit; + font-size: inherit; + background: none; +} +.product-like-wrapper { + margin: 15px auto; + text-align: center; +} +.product-like-wrapper a { + display: inline-block; + width: 44px; + height: 44px; + line-height: 44px; + color: #999; + text-align: center; + background-color: #bebebe; + background-position: center center; + background-repeat: no-repeat; + -webkit-transition: background-color 300ms linear; + -moz-transition: background-color 300ms linear; + -o-transition: background-color 300ms linear; + transition: background-color 300ms linear; + -webkit-border-radius: 22px; + -webkit-background-clip: padding-box; + -moz-border-radius: 22px; + -moz-background-clip: padding; + border-radius: 22px; + background-clip: padding-box; + vertical-align: middle; +} +.product-like-wrapper a.product-like { + position: relative; + margin-right: 5px; + background-color: #46c37b; +} +.product-like-wrapper a.product-like:hover { + background-color: #08aa73; +} +.product-like-wrapper a.product-dislike { + position: relative; + margin-left: 5px; +} +.product-like-wrapper a.product-dislike:hover { + background-color: #999; +} +.product-like-wrapper a i.fa { + font-size: 20px; + color: #fff; +} +.product-like-wrapper .like-bar-wrapper { + position: relative; + display: inline-block; + vertical-align: -18%; +} +.product-like-wrapper .bar { + width: 110px; + height: 7px; + overflow: hidden; + background-color: #dcdcdc; + -webkit-border-radius: 4px; + -webkit-background-clip: padding-box; + -moz-border-radius: 4px; + -moz-background-clip: padding; + border-radius: 4px; + background-clip: padding-box; +} +.product-like-wrapper .bar span { + display: block; + height: 100%; + width: 50%; + background-color: #46c37b; + -webkit-transition: width 300ms linear; + -moz-transition: width 300ms linear; + -o-transition: width 300ms linear; + transition: width 300ms linear; +} +.product-like-wrapper .num { + position: absolute; + top: -18px; + display: block; + width: 100%; + font-style: normal; + font-size: 10px; + color: #999; + text-align: center; +} +.product-like-wrapper .num i { + position: absolute; + right: 55%; + color: #46c37b; + font-style: normal; +} +.product-like-wrapper .num span { + position: absolute; + left: 55%; +} +.product-like-wrapper.like-status-1 .product-like { + position: relative; + background: #86a4d5; +} +.product-like-wrapper.like-status-1 .product-like::before { + content: "\5df2\8d5e"; + position: absolute; + top: 0; + left: 0; + display: block; + height: 100%; + width: 100%; + font-size: 14px; + line-height: 44px; + color: #fff; +} +.product-like-wrapper.like-status-3 .product-dislike { + position: relative; + background: #bebebe; +} +.product-like-wrapper.like-status-3 .product-dislike::before { + content: "\5df2\8e29"; + position: absolute; + top: 0; + left: 0; + display: block; + height: 100%; + width: 100%; + font-size: 14px; + line-height: 44px; + color: #fff; +} +.entry-meta ul { + overflow: hidden; + margin: 0 0 10px 0; + padding: 0 0 10px 0; + border-bottom: 1px solid #dedede; +} +.entry-meta ul li { + line-height: 26px; +} +.related-article { + margin-top: 10px; +} +.related-article .row { + margin: 0 -5px; +} +.related-article .col-sm-4 { + position: relative; + display: block; + padding: 0 5px; + margin: 5px auto; +} +.related-article .related-item { + position: relative; + -webkit-border-radius: 2px; + -webkit-background-clip: padding-box; + -moz-border-radius: 2px; + -moz-background-clip: padding; + border-radius: 2px; + background-clip: padding-box; + overflow: hidden; +} +.related-article .related-item img { + width: 100%; +} +.related-article .title { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 10px 20px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + color: #fff; + z-index: 999; +} +.panel-default { + border: none; + padding: 0 15px; + -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); +} +.panel-default > .panel-heading { + position: relative; + font-size: 16px; + padding: 15px 0; + background: #fff; + border-bottom: 1px solid #f5f5f5; +} +.panel-default > .panel-heading .panel-title { + /*color: @gray-dark;*/ +} +.panel-default > .panel-heading .panel-title > i { + display: none; +} +.panel-default > .panel-heading .more { + position: absolute; + top: 13px; + right: 0; + display: block; + color: #919191; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.panel-default > .panel-heading .more:hover { + color: #616161; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.panel-default > .panel-heading .panel-bar { + position: absolute; + top: 7px; + right: 0; + display: block; +} +.panel-default > .panel-footer { + padding: 15px 0; + background: none; +} +.panel-default > .panel-body { + position: relative; + padding: 15px 0; +} +.panel-primary > .panel-heading { + background-color: #46c37b; + color: #fff; +} +.panel-primary > .panel-body { + background: #fafafa; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} +.panel-gray { + -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); + -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); +} +.panel-gray > .panel-heading { + background-color: #f5f5f5; + color: #919191; +} +.panel-gray > .panel-body { + color: #919191; + background: #fff; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} +.panel-page { + padding: 45px 50px 50px; + min-height: 500px; +} +.panel-page .panel-heading { + background: transparent; + border-bottom: none; + margin: 0 0 30px 0; + padding: 0; +} +.panel-page .panel-heading h2 { + font-size: 25px; + margin-top: 0; +} +@media (max-width: 767px) { + .panel-page { + padding: 15px; + min-height: 300px; + } +} +.tabs-wrapper { + border: 1px solid #e4ecf3; + -webkit-border-radius: 4px; + -webkit-background-clip: padding-box; + -moz-border-radius: 4px; + -moz-background-clip: padding; + border-radius: 4px; + background-clip: padding-box; + margin-bottom: 30px; + background-color: #fff; +} +.tabs-wrapper .tabs-mark-group { + border-bottom: 1px dashed #e4ecf3; + padding: 10px; +} +.tabs-wrapper .tabs-mark-group .title { + width: 90px; + margin-top: 3px; + float: left; +} +.tabs-wrapper .tabs-mark-group .classify { + margin-top: 3px; +} +.tabs-wrapper .tabs-mark-group .classify a, +.tabs-wrapper .tabs-mark-group .classify i { + color: #919191; +} +.tabs-wrapper .tabs-mark-group .classify a:focus, +.tabs-wrapper .tabs-mark-group .classify a:hover { + color: #43bc60; +} +.tabs-wrapper .tabs-mark-group .content { + margin-left: 100px; +} +.tabs-wrapper .tabs-mark { + margin: 0 4px; +} +.tabs-wrapper .tabs-mark a { + border: 1px solid #e4ecf3; + padding: 2px 5px; + color: #919191; +} +.tabs-wrapper .tabs-mark i { + font-size: 10px; + margin-left: 5px; +} +.tabs-wrapper .tabs-mark.active a, +.tabs-wrapper .tabs-mark:focus a, +.tabs-wrapper .tabs-mark:hover a { + color: #43bc60; + border: 1px solid #43bc60; +} +.tabs-wrapper .tabs-group { + padding: 0 60px 0 15px; + position: relative; + overflow-y: hidden; +} +.tabs-wrapper .tabs-group .title { + float: left; + padding: 15px 0; + width: 100px; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + word-wrap: normal; +} +.tabs-wrapper .tabs-group .content { + list-style: none; + padding: 0; + margin: 0 0 0 100px; +} +.tabs-wrapper .tabs-group .content > li { + float: left; + padding: 10px 12px; +} +.tabs-wrapper .tabs-group .content > li > a { + display: block; + padding: 5px 10px; + border: none; + -webkit-border-radius: 4px; + -webkit-background-clip: padding-box; + -moz-border-radius: 4px; + -moz-background-clip: padding; + border-radius: 4px; + background-clip: padding-box; + color: #919191; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.tabs-wrapper .tabs-group .content > li.active > a, +.tabs-wrapper .tabs-group .content > li:focus > a, +.tabs-wrapper .tabs-group .content > li:hover > a { + color: #43bc60; +} +.tabs-wrapper .tabs-group .tabs-toggle { + position: absolute; + right: 20px; + top: 18px; + font-size: 12px; + line-height: 1; + cursor: pointer; +} +.tabs-wrapper .tabs-group + .tabs-group { + border-top: 1px dashed #e4ecf3; +} +.article-filter { + position: relative; + background-color: #fafafa; + -webkit-border-radius: 4px; + -webkit-background-clip: padding-box; + -moz-border-radius: 4px; + -moz-background-clip: padding; + border-radius: 4px; + background-clip: padding-box; + margin-bottom: 30px; +} +.article-filter .nav-sort > li { + float: left; +} +.article-filter .nav-sort > li > a { + height: 40px; + padding: 10px 15px; + color: #616161; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-filter .nav-sort > li > a:hover { + color: #43bc60; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-filter .nav-sort > li > a.active { + color: #fff; + background-color: #43bc60; +} +.article-filter .nav-sort > li > a.active:hover { + color: #fff; +} +.article-filter .btn-group.open .dropdown-toggle { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + color: #43bc60; +} +.article-filter .filter { + position: absolute; + text-align: right; + top: 0; + right: 15px; + width: 300px; +} +.article-filter .filter .btn { + background: none; + padding: 10px 0; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-filter .filter .btn:hover { + color: #43bc60; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-filter .filter .btn > i { + font-size: 18px; +} +.article-filter .filter label { + margin-left: 15px; + margin-top: 11px; + vertical-align: top; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +.article-filter .filter label:hover { + color: #43bc60; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} +h1 .breadcrumb { + padding: 0 5px; + margin-bottom: 5px; +} +h1 .breadcrumb li { + font-size: 12px; + font-weight: 400; +} +#carousel-focus-captions .item .carousel-img { + background-size: cover; + width: 100%; + height: 120px; + background-position: center center; +} +#carousel-focus-captions .carousel-control.left, +#carousel-focus-captions .carousel-control.right { + background-image: none; +} +#carousel-focus-captions .carousel-control.left span, +#carousel-focus-captions .carousel-control.right span { + display: none; +} +#carousel-focus-captions .carousel-control.left:hover, +#carousel-focus-captions .carousel-control.right:hover { + -webkit-transition: all 1s ease; + -moz-transition: all 1s ease; + -o-transition: all 1s ease; + transition: all 1s ease; +} +#carousel-focus-captions .carousel-control.left:hover span, +#carousel-focus-captions .carousel-control.right:hover span { + display: block; +} +/* Extra small devices (phones, less than 768px) */ +/* No media query since this is the default in Bootstrap */ +/* Small devices (tablets, 768px and up) */ +@media (min-width: 768px) { + #carousel-focus-captions .item .carousel-img { + height: 340px; + width: 100%; + } +} +/* Medium devices (desktops, 992px and up) */ +.article-sidebar .panel-adimg img { + width: 100%; +} +.hot-tags .panel-body a span { + margin-bottom: 10px; +} +.product-list .product { + position: relative; + margin-bottom: 20px; +} +.product-list .product .detail { + position: absolute; + z-index: 1; + height: 30px; + right: 15px; + bottom: 12px; + padding: 0 15px; + line-height: 30px; + text-align: center; + text-transform: capitalize; + letter-spacing: 0.02em; + font-size: 14px; + color: #00b22d; + border-radius: 2px; + background: whitesmoke; +} +.product-list .product .detail:hover { + background: #eee; + text-decoration: none; +} +@media (min-width: 769px) { + .product-list .product:hover .detail { + display: block; + } +} +.card { + border-radius: 4px; + position: relative; + padding: 12px; + margin: 0 auto 50px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + -webkit-transition: all 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19); + -moz-transition: all 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19); + -o-transition: all 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19); + transition: all 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19); + min-height: 325px; + background-color: #FFF; +} +.card:hover { + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +} +.card .image { + position: relative; + width: 100%; + height: 1px; + overflow: hidden; + padding-bottom: 75%; + background-repeat: no-repeat; + background-size: cover; + background-position: center center; +} +.card .title { + padding-top: 10px; +} +.card h2 { + color: #000; + padding: 0; + margin-bottom: 5px; + margin-top: 10px; + font-size: 16px; + font-weight: 700; + line-height: 1.4; + text-transform: uppercase; + text-align: left; +} +#content-container > h1 { + margin-top: 0; +} +.lasest-update .panel-body { + padding: 8px 0; +} +.lasest-update .panel-body ul { + margin-bottom: 0; +} +.lasest-update .panel-body ul li { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; + height: 35px; + line-height: 35px; +} +.channel-list .row .col-xs-6 { + min-height: 315px; +} +.channel-list .row .col-xs-6 h3 { + border-bottom: 2px solid #eee; + padding-bottom: 10px; + position: relative; +} +.channel-list .row .col-xs-6 h3 > a { + font-size: 16px; + border-bottom: 2px solid #17bb9c; + padding-bottom: 10px; +} +.channel-list .row .col-xs-6 h3 em { + position: absolute; + right: 5px; + top: 5px; + font-style: normal; + font-weight: 400; +} +.channel-list .row .col-xs-6 h3 em a { + font-size: 12px; +} +.channel-list .row .media { + margin-bottom: 10px; +} +.channel-list .row .media .media-body { + font-size: 12px; +} +.channel-list .row ul li { + border-bottom: 1px solid #eee; + margin-bottom: 5px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; + padding-right: 40px; + height: 30px; + line-height: 30px; +} +.channel-list .row ul li a { + color: #616161; +} +.channel-list .row ul li span { + position: absolute; + right: 0; +} +#comment-container #commentlist dl { + position: relative; + border-bottom: 1px solid #eee; + clear: both; + padding: 10px 0; + margin-bottom: 5px; +} +#comment-container #commentlist dl dt { + float: left; + margin-right: 10px; + width: 54px; + height: 54px; + display: block; + position: absolute; +} +#comment-container #commentlist dl dt img { + width: 50px; + height: 50px; + border-radius: 50%; +} +#comment-container #commentlist dl dd { + padding-left: 60px; + float: left; + width: 100%; +} +#comment-container #commentlist dl dd small { + display: block; + color: #999; + margin: -2px 0; + height: 20px; + line-height: 20px; + font-size: 10px; +} +#comment-container #commentlist dl dd small a { + display: none; +} +#comment-container #commentlist dl dd dl { + margin: 0px; + border-top: 1px solid #eee; + border-bottom: none; + padding-top: 15px; + padding-bottom: 0; +} +#comment-container #commentlist dl dd dl dd { + width: 550px; +} +#comment-container #commentlist dl dd p { + margin-bottom: 10px; +} +#comment-container #commentlist cite { + font-style: normal; +} +#comment-container h3 { + position: relative; + font-size: 16px; + padding: 15px 0; + background: #fff; + border-bottom: 1px solid #f5f5f5; + font-weight: 400; +} +#comment-container h3 a { + display: none; +} +#comment-container #postcomment .form-group { + margin-bottom: 10px; +} +#comment-container #postcomment label { + font-weight: normal; +} +#comment-container #postcomment a small { + display: inline !important; +} diff --git a/addons/cms/assets/css/font-awesome.min.css b/addons/cms/assets/css/font-awesome.min.css new file mode 100644 index 0000000000000000000000000000000000000000..d22045eaed47011b20855b8c8a6dbbcf3dc33365 --- /dev/null +++ b/addons/cms/assets/css/font-awesome.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} + \ No newline at end of file diff --git a/addons/cms/assets/css/jquery.colorbox.css b/addons/cms/assets/css/jquery.colorbox.css new file mode 100644 index 0000000000000000000000000000000000000000..09b7f3556055b57a6ae79c7da184d8c29c555ecc --- /dev/null +++ b/addons/cms/assets/css/jquery.colorbox.css @@ -0,0 +1,70 @@ +/* + Colorbox Core Style: + The following CSS is consistent between example themes and should not be altered. +*/ +#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} +#cboxWrapper {max-width:none;} +#cboxOverlay{position:fixed; width:100%; height:100%;} +#cboxMiddleLeft, #cboxBottomLeft{clear:left;} +#cboxContent{position:relative;} +#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;} +#cboxTitle{margin:0;} +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} +#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} +.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;} +.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;} +#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;} + +/* + User Style: + Change the following styles to modify the appearance of Colorbox. They are + ordered & tabbed in a way that represents the nesting of the generated HTML. +*/ +#cboxOverlay{background:url(../img/overlay.png) repeat 0 0;} +#colorbox{outline:0;} + #cboxTopLeft{width:21px; height:21px; background:url(../img/controls.png) no-repeat -101px 0;} + #cboxTopRight{width:21px; height:21px; background:url(../img/controls.png) no-repeat -130px 0;} + #cboxBottomLeft{width:21px; height:21px; background:url(../img/controls.png) no-repeat -101px -29px;} + #cboxBottomRight{width:21px; height:21px; background:url(../img/controls.png) no-repeat -130px -29px;} + #cboxMiddleLeft{width:21px; background:url(../img/controls.png) left top repeat-y;} + #cboxMiddleRight{width:21px; background:url(../img/controls.png) right top repeat-y;} + #cboxTopCenter{height:21px; background:url(../img/border.png) 0 0 repeat-x;} + #cboxBottomCenter{height:21px; background:url(../img/border.png) 0 -29px repeat-x;} + #cboxContent{background:#fff; overflow:hidden;} + .cboxIframe{background:#fff;} + #cboxError{padding:50px; border:1px solid #ccc;} + #cboxLoadedContent{margin-bottom:28px;} + #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} + #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} + #cboxLoadingOverlay{background:url(../img/loading_background.png) no-repeat center center;} + #cboxLoadingGraphic{background:url(../img/loading.gif) no-repeat center center;} + + /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */ + #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; } + + /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */ + #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;} + + #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;} + #cboxPrevious{position:absolute; bottom:0; left:0; background:url(../img/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;} + #cboxPrevious:hover{background-position:-75px -25px;} + #cboxNext{position:absolute; bottom:0; left:27px; background:url(../img/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;} + #cboxNext:hover{background-position:-50px -25px;} + #cboxClose{position:absolute; bottom:0; right:0; background:url(../img/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;} + #cboxClose:hover{background-position:-25px -25px;} + +/* + The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill + when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9. + See: http://jacklmoore.com/notes/ie-transparency-problems/ +*/ +.cboxIE #cboxTopLeft, +.cboxIE #cboxTopCenter, +.cboxIE #cboxTopRight, +.cboxIE #cboxBottomLeft, +.cboxIE #cboxBottomCenter, +.cboxIE #cboxBottomRight, +.cboxIE #cboxMiddleLeft, +.cboxIE #cboxMiddleRight { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF); +} \ No newline at end of file diff --git a/addons/cms/assets/css/jquery.justifiedGallery.min.css b/addons/cms/assets/css/jquery.justifiedGallery.min.css new file mode 100644 index 0000000000000000000000000000000000000000..49f43476e42d63f9fde129c7dee7fd4278a33671 --- /dev/null +++ b/addons/cms/assets/css/jquery.justifiedGallery.min.css @@ -0,0 +1,7 @@ +/*! + * Justified Gallery - v3.6.4 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2016 Miro Mannino + * Licensed under the MIT license. + */ +.justified-gallery{width:100%;position:relative;overflow:hidden}.justified-gallery>a,.justified-gallery>div,.justified-gallery>figure{position:absolute;display:inline-block;overflow:hidden;filter:"alpha(opacity=10)";opacity:.1;margin:0;padding:0}.justified-gallery>a>img,.justified-gallery>div>img,.justified-gallery>figure>img,.justified-gallery>a>a>img,.justified-gallery>div>a>img,.justified-gallery>figure>a>img{position:absolute;top:50%;left:50%;margin:0;padding:0;border:0;filter:"alpha(opacity=0)";opacity:0}.justified-gallery>a>.caption,.justified-gallery>div>.caption,.justified-gallery>figure>.caption{display:none;position:absolute;bottom:0;padding:5px;background-color:#000;left:0;right:0;margin:0;color:#fff;font-size:12px;font-weight:300;font-family:sans-serif}.justified-gallery>a>.caption.caption-visible,.justified-gallery>div>.caption.caption-visible,.justified-gallery>figure>.caption.caption-visible{display:initial;filter:"alpha(opacity=70)";opacity:.7;-webkit-transition:opacity 500ms ease-in;-moz-transition:opacity 500ms ease-in;-o-transition:opacity 500ms ease-in;transition:opacity 500ms ease-in}.justified-gallery>.entry-visible{filter:"alpha(opacity=100)";opacity:1;background:0 0}.justified-gallery>.entry-visible>img,.justified-gallery>.entry-visible>a>img{filter:"alpha(opacity=100)";opacity:1;-webkit-transition:opacity 500ms ease-in;-moz-transition:opacity 500ms ease-in;-o-transition:opacity 500ms ease-in;transition:opacity 500ms ease-in}.justified-gallery>.jg-filtered{display:none}.justified-gallery>.spinner{position:absolute;bottom:0;margin-left:-24px;padding:10px 0;left:50%;filter:"alpha(opacity=100)";opacity:1;overflow:initial}.justified-gallery>.spinner>span{display:inline-block;filter:"alpha(opacity=0)";opacity:0;width:8px;height:8px;margin:0 4px;background-color:#000;border-radius:6px} \ No newline at end of file diff --git a/addons/cms/assets/css/swipebox.min.css b/addons/cms/assets/css/swipebox.min.css new file mode 100644 index 0000000000000000000000000000000000000000..38db35c847d5a60f7275f3f747cd1aa5d2f17193 --- /dev/null +++ b/addons/cms/assets/css/swipebox.min.css @@ -0,0 +1 @@ +/*! Swipebox v1.3.0 | Constantin Saguin csag.co | MIT License | github.com/brutaldesign/swipebox */html.swipebox-html.swipebox-touch{overflow:hidden!important}#swipebox-overlay img{border:none!important}#swipebox-overlay{width:100%;height:100%;position:fixed;top:0;left:0;z-index:99999!important;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#swipebox-container{position:relative;width:100%;height:100%}#swipebox-slider{-webkit-transition:-webkit-transform .4s ease;transition:transform .4s ease;height:100%;left:0;top:0;width:100%;white-space:nowrap;position:absolute;display:none;cursor:pointer}#swipebox-slider .slide{height:100%;width:100%;line-height:1px;text-align:center;display:inline-block}#swipebox-slider .slide:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}#swipebox-slider .slide .swipebox-inline-container,#swipebox-slider .slide .swipebox-video-container,#swipebox-slider .slide img{display:inline-block;max-height:100%;max-width:100%;margin:0;padding:0;width:auto;height:auto;vertical-align:middle}#swipebox-slider .slide .swipebox-video-container{background:0 0;max-width:1140px;max-height:100%;width:100%;padding:5%;-webkit-box-sizing:border-box;box-sizing:border-box}#swipebox-slider .slide .swipebox-video-container .swipebox-video{width:100%;height:0;padding-bottom:56.25%;overflow:hidden;position:relative}#swipebox-slider .slide .swipebox-video-container .swipebox-video iframe{width:100%!important;height:100%!important;position:absolute;top:0;left:0}#swipebox-slider .slide-loading{background:url(../img/loader.gif) center center no-repeat}#swipebox-bottom-bar,#swipebox-top-bar{-webkit-transition:.5s;transition:.5s;position:absolute;left:0;z-index:999;height:50px;width:100%}#swipebox-bottom-bar{bottom:-50px}#swipebox-bottom-bar.visible-bars{-webkit-transform:translate3d(0,-50px,0);transform:translate3d(0,-50px,0)}#swipebox-top-bar{top:-50px}#swipebox-top-bar.visible-bars{-webkit-transform:translate3d(0,50px,0);transform:translate3d(0,50px,0)}#swipebox-title{display:block;width:100%;text-align:center}#swipebox-close,#swipebox-next,#swipebox-prev{background-image:url(../img/icons.png);background-repeat:no-repeat;border:none!important;text-decoration:none!important;cursor:pointer;width:50px;height:50px;top:0}#swipebox-arrows{display:block;margin:0 auto;width:100%;height:50px}#swipebox-prev{background-position:-32px 13px;float:left}#swipebox-next{background-position:-78px 13px;float:right}#swipebox-close{top:0;right:0;position:absolute;z-index:9999;background-position:15px 12px}.swipebox-no-close-button #swipebox-close{display:none}#swipebox-next.disabled,#swipebox-prev.disabled{opacity:.3}.swipebox-no-touch #swipebox-overlay.rightSpring #swipebox-slider{-webkit-animation:rightSpring .3s;animation:rightSpring .3s}.swipebox-no-touch #swipebox-overlay.leftSpring #swipebox-slider{-webkit-animation:leftSpring .3s;animation:leftSpring .3s}.swipebox-touch #swipebox-container:after,.swipebox-touch #swipebox-container:before{-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transition:all .3s ease;transition:all .3s ease;content:' ';position:absolute;z-index:999;top:0;height:100%;width:20px;opacity:0}.swipebox-touch #swipebox-container:before{left:0;-webkit-box-shadow:inset 10px 0 10px -8px #656565;box-shadow:inset 10px 0 10px -8px #656565}.swipebox-touch #swipebox-container:after{right:0;-webkit-box-shadow:inset -10px 0 10px -8px #656565;box-shadow:inset -10px 0 10px -8px #656565}.swipebox-touch #swipebox-overlay.leftSpringTouch #swipebox-container:before,.swipebox-touch #swipebox-overlay.rightSpringTouch #swipebox-container:after{opacity:1}@-webkit-keyframes rightSpring{0%{left:0}50%{left:-30px}100%{left:0}}@keyframes rightSpring{0%{left:0}50%{left:-30px}100%{left:0}}@-webkit-keyframes leftSpring{0%{left:0}50%{left:30px}100%{left:0}}@keyframes leftSpring{0%{left:0}50%{left:30px}100%{left:0}}@media screen and (min-width:800px){#swipebox-close{right:10px}#swipebox-arrows{width:92%;max-width:800px}}#swipebox-overlay{background:#0d0d0d}#swipebox-bottom-bar,#swipebox-top-bar{text-shadow:1px 1px 1px #000;background:#000;opacity:.95}#swipebox-top-bar{color:#fff!important;font-size:15px;line-height:43px;font-family:Helvetica,Arial,sans-serif} \ No newline at end of file diff --git a/addons/cms/assets/fonts/FontAwesome.otf b/addons/cms/assets/fonts/FontAwesome.otf new file mode 100644 index 0000000000000000000000000000000000000000..81c9ad949b47f64afeca5642ee2494b6e3147f44 Binary files /dev/null and b/addons/cms/assets/fonts/FontAwesome.otf differ diff --git a/addons/cms/assets/fonts/fontawesome-webfont.eot b/addons/cms/assets/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..84677bc0c5f37f1fac9d87548c4554b5c91717cf Binary files /dev/null and b/addons/cms/assets/fonts/fontawesome-webfont.eot differ diff --git a/addons/cms/assets/fonts/fontawesome-webfont.svg b/addons/cms/assets/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..d907b25ae60ec7e3d32e4027aa6e6b7595de97af --- /dev/null +++ b/addons/cms/assets/fonts/fontawesome-webfont.svg @@ -0,0 +1,520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/cms/assets/fonts/fontawesome-webfont.ttf b/addons/cms/assets/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..96a3639cdde5e8ab459c6380e3b9524ee81641dc Binary files /dev/null and b/addons/cms/assets/fonts/fontawesome-webfont.ttf differ diff --git a/addons/cms/assets/fonts/fontawesome-webfont.woff b/addons/cms/assets/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..628b6a52a87e62c6f22426e17c01f6a303aa194e Binary files /dev/null and b/addons/cms/assets/fonts/fontawesome-webfont.woff differ diff --git a/addons/cms/assets/fonts/fontawesome-webfont.woff2 b/addons/cms/assets/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3311d585145b1cc1b9581e914acbb32d8542b4f5 Binary files /dev/null and b/addons/cms/assets/fonts/fontawesome-webfont.woff2 differ diff --git a/addons/cms/assets/img/banner/1.jpg b/addons/cms/assets/img/banner/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..140f636fd0be1c807c0d69cd4667ea93bf2a6a63 Binary files /dev/null and b/addons/cms/assets/img/banner/1.jpg differ diff --git a/addons/cms/assets/img/border.png b/addons/cms/assets/img/border.png new file mode 100644 index 0000000000000000000000000000000000000000..f463a10d838aeba263ff44e5c3578dfe7ba07648 Binary files /dev/null and b/addons/cms/assets/img/border.png differ diff --git a/addons/cms/assets/img/focus/1.jpg b/addons/cms/assets/img/focus/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdaf9723ab5da20fe204ee143aab9db93b358a21 Binary files /dev/null and b/addons/cms/assets/img/focus/1.jpg differ diff --git a/addons/cms/assets/img/focus/2.jpg b/addons/cms/assets/img/focus/2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cb110e2041260d14ce11a67e60c6b668a7ebae7f Binary files /dev/null and b/addons/cms/assets/img/focus/2.jpg differ diff --git a/addons/cms/assets/img/focus/3.jpg b/addons/cms/assets/img/focus/3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76873165efe52916299e0fc2fdff0dd7c09f0064 Binary files /dev/null and b/addons/cms/assets/img/focus/3.jpg differ diff --git a/addons/cms/assets/img/focus/5.jpg b/addons/cms/assets/img/focus/5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fb6b190c43b5236d34719d1f09c2ebeeff544590 Binary files /dev/null and b/addons/cms/assets/img/focus/5.jpg differ diff --git a/addons/cms/assets/img/icons.png b/addons/cms/assets/img/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..7a79f7a75cc17d4dd61795b9f4c82cca02853ca8 Binary files /dev/null and b/addons/cms/assets/img/icons.png differ diff --git a/addons/cms/assets/img/icons.svg b/addons/cms/assets/img/icons.svg new file mode 100644 index 0000000000000000000000000000000000000000..414e84411017de5752eceacda32e11b899947bf6 --- /dev/null +++ b/addons/cms/assets/img/icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/cms/assets/img/loader.gif b/addons/cms/assets/img/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..a82c2aa4dc6114efde112eee35bc36975e0e67e4 Binary files /dev/null and b/addons/cms/assets/img/loader.gif differ diff --git a/addons/cms/assets/img/loading.gif b/addons/cms/assets/img/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..a32df5c0881b563e18f3660758009a4aec47a5a0 Binary files /dev/null and b/addons/cms/assets/img/loading.gif differ diff --git a/addons/cms/assets/img/logo.png b/addons/cms/assets/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d76d7cac6bbf3ca25ae1dfe29e769cf26450decc Binary files /dev/null and b/addons/cms/assets/img/logo.png differ diff --git a/addons/cms/assets/img/noimage.jpg b/addons/cms/assets/img/noimage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..347735c7f88f59b012223484e7875a20822c1ec2 Binary files /dev/null and b/addons/cms/assets/img/noimage.jpg differ diff --git a/addons/cms/assets/img/overlay.png b/addons/cms/assets/img/overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..53ea98f7003cf014cda2f764a7d982e405bd1b5f Binary files /dev/null and b/addons/cms/assets/img/overlay.png differ diff --git a/addons/cms/assets/img/qrcode.png b/addons/cms/assets/img/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..09711165c3594d31453dd0ca3ac9caaaef0e7332 Binary files /dev/null and b/addons/cms/assets/img/qrcode.png differ diff --git a/addons/cms/assets/img/sidebar/1.jpg b/addons/cms/assets/img/sidebar/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9baf528b691675c8e278b79bb6c98c5e9decfc40 Binary files /dev/null and b/addons/cms/assets/img/sidebar/1.jpg differ diff --git a/addons/cms/assets/img/sidebar/2.jpg b/addons/cms/assets/img/sidebar/2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a3f163189a6f0db288a9e284ad3e259d0fa906d6 Binary files /dev/null and b/addons/cms/assets/img/sidebar/2.jpg differ diff --git a/addons/cms/assets/js/bootstrap-typeahead.min.js b/addons/cms/assets/js/bootstrap-typeahead.min.js new file mode 100644 index 0000000000000000000000000000000000000000..766968716d1657cb9b1902a7423921b136d22f60 --- /dev/null +++ b/addons/cms/assets/js/bootstrap-typeahead.min.js @@ -0,0 +1,10 @@ +/*! + * bootstrap-typeahead.js v0.0.5 (http://www.upbootstrap.com) + * Copyright 2012-2016 Twitter Inc. + * Licensed under MIT (https://github.com/biggora/bootstrap-ajax-typeahead/blob/master/LICENSE) + * See Demo: http://plugins.upbootstrap.com/bootstrap-ajax-typeahead + * Updated: 2016-11-09 04:40:04 + * + * Modifications by Paul Warelis and Alexey Gordeyev + */ +!function(a){"use strict";var b=function(b,c){a.fn.typeahead.defaults;c.scrollBar&&(c.items=100,c.menu='');var d=this;if(d.$element=a(b),d.options=a.extend({},a.fn.typeahead.defaults,c),d.$menu=a(d.options.menu).insertAfter(d.$element),d.eventSupported=d.options.eventSupported||d.eventSupported,d.grepper=d.options.grepper||d.grepper,d.highlighter=d.options.highlighter||d.highlighter,d.lookup=d.options.lookup||d.lookup,d.matcher=d.options.matcher||d.matcher,d.render=d.options.render||d.render,d.onSelect=d.options.onSelect||null,d.sorter=d.options.sorter||d.sorter,d.select=d.options.select||d.select,d.source=d.options.source||d.source,d.displayField=d.options.displayField||d.displayField,d.valueField=d.options.valueField||d.valueField,d.autoSelect=d.options.autoSelect||d.autoSelect,d.options.ajax){var e=d.options.ajax;"string"==typeof e?d.ajax=a.extend({},a.fn.typeahead.defaults.ajax,{url:e}):("string"==typeof e.displayField&&(d.displayField=d.options.displayField=e.displayField),"string"==typeof e.valueField&&(d.valueField=d.options.valueField=e.valueField),d.ajax=a.extend({},a.fn.typeahead.defaults.ajax,e)),d.ajax.url||(d.ajax=null),d.query=""}else d.source=d.options.source,d.ajax=null;d.shown=!1,d.listen()};b.prototype={constructor:b,eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b="function"==typeof this.$element[a]),b},select:function(){var a=this.$menu.find(".active");if(a.length){var b=a.data("value"),c=this.$menu.find(".active a").text();this.$element.val(this.updater(c)).change(),this.options.onSelect&&this.options.onSelect({value:b,text:c})}return this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});if(this.$menu.css({top:b.top+b.height,left:b.left}),this.options.alignWidth){var c=a(this.$element[0]).outerWidth();this.$menu.css({width:c})}return this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},ajaxLookup:function(){function b(){this.ajaxToggleLoadClass(!0),this.ajax.xhr&&this.ajax.xhr.abort();var b=this.ajax.preDispatch?this.ajax.preDispatch(c):{query:c};this.ajax.xhr=a.ajax({url:this.ajax.url,data:b,success:a.proxy(this.ajaxSource,this),type:this.ajax.method||"get",dataType:"json",headers:this.ajax.headers||{}}),this.ajax.timerId=null}var c=a.trim(this.$element.val());return c===this.query?this:(this.query=c,this.ajax.timerId&&(clearTimeout(this.ajax.timerId),this.ajax.timerId=null),!c||c.length"+b+""})},render:function(b){var c,d=this,e="string"==typeof d.options.displayField;return b=a(b).map(function(b,f){return"object"==typeof f?(c=e?f[d.options.displayField]:d.options.displayField(f),b=a(d.options.item).data("value",f[d.options.valueField])):(c=f,b=a(d.options.item).data("value",f)),b.find("a").html(d.highlighter(c)),b[0]}),d.autoSelect&&b.first().addClass("active"),this.$menu.html(b),this},grepper:function(b){var c,d,e=this,f="string"==typeof e.options.displayField;if(!(f&&b&&b.length))return null;if(b[0].hasOwnProperty(e.options.displayField))c=a.grep(b,function(a){return d=f?a[e.options.displayField]:e.options.displayField(a),e.matcher(d)});else{if("string"!=typeof b[0])return null;c=a.grep(b,function(a){return e.matcher(a)})}return this.sorter(c)},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();if(d.length||(d=a(this.$menu.find("li")[0])),this.options.scrollBar){var e=this.$menu.children("li").index(d);e%8==0&&this.$menu.scrollTop(26*e)}d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();if(c.length||(c=this.$menu.find("li").last()),this.options.scrollBar){var d=this.$menu.children("li"),e=d.length-1,f=d.index(c);(e-f)%8==0&&this.$menu.scrollTop(26*(f-7))}c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},move:function(a){if(this.shown){switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()}},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){this.suppressKeyPressRepeat||this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.ajax?this.ajaxLookup():this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()},destroy:function(){this.$element.off("focus",a.proxy(this.focus,this)).off("blur",a.proxy(this.blur,this)).off("keypress",a.proxy(this.keypress,this)).off("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.off("keydown",a.proxy(this.keydown,this)),this.$menu.off("click",a.proxy(this.click,this)).off("mouseenter","li",a.proxy(this.mouseenter,this)).off("mouseleave","li",a.proxy(this.mouseleave,this)),this.$element.removeData("typeahead")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f="object"==typeof c&&c;e||d.data("typeahead",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.typeahead.defaults={source:[],items:10,scrollBar:!1,alignWidth:!0,menu:'',item:'
                • ',valueField:"id",displayField:"name",autoSelect:!0,onSelect:function(){},ajax:{url:null,timeout:300,method:"get",triggerLength:1,loadingClass:null,preDispatch:null,preProcess:null}},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);c.data("typeahead")||(b.preventDefault(),c.typeahead(c.data()))})})}(window.jQuery); \ No newline at end of file diff --git a/addons/cms/assets/js/common.js b/addons/cms/assets/js/common.js new file mode 100644 index 0000000000000000000000000000000000000000..23b71598208e882cf859883fd50231a1d8c8bfd4 --- /dev/null +++ b/addons/cms/assets/js/common.js @@ -0,0 +1,224 @@ +$(function () { + function AddFavorite(sURL, sTitle) { + if (/firefox/i.test(navigator.userAgent)) { + return false; + } else if (window.external && window.external.addFavorite) { + window.external.addFavorite(sURL, sTitle); + return true; + } else if (window.sidebar && window.sidebar.addPanel) { + window.sidebar.addPanel(sTitle, sURL, ""); + return true; + } else { + var touch = (navigator.userAgent.toLowerCase().indexOf('mac') != -1 ? 'Command' : 'CTRL'); + alert('请使用 ' + touch + ' + D 添加到收藏夹.'); + return false; + } + } + var len = function (str) { + if (!str) + return 0; + var length = 0; + for (var i = 0; i < str.length; i++) { + if (str.charCodeAt(i) >= 0x4e00 && str.charCodeAt(i) <= 0x9fa5) { + length += 2; + } else { + length++; + } + } + return length; + }; + //搜索框 + $("input[name='search']").on("focus", function(){ + $(this).closest(".form-search").addClass("focused"); + }).on("blur", function(){ + var that = this; + setTimeout(function(){ + $(that).closest(".form-search").removeClass("focused"); + }, 1000); + }); + // 点击收藏 + $(".addbookbark").attr("rel", "sidebar").click(function () { + return !AddFavorite(window.location.href, $(this).attr("title")); + }); + // 点赞 + $(document).on("click", ".product-like-wrapper > a", function () { + var ids = JSON.parse(localStorage.getItem("vote")); + ids = $.isArray(ids) ? ids : []; + var id = $(this).data("id"); + if ($.inArray(id, ids) > -1) { + alert("你已经投过票了"); + return false; + } + $.ajax({ + type: "post", + data: $(this).data(), + dataType: 'json', + success: function (ret) { + if (ret.code === 1) { + ids.push(id); + $(".like-bar-wrapper .bar span").css("width", ret.data.likeratio + "%"); + $(".like-bar-wrapper .num i").text(ret.data.likes); + $(".like-bar-wrapper .num span").text(ret.data.dislikes); + localStorage.setItem("vote", JSON.stringify(ids)); + } + } + }); + }); + if ($("#comment-container").size() > 0) { + var ci, si; + $("#commentlist dl dd div,#commentlist dl dd dl dd").on({ + mouseenter: function () { + clearTimeout(ci); + var _this = this; + ci = setTimeout(function () { + $(_this).find("small:first").find("a").stop(true, true).fadeIn(); + }, 100); + }, + mouseleave: function () { + clearTimeout(ci); + $(this).find("small:first").find("a").stop(true, true).fadeOut(); + } + }); + $(".reply").on("click", function () { + $("#pid").val($(this).data("id")); + $(this).parent().parent().append($("div#postcomment").detach()); + $("#postcomment h3 a").show(); + $("#commentcontent").focus().val($(this).attr("title")); + }); + $("#postcomment h3 a").bind("click", function () { + $("#comment-container").append($("div#postcomment").detach()); + $(this).hide(); + }); + $(".expandall a").on("click", function () { + $(this).parent().parent().find("dl.hide").fadeIn(); + $(this).fadeOut(); + }); + + $(document).on("click", "#submit", function () { + var btn = $(this); + var tips = $("#actiontips"); + tips.removeClass(); + var content = $("#commentcontent").val(); + if (len(content) < 3) { + tips.addClass("text-danger").html("评论内容长度不正确!最少3个字符").fadeIn().change(); + return false; + } + var form = $("#postform"); + btn.attr("disabled", "disabled"); + tips.html('正在提交...'); + $.ajax({ + url: form.prop("action"), + type: 'POST', + data: form.serialize(), + dataType: 'json', + success: function (json) { + btn.removeAttr("disabled"); + if (json.code == 1) { + $("#pid").val(0); + tips.addClass("text-success").html("评论成功!").fadeIn(300).change(); + $("#commentcontent").val(''); + $("#commentcount").text(parseInt($("#commentcount").text()) + 1); + setTimeout(function () { + location.reload(); + }, 300); + } else { + tips.addClass("text-danger").html(json.msg).fadeIn().change(); + } + if (json.data && json.data.token) { + $("#postform input[name='__token__']").val(json.data.token); + } + }, + error: function () { + btn.removeAttr("disabled"); + tips.addClass("text-danger").html("评论失败!请刷新页面重试!").fadeIn(); + } + }); + return false; + }); + $("#commentcontent").on("keydown", function (e) { + if ((e.metaKey || e.ctrlKey) && (e.keyCode == 13 || e.keyCode == 10)) { + $("#submit").trigger('click'); + } + }); + $("#actiontips").on("change", function () { + clearTimeout(si); + si = setTimeout(function () { + $("#actiontips").fadeOut(); + }, 8000); + }); + $(document).on("keyup change", "#commentcontent", function () { + var max = 1000; + var c = $(this).val(); + var length = len(c); + var t = $("#actiontips"); + if (max >= length) { + t.removeClass().show().addClass("loading").html("你还可以输入 " + (Math.floor((max - length) / 2)) + " 字"); + $("#submit").removeAttr("disabled"); + } else { + t.removeClass().show().addClass("loading").html("你已经超出 " + (Math.ceil((length - max) / 2)) + " 字"); + $("#submit").attr("disabled", "disabled"); + } + }); + } + // 回到顶部 + $('#back-to-top').on('click', function (e) { + e.preventDefault(); + $('html,body').animate({ + scrollTop: 0 + }, 700); + }); + // 如果是PC则移除navbar的dropdown点击事件 + if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobi/i.test(navigator.userAgent)) { + $("#navbar-collapse [data-toggle='dropdown']").removeAttr("data-toggle"); + } else { + $(".navbar-nav ul li:not(.dropdown-submenu):not(.dropdown) a").removeAttr("data-toggle"); + } + $.fn.typeahead.Constructor.prototype.click = function (e) { + + }; + // 搜索自动完成 + $("#searchinput").typeahead({ + onSelect: function (item) { + console.log(item); + location.href = item.value.url; + }, + grepper: function (data) { + return data; + }, + render: function (items) { + var that = this; + items = $(items).map(function (i, item) { + var i = $(that.options.item); + i.data("value", item); + i.find('a').attr('href', item.url); + i.find('a').html('
                  ' + item.title + '
                  '); + return i[0]; + }); + items.first().addClass('active'); + that.$menu.css("width", "250px"); + that.$menu.html(items); + return that; + }, + alignWidth: false, + ajax: { + url: $("#searchinput").data("typeahead-url"), + valueField: "url", + method: "post", + dataType: "JSON", + preDispatch: function (query) { + return { + search: query + }; + }, + preProcess: function (data) { + return data; + } + } + }); + // 百度分享 + if ($(".bdsharebuttonbox").size() > 0) { + window._bd_share_config = {"common": {"bdSnsKey": {}, "bdText": "", "bdMini": "2", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "116"}, "share": {}}; + with (document) + 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)]; + } +}); \ No newline at end of file diff --git a/addons/cms/assets/js/jquery.justifiedGallery.min.js b/addons/cms/assets/js/jquery.justifiedGallery.min.js new file mode 100644 index 0000000000000000000000000000000000000000..2be4903fb97516200cfb4878c498cc51d0613a07 --- /dev/null +++ b/addons/cms/assets/js/jquery.justifiedGallery.min.js @@ -0,0 +1,7 @@ +/*! + * Justified Gallery - v3.6.4 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2016 Miro Mannino + * Licensed under the MIT license. + */ +!function(a){function b(){return a("body").height()>a(window).height()}var c=function(b,c){this.settings=c,this.checkSettings(),this.imgAnalyzerTimeout=null,this.entries=null,this.buildingRow={entriesBuff:[],width:0,height:0,aspectRatio:0},this.lastFetchedEntry=null,this.lastAnalyzedIndex=-1,this["yield"]={every:2,flushed:0},this.border=c.border>=0?c.border:c.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges(),this.offY=this.border,this.rows=0,this.spinner={phase:0,timeSlot:150,$el:a('
                  '),intervalId:null},this.checkWidthIntervalId=null,this.galleryWidth=b.width(),this.$gallery=b};c.prototype.getSuffix=function(a,b){var c,d;for(c=a>b?a:b,d=0;d img, > a > img").stop().fadeTo(this.settings.imagesAnimationDuration,1,b))},c.prototype.extractImgSrcFromImage=function(a){var b="undefined"!=typeof a.data("safe-src")?a.data("safe-src"):a.attr("src");return a.data("jg.originalSrc",b),b},c.prototype.imgFromEntry=function(a){var b=a.find("> img");return 0===b.length&&(b=a.find("> a > img")),0===b.length?null:b},c.prototype.captionFromEntry=function(a){var b=a.find("> .caption");return 0===b.length?null:b},c.prototype.displayEntry=function(b,c,d,e,f,g){b.width(e),b.height(g),b.css("top",d),b.css("left",c);var h=this.imgFromEntry(b);if(null!==h){h.css("width",e),h.css("height",f),h.css("margin-left",-e/2),h.css("margin-top",-f/2);var i=h.attr("src"),j=this.newSrc(i,e,f,h[0]);h.one("error",function(){h.attr("src",h.data("jg.originalSrc"))});var k=function(){i!==j&&h.attr("src",j)};"skipped"===b.data("jg.loaded")?this.onImageEvent(i,a.proxy(function(){this.showImg(b,k),b.data("jg.loaded",!0)},this)):this.showImg(b,k)}else this.showImg(b);this.displayEntryCaption(b)},c.prototype.displayEntryCaption=function(b){var c=this.imgFromEntry(b);if(null!==c&&this.settings.captions){var d=this.captionFromEntry(b);if(null===d){var e=c.attr("alt");this.isValidCaption(e)||(e=b.attr("title")),this.isValidCaption(e)&&(d=a('
                  '+e+"
                  "),b.append(d),b.data("jg.createdCaption",!0))}null!==d&&(this.settings.cssAnimation||d.stop().fadeTo(0,this.settings.captionSettings.nonVisibleOpacity),this.addCaptionEventsHandlers(b))}else this.removeCaptionEventsHandlers(b)},c.prototype.isValidCaption=function(a){return"undefined"!=typeof a&&a.length>0},c.prototype.onEntryMouseEnterForCaption=function(b){var c=this.captionFromEntry(a(b.currentTarget));this.settings.cssAnimation?c.addClass("caption-visible").removeClass("caption-hidden"):c.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.visibleOpacity)},c.prototype.onEntryMouseLeaveForCaption=function(b){var c=this.captionFromEntry(a(b.currentTarget));this.settings.cssAnimation?c.removeClass("caption-visible").removeClass("caption-hidden"):c.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.nonVisibleOpacity)},c.prototype.addCaptionEventsHandlers=function(b){var c=b.data("jg.captionMouseEvents");"undefined"==typeof c&&(c={mouseenter:a.proxy(this.onEntryMouseEnterForCaption,this),mouseleave:a.proxy(this.onEntryMouseLeaveForCaption,this)},b.on("mouseenter",void 0,void 0,c.mouseenter),b.on("mouseleave",void 0,void 0,c.mouseleave),b.data("jg.captionMouseEvents",c))},c.prototype.removeCaptionEventsHandlers=function(a){var b=a.data("jg.captionMouseEvents");"undefined"!=typeof b&&(a.off("mouseenter",void 0,b.mouseenter),a.off("mouseleave",void 0,b.mouseleave),a.removeData("jg.captionMouseEvents"))},c.prototype.prepareBuildingRow=function(a){var b,c,d,e,f,g=!0,h=0,i=this.galleryWidth-2*this.border-(this.buildingRow.entriesBuff.length-1)*this.settings.margins,j=i/this.buildingRow.aspectRatio,k=this.settings.rowHeight,l=this.buildingRow.width/i>this.settings.justifyThreshold;if(a&&"hide"===this.settings.lastRow&&!l){for(b=0;b img, > a > img").fadeTo(0,0));return-1}for(a&&!l&&"justify"!==this.settings.lastRow&&"hide"!==this.settings.lastRow&&(g=!1,this.rows>0&&(k=(this.offY-this.border-this.settings.margins*this.rows)/this.rows,g=k*this.buildingRow.aspectRatio/i>this.settings.justifyThreshold)),b=0;bf)&&(h=f);return this.buildingRow.height=h,g},c.prototype.clearBuildingRow=function(){this.buildingRow.entriesBuff=[],this.buildingRow.aspectRatio=0,this.buildingRow.width=0},c.prototype.flushRow=function(a){var b,c,d,e=this.settings,f=this.border;if(c=this.prepareBuildingRow(a),a&&"hide"===e.lastRow&&-1===c)return void this.clearBuildingRow();if(this.maxRowHeight&&(this.maxRowHeight.isPercentage&&this.maxRowHeight.value*e.rowHeight=e.rowHeight&&this.maxRowHeight.valuethis.settings.refreshSensitivity&&(this.galleryWidth=a,this.rewind(),this.startImgAnalyzer(!0)):(d=b(),this.galleryWidth=a)},this),this.settings.refreshTime)},c.prototype.isSpinnerActive=function(){return null!==this.spinner.intervalId},c.prototype.getSpinnerHeight=function(){return this.spinner.$el.innerHeight()},c.prototype.stopLoadingSpinnerAnimation=function(){clearInterval(this.spinner.intervalId),this.spinner.intervalId=null,this.$gallery.height(this.$gallery.height()-this.getSpinnerHeight()),this.spinner.$el.detach()},c.prototype.startLoadingSpinnerAnimation=function(){var a=this.spinner,b=a.$el.find("span");clearInterval(a.intervalId),this.$gallery.append(a.$el),this.$gallery.height(this.offY+this.buildingRow.height+this.getSpinnerHeight()),a.intervalId=setInterval(function(){a.phase0&&(a.isFunction(this.settings.sort)?c=this.sortArray(c):this.settings.randomize&&(c=this.shuffleArray(c)),this.lastFetchedEntry=c[c.length-1],this.settings.filter?c=this.filterArray(c):this.resetFilters(c)),this.entries=this.entries.concat(c),!0},c.prototype.insertToGallery=function(b){var c=this;a.each(b,function(){a(this).appendTo(c.$gallery)})},c.prototype.shuffleArray=function(a){var b,c,d;for(b=a.length-1;b>0;b--)c=Math.floor(Math.random()*(b+1)),d=a[b],a[b]=a[c],a[c]=d;return this.insertToGallery(a),a},c.prototype.sortArray=function(a){return a.sort(this.settings.sort),this.insertToGallery(a),a},c.prototype.resetFilters=function(b){for(var c=0;c=this["yield"].every))return void this.startImgAnalyzer(b);this.buildingRow.entriesBuff.push(d),this.buildingRow.aspectRatio+=f,this.buildingRow.width+=f*this.settings.rowHeight,this.lastAnalyzedIndex=c}else if("error"!==d.data("jg.loaded"))return}this.buildingRow.entriesBuff.length>0&&this.flushRow(!0),this.isSpinnerActive()&&this.stopLoadingSpinnerAnimation(),this.stopImgAnalyzerStarter(),this.$gallery.trigger(b?"jg.resize":"jg.complete"),this.$gallery.height(this.galleryHeightToSet)},c.prototype.stopImgAnalyzerStarter=function(){this["yield"].flushed=0,null!==this.imgAnalyzerTimeout&&clearTimeout(this.imgAnalyzerTimeout)},c.prototype.startImgAnalyzer=function(a){var b=this;this.stopImgAnalyzerStarter(),this.imgAnalyzerTimeout=setTimeout(function(){b.analyzeImages(a)},.001)},c.prototype.onImageEvent=function(b,c,d){if(c||d){var e=new Image,f=a(e);c&&f.one("load",function(){f.off("load error"),c(e)}),d&&f.one("error",function(){f.off("load error"),d(e)}),e.src=b}},c.prototype.init=function(){var b=!1,c=!1,d=this;a.each(this.entries,function(e,f){var g=a(f),h=d.imgFromEntry(g);if(g.addClass("jg-entry"),g.data("jg.loaded")!==!0&&"skipped"!==g.data("jg.loaded"))if(null!==d.settings.rel&&g.attr("rel",d.settings.rel),null!==d.settings.target&&g.attr("target",d.settings.target),null!==h){var i=d.extractImgSrcFromImage(h);if(h.attr("src",i),d.settings.waitThumbnailsLoad===!1){var j=parseFloat(h.attr("width")),k=parseFloat(h.attr("height"));if(!isNaN(j)&&!isNaN(k))return g.data("jg.width",j),g.data("jg.height",k),g.data("jg.loaded","skipped"),c=!0,d.startImgAnalyzer(!1),!0}g.data("jg.loaded",!1),b=!0,d.isSpinnerActive()||d.startLoadingSpinnerAnimation(),d.onImageEvent(i,function(a){g.data("jg.width",a.width),g.data("jg.height",a.height),g.data("jg.loaded",!0),d.startImgAnalyzer(!1)},function(){g.data("jg.loaded","error"),d.startImgAnalyzer(!1)})}else g.data("jg.loaded",!0),g.data("jg.width",g.width()|parseFloat(g.css("width"))|1),g.data("jg.height",g.height()|parseFloat(g.css("height"))|1)}),b||c||this.startImgAnalyzer(!1),this.checkWidth()},c.prototype.checkOrConvertNumber=function(b,c){if("string"===a.type(b[c])&&(b[c]=parseFloat(b[c])),"number"!==a.type(b[c]))throw c+" must be a number";if(isNaN(b[c]))throw"invalid number for "+c},c.prototype.checkSizeRangesSuffixes=function(){if("object"!==a.type(this.settings.sizeRangeSuffixes))throw"sizeRangeSuffixes must be defined and must be an object";var b=[];for(var c in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(c)&&b.push(c);for(var d={0:""},e=0;e1)throw"justifyThreshold must be in the interval [0,1]";if("boolean"!==a.type(this.settings.cssAnimation))throw"cssAnimation must be a boolean";if("boolean"!==a.type(this.settings.captions))throw"captions must be a boolean";if(this.checkOrConvertNumber(this.settings.captionSettings,"animationDuration"),this.checkOrConvertNumber(this.settings.captionSettings,"visibleOpacity"),this.settings.captionSettings.visibleOpacity<0||this.settings.captionSettings.visibleOpacity>1)throw"captionSettings.visibleOpacity must be in the interval [0, 1]";if(this.checkOrConvertNumber(this.settings.captionSettings,"nonVisibleOpacity"),this.settings.captionSettings.nonVisibleOpacity<0||this.settings.captionSettings.nonVisibleOpacity>1)throw"captionSettings.nonVisibleOpacity must be in the interval [0, 1]";if(this.checkOrConvertNumber(this.settings,"imagesAnimationDuration"),this.checkOrConvertNumber(this.settings,"refreshTime"),this.checkOrConvertNumber(this.settings,"refreshSensitivity"),"boolean"!==a.type(this.settings.randomize))throw"randomize must be a boolean";if("string"!==a.type(this.settings.selector))throw"selector must be a string";if(this.settings.sort!==!1&&!a.isFunction(this.settings.sort))throw"sort must be false or a comparison function";if(this.settings.filter!==!1&&!a.isFunction(this.settings.filter)&&"string"!==a.type(this.settings.filter))throw"filter must be false, a string or a filter function"},c.prototype.retrieveSuffixRanges=function(){var a=[];for(var b in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(b)&&a.push(parseInt(b,10));return a.sort(function(a,b){return a>b?1:b>a?-1:0}),a},c.prototype.updateSettings=function(b){this.settings=a.extend({},this.settings,b),this.checkSettings(),this.border=this.settings.border>=0?this.settings.border:this.settings.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges()},a.fn.justifiedGallery=function(b){return this.each(function(d,e){var f=a(e);f.addClass("justified-gallery");var g=f.data("jg.controller");if("undefined"==typeof g){if("undefined"!=typeof b&&null!==b&&"object"!==a.type(b)){if("destroy"===b)return;throw"The argument must be an object"}g=new c(f,a.extend({},a.fn.justifiedGallery.defaults,b)),f.data("jg.controller",g)}else if("norewind"===b);else{if("destroy"===b)return void g.destroy();g.updateSettings(b),g.rewind()}g.updateEntries("norewind"===b)&&g.init()})},a.fn.justifiedGallery.defaults={sizeRangeSuffixes:{},thumbnailPath:void 0,rowHeight:120,maxRowHeight:!1,margins:1,border:-1,lastRow:"nojustify",justifyThreshold:.9,waitThumbnailsLoad:!0,captions:!0,cssAnimation:!0,imagesAnimationDuration:500,captionSettings:{animationDuration:500,visibleOpacity:.7,nonVisibleOpacity:0},rel:null,target:null,extension:/\.[^.\\/]+$/,refreshTime:200,refreshSensitivity:0,randomize:!1,sort:!1,filter:!1,selector:"a, div:not(.spinner)"}}(jQuery); \ No newline at end of file diff --git a/addons/cms/assets/js/jquery.swipebox.min.js b/addons/cms/assets/js/jquery.swipebox.min.js new file mode 100644 index 0000000000000000000000000000000000000000..3c851baabcf723c4ee5bc9743ff3fb474c9f4c1c --- /dev/null +++ b/addons/cms/assets/js/jquery.swipebox.min.js @@ -0,0 +1,2 @@ +/*! Swipebox v1.4.4 | Constantin Saguin csag.co | MIT License | github.com/brutaldesign/swipebox */ +!function(a,b,c,d){c.swipebox=function(e,f){var g,h,i={useCSS:!0,useSVG:!0,initialIndexOnArray:0,removeBarsOnMobile:!0,hideCloseButtonOnMobile:!1,hideBarsDelay:3e3,videoMaxWidth:1140,vimeoColor:"cccccc",beforeOpen:null,afterOpen:null,afterClose:null,afterMedia:null,nextSlide:null,prevSlide:null,loopAtEnd:!1,autoplayVideos:!1,queryStringData:{},toggleClassOnLoad:""},j=this,k=[],l=e.selector,m=navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(Android)|(PlayBook)|(BB10)|(BlackBerry)|(Opera Mini)|(IEMobile)|(webOS)|(MeeGo)/i),n=null!==m||b.createTouch!==d||"ontouchstart"in a||"onmsgesturechange"in a||navigator.msMaxTouchPoints,o=!!b.createElementNS&&!!b.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,p=a.innerWidth?a.innerWidth:c(a).width(),q=a.innerHeight?a.innerHeight:c(a).height(),r=0,s='
                  ';j.settings={},c.swipebox.close=function(){g.closeSlide()},c.swipebox.extend=function(){return g},j.init=function(){j.settings=c.extend({},i,f),c.isArray(e)?(k=e,g.target=c(a),g.init(j.settings.initialIndexOnArray)):c(b).on("click",l,function(a){if("slide current"===a.target.parentNode.className)return!1;c.isArray(e)||(g.destroy(),h=c(l),g.actions()),k=[];var b,d,f;f||(d="data-rel",f=c(this).attr(d)),f||(d="rel",f=c(this).attr(d)),h=f&&""!==f&&"nofollow"!==f?c(l).filter("["+d+'="'+f+'"]'):c(l),h.each(function(){var a=null,b=null;c(this).attr("title")&&(a=c(this).attr("title")),c(this).attr("href")&&(b=c(this).attr("href")),k.push({href:b,title:a})}),b=h.index(c(this)),a.preventDefault(),a.stopPropagation(),g.target=c(a.target),g.init(b)})},g={init:function(a){j.settings.beforeOpen&&j.settings.beforeOpen(),this.target.trigger("swipebox-start"),c.swipebox.isOpen=!0,this.build(),this.openSlide(a),this.openMedia(a),this.preloadMedia(a+1),this.preloadMedia(a-1),j.settings.afterOpen&&j.settings.afterOpen(a)},build:function(){var a,b=this;c("body").append(s),o&&j.settings.useSVG===!0&&(a=c("#swipebox-close").css("background-image"),a=a.replace("png","svg"),c("#swipebox-prev, #swipebox-next, #swipebox-close").css({"background-image":a})),m&&j.settings.removeBarsOnMobile&&c("#swipebox-bottom-bar, #swipebox-top-bar").remove(),c.each(k,function(){c("#swipebox-slider").append('
                  ')}),b.setDim(),b.actions(),n&&b.gesture(),b.keyboard(),b.animBars(),b.resize()},setDim:function(){var b,d,e={};"onorientationchange"in a?a.addEventListener("orientationchange",function(){0===a.orientation?(b=p,d=q):(90===a.orientation||-90===a.orientation)&&(b=q,d=p)},!1):(b=a.innerWidth?a.innerWidth:c(a).width(),d=a.innerHeight?a.innerHeight:c(a).height()),e={width:b,height:d},c("#swipebox-overlay").css(e)},resize:function(){var b=this;c(a).resize(function(){b.setDim()}).resize()},supportTransition:function(){var a,c="transition WebkitTransition MozTransition OTransition msTransition KhtmlTransition".split(" ");for(a=0;a=m||i)){var q=.75-Math.abs(d)/s.height();s.css({top:d+"px"}),s.css({opacity:q}),i=!0}e=b,b=o.pageX-n.pageX,g=100*b/p,!j&&!i&&Math.abs(b)>=l&&(c("#swipebox-slider").css({"-webkit-transition":"",transition:""}),j=!0),j&&(b>0?0===a?c("#swipebox-overlay").addClass("leftSpringTouch"):(c("#swipebox-overlay").removeClass("leftSpringTouch").removeClass("rightSpringTouch"),c("#swipebox-slider").css({"-webkit-transform":"translate3d("+(r+g)+"%, 0, 0)",transform:"translate3d("+(r+g)+"%, 0, 0)"})):0>b&&(k.length===a+1?c("#swipebox-overlay").addClass("rightSpringTouch"):(c("#swipebox-overlay").removeClass("leftSpringTouch").removeClass("rightSpringTouch"),c("#swipebox-slider").css({"-webkit-transform":"translate3d("+(r+g)+"%, 0, 0)",transform:"translate3d("+(r+g)+"%, 0, 0)"}))))}),!1}).bind("touchend",function(a){if(a.preventDefault(),a.stopPropagation(),c("#swipebox-slider").css({"-webkit-transition":"-webkit-transform 0.4s ease",transition:"transform 0.4s ease"}),d=o.pageY-n.pageY,b=o.pageX-n.pageX,g=100*b/p,i)if(i=!1,Math.abs(d)>=2*m&&Math.abs(d)>Math.abs(f)){var k=d>0?s.height():-s.height();s.animate({top:k+"px",opacity:0},300,function(){h.closeSlide()})}else s.animate({top:0,opacity:1},300);else j?(j=!1,b>=l&&b>=e?h.getPrev():-l>=b&&e>=b&&h.getNext()):q.hasClass("visible-bars")?(h.clearTimeout(),h.hideBars()):(h.showBars(),h.setTimeout());c("#swipebox-slider").css({"-webkit-transform":"translate3d("+r+"%, 0, 0)",transform:"translate3d("+r+"%, 0, 0)"}),c("#swipebox-overlay").removeClass("leftSpringTouch").removeClass("rightSpringTouch"),c(".touching").off("touchmove").removeClass("touching")})},setTimeout:function(){if(j.settings.hideBarsDelay>0){var b=this;b.clearTimeout(),b.timeout=a.setTimeout(function(){b.hideBars()},j.settings.hideBarsDelay)}},clearTimeout:function(){a.clearTimeout(this.timeout),this.timeout=null},showBars:function(){var a=c("#swipebox-top-bar, #swipebox-bottom-bar");this.doCssTrans()?a.addClass("visible-bars"):(c("#swipebox-top-bar").animate({top:0},500),c("#swipebox-bottom-bar").animate({bottom:0},500),setTimeout(function(){a.addClass("visible-bars")},1e3))},hideBars:function(){var a=c("#swipebox-top-bar, #swipebox-bottom-bar");this.doCssTrans()?a.removeClass("visible-bars"):(c("#swipebox-top-bar").animate({top:"-50px"},500),c("#swipebox-bottom-bar").animate({bottom:"-50px"},500),setTimeout(function(){a.removeClass("visible-bars")},1e3))},animBars:function(){var a=this,b=c("#swipebox-top-bar, #swipebox-bottom-bar");b.addClass("visible-bars"),a.setTimeout(),c("#swipebox-slider").click(function(){b.hasClass("visible-bars")||(a.showBars(),a.setTimeout())}),c("#swipebox-bottom-bar").hover(function(){a.showBars(),b.addClass("visible-bars"),a.clearTimeout()},function(){j.settings.hideBarsDelay>0&&(b.removeClass("visible-bars"),a.setTimeout())})},keyboard:function(){var b=this;c(a).bind("keyup",function(a){a.preventDefault(),a.stopPropagation(),37===a.keyCode?b.getPrev():39===a.keyCode?b.getNext():27===a.keyCode&&b.closeSlide()})},actions:function(){var a=this,b="touchend click";k.length<2?(c("#swipebox-bottom-bar").hide(),d===k[1]&&c("#swipebox-top-bar").hide()):(c("#swipebox-prev").bind(b,function(b){b.preventDefault(),b.stopPropagation(),a.getPrev(),a.setTimeout()}),c("#swipebox-next").bind(b,function(b){b.preventDefault(),b.stopPropagation(),a.getNext(),a.setTimeout()})),c("#swipebox-close").bind(b,function(){a.closeSlide()})},setSlide:function(a,b){b=b||!1;var d=c("#swipebox-slider");r=100*-a,this.doCssTrans()?d.css({"-webkit-transform":"translate3d("+100*-a+"%, 0, 0)",transform:"translate3d("+100*-a+"%, 0, 0)"}):d.animate({left:100*-a+"%"}),c("#swipebox-slider .slide").removeClass("current"),c("#swipebox-slider .slide").eq(a).addClass("current"),this.setTitle(a),b&&d.fadeIn(),c("#swipebox-prev, #swipebox-next").removeClass("disabled"),0===a?c("#swipebox-prev").addClass("disabled"):a===k.length-1&&j.settings.loopAtEnd!==!0&&c("#swipebox-next").addClass("disabled")},openSlide:function(b){c("html").addClass("swipebox-html"),n?(c("html").addClass("swipebox-touch"),j.settings.hideCloseButtonOnMobile&&c("html").addClass("swipebox-no-close-button")):c("html").addClass("swipebox-no-touch"),c(a).trigger("resize"),this.setSlide(b,!0)},preloadMedia:function(a){var b=this,c=null;k[a]!==d&&(c=k[a].href),b.isVideo(c)?b.openMedia(a):setTimeout(function(){b.openMedia(a)},1e3)},openMedia:function(a){var b,e,f=this;return k[a]!==d&&(b=k[a].href),0>a||a>=k.length?!1:(e=c("#swipebox-slider .slide").eq(a),void(f.isVideo(b)?(e.html(f.getVideo(b)),j.settings.afterMedia&&j.settings.afterMedia(a)):(e.addClass("slide-loading"),f.loadMedia(b,function(){e.removeClass("slide-loading"),e.html(this),j.settings.afterMedia&&j.settings.afterMedia(a)}))))},setTitle:function(a){var b=null;c("#swipebox-title").empty(),k[a]!==d&&(b=k[a].title),b?(c("#swipebox-top-bar").show(),c("#swipebox-title").append(b)):c("#swipebox-top-bar").hide()},isVideo:function(a){if(a){if(a.match(/(youtube\.com|youtube-nocookie\.com)\/watch\?v=([a-zA-Z0-9\-_]+)/)||a.match(/vimeo\.com\/([0-9]*)/)||a.match(/youtu\.be\/([a-zA-Z0-9\-_]+)/))return!0;if(a.toLowerCase().indexOf("swipeboxvideo=1")>=0)return!0}},parseUri:function(a,d){var e=b.createElement("a"),f={};return e.href=decodeURIComponent(a),e.search&&(f=JSON.parse('{"'+e.search.toLowerCase().replace("?","").replace(/&/g,'","').replace(/=/g,'":"')+'"}')),c.isPlainObject(d)&&(f=c.extend(f,d,j.settings.queryStringData)),c.map(f,function(a,b){return a&&a>""?encodeURIComponent(b)+"="+encodeURIComponent(a):void 0}).join("&")},getVideo:function(a){var b="",c=a.match(/((?:www\.)?youtube\.com|(?:www\.)?youtube-nocookie\.com)\/watch\?v=([a-zA-Z0-9\-_]+)/),d=a.match(/(?:www\.)?youtu\.be\/([a-zA-Z0-9\-_]+)/),e=a.match(/(?:www\.)?vimeo\.com\/([0-9]*)/),f="";return c||d?(d&&(c=d),f=g.parseUri(a,{autoplay:j.settings.autoplayVideos?"1":"0",v:""}),b=''):e?(f=g.parseUri(a,{autoplay:j.settings.autoplayVideos?"1":"0",byline:"0",portrait:"0",color:j.settings.vimeoColor}),b=''):b='','
                  '+b+"
                  "},loadMedia:function(a,b){if(0===a.trim().indexOf("#"))b.call(c("
                  ",{"class":"swipebox-inline-container"}).append(c(a).clone().toggleClass(j.settings.toggleClassOnLoad)));else if(!this.isVideo(a)){var d=c("").on("load",function(){b.call(d)});d.attr("src",a)}},getNext:function(){var a,b=this,d=c("#swipebox-slider .slide").index(c("#swipebox-slider .slide.current"));d+10?(a=c("#swipebox-slider .slide").eq(b).contents().find("iframe").attr("src"),c("#swipebox-slider .slide").eq(b).contents().find("iframe").attr("src",a),b--,this.setSlide(b),this.preloadMedia(b-1),j.settings.prevSlide&&j.settings.prevSlide(b)):(c("#swipebox-overlay").addClass("leftSpring"),setTimeout(function(){c("#swipebox-overlay").removeClass("leftSpring")},500))},nextSlide:function(a){},prevSlide:function(a){},closeSlide:function(){c("html").removeClass("swipebox-html"),c("html").removeClass("swipebox-touch"),c(a).trigger("resize"),this.destroy()},destroy:function(){c(a).unbind("keyup"),c("body").unbind("touchstart"),c("body").unbind("touchmove"),c("body").unbind("touchend"),c("#swipebox-slider").unbind(),c("#swipebox-overlay").remove(),c.isArray(e)||e.removeData("_swipebox"),this.target&&this.target.trigger("swipebox-destroy"),c.swipebox.isOpen=!1,j.settings.afterClose&&j.settings.afterClose()}},j.init()},c.fn.swipebox=function(a){if(!c.data(this,"_swipebox")){var b=new c.swipebox(this,a);this.data("_swipebox",b)}return this.data("_swipebox")}}(window,document,jQuery); \ No newline at end of file diff --git a/addons/cms/assets/js/layerloader.min.js b/addons/cms/assets/js/layerloader.min.js new file mode 100644 index 0000000000000000000000000000000000000000..2a763d04ed74f474924866fc666fb273eedaefe7 --- /dev/null +++ b/addons/cms/assets/js/layerloader.min.js @@ -0,0 +1 @@ +var lazyloader=function(e,t){function n(e){e=e.toLowerCase();var t=e.indexOf("js"),n=e.indexOf("css");return-1==t&&-1==n?!1:t>n?"js":"css"}function s(e){var t=document.createElement("link");t.href=e,t.rel="stylesheet",t.type="text/css",t.onload=c,t.onreadystatechange=function(){("loaded"==this.readyState||"complete"==this.readyState)&&c()},document.getElementsByTagName("head")[0].appendChild(t)}function a(e){try{document.styleSheets[e].cssRules?c():document.styleSheets[e].rules&&document.styleSheets[e].rules.length?c():setTimeout(function(){a(e)},250)}catch(t){setTimeout(function(){a(e)},250)}}function o(e){var t=document.createElement("script");t.type="text/javascript",t.src=e,t.onload=c,document.getElementsByTagName("head")[0].appendChild(t)}function c(){d--,0==d&&t()}var r,d=0,i=document.styleSheets.length-1;for(var l in e){d++;var r=e[l];"css"==n(r)&&(s(r),i++,window.opera||-1!=navigator.userAgent.indexOf("MSIE")||a(i)),"js"==n(r)&&o(r)}}; \ No newline at end of file diff --git a/addons/cms/assets/less/common.less b/addons/cms/assets/less/common.less new file mode 100644 index 0000000000000000000000000000000000000000..00fad24b1f537a5712379c996abaeff6416c62fd --- /dev/null +++ b/addons/cms/assets/less/common.less @@ -0,0 +1,1301 @@ +@import (reference) "../../../../public/assets/less/bootstrap-less/mixins.less"; +@import (reference) "../../../../public/assets/less/bootstrap-less/variables.less"; +@import (reference) "../../../../public/assets/less/fastadmin/mixins.less"; +@import (reference) "../../../../public/assets/less/fastadmin/variables.less"; +@import "../../../../public/assets/less/lesshat.less"; +@import url("../../../css/bootstrap.min.css"); +@import url("../../../libs/font-awesome/css/font-awesome.min.css"); + +html, +body { + height: 100%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 400; + overflow-x: hidden; + overflow-y: auto; + padding-top: 40px; + background: #f4f6f8; + font-size: 14px; + color: #616161; +} + +.wow { + visibility: hidden; +} + +.dropdown:hover > .dropdown-menu { + display: block; + margin-top: 0; +} + +.dropdown-submenu { + position: relative; + > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + .border-radius(3px 0 3px 3px); + } + &:hover { + > .dropdown-menu { + display: block; + } + > a:after { + border-left-color: #fff; + } + } + > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #ccc; + margin-top: 5px; + margin-right: -10px; + } + &.pull-left { + float: none; + > .dropdown-menu { + left: -100%; + margin-left: 10px; + .border-radius(3px 0 3px 3px); + } + } + +} + +.navbar { + border: none; +} + +.navbar-nav { + .form-search { + &.focused { + position: relative; + input { + position: absolute; + top: 0; + right: 0; + width: 250px; + } + } + } +} + +.navbar-nav { + li > a { + font-size: 13px; + h5 { + overflow: hidden; + text-overflow: ellipsis; + } + } + > li > a { + font-size: 14px; + } +} + +@media (max-width: 769px) { + ul.dropdown-menu { + position: relative; + width: 100%; + background: #222; + .open > a, .open > a:hover, .open > a:focus { + background: none; + color: #9d9d9d; + } + > .dropdown-menu { + position: relative; + width: 100%; + margin: 0; + } + .open { + > a, > a:hover, > a:focus { + } + + } + } + + .navbar-nav { + .form-search { + padding: 0 10px; + } + .open .dropdown-menu { + position: relative; + width: 100%; + margin: 0; + left: 0; + } + } + + .dropdown-submenu > a:after { + display: none; + } +} + +.navbar-brand { + padding: 5px 5px; +} + +.toast-top-center { + top: 50px; +} + +#toast-container > div { + .box-shadow(none); +} + +/*修复nice-validator和summernote的编辑框冲突*/ +.nice-validator .note-editor .note-editing-area .note-editable { + display: inherit; +} + +/*预览区域*/ +.plupload-preview { + padding: 10px; + margin-bottom: 0; + li { + margin-bottom: 10px; + } + .thumbnail { + margin-bottom: 10px; + } + a { + display: block; + &:first-child { + height: 90px; + } + img { + height: 80px; + object-fit: cover; + } + } +} + +#floatbtn { + width: 50px; + height: auto; + position: fixed; + top: auto; + right: 50%; + bottom: 10px; + left: auto; + z-index: 80; + margin-right: -620px; + &.fixed { + position: absolute; + bottom: 279px; + right: 50%; + } + a { + position: relative; + z-index: 90; + display: block; + margin-top: 4px; + width: 50px; + height: 50px; + line-height: 50px; + text-align: center; + font-size: 20px; + color: #d5d5d5; + background-color: #fff; + border: 1px solid #eee; + .user-select(none); + &.hover:hover { + .transition(background-color 200ms ease-out); + &:before { + content: ""; + position: absolute; + z-index: 100; + display: block; + width: 100%; + height: 100%; + padding: 10px; + font-size: 14px; + line-height: 15px; + color: #fff; + text-align: center; + background-color: #17bb9c; + -webkit-pointer-events: none; + -moz-pointer-events: none; + pointer-events: none; + } + i { + display: none; + } + &#fb-tipoff:before { + content: "\7206\6599\6295\7a3f"; + font-weight: 400 + } + &#feedback:before { + content: "\53d1\8868\8bc4\8bba" + } + &#back-to-top:before { + content: "\56de\5230\9876\90e8" + } + } + &#fb-qrcode:hover #fb-qrcode-wrapper { + display: block; + } + } + .iconfont { + display: inline-block; + font: normal normal normal 14px/1 iconfont; + font-size: inherit; + } +} + +#fb-qrcode-wrapper { + position: absolute; + right: 59px; + top: -55px; + z-index: 120; + display: none; + width: 190px; + height: 212px; + background-color: #fff; + border: 1px solid #eee; + &:after { + content: ""; + position: absolute; + right: -6px; + top: 73px; + display: block; + width: 0; + height: 0; + border-left: 6px solid #d5d5d5; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + } + .qrcode { + margin-top: 20px; + line-height: 1; + img { + width: 128px; + height: 128px; + } + } + p { + font-size: 12px; + line-height: 20px; + color: #999; + em { + color: #dd3067; + } + } +} + +.text-primary, +.text-primary:hover { + color: @brand-primary; +} + +.text-success, +.text-success:hover { + color: @brand-success; +} + +.text-danger, +.text-danger:hover { + color: @brand-danger; +} + +.text-warning, +.text-warning:hover { + color: @brand-warning; +} + +.text-info, +.text-info:hover { + color: @brand-info; +} + +.well { + .box-shadow(none); +} + +.clearfix() { + &:before, + &:after { + content: " "; // 1 + display: table; // 2 + } + &:after { + clear: both; + } +} + +.responsive-container { + position: relative; + width: 100%; + border: 1px solid #f8f8f8; +} + +footer { + padding: 30px 0; +} + +@media (min-width: 979px) { + ul.nav li.dropdown:hover > ul.dropdown-menu { + display: block; + } +} + +.main { + background: #fff; + padding: 15px; + min-height: 500px; + h3 { + margin: 0; + margin-bottom: 10px; + height: 35px; + line-height: 35px; + label { + display: inline-block; + font-size: 14px; + font-weight: 400; + vertical-align: middle; + } + } + > row { + margin-top: 15px; + } + label { + font-weight: 400; + } + .fixed-table-container thead th .th-inner { + font-weight: 500; + } + table a:not(.btn), .table a:not(.btn) { + text-decoration: none; + } +} + +.nav-sidebar { + li.active a { + text-decoration: none; + background-color: #ecf0f1; + } +} + +.navbar-toggle .icon-bar { + width: 18px; +} + +.footer-inner { + padding: 2em 0; + .copyright { + margin-bottom: 20px !important; + line-height: 1.5; + } + .footer-logo { + margin-bottom: 20px; + a { + padding: 15px 15px; + background: rgba(0, 0, 0, .07); + font-size: 40px; + font-weight: 700; + &:hover, &:focus { + text-decoration: none; + } + } + } + h3 { + font-weight: 400; + margin-bottom: 20px; + } + p { + font-weight: 40; + &:last-child { + margin-bottom: 0; + } + } + .links { + padding: 0; + margin: 0 0 20px 0; + li { + list-style: none; + padding: 5px 0; + a { + &:hover { + text-decoration: none; + } + } + } + } + .footer-social { + text-align: right; + margin-top: 0; + a { + margin-right: 15px; + margin-bottom: 10px; + font-size: 20px; + &:hover { + text-decoration: none; + } + } + } + +} + +#footer { + border-top: 1px solid #ddd; + margin-top: 50px; + padding-top: 20px; +} + +.article-section { + background: #fff; + padding: 15px; + margin-bottom: 20px; + .border-radius(2px); + .box-shadow(0 1px 2px 0 rgba(0, 0, 0, 0.1)); +} + +.article-list-main { + .article-item .content { + margin-top: 15px; + color: #919191; + } + .media { + color: #919191; + .media-body { + padding-left: 10px; + line-height: 25px; + } + img { + .border-radius(6px); + width: 220px; + } + } + .article-tag { + display: block; + clear: both; + margin-top: 20px; + padding-top: 15px; + border-top: 1px solid #efefef; + .pull-left { + height: 34px; + line-height: 34px; + color: #919191; + a { + color: #919191; + } + } + } + .pager { + margin: 40px 0 20px 0; + } +} + +@media (max-width: 767px) { + .article-list-main { + .media { + img { + width: 140px; + } + } + } +} + +.article-metas { + overflow: hidden; + margin-bottom: 10px; + .date { + height: 45px; + width: 45px; + margin-top: 10px; + text-align: center; + color: #c1c1c1; + border: 1px solid #c1c1c1; + .border-radius(50%); + .day { + margin-top: 2px; + font-size: 16px; + line-height: 1.2; + } + .month { + font-size: 12px; + } + } + .metas-body { + padding-left: 60px; + p { + margin-bottom: 0; + margin-top: 0px; + font-size: 12px; + } + .title { + margin: 5px 0 0 0; + line-height: 36px; + a { + color: #616161; + .transition(all 0.3s ease); + &:hover { + color: #46c37b; + .transition(all 0.3s ease); + } + } + } + .sns { + color: #e1e1e1; + margin: 0px auto; + span { + margin-right: 10px; + i { + margin-right: 5px; + } + } + } + } +} + +@media (max-width: 1199px) { + .article-metas .metas-body .title { + font-size: 20px; + line-height: 30px; + } +} + +@media (max-width: 767px) { + .article-metas .metas-body .title { + font-size: 16px; + line-height: 20px; + } +} + +.article-text p { + line-height: 30px; + margin: 20px auto 30px auto; +} + +@media (max-width: 767px) { + .article-text p { + margin: 10px auto 20px auto; + } +} + +.article-text img { + margin: 10px auto; + display: block; + max-width: 100%; + height: auto; + .border-radius(2px); +} + +.product-action-btn { + color: #999; + + .bdshare-button-style0-16 .bds_more { + float: none; + padding: 0; + height: inherit; + line-height: inherit; + font-size: inherit; + background: none; + } +} + +.product-like-wrapper { + margin: 15px auto; + text-align: center; + a { + display: inline-block; + width: 44px; + height: 44px; + line-height: 44px; + color: #999; + text-align: center; + background-color: #bebebe; + background-position: center center; + background-repeat: no-repeat; + .transition(background-color 300ms linear); + .border-radius(22px); + vertical-align: middle; + &.product-like { + position: relative; + margin-right: 5px; + background-color: #46c37b; + &:hover { + background-color: #08aa73 + } + } + &.product-dislike { + position: relative; + margin-left: 5px; + &:hover { + background-color: #999 + } + + } + i.fa { + font-size: 20px; + color: #fff; + } + } + .like-bar-wrapper { + position: relative; + display: inline-block; + vertical-align: -18% + } + .bar { + width: 110px; + height: 7px; + overflow: hidden; + background-color: #dcdcdc; + .border-radius(4px); + span { + display: block; + height: 100%; + width: 50%; + background-color: #46c37b; + .transition(width 300ms linear); + } + } + .num { + position: absolute; + top: -18px; + display: block; + width: 100%; + font-style: normal; + font-size: 10px; + color: #999; + text-align: center; + i { + position: absolute; + right: 55%; + color: #46c37b; + font-style: normal; + } + span { + position: absolute; + left: 55% + } + } +} + +.product-like-wrapper.like-status-1 .product-like { + position: relative; + background: #86a4d5; + &::before { + content: "\5df2\8d5e"; + position: absolute; + top: 0; + left: 0; + display: block; + height: 100%; + width: 100%; + font-size: 14px; + line-height: 44px; + color: #fff + } +} + +.product-like-wrapper.like-status-3 .product-dislike { + position: relative; + background: #bebebe; + &::before { + content: "\5df2\8e29"; + position: absolute; + top: 0; + left: 0; + display: block; + height: 100%; + width: 100%; + font-size: 14px; + line-height: 44px; + color: #fff + } +} + +.entry-meta ul { + overflow: hidden; + margin: 0 0 10px 0; + padding: 0 0 10px 0; + border-bottom: 1px solid #dedede; + li { + line-height: 26px; + } +} + +.related-article { + margin-top: 10px; + .row { + margin: 0 -5px; + } + .col-sm-4 { + position: relative; + display: block; + padding: 0 5px; + margin: 5px auto; + } + .related-item { + position: relative; + .border-radius(2px); + overflow: hidden; + img { + width: 100%; + } + } + .title { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 10px 20px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + color: #fff; + z-index: 999; + } +} + +.panel-default { + border: none; + padding: 0 15px; + .box-shadow(0 1px 2px 0 rgba(0, 0, 0, 0.1)); +} + +.panel-default { + > .panel-heading { + position: relative; + font-size: 16px; + padding: 15px 0; + background: #fff; + border-bottom: 1px solid #f5f5f5; + .panel-title { + /*color: @gray-dark;*/ + > i { + display: none; + } + } + .more { + position: absolute; + top: 13px; + right: 0; + display: block; + color: #919191; + .transition(all 0.3s ease); + &:hover { + color: #616161; + .transition(all 0.3s ease); + } + } + .panel-bar { + position: absolute; + top: 7px; + right: 0; + display: block; + } + } + > .panel-footer { + padding: 15px 0; + background: none; + } + > .panel-body { + position: relative; + padding: 15px 0; + } +} + +.panel-primary { + > .panel-heading { + background-color: #46c37b; + color: #fff; + } + > .panel-body { + background: #fafafa; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } +} + +.panel-gray { + .box-shadow(0 2px 4px rgba(0, 0, 0, 0.08)); + > .panel-heading { + background-color: #f5f5f5; + color: #919191; + } + > .panel-body { + color: #919191; + background: #fff; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + } +} + +.panel-page { + padding: 45px 50px 50px; + min-height: 500px; + .panel-heading { + background: transparent; + border-bottom: none; + margin: 0 0 30px 0; + padding: 0; + h2 { + font-size: 25px; + margin-top: 0; + } + } +} + +@media (max-width: 767px) { + .panel-page { + padding: 15px; + min-height: 300px; + } +} + +.tabs-wrapper { + border: 1px solid #e4ecf3; + .border-radius(4px); + margin-bottom: 30px; + background-color: #fff; + .tabs-mark-group { + border-bottom: 1px dashed #e4ecf3; + padding: 10px; + .title { + width: 90px; + margin-top: 3px; + float: left + } + .classify { + margin-top: 3px; + a, i { + color: #919191 + } + a:focus, a:hover { + color: #43bc60 + } + } + .content { + margin-left: 100px + } + + } + .tabs-mark { + margin: 0 4px; + a { + border: 1px solid #e4ecf3; + padding: 2px 5px; + color: #919191 + } + i { + font-size: 10px; + margin-left: 5px + } + &.active a, &:focus a, &:hover a { + color: #43bc60; + border: 1px solid #43bc60 + } + } + .tabs-group { + padding: 0 60px 0 15px; + position: relative; + overflow-y: hidden; + .title { + float: left; + padding: 15px 0; + width: 100px; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + word-wrap: normal + } + .content { + list-style: none; + padding: 0; + margin: 0 0 0 100px; + > li { + float: left; + padding: 10px 12px; + > a { + display: block; + padding: 5px 10px; + border: none; + .border-radius(4px); + color: #919191; + .transition(all .3s ease); + } + &.active > a, &:focus > a, &:hover > a { + color: #43bc60 + } + } + } + .tabs-toggle { + position: absolute; + right: 20px; + top: 18px; + font-size: 12px; + line-height: 1; + cursor: pointer + } + + .tabs-group { + border-top: 1px dashed #e4ecf3 + } + } +} + +.article-filter { + position: relative; + background-color: #fafafa; + .border-radius(4px); + margin-bottom: 30px; + .nav-sort > li { + float: left; + > a { + height: 40px; + padding: 10px 15px; + color: #616161; + .transition(all .3s ease); + &:hover { + color: #43bc60; + .transition(all .3s ease); + } + &.active { + color: #fff; + background-color: #43bc60; + &:hover { + color: #fff + } + } + } + } + .btn-group.open .dropdown-toggle { + .box-shadow(none); + color: #43bc60 + } + .filter { + position: absolute; + text-align: right; + top: 0; + right: 15px; + width: 300px; + .btn { + background: none; + padding: 10px 0; + .transition(all .3s ease); + &:hover { + color: #43bc60; + .transition(all .3s ease); + } + > i { + font-size: 18px + } + } + label { + margin-left: 15px; + margin-top: 11px; + vertical-align: top; + .transition(all .3s ease); + &:hover { + color: #43bc60; + .transition(all .3s ease); + } + } + } +} + +h1 .breadcrumb { + padding: 0 5px; + margin-bottom: 5px; + li { + font-size: 12px; + font-weight: 400; + } +} + +#carousel-focus-captions { + .item { + .carousel-img { + background-size: cover; + width: 100%; + height: 120px; + background-position: center center; + } + } + .carousel-control { + &.left, &.right { + background-image: none; + span { + display: none; + } + &:hover { + .transition(all 1s ease); + span { + display: block; + } + } + } + } +} + +@media (max-width: @screen-sm-min) { + +} + +/* Extra small devices (phones, less than 768px) */ +/* No media query since this is the default in Bootstrap */ + +/* Small devices (tablets, 768px and up) */ +@media (min-width: @screen-sm-min) { + #carousel-focus-captions .item { + .carousel-img { + height: 340px; + width: 100%; + } + } +} + +/* Medium devices (desktops, 992px and up) */ +@media (min-width: @screen-md-min) { + +} + +.article-sidebar .panel-adimg img { + width: 100%; +} + +.hot-tags { + .panel-body a { + span { + margin-bottom: 10px; + } + } +} + +.product-list { + .product { + position: relative; + margin-bottom: 20px; + .detail { + position: absolute; + z-index: 1; + height: 30px; + right: 15px; + bottom: 12px; + padding: 0 15px; + line-height: 30px; + text-align: center; + text-transform: capitalize; + letter-spacing: 0.02em; + font-size: 14px; + color: #00b22d; + border-radius: 2px; + background: whitesmoke; + + &:hover { + background: #eee; + text-decoration: none; + } + } + } +} + +@media (min-width: 769px) { + .product-list .product:hover .detail { + display: block + } +} + +.card { + border-radius: 4px; + position: relative; + padding: 12px; + margin: 0 auto 50px; + .box-shadow(0 1px 3px rgba(0, 0, 0, .2)); + .transition(all 200ms cubic-bezier(0.55, 0.055, 0.675, 0.19)); + min-height: 325px; + background-color: #FFF; + &:hover { + .box-shadow(0 2px 8px rgba(0, 0, 0, 0.2)); + } + .image { + position: relative; + width: 100%; + height: 1px; + overflow: hidden; + padding-bottom: 75%; + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + } + .title { + padding-top: 10px + } + h2 { + color: #000; + padding: 0; + margin-bottom: 5px; + margin-top: 10px; + font-size: 16px; + font-weight: 700; + line-height: 1.4; + text-transform: uppercase; + text-align: left; + } +} + +#content-container > h1 { + margin-top: 0; +} + +.lasest-update { + .panel-body { + padding: 8px 0; + ul { + margin-bottom: 0; + } + ul li { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; + height: 35px; + line-height: 35px; + } + } +} + +.channel-list { + .row { + .col-xs-6 { + min-height: 315px; + h3 { + border-bottom: 2px solid #eee; + padding-bottom: 10px; + position: relative; + > a { + font-size: 16px; + border-bottom: 2px solid #17bb9c; + padding-bottom: 10px; + } + em { + position: absolute; + right: 5px; + top: 5px; + font-style: normal; + font-weight: 400; + a { + font-size: 12px; + } + } + } + } + .media { + margin-bottom: 10px; + .media-body { + font-size: 12px; + } + } + ul li { + border-bottom: 1px solid #eee; + margin-bottom: 5px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + position: relative; + padding-right: 40px; + height: 30px; + line-height: 30px; + a { + color: #616161; + } + span { + position: absolute; + right: 0; + } + } + } +} + +#comment-container { + #commentlist { + dl { + position: relative; + border-bottom: 1px solid #eee; + clear: both; + padding: 10px 0; + margin-bottom: 5px; + dt { + float: left; + margin-right: 10px; + width: 54px; + height: 54px; + display: block; + position: absolute; + img { + width: 50px; + height: 50px; + border-radius: 50%; + } + } + dd { + padding-left: 60px; + float: left; + width: 100%; + small { + display: block; + color: #999; + margin: -2px 0; + height: 20px; + line-height: 20px; + font-size: 10px; + a { + display: none; + } + } + dl { + margin: 0px; + border-top: 1px solid #eee; + border-bottom: none; + padding-top: 15px; + padding-bottom: 0; + + dd { + width: 550px; + } + } + p { + margin-bottom: 10px; + } + } + } + cite { + font-style: normal; + } + } + h3 { + position: relative; + font-size: 16px; + padding: 15px 0; + background: #fff; + border-bottom: 1px solid #f5f5f5; + font-weight: 400; + a { + display: none; + } + } + #postcomment { + .form-group { + margin-bottom: 10px; + } + label { + font-weight: normal; + } + a { + small { + display: inline !important; + } + } + } + +} \ No newline at end of file diff --git a/addons/cms/config.php b/addons/cms/config.php new file mode 100644 index 0000000000000000000000000000000000000000..52ea2baf48c7ffacf26897d2c40f2c7d495c1ff6 --- /dev/null +++ b/addons/cms/config.php @@ -0,0 +1,180 @@ + + array( + 'name' => 'sitename', + 'title' => '站点名称', + 'type' => 'string', + 'content' => + array(), + 'value' => '我的CMS网站', + 'rule' => 'required', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 1 => + array( + 'name' => 'theme', + 'title' => '皮肤', + 'type' => 'string', + 'content' => + array(), + 'value' => 'default', + 'rule' => 'required', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 2 => + array( + 'name' => 'qrcode', + 'title' => '公众号二维码', + 'type' => 'image', + 'content' => + array(), + 'value' => '/assets/addons/cms/img/qrcode.png', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 3 => + array( + 'name' => 'default_archives_img', + 'title' => '文档默认图片', + 'type' => 'image', + 'content' => + array(), + 'value' => '/assets/addons/cms/img/noimage.jpg', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 4 => + array( + 'name' => 'default_channel_img', + 'title' => '栏目默认图片', + 'type' => 'image', + 'content' => + array(), + 'value' => '/assets/addons/cms/img/noimage.jpg', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 5 => + array( + 'name' => 'default_block_img', + 'title' => '区块默认图片', + 'type' => 'image', + 'content' => + array(), + 'value' => '/assets/addons/cms/img/noimage.jpg', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 6 => + array( + 'name' => 'default_page_img', + 'title' => '单页默认图片', + 'type' => 'image', + 'content' => + array(), + 'value' => '/assets/addons/cms/img/noimage.jpg', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 7 => + array( + 'name' => 'domain', + 'title' => '绑定二级域名前缀', + 'type' => 'string', + 'content' => + array(), + 'value' => '', + 'rule' => '', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 8 => + array( + 'name' => 'rewrite', + 'title' => '伪静态', + 'type' => 'array', + 'content' => + array(), + 'value' => + array( + 'index/index' => '/cms$', + 'channel/index' => '/cms/c/[:diyname]', + 'tags/index' => '/cms/t/[:name]', + 'archives/index' => '/cms/a/[:diyname]', + 'page/index' => '/cms/p/[:diyname]', + 'search/index' => '/cms/s', + ), + 'rule' => 'required', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 9 => + array( + 'name' => 'wxappid', + 'title' => '小程序AppID', + 'type' => 'string', + 'content' => + array(), + 'value' => '小程序appid', + 'rule' => 'required', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 10 => + array( + 'name' => 'wxappsecret', + 'title' => '小程序AppSecret', + 'type' => 'string', + 'content' => + array(), + 'value' => '小程序secret', + 'rule' => 'required', + 'msg' => '', + 'tip' => '', + 'ok' => '', + 'extend' => '', + ), + 11 => + array( + 'name' => 'apikey', + 'title' => 'ApiKey', + 'type' => 'string', + 'content' => + array(), + 'value' => '', + 'rule' => '', + 'msg' => '', + 'tip' => '用于调用API接口时写入数据权限控制
                  可以为空', + 'ok' => '', + 'extend' => '', + ), +); diff --git a/addons/cms/controller/Api.php b/addons/cms/controller/Api.php new file mode 100644 index 0000000000000000000000000000000000000000..3beebbbe664d1a80046fa33d37c4016caa711d01 --- /dev/null +++ b/addons/cms/controller/Api.php @@ -0,0 +1,58 @@ +request->request('apikey'); + $config = get_addon_config('cms'); + if (!$config['apikey']) { + $this->error('请先在后台配置API密钥'); + } + if ($config['apikey'] != $apikey) { + $this->error('密钥不正确'); + } + $channel_id = $this->request->request('channel_id'); + $data = $this->request->request(); + $channel = \addons\cms\model\Channel::get($channel_id); + if (!$channel) { + $this->error('栏目未找到'); + } + $model = Modelx::get($channel['model_id']); + if (!$model) { + $this->error('模型未找到'); + } + $data['model_id'] = $model['id']; + $data['content'] = !isset($data['content']) ? '' : $data['content']; + Db::startTrans(); + try { + (new \app\admin\model\Archives)->allowField(true)->save($data); + Db::commit(); + } catch (PDOException $e) { + Db::rollback(); + $this->error($e->getMessage()); + } catch (Exception $e) { + Db::rollback(); + $this->error($e->getMessage()); + } + $this->success('新增成功'); + return; + } + +} diff --git a/addons/cms/controller/Archives.php b/addons/cms/controller/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..6a730d8f3e073101ad5a6032724c677b581dd6b9 --- /dev/null +++ b/addons/cms/controller/Archives.php @@ -0,0 +1,84 @@ +request->post("action"); + if ($action && $this->request->isPost()) { + return $this->$action(); + } + $diyname = $this->request->param('diyname'); + if ($diyname && !is_numeric($diyname)) { + $archives = ArchivesModel::getByDiyname($diyname); + } else { + $id = $diyname ? $diyname : $this->request->get('id', ''); + $archives = ArchivesModel::get($id); + } + if (!$archives || $archives['status'] == 'hidden' || $archives['deletetime']) { + $this->error(__('No specified article found')); + } + $channel = Channel::get($archives['channel_id']); + 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) { + $fieldsContentList = $model->getFieldsContentList($model->id); + //附加列表字段 + array_walk($fieldsContentList, function ($content, $field) use (&$addon) { + $addon[$field . '_text'] = isset($content[$addon[$field]]) ? $content[$addon[$field]] : $addon[$field]; + }); + } + $archives->setData($addon); + } else { + $this->error('No specified addon article found'); + } + $archives->setInc("views", 1); + $this->view->assign("__ARCHIVES__", $archives); + $this->view->assign("__CHANNEL__", $channel); + Config::set('cms.title', $archives['title']); + Config::set('cms.keywords', $archives['keywords']); + Config::set('cms.description', $archives['description']); + $template = preg_replace('/\.html$/', '', $channel['showtpl']); + 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['status'] == 'hidden') { + $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]); + } + +} diff --git a/addons/cms/controller/Base.php b/addons/cms/controller/Base.php new file mode 100644 index 0000000000000000000000000000000000000000..5d375aec1dff036827f5d4ac6a99f83f973ba1a9 --- /dev/null +++ b/addons/cms/controller/Base.php @@ -0,0 +1,36 @@ +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); + // 定义CMS首页的URL + $config['indexurl'] = addon_url('cms/index/index', [], false); + \think\Config::set('cms', $config); + } + + public function _initialize() + { + parent::_initialize(); + // 如果请求参数action的值为一个方法名,则直接调用 + $action = $this->request->post("action"); + if ($action && $this->request->isPost()) { + return $this->$action(); + } + } + +} diff --git a/addons/cms/controller/Channel.php b/addons/cms/controller/Channel.php new file mode 100644 index 0000000000000000000000000000000000000000..0d7e818c1092f537abee4dd8a2be65d758ced925 --- /dev/null +++ b/addons/cms/controller/Channel.php @@ -0,0 +1,116 @@ +request->param('diyname'); + + if ($diyname && !is_numeric($diyname)) { + $channel = ChannelModel::getByDiyname($diyname); + } else { + $id = $diyname ? $diyname : $this->request->get('id', ''); + $channel = ChannelModel::get($id); + } + if (!$channel) { + $this->error(__('No specified channel found')); + } + + $filterlist = []; + $orderlist = []; + + $filter = $this->request->get('filter/a', []); + $orderby = $this->request->get('orderby', ''); + $orderway = $this->request->get('orderway', '', 'strtolower'); + $params = ['filter' => '', 'id' => $channel->id, 'diyname' => $channel->diyname]; + if ($filter) + $params['filter'] = $filter; + if ($orderby) + $params['orderby'] = $orderby; + if ($orderway) + $params['orderway'] = $orderway; + if ($channel['type'] === 'link') { + $this->redirect($channel['outlink']); + } + + $model = Modelx::get($channel['model_id']); + if (!$model) { + $this->error(__('No specified model found')); + } + $fields = []; + foreach ($model->fields_list as $k => $v) { + if (!$v['isfilter'] || !in_array($v['type'], ['select', 'selects', 'checkbox', 'radio', 'array']) || !$v['content_list']) + continue; + $fields[] = [ + 'name' => $v['name'], 'title' => $v['title'], 'content' => $v['content_list'] + ]; + } + $filter = array_intersect_key($filter, array_flip(array_column($fields, 'name'))); + foreach ($fields as $k => $v) { + $content = []; + $all = ['' => __('All')] + $v['content']; + foreach ($all as $m => $n) { + $active = ($m === '' && !isset($filter[$v['name']])) || (isset($filter[$v['name']]) && $filter[$v['name']] == $m) ? TRUE : FALSE; + $prepare = $m === '' ? array_diff_key($filter, [$v['name'] => $m]) : array_merge($filter, [$v['name'] => $m]); + $url = '?' . http_build_query(array_merge(['filter' => $prepare], array_diff_key($params, ['filter' => '']))); + $content[] = ['value' => $m, 'title' => $n, 'active' => $active, 'url' => $url]; + } + $filterlist[] = [ + 'name' => $v['name'], + 'title' => $v['title'], + 'content' => $content, + ]; + } + + $sortrank = [ + ['name' => 'default', 'field' => 'weigh', 'title' => __('Default')], + ['name' => 'views', 'field' => 'views', 'title' => __('Views')], + ['name' => 'id', 'field' => 'id', 'title' => __('Post date')], + ]; + + $orderby = $orderby && in_array($orderby, ['default', 'id', 'views']) ? $orderby : 'default'; + $orderway = $orderway ? $orderway : 'desc'; + foreach ($sortrank as $k => $v) { + $url = '?' . http_build_query(array_merge($params, ['orderby' => $v['name'], 'orderway' => ($orderway == 'desc' ? 'asc' : 'desc')])); + $v['active'] = $orderby == $v['name'] ? true : false; + $v['orderby'] = $orderway; + $v['url'] = $url; + $orderlist[] = $v; + } + $orderby = $orderby == 'default' ? 'weigh' : $orderby; + $pagelist = Archives::alias('a') + ->where('status', 'normal') + ->where('deletetime', 'exp', \think\Db::raw('IS NULL')) + ->where($filter) + ->join($model['table'] . ' n', 'a.id=n.id', 'LEFT') + ->field('a.*') + ->field('id,content', true, config('database.prefix') . $model['table'], 'n') + ->where('channel_id', $channel['id']) + ->order($orderby, $orderway) + ->paginate($channel['pagesize'], false, ['type' => '\\addons\\cms\\library\\Bootstrap']); + $pagelist->appends($params); + $this->view->assign("__FILTERLIST__", $filterlist); + $this->view->assign("__ORDERLIST__", $orderlist); + $this->view->assign("__PAGELIST__", $pagelist); + $this->view->assign("__CHANNEL__", $channel); + Config::set('cms.title', $channel['name']); + Config::set('cms.keywords', $channel['keywords']); + Config::set('cms.description', $channel['description']); + $template = preg_replace('/\.html$/', '', $channel["{$channel['type']}tpl"]); + return $this->view->fetch('/' . $template); + } + +} diff --git a/addons/cms/controller/Comment.php b/addons/cms/controller/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..d8e6f21253c361e3907f56740a40ac24edb8da7f --- /dev/null +++ b/addons/cms/controller/Comment.php @@ -0,0 +1,60 @@ +request->post(); + CommentModel::postComment($params); + } 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); + if (!$comment) { + $this->error("评论未找到"); + } + if ($key !== md5($comment['id'] . $comment['email'])) { + $this->error("无法进行该操作"); + } + if (!$comment['subscribe']) { + $this->error("评论已经取消订阅,请勿重复操作"); + } + $comment->subscribe = 0; + $comment->save(); + $this->success('取消评论订阅成功'); + } + +} diff --git a/addons/cms/controller/Index.php b/addons/cms/controller/Index.php new file mode 100644 index 0000000000000000000000000000000000000000..e41feaa7e159a565fe63b1f844c1424bfc747d3f --- /dev/null +++ b/addons/cms/controller/Index.php @@ -0,0 +1,24 @@ +view->fetch('/index'); + } + +} diff --git a/addons/cms/controller/Page.php b/addons/cms/controller/Page.php new file mode 100644 index 0000000000000000000000000000000000000000..12d77bab8f141d6523a0dd5a63c99ca8d50d0a9e --- /dev/null +++ b/addons/cms/controller/Page.php @@ -0,0 +1,36 @@ +request->param('diyname'); + if ($diyname && !is_numeric($diyname)) { + $page = PageModel::getByDiyname($diyname); + } else { + $id = $diyname ? $diyname : $this->request->get('id', ''); + $page = PageModel::get($id); + } + if (!$page || $page['status'] == 'hidden') { + $this->error(__('No specified page found')); + } + $this->view->assign("__PAGE__", $page); + Config::set('cms.title', $page['title']); + Config::set('cms.keywords', $page['keywords']); + Config::set('cms.description', $page['description']); + $template = preg_replace("/\.html$/i", "", $page['showtpl'] ? $page['showtpl'] : 'page'); + return $this->view->fetch('/' . $template); + } + +} diff --git a/addons/cms/controller/Search.php b/addons/cms/controller/Search.php new file mode 100644 index 0000000000000000000000000000000000000000..e5639d35ed24eea1a62ab88596df6c88f381d610 --- /dev/null +++ b/addons/cms/controller/Search.php @@ -0,0 +1,75 @@ +request->request("search"); + + $filterlist = []; + $orderlist = []; + + $orderby = $this->request->get('orderby', ''); + $orderway = $this->request->get('orderway', '', 'strtolower'); + $params = ['search' => $search]; + if ($orderby) + $params['orderby'] = $orderby; + if ($orderway) + $params['orderway'] = $orderway; + + $sortrank = [ + ['name' => 'default', 'field' => 'weigh', 'title' => __('Default')], + ['name' => 'views', 'field' => 'views', 'title' => __('Views')], + ['name' => 'id', 'field' => 'id', 'title' => __('Post date')], + ]; + + $orderby = $orderby && in_array($orderby, ['default', 'id', 'views']) ? $orderby : 'default'; + $orderway = $orderway ? $orderway : 'desc'; + foreach ($sortrank as $k => $v) { + $url = '?' . http_build_query(array_merge($params, ['orderby' => $v['name'], 'orderway' => ($orderway == 'desc' ? 'asc' : 'desc')])); + $v['active'] = $orderby == $v['name'] ? true : false; + $v['orderby'] = $orderway; + $v['url'] = $url; + $orderlist[] = $v; + } + $orderby = $orderby == 'default' ? 'weigh' : $orderby; + + $pagelist = Archives + ::where('status', 'normal') + ->where('title', 'like', "%{$search}%") + ->order($orderby, $orderway) + ->paginate(10, false, ['type' => '\\addons\\cms\\library\\Bootstrap']); + $pagelist->appends($params); + $this->view->assign("__FILTERLIST__", $filterlist); + $this->view->assign("__ORDERLIST__", $orderlist); + $this->view->assign("__PAGELIST__", $pagelist); + \think\Config::set('cms.title', __("Search for %s", $search)); + return $this->view->fetch('/search'); + } + + public function typeahead() + { + $search = $this->request->post("search"); + $list = Archives + ::where('status', 'normal') + ->where('title', 'like', "%{$search}%") + ->order('id', 'desc') + ->field('id,title,diyname,channel_id,likes,dislikes,tags,createtime') + ->limit(10) + ->select(); + $result = collection($list)->toArray(); + $result[] = ['id' => 0, 'title' => __('Search more %s', $search), 'url' => addon_url("cms/search/index", [':search' => $search, 'search' => $search])]; + return json($result); + } + +} diff --git a/addons/cms/controller/Tags.php b/addons/cms/controller/Tags.php new file mode 100644 index 0000000000000000000000000000000000000000..8f1186a91bf9dee39fcd6e0e3e8ba17f871184b0 --- /dev/null +++ b/addons/cms/controller/Tags.php @@ -0,0 +1,69 @@ +request->param('name'); + + if ($name) { + $tags = TagsModel::getByName($name); + } + if (!$tags) { + $this->error(__('No specified tags found')); + } + + $filterlist = []; + $orderlist = []; + + $orderby = $this->request->get('orderby', ''); + $orderway = $this->request->get('orderway', '', 'strtolower'); + $params = []; + if ($orderby) + $params['orderby'] = $orderby; + if ($orderway) + $params['orderway'] = $orderway; + if ($tags) { + $sortrank = [ + ['name' => 'default', 'field' => 'weigh', 'title' => __('Default')], + ['name' => 'views', 'field' => 'views', 'title' => __('Views')], + ['name' => 'id', 'field' => 'id', 'title' => __('Post date')], + ]; + + $orderby = $orderby && in_array($orderby, ['default', 'id', 'views']) ? $orderby : 'default'; + $orderway = $orderway ? $orderway : 'desc'; + foreach ($sortrank as $k => $v) { + $url = '?' . http_build_query(array_merge($params, ['orderby' => $v['name'], 'orderway' => ($orderway == 'desc' ? 'asc' : 'desc')])); + $v['active'] = $orderby == $v['name'] ? true : false; + $v['orderby'] = $orderway; + $v['url'] = $url; + $orderlist[] = $v; + } + $orderby = $orderby == 'default' ? 'weigh' : $orderby; + } + $pagelist = Archives + ::where('status', 'normal') + ->where('id', 'in', explode(',', $tags['archives'])) + ->order($orderby, $orderway) + ->paginate(10, false, ['type' => '\\addons\\cms\\library\\Bootstrap']); + $pagelist->appends($params); + $this->view->assign("__FILTERLIST__", $filterlist); + $this->view->assign("__ORDERLIST__", $orderlist); + $this->view->assign("__TAGS__", $tags); + $this->view->assign("__PAGELIST__", $pagelist); + \think\Config::set('cms.title', $tags['name']); + return $this->view->fetch('/tags'); + } + +} diff --git a/addons/cms/controller/wxapp/Archives.php b/addons/cms/controller/wxapp/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..570fbeb3ed792f3e9337bdfb833ffadf5965ac8d --- /dev/null +++ b/addons/cms/controller/wxapp/Archives.php @@ -0,0 +1,110 @@ +request->request('model'); + $channel = (int)$this->request->request('channel'); + $page = (int)$this->request->request('page'); + + if ($model) { + $params['model'] = $model; + } + if ($channel) { + $params['channel'] = $channel; + } + $page = max(1, $page); + $params['limit'] = ($page - 1) * 10 . ',10'; + + $list = ArchivesModel::getArchivesList($params); + $this->success('', ['archivesList' => $list]); + } + + public function detail() + { + $action = $this->request->post("action"); + if ($action && $this->request->isPost()) { + return $this->$action(); + } + $diyname = $this->request->param('diyname'); + if ($diyname && !is_numeric($diyname)) { + $archives = ArchivesModel::getByDiyname($diyname); + } else { + $id = $diyname ? $diyname : $this->request->request('id', ''); + $archives = ArchivesModel::get($id); + } + if (!$archives || $archives['status'] == 'hidden' || $archives['deletetime']) { + $this->error(__('No specified article found')); + } + $channel = Channel::get($archives['channel_id']); + if (!$channel) { + $this->error(__('No specified channel found')); + } + $model = Modelx::get($channel['model_id']); + if (!$model) { + $this->error(__('No specified model found')); + } + $archives->setInc("views", 1); + $addon = db($model['table'])->where('id', $archives['id'])->find(); + if ($addon) { + if ($model->fields) { + $fieldsContentList = $model->getFieldsContentList($model->id); + //附加列表字段 + array_walk($fieldsContentList, function ($content, $field) use (&$addon) { + $addon[$field . '_text'] = isset($content[$addon[$field]]) ? $content[$addon[$field]] : $addon[$field]; + }); + } + $archives->setData($addon); + } else { + $this->error(__('No specified article addon found')); + } + $archives = array_merge($archives->toArray(), $addon); + + $commentList = Comment::getCommentList(['aid' => $archives['id']]); + + $this->success('', ['archivesInfo' => $archives, 'channelInfo' => $channel, 'commentList' => $commentList->getCollection()]); + } + + /** + * 赞与踩 + */ + 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['status'] == 'hidden') { + $this->error(__('No specified article found')); + } + $archives->where('id', $id)->setInc($type === 'like' ? 'likes' : 'dislikes', 1); + $archives = ArchivesModel::get($id); + $this->success(__('Operation completed'), ['likes' => $archives->likes, 'dislikes' => $archives->dislikes, 'likeratio' => $archives->likeratio]); + } + +} diff --git a/addons/cms/controller/wxapp/Base.php b/addons/cms/controller/wxapp/Base.php new file mode 100644 index 0000000000000000000000000000000000000000..64ab1bbe38e5168063acfd685f15b20c88f59eac --- /dev/null +++ b/addons/cms/controller/wxapp/Base.php @@ -0,0 +1,29 @@ +setAllowFields($this->allowFields); + + //这里手动载入语言包 + Lang::load(ROOT_PATH . '/addons/cms/lang/zh-cn.php'); + Lang::load(APP_PATH . '/index/lang/zh-cn/user.php'); + } + + +} diff --git a/addons/cms/controller/wxapp/Comment.php b/addons/cms/controller/wxapp/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..ce1e3653528fb097d679c544c0ccf686d3089f12 --- /dev/null +++ b/addons/cms/controller/wxapp/Comment.php @@ -0,0 +1,47 @@ +request->request('aid'); + $page = (int)$this->request->request('page'); + Config::set('paginate.page', $page); + $commentList = \addons\cms\model\Comment::getCommentList(['aid' => $aid]); + $this->success('', ['commentList' => $commentList->getCollection()]); + } + + /** + * 发表评论 + */ + public function post() + { + try { + $params = $this->request->post(); + \addons\cms\model\Comment::postComment($params); + } catch (Exception $e) { + $this->error($e->getMessage(), null, ['token' => $this->request->token()]); + } + $this->success(__('评论成功')); + } + +} diff --git a/addons/cms/controller/wxapp/Common.php b/addons/cms/controller/wxapp/Common.php new file mode 100644 index 0000000000000000000000000000000000000000..24692dab1bd108aecb48d67679d39ef9557e730f --- /dev/null +++ b/addons/cms/controller/wxapp/Common.php @@ -0,0 +1,73 @@ + 'focus', 'row' => 5]); + foreach ($list as $index => $item) { + $bannerList[] = ['image' => cdnurl($item['image'], true), 'url' => '/', 'title' => $item['title']]; + } + + //首页Tab列表 + $indexTabList = $newsTabList = $productTabList = [['id' => 0, 'title' => '全部']]; + $channelList = Channel::where('status', 'normal') + ->where('type', 'in', ['list']) + ->field('id,parent_id,model_id,name,diyname') + ->order('weigh desc,id desc') + ->select(); + foreach ($channelList as $index => $item) { + $data = ['id' => $item['id'], 'title' => $item['name']]; + $indexTabList[] = $data; + if ($item['model_id'] == 1) { + $newsTabList[] = $data; + } + if ($item['model_id'] == 2) { + $productTabList[] = $data; + } + } + + //配置信息 + $upload = Config::get('upload'); + $upload['cdnurl'] = $upload['cdnurl'] ? $upload['cdnurl'] : cdnurl('', true); + $upload['uploadurl'] = $upload['uploadurl'] == 'ajax/upload' ? cdnurl('/ajax/upload', true) : $upload['cdnurl']; + $config = [ + 'upload' => $upload + ]; + + $data = [ + 'bannerList' => $bannerList, + 'indexTabList' => $indexTabList, + 'newsTabList' => $newsTabList, + 'productTabList' => $productTabList, + 'config' => $config + ]; + $this->success('', $data); + + } + + +} diff --git a/addons/cms/controller/wxapp/Index.php b/addons/cms/controller/wxapp/Index.php new file mode 100644 index 0000000000000000000000000000000000000000..affc5d622832a726bb8164439bf2502f0d71eb9a --- /dev/null +++ b/addons/cms/controller/wxapp/Index.php @@ -0,0 +1,57 @@ + 'focus', 'row' => 5]); + foreach ($list as $index => $item) { + $bannerList[] = ['image' => cdnurl($item['image'], true), 'url' => '/', 'title' => $item['title']]; + } + + $tabList = [ + ['id' => 0, 'title' => '全部'], + ]; + $channelList = Channel::where('status', 'normal') + ->where('type', 'in', ['list']) + ->field('id,parent_id,name,diyname') + ->order('weigh desc,id desc') + ->cache(false) + ->select(); + foreach ($channelList as $index => $item) { + $tabList[] = ['id' => $item['id'], 'title' => $item['name']]; + } + $archivesList = Archives::getArchivesList([]); + $data = [ + 'bannerList' => $bannerList, + 'tabList' => $tabList, + 'archivesList' => $archivesList, + ]; + $this->success('', $data); + + } + + +} diff --git a/addons/cms/controller/wxapp/My.php b/addons/cms/controller/wxapp/My.php new file mode 100644 index 0000000000000000000000000000000000000000..161a5af6dd8f4bf45a22bf7600bb2b2b8e17f14d --- /dev/null +++ b/addons/cms/controller/wxapp/My.php @@ -0,0 +1,51 @@ +request->request('page'); + $commentList = Comment:: + with('archives') + ->where(['user_id' => $this->auth->id]) + ->order('id desc') + ->page($page, 10) + ->select(); + foreach ($commentList as $index => $item) { + $item->create_date = human_date($item->createtime); + } + + $this->success('', ['commentList' => $commentList]); + } + + /** + * 关于我们 + */ + public function aboutus() + { + $pageInfo = Page::getByDiyname('aboutus'); + if (!$pageInfo || $pageInfo['status'] == 'hidden') { + $this->error(__('单页未找到')); + } + $this->success('', ['pageInfo' => $pageInfo]); + } +} diff --git a/addons/cms/controller/wxapp/User.php b/addons/cms/controller/wxapp/User.php new file mode 100644 index 0000000000000000000000000000000000000000..f03640fa06db0b8512e64da34f0ee37e1eda13c9 --- /dev/null +++ b/addons/cms/controller/wxapp/User.php @@ -0,0 +1,203 @@ +token = $this->request->post('token'); + if ($this->request->action() == 'login' && $this->token) { + $this->request->post(['token' => '']); + } + parent::_initialize(); + + if (!Config::get('fastadmin.usercenter')) { + $this->error(__('User center already closed')); + } + + $ucenter = get_addon_info('ucenter'); + if ($ucenter && $ucenter['state']) { + include ADDON_PATH . 'ucenter' . DS . 'uc.php'; + } + + } + + /** + * 登录 + */ + public function login() + { + $config = get_addon_config('cms'); + $code = $this->request->post("code"); + $rawData = $this->request->post("rawData"); + if (!$code || !$rawData) { + $this->error("参数不正确"); + } + $userInfo = (array)json_decode($rawData, true); + + $params = [ + 'appid' => $config['wxappid'], + 'secret' => $config['wxappsecret'], + 'js_code' => $code, + 'grant_type' => 'authorization_code' + ]; + $result = Http::sendRequest("https://api.weixin.qq.com/sns/jscode2session", $params, 'GET'); + if ($result['ret']) { + $json = (array)json_decode($result['msg'], true); + if (isset($json['openid'])) { + //如果有传Token + if ($this->token) { + $this->auth->init($this->token); + //检测是否登录 + if ($this->auth->isLogin()) { + $third = Third::where(['openid' => $json['openid'], 'platform' => 'wxapp'])->find(); + if ($third && $third['user_id'] == $this->auth->id) { + $this->success("登录成功", ['userInfo' => $this->auth->getUserinfo()]); + } + } + } + + $platform = 'wxapp'; + $result = [ + 'openid' => $json['openid'], + 'userinfo' => [ + 'nickname' => $userInfo['nickName'], + ], + 'access_token' => $json['session_key'], + 'refresh_token' => '', + 'expires_in' => isset($json['expires_in']) ? $json['expires_in'] : 0, + ]; + $extend = ['gender' => $userInfo['gender'], 'nickname' => $userInfo['nickName'], 'avatar' => $userInfo['avatarUrl']]; + $ret = Service::connect($platform, $result, $extend); + if ($ret) { + $auth = Auth::instance(); + $this->success("登录成功", ['userInfo' => $auth->getUserinfo()]); + } else { + $this->error("连接失败"); + } + } else { + $this->error("登录失败"); + } + } + + return; + } + + /** + * 绑定账号 + */ + public function bind() + { + $account = $this->request->post("account"); + $password = $this->request->post("password"); + if (!$account || !$password) { + $this->error("参数不正确"); + } + + $account = $this->request->post('account'); + $password = $this->request->post('password'); + $rule = [ + 'account' => 'require|length:3,50', + 'password' => 'require|length:6,30', + ]; + + $msg = [ + 'account.require' => 'Account can not be empty', + 'account.length' => 'Account must be 3 to 50 characters', + 'password.require' => 'Password can not be empty', + 'password.length' => 'Password must be 6 to 30 characters', + ]; + $data = [ + 'account' => $account, + 'password' => $password, + ]; + $validate = new Validate($rule, $msg); + $result = $validate->check($data); + if (!$result) { + $this->error(__($validate->getError())); + return FALSE; + } + $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username'); + $user = \app\common\model\User::get([$field => $account]); + if (!$user) { + $this->error('账号未找到'); + } + $third = Third::where(['user_id' => $user->id, 'platform' => 'wxapp'])->find(); + if ($third) { + $this->error('账号已经绑定其他小程序账号'); + } + + $third = Third::where(['user_id' => $this->auth->id, 'platform' => 'wxapp'])->find(); + if (!$third) { + $this->error('未找到登录信息'); + } + + if ($this->auth->login($account, $password)) { + $third->user_id = $this->auth->id; + $third->save(); + $this->success("绑定成功", ['userInfo' => $this->auth->getUserinfo()]); + } else { + $this->error($this->auth->getError()); + } + } + + /** + * 个人资料 + */ + public function profile() + { + $user = $this->auth->getUser(); + $username = $this->request->request('username'); + $nickname = $this->request->request('nickname'); + $bio = $this->request->request('bio'); + $avatar = $this->request->request('avatar'); + if (!$username || !$nickname) { + $this->error("用户名和昵称不能为空"); + } + $exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find(); + if ($exists) { + $this->error(__('Username already exists')); + } + $avatar = str_replace(Config::get('upload.cdnurl'), '', $avatar); + $user->username = $username; + $user->nickname = $nickname; + $user->bio = $bio; + $user->avatar = $avatar; + $user->save(); + $this->success('', ['userInfo' => $this->auth->getUserinfo()]); + } + + /** + * 保存头像 + */ + public function avatar() + { + $user = $this->auth->getUser(); + $avatar = $this->request->request('avatar'); + if (!$avatar) { + $this->error("头像不能为空"); + } + $avatar = str_replace(Config::get('upload.cdnurl'), '', $avatar); + $user->avatar = $avatar; + $user->save(); + $this->success('', ['userInfo' => $this->auth->getUserInfo()]); + } + +} diff --git a/addons/cms/info.ini b/addons/cms/info.ini new file mode 100644 index 0000000000000000000000000000000000000000..b6e769a8370808d350e6852282c08d053de0e397 --- /dev/null +++ b/addons/cms/info.ini @@ -0,0 +1,8 @@ +name = cms +title = CMS内容管理插件 +intro = 基于ThinkPHP5的内容管理系统含小程序 +author = Karson +website = http://www.fastadmin.net +version = 1.0.15 +state = 1 +url = /addons/cms.html diff --git a/addons/cms/install.sql b/addons/cms/install.sql new file mode 100644 index 0000000000000000000000000000000000000000..77b51648f30018c31bb22c7d17592905a7ee497f --- /dev/null +++ b/addons/cms/install.sql @@ -0,0 +1,423 @@ + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET AUTOCOMMIT = 0; +START TRANSACTION; +SET time_zone = "+00:00"; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_addonnews` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_addonnews` ( + `id` int(10) NOT NULL, + `content` longtext NOT NULL, + `author` varchar(255) DEFAULT '' COMMENT '作者', + `area` enum('domestic','overseas','local') DEFAULT 'domestic' COMMENT '地区', + `device` enum('vr','ar') DEFAULT 'vr' COMMENT '设备', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='新闻' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_addonnews` +-- + +INSERT INTO `__PREFIX__cms_addonnews` (`id`, `content`, `author`, `area`, `device`) VALUES +(1, '
                  \r\n
                  \r\n
                  \r\n
                  \r\n

                  据悉,驰为 HiGame 迷你 PC 配备了英特尔八代酷睿 i5-8305G 处理器,集成了移动版 Radeon Vega M 显卡和 4GB HMB 显存,性能不弱于 Nvidia GTX 1050 。

                  \r\n

                  \r\n

                  存储方面,入门机型从 8GB DDR4 RAM + 128GB M.2 SSD 起跳,消费者可根据实际需要后续升级,此外厂家宣称该机支持 VR 与 AR 系统。

                  \r\n

                  \r\n

                  扩展性方面,该机提供了 1×雷电 3、5×USB 3.0、2×HDMI 2.0、2×DisplayPort 1.3、以及耳机 / 麦克风插孔。

                  \r\n

                  驰为将于 5 月中旬发起 Indiegogo 众筹,感兴趣的朋友可以拿出 999 美元支持下,且可享受早鸟特惠。

                  \r\n

                  [编译自:SlashGear]

                  \r\n
                  \r\n
                  \r\n
                  \r\n
                  \r\n
                  \r\n
                  \r\n
                  \r\n
                   
                  \r\n
                  \r\n
                  \r\n
                  ', '', 'overseas', 'vr'), +(2, '

                  Chromebox CXI3 价钱实惠,很适合在课堂上使用。但在教育市场之外,它也有着一番用武之地。

                  \r\n

                  宏碁为该系列机型提供了多种配置,入门款搭载的是英特尔赛扬 3865U 处理器,顶配版则是英特尔八代酷睿 i7-8550U 。

                  \r\n

                  存储方面,其提供了 4~16GB RAM + 32~64GB ROM 的组合。扩展方面,则有 2×USB 2.1、3×USB 3.0、1× USB-C 端口,以及 HDMI 输出、以太网、音频复合插孔。

                  \r\n

                  \r\n

                  Chromebox CXI3 支持 VESA 壁挂、垂直摆放、还有一根无线天线。

                  \r\n

                  CXI3 最先由 Chrome Unboxed 在 TigerDirect 上发现,网页给出的发货时间为 4 月 19 号起。赛扬版本售价 279 美元,酷睿 i3 / i5 / i7 版本则是 279 / 469 / 511 / 744 美元。

                  \r\n

                  [编译自:SlashGear , 来源:Chrome Unboxed]

                  ', '', 'overseas', 'vr'), +(3, '

                  您可以跟踪您的步数,睡眠,消耗的卡路里以及全天行走的距离,并将所有数据同步到Misfit的移动应用程序。它的防水深度可达50米,可以使用可更换的纽扣电池,使用寿命长达六个月。

                  \r\n

                  混合手表变得越来越流行,因为它们看起来比传统智能手表更时尚。对于那些觉得自己不能持续充电的人来说,它们也特别方便。当然,你必须放弃一些功能,以便照顾它们圆滑的外观,比如阅读和回复邮件或电子邮件的能力。

                  \r\n

                  \r\n

                  \r\n

                  \"\"

                  ', '', 'overseas', 'vr'), +(4, '

                  大多数消费者可能熟悉UE推出的色彩鲜艳的蓝牙音箱,但该公司也有一系列定制入耳式耳机,UE刚刚推出了一款新的顶级旗舰机型:2,200美元的UE Live。UE Live耳机是该公司以前的旗舰UE18 Pro型号的进化版本,将每个耳机的扬声器数量从6个增加到8个,共计6个平衡电枢,一个True Tone Plus驱动器和一个6mm钕制动态扬声器,以提供更好的声音。

                  \r\n

                  但是,这些改进需要付出代价:UE Live耳机的起价为2,199美元,自定义选项价格可能会更高。

                  \r\n

                  Ultimate Ears的定制入耳式耳机倾向于专业音乐家在工作室或舞台上使用,而UE Live也不例外。 Ultimate Ears表示,新款耳机专为在音乐节,舞台和体育场举办音乐会的音乐家而设计 - 尽管如果您只是在家里听音乐,他们听起来也会非常出色。

                  \r\n

                  与UE Live一起,Ultimate Ears还宣布推出Ultimate Ears 6 PRO,这是一款价格为699美元的入耳式监听音箱,该监听音箱专为鼓手,贝斯手,DJ和嘻哈音乐家设计,并配有两个动态驱动程序中音和低音。

                  \r\n

                  这两款耳返将于2018年5月开始发货。

                  \r\n

                  \"QQ图片20180413011632.png\"

                  ', '', 'overseas', 'vr'), +(5, '

                  想必大家都遇到过这样尴尬的事情:家里有很多电池,用的时候也分不清哪个有电、哪个没电,扔了又怕浪费。于是旧的不丢掉,新的买来用,这样家里的电池越积攒越多,造成恶性循环。而现在,南孚带来了一款全新产品——南孚测电器装电池,包含南孚测电器和南孚碱性电池,轻轻松松测一测,电池电量一目了然。

                  \r\n

                  而且测电器5号电池和7号电池均可以测量,一器双用。

                  \r\n

                  这款南孚测电器体积非常小巧,仅有iPhone 8手机的四分之一大小(长60mm、宽36mm、厚12mm)。测电器通体白色,侧边有纹路处理,方便持握。

                  \r\n

                  正面有“南孚聚能环”字样、电池放置正负极标志、电池剩余电量指示灯;背面有测试结果说明——3灯全亮表示电量充足,2灯为还能用,1灯为建议更换,不亮则代表没电,显示结果简单易懂,学习成本几乎为0。

                  \r\n

                  对于正在使用的电池,我们也可以用南孚测电器去测试它的剩余电量,以达到心中有数的目的。比如家里孩子玩的玩具车,对于电池电量要求比较高,我们可以在玩具使用一段时间后,测试电池剩余电量,若指示为“2灯亮”及以下时,将该电池换到那些功率小的玩具上继续使用,让电池不至于浪费,物尽其用。

                  \r\n

                  最关键的是,这个测电器是南孚免费赠送的。从18年开始,南孚将狂送150万个测电器。只要在线下商超或者线上旗舰店购买南孚大包装,就能免费获得测电器。

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  \r\n

                  ', '', 'domestic', 'vr'), +(6, '

                  \"acuvue-oasys-tinting-contacts-1.jpeg\"

                  \r\n

                  据了解,这款叫做Acuvue Oasys With Ttransitions的隐形镜片由强生和Transitions Potical合作研发。除了像普通隐形眼镜一样能够帮助佩戴者看清东西而且还能在光线条件发生变化时做出快速、无缝的调整,它能过滤掉蓝光并阻断紫外线的进入。

                  \r\n

                  不过强生强调,这款隐形眼镜并不是为取代太阳镜而开发,毕竟它们不能覆盖住整个眼睛。

                  \r\n

                  据悉,Acuvue Oasys With Transitions隐形眼镜已经获得美国食品与药物管理局批准,其佩戴周期为2周,预计会在今年上半年进入市场。

                  ', '', 'domestic', 'vr'), +(7, '

                  据 Variety 报道,FCC 辐射实验室刚刚证实了一副来自 Snap 的新眼镜。今日曝光的这款穿戴设备的文档称,这是一款由 Snap Inc. 制作的穿戴式视频拍摄装置。从印刷标签来看,其品牌名称为 Spectacles,型号为 Model 002 。尽管文件中所附的大部分内容都以保密为由被遮掩,但还是可以知道它支持低功耗蓝牙 4.2 和 802.11ac Wi-Fi 。

                  \r\n

                  \"DSC_2124_2040b.0.jpg\"

                  \r\n

                  2016 年发布的初代 Spectacles 眼镜

                  \r\n

                  上个月的时候,Cheddar 爆料了两款即将到来的 Spectacles 眼镜。其中一款是计划在 2018 年发布的二代产品,改进了性能并修复了 bug 。

                  \r\n

                  另外还有一款计划在 2019 年发布的第三代产品,据说它配备了 2 个摄像头、支持 GPS、售价 300 美元。

                  \r\n

                  \"screenshot_2018_04_11_08.31.06_1024.png.jpg\"

                  \r\n

                  2016 年发布的初代 Spectacles 在营销上一度相当成功,很多人排着长队、甚至愿意出高价购买一副。即便炒作的热度很快就消散,但至少为该公司赚到了 4000 万美元。

                  \r\n

                  从 FCC 文件来看,Spectacles 二代产品的发布应该无需等待太久。当然,通过 FCC 认证也不见得产品会真的上市。

                  \r\n

                  [编译自:TheVerge]

                  ', '', 'overseas', 'vr'), +(8, '

                  云存储服务商Dropbox今日宣布,由于投资者需求强劲,现将IPO(数次公开招股)发行价区间调高2美元。上周一,Dropbox宣布将IPO发行价区间定为每股16美元至18美元,最高融资6.48亿美元,公司市值将达到约71亿美元。

                  \r\n

                  \r\n

                  但Dropbox今日宣布,由于投资者需求强劲,现将发行价区间调高2美元,至每股18美元至20美元。这意味着Dropbox此次IPO最多将融资7.2亿美元,公司市值将达到约78.5亿美元。

                  \r\n

                  业内专家杰伊·瑞特(Jay Ritter)称,与Box等竞争对手相比,Dropbox最初给出的IPO发行价区间确实有些保守。

                  \r\n

                  虽然调高了发行价区间,但Dropbox当前估值仍低于2014年100亿美元的估值。

                  \r\n

                  昨日就有报道称,Dropbox IPO股票已被超额认购,表明今年市场对第一大科技股的需求十分旺盛。

                  \r\n

                  Dropbox成立于2007年,上个月提交了IPO招股书。Dropbox计划在纳斯达克上市,证券代码为“DBX”。

                  ', '', 'overseas', 'ar'), +(9, '

                  著名云存储服务提供商Dropbox在上市交易首日股价大涨36%,开盘定价为21美元每股,在当日最高时达到31.6美元每股,最终以28.48美元每股的价格收盘,现在市值超过120亿美元。可以明显看出公开市场投资者十分看好Dropbox这家主营业务为云存储服务和内容协作平台的公司。Dropbox最先对自己股价的预期是16到18美元每股,后来提升到18到20美元每股。而由于上市交易首日表现出色,超过了2014年私募时100亿美元的估值。

                  \r\n

                  \r\n

                  在2017年,Dropbox实现营收11亿美元。较2016年的8.45亿美元和2015年的6.04亿美元的年度总营收增长不少。不过,Dropbox至今尚未实现盈利,去年净亏损为1.12亿美元。该数字在2016年和2015年分别是2.1亿美元和3.26亿美元,可以看出其净亏损在逐年减少。其从每个付费用户获得的平均收入为111.91美元。

                  \r\n
                   
                  \r\n

                  由于Dropbox采用的是免费+付费模式,既有面向消费者的业务也有面向企业的业务。Dropbox曾表示其所有5亿注册用户中只有1100万为其产品付费。

                  \r\n

                  著名风投公司红杉资本合伙人、Dropbox董事会成员布莱恩·施莱尔(Bryan Schreier)称:“Dropbox结合了一家消费者公司该有的规模和影响力和一家软件公司该有的长期收益的优势。”他表示现在正是Dropbox上市的最佳时机,因为“其业务规模和现金流都已经达到一定程度,足以支撑其上市计划”。

                  \r\n

                  作为Dropbox的早期投资机构,红杉资本如今持有Dropbox 23.2%的股份。另一家风投公司Accel是第二大机构股东,持有5%的股份。Dropbox创始人兼首席执行官德鲁·休斯敦(Drew Houston)持有公司25.3%的股份。

                  \r\n

                  投资机构Greylock Partners也拥有少量Dropbox股份,其合伙人约翰·里利(John Lilly)说:“之所以投资Dropbox,是因为德鲁和他的团队对未来的工作模式有着清晰的认识,并打造了一个满足现代生产力需求的产品。”

                  \r\n

                  不过,目前市场上有大量与Dropbox相似的产品。Dropbox称:“内容协作平台市场竞争激烈且变化很快。在云存储业务方面,我们面临来自亚马逊、苹果、谷歌、和微软公司同类产品的竞争。而在内容协作市场则有来自Atlassian、谷歌、和微软公司的竞争。我们与Box的竞争则主要局限在面向大型企业用户的云存储服务领域。”

                  \r\n

                  Box是一家从事与Dropbox类似业务的公司,经常与Dropbox一起被提到。不过Box商业模式与Dropbox不同,其更专注于企业用户。在Dropbox上市首日,Box股价下跌了8.2%。

                  ', '', 'overseas', 'ar'), +(10, '

                  云存储公司Dropbox周五向美国证券交易委员会(SEC)提交了IPO(首次公开招股)申请文件,寻求筹集5亿美元资金。Dropbox的IPO交易长期以来备受市场期待,该公司四年前在私募投资市场上的估值就已高达100亿美元。

                  \r\n

                  \r\n

                  这家硅谷创业公司成立于2007年。在IPO申请文件中,该公司披露信息称其过去三年的营收分别为6.038亿美元、8.448亿美元和11.1亿美元,而亏损则从3.259亿美元渐次收窄到了2.102亿美元和1.117亿美元。

                  \r\n

                  据《华尔街日报》报道,Dropbox此前通过私募融资回合已经筹集到6亿美元资金。在2014年1月进行的最后一个融资回合中,该公司估值达100亿美元。

                  \r\n
                   
                  \r\n

                  Dropbox计划在纳斯达克挂牌上市,股票代码为“DBX”。共有12家银行将担任该公司IPO交易的承销商,其中主承销商是高盛集团和摩根大通。

                  \r\n

                  文件还披露信息称,Dropbox去年每付费用户平均收入为11.91美元,高于2016年,但低于2015年;注册用户总数达5亿人,自2017年初以来的新注册用户人数为1亿人;付费用户总数达1100万人以上;毛利率为67%。

                  \r\n

                  Dropbox此前就已秘密向美国证券交易委员会提交了IPO申请文件,后者在周五对外公布了该文件。文件显示,Dropbox联合创始人及CEO德鲁·休斯顿(Drew Houston)持有24.4%具备投票权的股票,风投公司红杉资本(Sequoia Capital)持有24.8%股权。

                  \r\n

                  受研发预算扩大的影响,Dropbox的支出有所增长,但该公司已在2016年实现了正向的自由现金流。很多云公司都依靠企业销售团队来获取收入,但Dropbox则与众不同,该公司90%以上营收都来自购买自己的订阅服务的用户。不过,这家仍未摆脱亏损的公司仍面临约17亿美元的合同义务,如租约和未偿还债务等。

                  \r\n

                  另外,Dropbox还面临着严峻的竞争压力,其各方面业务与亚马逊、苹果公司、谷歌和微软等科技巨头之间存在竞争关系。

                  \r\n

                  来自于IPO交易的收入将被用于融资一项扩张计划,内容包括将更多用户升级至订阅用户,以及扩大与第三方软件之间的整合等。

                  \r\n

                  在Dropbox的IPO申请文件公布以后,其竞争对手Box的股价上涨2.8%。Dropbox曾五次入选“CNBC Disruptor 50”榜单,该榜单每年公布一次,评选出50家最有影响力、最具有开拓精神的创业公司。

                  ', '', 'overseas', 'ar'), +(11, '

                  通用电气(GE)为推广Predix云平台的应用开发,在国内推出首期\"Predix星火计划\",以奖励基于该平台的工业互联网开发者。首期有4家企业获奖,将进驻GE孵化器并获得技术支持和潜在投资机会。

                  \r\n

                  \r\n

                  参与该计划的团队需基于GE Predix平台,开发适合工业领域的资产绩效管理(APM)应用,用于工业企业实时、安全地收集和分析数据,增加正常运行时间、降低成本、减少运营风险。

                  \r\n

                  GE Predix是一个基于Cloud Foundry(CF)的云平台,专攻制造业。跟Azure,AWS的PaaS服务相比,Predix的优势在于对于工业数据的导入做了专门优化。

                  \r\n

                  2017年\"Predix星火计划\"采用提名邀请,共有16家GE合作伙伴及创业公司提交了内容涵盖包括能源、医疗、设备制造等领域的工业应用项目方案。

                  \r\n

                  获奖企业中,广采科技由思科参与投资,提供货物与集装箱的全球跟踪服务。实视科技面向汽车、装备制造等客户开发用于智能眼镜的AR应用。华瑞特信息主要开发企业业务管理流程整合应用。华中思能主要针对电力企业开发节能减排、运营优化、故障诊断应用。

                  \r\n

                  四家获奖企业将获得的资源支持包括,进驻位于上海的GE数字创新坊孵化1个月、期间将有GE技术团队支持和GE创投部门考察进一步投资机会。

                  ', '', 'local', 'ar'), +(12, '

                  据外媒报道,Cloudflare 公司正将其业务拓展到网站和云应用之外的互联网安全领域。此前,Cloudflare 帮助过企业屏蔽恶意流量,并且让它们的线上内容加载得更加迅速。而根据今日披露的内容,这项新服务旨在保护那些在公共网络背景下运行的联网基础设施,涵盖了从企业内部电子邮件服务器、到领域内部署的联网设备等各个方面。

                  \r\n

                  \"cloudflare.png\"

                  \r\n

                  尽管其中有一些是在孤立的网络中运行,但又许多这样的系统是通过开放的 Web 进行通讯的。如此一来,它们就和网站一样,很容易受到分布式拒绝服务攻击的影响。

                  \r\n

                  Cloudflare 表示,Spectrum 允许企业通过相同的 DDoS 缓解功能(其一直为在线服务提供的那种),来应付这些威胁。

                  \r\n

                  对于这些攻击的抵御,Cloudflare 的解决方案其实很简单:

                  \r\n
                  \r\n

                  当流量突然激增的时候,系统会猜测事件可能由 DDoS 引发,然后将请求转发到自家的 150 个数据中心网络。

                  \r\n

                  Cloudflare 的基础设施相当强大,能够承受住巨量的攻击而不被斩断。

                  \r\n
                  \r\n

                  当然,这么做还有另一个好处 —— 即便企业没有一个内置的连接保护机制,Spectrum 服务也允许企业对系统传输的数据进行加密。

                  \r\n
                  \r\n

                  对企业来说,Cloudflare 提供的这项服务极具吸引力。作为附加措施,Spectrum 还提供了 Cloudflare 防火墙工具的集成。

                  \r\n
                  \r\n

                  后者可以自动阻止某些 IP 地址的流量,比如那些被网络安全机构标记的恶意来源。

                  \r\n

                  Cloudflare 早就声称担负了 10% 的全 Web 流量,此前该公司还推出了一项免费的系统服务,承诺让人们浏览的互联网更具隐私。

                  \r\n

                  [编译自:SiliconAngle]

                  ', '', 'overseas', 'ar'), +(13, '

                  当英特尔上周推出更多更多 Coffee Lake CPU 和配套主板时,传说中的 Z390 芯片组却意外缺席了。不过有眼尖的人们发现,主板厂商映泰(Biostar)在自家 B360 Racing GT5 手册中,竟然清楚地列明了另一款名叫“Z390GT5”主板的存在。作为一个二线品牌,映泰的产品主打平价而不是古怪的设计。不过它与现有的 Z370 系列没有太大差别,而且最高支持的 CPU TDP 也仅为 95W,刚好够酷睿 i7-8700K 使用而已。

                  \r\n

                  \"Biostar-Z390-Racing-GT3-1000x658.jpg\"

                  \r\n

                  此前有传闻称,某款八核 Coffee Lake 芯片的 TDP 可能超过这个数值。若真如此,Z390 芯片组存在的意义,可能就是比 H370 系列多一些 PCIe 通道、内建 USB 3.1 Gen 2、以及 CNVi Wi-Fi 支持。

                  \r\n

                  \"z390gt5.png\"

                  \r\n

                  映泰的公告中并未详细给出这些特性,所以仍有待证实。去年的泄露似乎表明,该公司的 Z390 芯片组会包含自家的音频硬件,但这块板子仍然采用了老旧的瑞昱(Realtek)编解码器。

                  \r\n

                  \"Biostar-Z390-GT5-layout.png\"

                  \r\n

                  [编译自:TechReport , 来源:VideoCardz]

                  ', '', 'overseas', 'ar'), +(14, '

                  4 月 11 日,Valve 宣布旗下著名的 PC 游戏发行平台 Steam 会推出新的用户数据隐私安全措施。今后玩家们可以选择隐藏你的游戏库内容,也可以隐藏你的活动细节,具体到最近收藏什么游戏,买了什么游戏,玩了什么游戏以及在某游戏上花了多少小时等等。

                  \r\n

                  此前,这些信息全部是公开的,不仅你的好友可以看到,发表评论的时候社区用户可以看到,而且第三方可以采用 Steam API 轻而易举的获得,那些 PC 游戏数据提供商(Steam Spy 之类)就是依靠这些用户数据提供服务的。

                  \r\n

                  新的隐私措施实行后,不管是其他用户还是第三方,将无法轻易获取这些数据。也就是说,如果你想要隐藏,那就永远不会有第三者知道你在某成人视觉小说游戏上面花了多少时间。

                  \r\n
                   
                  \r\n

                  这对 Steam 用户当然是个不错的消息,而受影响最大的是 Steam Spy 这种收集并分析数据的第三方。Steam Spy 说起来大家都不会太陌生,很多相关新闻也会引用 Steam Spy 的数据报告。他们根据过滤器筛选数据,然后将 Steam 上的游戏统计呈现给更多人浏览,但随着 Valve 关闭 Steam 可用库数据,包括 Steam Spy 在内的第三方可能都要面临倒闭。

                  \r\n

                  目前还未清楚 Valve 有没有其他替代方案,用以让第三方继续提供数据服务,或者单独推出面向开发者的数据统计工具。

                  \r\n

                  Steam Spy 的创始人 Sergey Galyonkin 在接受外媒采访时说,“如果他们真的想遵守法律,应该隐藏所有的个人资料信息。目前他们有默认情况下暴露的敏感信息,只有游戏库被隐藏。这并不合理。”默认情况下,你的 Steam 个人资料仍会向所有人显示识别信息,例如你的社交媒体帐户。

                  \r\n

                  Steam Spy 创始人提到的“法律”,其实是 5 月 25 日生效的欧盟“GPDR”,全称“通用数据保护条例”,欧盟的新规定要求公司加密所有“非公开信息”。

                  \r\n

                  \r\n

                  所以我们可以认为 Valve 做出这一决定并不绝对与近期爆发的 Facebook 数据泄露事件有关,但是这一事件肯定推动了 G 胖尽快落实自己的隐私安全措施。在这个时期,恰到好处地透露给用户“我们是一家坚定保护用户信息安全的公司”这样的信息,就是一颗很好的定心丸了。

                  \r\n

                  可以想见 Facebook 数据泄露以及后来的 Cambridge Analytica 丑闻给各大科技公司带来了怎样的压力。尽管 Steam 光是卖游戏就能保证自己足够赚钱,看起来完全没有出卖数据的必要,Steam Spy 上收集的游戏数据和用户游戏行为,于操弄政治的 Cambridge Analytica(剑桥分析公司)之流也产生不了什么价值,但谁敢说有朝一日不会因金钱诱惑发生与 Facebook 丑闻类似的事情呢?

                  \r\n

                  Valve 宁愿让一家第三方数据服务商去死,也不会冒着 G 胖走进国会接受听证的风险,无数玩家还在苦苦等待《半条命3》呢。放整个业界来讲,不管是哪家公司,都不敢再承担一次这样的“风暴潮”。

                  \r\n

                  Facebook的教训

                  \r\n

                  Facebook 身处争议漩涡,人们的抗议达到了顶峰。有人怀疑它的用处,有人直接否认它的用处,在当前的信任危机下,一切情绪都持续放大,公司和公司的使命被极端质疑。Facebook的市值自从指控以来已经减少超过500亿美元,情况简直糟糕。

                  \r\n

                  上个月,根据纽约时报、卫报曝光 Facebook 发生了严重的数据泄露,波及用户有 5000 万人之多,外泄信息被商业公司利用建立成性格模型,用来操纵了 2016 年的美国大选。

                  \r\n

                  Facebook 日前承诺 ,对于受 Cambridge Analytica 数据丑闻影响的用户,该公司会专门进行通知。毫无疑问,自 Facebook 泄密丑闻曝光以来,许多人都在等待这样的消息。随着马克·扎克伯格(Mark Zuckerberg)在美国参议院听证会上作证,更多关于数据丑闻的细节浮出水面。

                  \r\n

                  在过去一年的动荡中,Facebook 广告的基本理念,即基于用户隐藏性格特征来投放广告,已被证明是一种恶意利用用户信息,且容易遭到滥用的做法。Facebook 对此的回应与其他科技行业巨头的态度类似:感到震惊,向用户保证这绝对不是有意的行为,以及承诺采取行动。

                  \r\n

                  扎克伯格面对数不清的镜头提出的观点也颇有意思,他说经过此事希望美国数据处理和隐私规则能发生演化,其中包括直接呼吁放松监管来避免美国公司落后于中国竞争对手——在西方人的脑子里,中国好像是毫无个人信息隐私而言的地方。

                  \r\n

                  他谈到了“让人们完全控制”自己所分享内容的概念,声称这是“Facebook 最重要的原则”。

                  \r\n

                  “你在 Facebook 上分享的所有内容都归你自己所有,而且你完全控制着谁能看到它以及如何进行分享。此外,你还可以随时删除它。”扎克伯格说道,并未提及该公司在其发展早期阶段距离这样的原则有多遥远。

                  \r\n

                  国外媒体纷纷认为扎克伯格的辩解不太含蓄,因为其他平台泄漏数据的规模都比不上 Facebook,而用户是否会买扎克伯格这个账还有待观察。

                  \r\n

                  怼怼苹果 更开心

                  \r\n

                  一般大公司的 CEO 都充当了企业发言人的角色,经常在各种访谈、社交媒体上发表自己的言论,甚至是向竞争对手开炮。

                  \r\n

                  Facebook 因为用户隐私泄露被网友围攻的时候,苹果 CEO 库克自然也被媒体围着追问对这件事情的看法,库克的回答十分尖锐:

                  \r\n

                  “对我们来说用户隐私等同于用户的权利和公民自由,但是 Facebook 是一个免费服务,所以用户在这个服务中反而成了卖给广告商的商品,如果苹果这么做,我们将能赚到很多钱,但苹果最好不、也永远不会这么做。”

                  \r\n

                  在隐私方面,苹果一直奉行着严格的标准,而且它自己也一直以这种严格为傲,苹果的隐私方案多次承诺“我们不会根据你的电子邮件内容或网页浏览习惯来建立档案,然后出售给广告商。我们不会用你存放在 iPhone 或 iCloud 上的信息来赚钱。”

                  \r\n

                  他们有时甚至把美国政府搞得灰头土脸。在对发生在加利福尼亚州圣贝纳迪诺的大规模枪击案调查期间,苹果拒绝帮助美国联邦调查局解锁一名嫌犯的 iPhone,甚至不惜为此与政府对簿公堂。解锁嫌犯的 iPhone 要求开发专门软件,苹果认为影响所有用户手机的安全功能。美国司法部随后在没有苹果帮助的情况下自己找到解锁嫌犯手机的方法。

                  \r\n

                  直到现在,FBI 还在想方设法的要破解 iPhone。库克的态度肯定是——抗争到底。

                  \r\n

                  当然,苹果对用户隐私的严格保护也是经过惨痛教训的,2014 年好莱坞女星照片泄露事件波及众多大腕,在全球引起了极大的注意,让苹果和 iCloud 都摊上了大事。虽然那一次隐私泄露是由于黑客行为,和今天说的用户数据泄露、滥用态度有所区别,但那一次事件让所有人开始思考应该如何给个人信息添加更严实的门锁,更谨慎细致地保护云端安全。

                  \r\n

                  所以,记住这些教训,可以让苹果和 Facebook 们以后不再那么惨痛。这次也一样。

                  ', '', 'local', 'vr'), +(15, '

                  今天,W3C和FIDO联盟标准机构宣布,Web浏览器正在构建一种新的登录方式。这款名为WebAuthn所呈现的新开放标准将在最新版本的Firefox中得到支持,并将在未来几个月发布的Chrome和Edge的版本中得到支持。这是多年来的最新举措,目的是让用户远离密码,转向更安全的登录方式,如生物识别和USB令牌。

                  \r\n

                  该系统已经在谷歌和Facebook等主要服务上就位,在那里你可以使用符合FIDO标准的Yubikey设备登录。

                  \r\n

                  \"Security-Key-by-Yubico.png\"

                  \r\n

                  WebAuthn将无疑将加速安全登录的实现,无论是将这些技术作为备用登陆方式,还是完全取代密码。随着更多的开源代码为新标准而编写出来,开发者将更容易实现新的登录方式。

                  \r\n

                  “以前,USB令牌登陆的模式只运用于谷歌、微软和Facebook等大公司,”参与Firefox工作的Selena Deckelmann说。“现在,通过WebAuthn,更多的用户将能够体验安全登录。”

                  \r\n

                  因为FIDO标准是建立在零知识的基础上的,所以没有一串字符可以保证对一个账户的访问,这使得传统的钓鱼攻击变得更加困难。它为有安全意识的用户和企业提供了保护自己的重要途径。随着越来越多的服务转向支持更安全的登录方式,FIDO-ready用户的数量会越来越多。

                  \r\n

                  Deckelmann说:“它能真正的规避安全隐患,但现在我们还没到那一步,这将是我们的美好未来。”

                  ', '', 'overseas', 'vr'), +(16, '

                  Github 去年推出的安全警告,极大减少了开发人员消除 Ruby 和 JavaScript 项目漏洞的时间。GitHub 安全警告服务,可以搜索依赖寻找已知漏洞然后通过开发者,以便帮助开发者尽可能快的打上补丁修复漏洞,消除有漏洞的依赖或者转到安全版本。

                  \r\n

                  \"36836206-97565a64-1ced-11e8-990f-d12cb4b003e5.png\"

                  \r\n

                  根据 Github 的说法,目前安全警告已经报告了 50 多万个库中的 400 多万个漏洞。在所有显示的警告中,有将近一半的在一周之内得到了响应,前7天的漏洞解决率大约为30%。实际上,情况可能更好,因为当把统计限制在最近有贡献的库时,也就是说过去90天中有贡献的库,98%的库在7天之内打上了补丁。

                  \r\n

                  这个安全警报服务会扫描所有公共库,对于私有库,只扫描依赖图。每当发现有漏洞,库管理员都可以收到消息提示,其中还有漏洞级别及解决步骤提供。

                  \r\n

                  安全警告服务现在只支持 Ruby 和 JavaScript,不过 Github 表示 2018 年计划支持 Python。

                  ', '', 'domestic', 'ar'), +(17, '

                  AV-TEST公布了2018年1~2月杀毒软件的最新测试情况,稍稍有点不接地气的是,基于Windows 10企业版平台。排名第一的依然是铁打的卡巴斯基,3个满分总计18分无悬念。不过,这次Symantec和Trend Micro也是18满分,令人刮目相看。

                  \r\n

                  \r\n

                  \r\n

                  Bitdefender稍稍遗憾,以0.5分的差距(易用性非满分)排名第二,第三名17分也有3名,分别是你Avast、McAfee和微软

                  \r\n

                  是的,你没有看错,微软自带的Defender居然防护力满分和性能/易用性两个5.5分并列第三名。

                  \r\n

                  这次排名最后的是F-Seecure,仅拿到14.5分。

                  ', '', 'domestic', 'ar'), +(19, '

                  今日,谷歌分享了 Semantic Experiences,在博客中展示了两大关于自然语言理解的互动工具。Talk to Books 是一个可以从书中的句子层面搜索书籍的全新检索模式;另一个互动内容则是 Semantris,一个由机器学习驱动的单词联想游戏。

                  \r\n

                  地址:

                  \r\n
                   
                  \r\n

                  https://research.google.com/semanticexperiences/

                  \r\n

                  谷歌还发布了「通用语句编码器」(Universal Sentence Encoder),更加详细地呈现了上述示例所使用的模型;当然,谷歌还为开源社区提供了一个预训练的 TensorFlow 模型,开发者可以测试自己的句子及短语编码。

                  \r\n

                  地址:

                  \r\n

                  https://tfhub.dev/google/universal-sentence-encoder/

                  \r\n

                  自然语言理解在近年已经有了极大进步,这得益于词向量(word vectors)的发展,这一技术使算法能根据实际语言使用的例子来学习单词之间的关系。这些向量模型根据概念和语言的等价性、相似性或关联性,将语义相似的词或短语投影到临近点。

                  \r\n

                  建模方法

                  \r\n

                  谷歌拓展了在向量空间中表征语言(language)的构想,这一想法通过为像完整句子或段落为代表的较大语言块创建向量来实现。语言是由具有概念的层次结构组成的,因此团队采用模块的层次结构来构建向量,每一模块都要考虑与不同时间尺度序列所对应的特征。各种类型的关系,如关联、同/反义、部分/整体等都可以用向量空间语言表示。团队在论文《Efficient Natural Language Response for Smart Reply》有更多介绍。

                  \r\n

                  论文地址:

                  \r\n

                  https://arxiv.org/abs/1803.11175

                  \r\n

                  Talk to Books

                  \r\n

                  \r\n

                  以往我们在检索书籍时,通常会从书名、作者、主题等表面标签入手。而谷歌发布的「Talk to Books」可以为用户提供一种检索书籍的全新方法。用户只需要做一段相关描述,或是提一个相关的问题,那么 Talk to Books 可以在不依赖关键词匹配的情况下,从超过 10 万本书籍中检索所有句子,并根据句子层面的语义,找到能匹配用户陈述或问题的句子。从某种意义上来说,Talk to Books 是一种用户与书「交谈」的新模式,系统给出的回答也能帮助用户确定自己是否对相关主题感兴趣。

                  \r\n

                  模型在正式发布前经历了超十亿次的对话训练,以打磨更好的用户体验——对用户的提问或陈述给出更加合适的回答。这一方式相比起普通的谷歌检索,可能会帮助用户找到一些更有趣的书籍,特别是在关键字搜索中并不会显示的一些结果。

                  \r\n

                  不过,这一模型还有更多的改进空间,比如搜索范围局限在句子层面上,而不是段落,因此可能会产生「断章取义」的情况。另外,因为只看某一句子的匹配程度,这也可能导致某些众所周知的、「符合口味」的书并不会出现在检索结果的前列。谷歌团队此举,更多的是希望帮助人们以一种新的探索方式,发现不曾料想过的作者和书名,竟然会有读者感兴趣的内容。

                  \r\n

                  地址:https://books.google.com/talktobooks

                  \r\n

                  Semantris

                  \r\n

                  \r\n

                  Semantris 是一个由相同技术驱动的单词联想游戏。屏幕上会呈现所有单词,用户可以输入某个单词,随即系统会根据屏幕上单词与用户输入单词的关联程度进行重新排序。不论是近义词、反义词还是相近概念,系统都能找到对应的排序模式。

                  \r\n

                  如图所示,用户输入「Photo」时,最顶部的「Camara」因为与输入单词的关联最为紧密,因此会更替排序调整到第一位「消掉」。这确实是一个锻炼联想能力的好机会,此外还有限时模式和不限时模式供用户体验。

                  \r\n

                  地址:https://research.google.com/semantris

                  \r\n

                  相信在这两个工具的驱动下,人工智能能够与用户更好地进行交互学习,并且帮助人类在现实生活中更好地理解科技,使用科技,并受惠于科技。

                  ', '', 'domestic', 'ar'), +(20, '

                  针对新兴市场,Google希望通过Google Go轻量级应用帮助身处网络速度慢、流量资费高昂地区的用户获得更流畅的网络搜索体验。现在谷歌正向在26个撒哈拉以南非洲国家/地区推广,Google Go轻量级应用可以让搜索数据用流量减少40%,并且支持对以往搜索记录的脱机访问。

                  \r\n

                  \"TIM截图20180413142756.png\"

                  \r\n

                  Google Go 应用本身只有 5MB 大小,对于低存储空间设备很友好,这款应用也是不意外地有离线模式,主要针对的是网络条件不好地区的用户。除了应用本身的性能优化以外,Google Go 还能显示搜索结果的主题摘要信息,同时也会向用户推荐更多可能会感兴趣的内容,也拥有当前流行趋势主题推荐和语音搜索功能。

                  \r\n

                  Google Go 还可配合 YouTube Go 和文件管理应用 Files Go 使用,该应用将在 Android Oreo( Go Edition )设备中预装进行分发,让非洲等新兴市场的消费者得到更流畅、更便捷的 Android 系统体验。

                  ', '', 'domestic', 'ar'), +(21, '

                  尽管已经研发两年多时间,但对于Fuchsia系统Google始终缄口不言。不过今天,公司发表了名为“The Book”的深度解析文档,详细介绍了这款计划取代Android和Chrome OS的操作系统。 目前Android和Chrome OS都是使用Linux内核,不过在最新发布的文档中谷歌明确Fuchsia并非基于Linux内核。

                  \r\n

                  \"google-says-its-upcoming-fuchsia-os-is-not-linux-uses-zircon-kernel-520641-2.jpg\"

                  \r\n

                  根据公布的文档,Fuchsia是基于功能的模块化系统,使用名为“Zircon”(锆石)的内核,该微内核为Fuchsia系统提供核心驱动以及C Library(libc)实例。

                  \r\n

                  虽然文档仍未完成,但是我们也注意到Google正在打造的Fuchsia OS非常独特,极具创新且前途无限。这款系统从头构建自己的库和组件,通过POSIX向后兼容性和使用基于Vulkan的驱动打造出类UNIX系统。

                  \r\n

                  Fuchsia系统使用名为“Escher”的物理渲染器,提供物体的Soft Shadows,镜头特效、光影扩散和色彩外溢等功能。此外Fuchsia的文件系统完全在用户空间之间进行操作,并没有链接或者加载到内核中。

                  \r\n

                  在文档中写道:“Fuchsia的文件系统本身可以很容易的进行更改--修改不需要重新编译内核。事实上,对Fuchsia的文件系统更新可以不需要重启。”

                  ', '', 'domestic', 'vr'), +(22, '

                  谷歌手机应用程序在2月份收到了主要更新,为快速通话控件添加了便捷的聊天功能。在接下来的几周里,Pixel,Nexus和Android One设备的默认拨号程序正在添加垃圾邮件过滤功能,并附带一个新的测试版程序,现在就可以试用该功能。

                  \r\n

                  2016年,该应用程序开始通过将来电屏幕以鲜红色闪烁,并通过电话号码下方的另一个“怀疑垃圾邮件来电者”警报来提醒用户潜在的垃圾邮件来电者。现在,测试中新的垃圾邮件过滤功能更进一步增强,不再打扰用户。当检测到潜在的垃圾邮件呼叫时,将直接把它发送到语音邮件。因此,手机不会响铃,用户也不会被打搅。

                  \r\n

                  同时,用户不会收到未接电话或语音邮件通知,但已过滤的电话将出现在通话记录中,并且任何留下的语音邮件仍将显示在相应的选项卡中。此功能将在未来几周内在全球范围内推出,但加入新版测试户可以率先使用该功能。和其他程序一样,Google指出允许用户在发布之前使用这种实验性功能。

                  \r\n

                  谷歌警告说,功能仍然在开发中,可能不稳定,并且存在“一些问题”。同时,用户将需要有能力在整个过程中提交应用内反馈。想要参与测试的用户可以前往电话应用的Google Play列表,然后向下滚动到“成为测试人员”以加入。

                  \r\n

                  \r\n

                  ', '', 'domestic', 'ar'), +(24, '

                  谷歌正在与美国医学协会(美国的一个医师游说团体)进行合作,双方达成一项挑战计划,其内容是让初创企业能够想出“促进健康监测设备数据共享的最佳新思路”。美国医学协会于周一表示,最终的挑战成果将会是一款手机应用或可穿戴设备。

                  \r\n

                  \r\n

                  这两者可以让慢性病患者更轻松地与医生分享数据。

                  \r\n
                   
                  \r\n

                  该声明称:“获奖作品将展示申请人是如何通过病人的健康数据,借助有效的方式,改善医生工作流程临床效果、降低医疗保健系统成本的。”

                  \r\n

                  为了在3万亿美元的医疗保健市场中分得一杯羹,一些科技巨头对于医疗保健该行业的公司展开跨界合作显示出越来越强烈的意向,以促进创新。

                  \r\n

                   

                  \r\n

                  去年,亚马逊公司与默克公司共同发起了一项创新挑战计划,以鼓励Alexa的开发人员们提出新的“技能”,以帮助在家中接受治疗以及医院中接受治疗的糖尿病患者。

                  \r\n

                  亚马逊并没有过多透露其意图,但CNBC在3月份报道了该公司下一步的宏伟目标:针对老龄人口发展其技术。与年轻人相比,老年人在不同程度上更容易罹患糖尿病等慢性病。

                  \r\n

                  Alphabet选择将本次挑战计划集中在医疗数据的互操作性问题上。这样做的目的,是让患者和提供者能够更容易以计算机可读的格式(而不是PDF格式)共享实验室结果或医学成像这样的数据。从历史角度看,许多医院和他们的技术供应商都倾向于选择将病人“锁定”到他们独家的设备上,而不是为病人提供便捷的数据访问服务。

                  \r\n

                  值得一提的是,苹果公司也正在通过其医疗记录产品来解决这个问题。

                  \r\n

                  本次“谷歌——美国医疗协会”挑战赛最终将会产生出3个最佳创意,来共同分享5万美元的谷歌云奖金。

                  ', '', 'domestic', 'ar'), +(25, '

                  最近 Google 在帮助开发者提升 App 可用性上可谓是动作频频,不只发布了无障碍技术指导方案,成立无障碍支援团队,近日还在博客上宣布开源 iOS 专用的自动化测试框架 GTXiLib ,以帮助开发者打造无障碍 App 。

                  \r\n

                  \"logo_accessibility_checker_color_3x_ios_133in167dp.png\"

                  \r\n

                  GTXiLib 采用 Objective-C 编写,能与现存的 XCTest 测试框架整合,并在 XCTest 结束调用 tearDown 前,执行所有注册的可用性检查。当 GTXiLib 检测失败时,XCTest 的测试也会失败,两者相辅相成,能够更好地修补和发现问题。

                  \r\n

                  GTXiLib 可用于:

                  \r\n
                    \r\n
                  • \r\n

                    重用测试: GTXiLib 集成整合到现有的功能测试流程中,能大幅提升现有测试价值。

                    \r\n
                  • \r\n
                  • \r\n

                    增量可访问性测试: GTXiLib 可安装在单一测试用例、测试类或测试的特定子集上,以允许灵活地增加可访问性测试。

                    \r\n
                  • \r\n
                  • \r\n

                    编写属于自己的检查: GTXiLib 有一个简单的 API 来根据你的应用的特定需求创建自定义检查。比如,可以检测应用中的每一个按钮是否都具备 accessibilityHint 属性。

                    \r\n
                  • \r\n
                  \r\n

                  Google 还表示,为了改进 GTXiLib ,该框架会收集一些使用数据上传至 Google Analytics ,像是测试应用通过或失败的状态,以及应用绑定 ID的 MD5 哈希值,这些信息会让 Google 知道 GTXiLib 的使用情况。若是用户不愿意,则可以选择添加代码片段来停用 Google Analytics 。

                  \r\n

                  相关链接

                  \r\n', '', 'domestic', 'vr'), +(26, '

                  Let\'s Encrypt 宣布 ACME v2 正式支持通配符证书。Let\'s Encrypt 宣称将继续清除 Web 上采用 HTTPS 的障碍,让每个网站轻松获取管理证书。ACMEv21.6k 是 ACME 协议的更新版本,考虑到行业专家和其他组织可能希望在某天使用 ACME 协议进行证书颁发和管理,它已经通过 IETF 标准流程。

                  \r\n

                  \"Wildcard_certificate.jpg\"

                  \r\n

                  (配图来自:维基百科)

                  \r\n

                  Wildcard certificates 1.9k 允许使用单个证书来保护域的所有子域。在某些情况下,通配符证书可以使证书更容易管理,以帮助使 Web 达到100% 的 HTTPS 协议。但是对于大多数用例,Let\'s Encrypt 仍然推荐使用非通配符证书。

                  \r\n

                  通配符证书只能通过 ACMEv2 获得。为了将 ACMEv2 用于通配符或非通配符证书,你需要一个已更新且支持 ACMEv23.5k 的客户端。Let\'s Encrypt 希望所有客户和订户转换为 ACMEv2,尽管 ACMEv1 API 还没有“报废”。

                  \r\n

                  另外,通配符域必须使用 DNS-01 质询类型进行验证。这表明你需要修改 DNS TXT 记录才能演示对域的控制以获得通配符证书。

                  \r\n

                  [via ArsTechnica]

                  ', '', 'domestic', 'vr'), +(27, '

                  欧洲电力传输系统运营商网络(ENTSOE)是建立内部能源市场并确保其最佳运作的机构,为解释欧洲的电子钟表运行缓慢超过一个月的原因发表了一份声明。在一篇引人入胜的题为“欧洲大陆的频率偏差对频率控制的电子钟表影响”新闻稿中,该组织解释说,频率偏差导致一些数字时钟滞后。

                  \r\n

                  许多数字时钟,主要是那些数字闹钟,烤箱和微波炉,使用电网的频率来保持时间。欧洲的电网运行稳定在50Hz,所有时钟都在计算电源周期。如果频率持续下降一段时间,这就造成电子钟表运行缓慢,这种问题在欧洲似乎已经发生。

                  \r\n

                  根据维基百科,频率随着电网负载而变化,但每24小时的周期数保持严格恒定,以使这些电子时钟保持长时间准确。ENTSOE表示,供应短缺是由东南欧的一个未指定的电力分销商造成的。由于欧洲电网相互连接,自1月中旬以来,这导致整个大陆出现频率问题,这些问题导致钟表回落至五分钟。

                  \r\n

                  在问题解决之前,重置你的时钟几乎是不值得的,因为它们只会滞后。 ENTSOE声明确实承诺欧洲的传输系统运营商为了让时钟恢复正常运行,将实施补偿计划,以纠正未来的时间,,需要多长时间仍然不得而知。与此同时,用户仍然可以依赖任何不联网的石英钟,或者通常通过互联网保持正确时间的电脑,智能手机时钟来查看时间。

                  \r\n

                  \"1024px-Digital-clock-alarm-796x562.jpg\"

                  ', '', 'domestic', 'vr'), +(30, '

                  北京时间4月11日早间消息,谷歌母公司Alphabet有望在2018进行新的投资,目前,该公司仍在研究如何优化电池的存储价值。作为世界上风能和太阳能的最大企业买家,谷歌可能很快要进行一项新的清洁能源投资,这次他们锁定的目标是电池。

                  \r\n

                  \"Solarpanel.jpg\"

                  \r\n

                  资料图

                  \r\n

                  本周二,Alphabet公司能源策略主管奈哈·帕尔默(Neha Palmer)在纽约彭博新能源财经机构举办的未来能源峰会上接受采访时说,“2018年我们想有所作为,我们正在对几个项目展开调研。”

                  \r\n

                  帕尔默指出,谷歌根据几个选项来决定合理的投资方向。其中一些项目包括:独立的可供给电网的电池场;用于家庭或企业的电表后端设备;一套与太阳能或风力发电场相连的系统。

                  \r\n

                  这一项目需要依靠一项长达数年的供应合同来保证营收,该公司仍在审查这种投资的市场需求。帕尔默说:“决策团队尚未搞清楚如何优化电力储存的价值。”

                  ', NULL, 'domestic', 'ar'), +(32, '

                  北京时间4月11日早间消息,谷歌母公司Alphabet有望在2018进行新的投资,目前,该公司仍在研究如何优化电池的存储价值。作为世界上风能和太阳能的最大企业买家,谷歌可能很快要进行一项新的清洁能源投资,这次他们锁定的目标是电池。

                  \r\n

                  \"Solarpanel.jpg\"

                  \r\n

                  资料图

                  \r\n

                  本周二,Alphabet公司能源策略主管奈哈·帕尔默(Neha Palmer)在纽约彭博新能源财经机构举办的未来能源峰会上接受采访时说,“2018年我们想有所作为,我们正在对几个项目展开调研。”

                  \r\n

                  帕尔默指出,谷歌根据几个选项来决定合理的投资方向。其中一些项目包括:独立的可供给电网的电池场;用于家庭或企业的电表后端设备;一套与太阳能或风力发电场相连的系统。

                  \r\n

                  这一项目需要依靠一项长达数年的供应合同来保证营收,该公司仍在审查这种投资的市场需求。帕尔默说:“决策团队尚未搞清楚如何优化电力储存的价值。”

                  ', '', 'overseas', 'vr'), +(33, '

                  据外媒报道,去年,GitHub 向安全研究人员支付了总计 166495 美元的奖励,针对 GitHub 这个为期四年的“漏洞赏金”项目,安全研究人员会上报自己发现的系统问题和漏洞。2016 年,GitHub 一共支付了81.7万美元,而去年的支出总额显然已经翻了一倍多,几乎相当于前三年的总支出(17.7万美元)。在 2014 和 2015 两年时间里,他们一共支付了95.3万美元的奖金。

                  \r\n

                  \r\n

                  2017 年,GitHub 一共收到了 840 份漏洞报告意见书,但是最终解决问题并获得奖金的比例只有15%(约121份)。2016年,GitHub 共收到了 795 份漏洞报告意见书,最终获得奖励的只有 73 份,而其中只有 48 份有效报告最终被罗列在了漏洞赏金项目的主页上。

                  \r\n

                  有效报告的数量上升推动了总支出的增加,也导致了 GitHub 在去年十月重新评估其支付结构。结果就是,奖金增加了一倍,其中最低奖金为 555 美元,最高奖金高达 20000 美元。

                  \r\n

                  GitHub 的 Greg Ose 指出,随着参与的项目、计划和研究人员规模不断增加,去年是迄今为止支付赏金最多的一年。不仅如此,他们还把 GitHub Enterprise 引入到漏洞赏金项目之中,让研究人员能够在 GitHub.com 平台上一些未公开的、或是特定于某个企业部署的领域里找到漏洞。Ose说道:

                  \r\n
                  \r\n

                  “去年年初,很多漏洞报告涉及到了我们的企业认证方法,这也促使我们不得不在内部关注这个问题,而且我们也在研究如何让研究人员也关注这个功能。”

                  \r\n
                  \r\n

                  此外,Ose还表示,GitHub 已经发布了首个研究人员捐赠,也是他们长期以来关注的一项举措。这项工作会为挖掘应用程序特定功能或领域的研究人员支付固定金额。当然,其他任何发现漏洞的人也能够通过漏洞赏金项目获得奖励。

                  \r\n

                  去年,GitHub 还推出了私人漏洞补丁服务,让用户能够限制生产漏洞的影响范围。不仅如此,他们还进行了内部改进,以更有效进行漏洞分类和修复提交,并计划在今年进一步完善流程。

                  \r\n

                  现在,GitHub 希望进一步扩大 2017 年所取得成绩,推出更多私人奖励和研究补助金,以便在代码公开发布之前及之后引起大家的关注。该公司还计划在今年晚些时候,推出额外的奖励计划。Ose总结道:

                  \r\n
                  \r\n

                  “鉴于漏洞赏金项目取得了成功,我们现在正考虑如何扩大其范围,为我们的生产服务提供更多帮助,同时保护整个GitHub生态系统。我们很期待下一步工作,并且会在今年对提交的漏洞内容进行分类和修正。”

                  \r\n
                  ', 'cnbeta1', 'overseas', 'ar'), +(34, '

                  本周我们正在研究Leap Motion为增强现实带来的新东西。我们已经看到他们之前创造了一些令人难以置信的技术,尤其是当涉及到运动跟踪和控制时。现在看起来他们认为他们是以面向优先的方式进入AR增强现实世界。

                  \r\n

                  Leap Motion有一款在性能和外形之间达到平衡的头显,这款头显达到了Leap Motion所说最高技术规格所在的平衡点。换句话说,他们创造了一款人们可以使用的产品,与当今世界上大多数其他消费类产品不同。

                  \r\n

                  为了制造这款头显,Leap Motion的团队使用了几款5.5英寸的智能手机。他们将这些智能手机放在佩戴者脸部的两侧,并将其内部的图像反映出来。通过这种设置,最终他们发现他们需要创建自己的LED显示系统。他们决定采用Analogix显示驱动器和两个“快速切换”BOE 3.5英寸显示屏的架构。

                  \r\n

                  他们已经创造了一款头显,正如他们所描述的那样,它会让所有其他头显(VR,AR等)感到羞耻。两个120 fps,1600x1440显示屏,100+视角范围和150 fps手动追踪180 x 180度FOV,打开这个头显,当今系统的分辨率,等待时间和视野限制就会消失。

                  \r\n

                  那么你可以在哪里购买这种现代技术的奇迹?你不能。目前,Leap Motion将此项目称为“北极星计划”,并将其作为一个跳板点。他们正在使用这个项目来表明我们所有人都关注于AR硬件是错误的,他们的产品可以带来最佳体验。

                  \r\n

                  \r\n

                  ', 'ks', 'domestic', 'ar'), +(35, '

                  据外媒报道,研究人员正在利用VR技术帮助教师们了解自闭症学s生进而能够真正地去帮助他们。近日,来自马耳他大学的一个研究小组决定通过VR技术帮助教师理解自闭症儿童的生活体验。通过利用自闭症儿童的音频和视觉技巧,研究团队开发出一个VR应用,它能模拟出自闭症儿童在教室里的体验情况。

                  \r\n

                  \"austim.png\"

                  \r\n

                  参与了软件开发工作的马耳他大学人工智能系讲师Vanessa Camilleri博士表示,他们希望让教师走进自闭症儿童的世界里了解他们的真实情况同时也希望VR能够成为一台同理心机器。与此同时,他们还希望能从中学到更多的东西进而能设计出能帮助改善自闭症儿童生活质量的工具。

                  \r\n

                  实际上将VR作为一种共情工具的想法已经存在一段时间了。电影制作人Chris Milk就曾和联合国联合制作过一部展示叙利亚难民营生活的VR影片《Clouds Over Sidra》。

                  \r\n

                  目前,研究小组的这款软件还不能使用,但他们希望未来能通过Samsung Gear头套让教师们用上它。

                  \r\n

                  Camilleri还强调,该项目并不能做到模拟出自闭症儿童的各个方面,如嗅觉、触觉。另外他还表示,他们开发的应用更多的是让老师们去了解他们的学生而不是教授他们如何去帮助自闭症学生。

                  \r\n

                  获悉,该团队希望最终还能为父母或家庭成员开发出另一个不同版本的同类型软件。

                  ', 'cnbeta', 'domestic', 'ar'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_addonproduct` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_addonproduct` ( + `id` int(10) NOT NULL, + `content` longtext NOT NULL, + `productdata` varchar(1500) DEFAULT '' COMMENT '产品列表', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='产品表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_addonproduct` +-- + +INSERT INTO `__PREFIX__cms_addonproduct` (`id`, `content`, `productdata`) VALUES +(18, '

                  据外媒报道,去年,GitHub 向安全研究人员支付了总计 166495 美元的奖励,针对 GitHub 这个为期四年的“漏洞赏金”项目,安全研究人员会上报自己发现的系统问题和漏洞。2016 年,GitHub 一共支付了81.7万美元,而去年的支出总额显然已经翻了一倍多,几乎相当于前三年的总支出(17.7万美元)。在 2014 和 2015 两年时间里,他们一共支付了95.3万美元的奖金。

                  \r\n

                  \r\n

                  2017 年,GitHub 一共收到了 840 份漏洞报告意见书,但是最终解决问题并获得奖金的比例只有15%(约121份)。2016年,GitHub 共收到了 795 份漏洞报告意见书,最终获得奖励的只有 73 份,而其中只有 48 份有效报告最终被罗列在了漏洞赏金项目的主页上。

                  \r\n

                  有效报告的数量上升推动了总支出的增加,也导致了 GitHub 在去年十月重新评估其支付结构。结果就是,奖金增加了一倍,其中最低奖金为 555 美元,最高奖金高达 20000 美元。

                  \r\n

                  GitHub 的 Greg Ose 指出,随着参与的项目、计划和研究人员规模不断增加,去年是迄今为止支付赏金最多的一年。不仅如此,他们还把 GitHub Enterprise 引入到漏洞赏金项目之中,让研究人员能够在 GitHub.com 平台上一些未公开的、或是特定于某个企业部署的领域里找到漏洞。Ose说道:

                  \r\n
                  \r\n

                  “去年年初,很多漏洞报告涉及到了我们的企业认证方法,这也促使我们不得不在内部关注这个问题,而且我们也在研究如何让研究人员也关注这个功能。”

                  \r\n
                  \r\n

                  此外,Ose还表示,GitHub 已经发布了首个研究人员捐赠,也是他们长期以来关注的一项举措。这项工作会为挖掘应用程序特定功能或领域的研究人员支付固定金额。当然,其他任何发现漏洞的人也能够通过漏洞赏金项目获得奖励。

                  \r\n

                  去年,GitHub 还推出了私人漏洞补丁服务,让用户能够限制生产漏洞的影响范围。不仅如此,他们还进行了内部改进,以更有效进行漏洞分类和修复提交,并计划在今年进一步完善流程。

                  \r\n

                  现在,GitHub 希望进一步扩大 2017 年所取得成绩,推出更多私人奖励和研究补助金,以便在代码公开发布之前及之后引起大家的关注。该公司还计划在今年晚些时候,推出额外的奖励计划。Ose总结道:

                  \r\n
                  \r\n

                  “鉴于漏洞赏金项目取得了成功,我们现在正考虑如何扩大其范围,为我们的生产服务提供更多帮助,同时保护整个GitHub生态系统。我们很期待下一步工作,并且会在今年对提交的漏洞内容进行分类和修正。”

                  \r\n
                  ', 'https://cdn.fastadmin.net/uploads/20180401/1f059faa0ba3bb502d7dd012565321e2.jpg,https://cdn.fastadmin.net/uploads/20180401/05e374fd1f784f9c4f634889bd7028ac.jpg,https://cdn.fastadmin.net/uploads/20180401/fdaca158bf96ed0fd59879f2c7f673d3.jpg,https://cdn.fastadmin.net/uploads/20180401/33b63f123cdee4c251590b73c2464fa9.jpg'), +(23, '

                  北京时间4月11日早间消息,谷歌母公司Alphabet有望在2018进行新的投资,目前,该公司仍在研究如何优化电池的存储价值。作为世界上风能和太阳能的最大企业买家,谷歌可能很快要进行一项新的清洁能源投资,这次他们锁定的目标是电池。

                  \r\n

                  \"Solarpanel.jpg\"

                  \r\n

                  资料图

                  \r\n

                  本周二,Alphabet公司能源策略主管奈哈·帕尔默(Neha Palmer)在纽约彭博新能源财经机构举办的未来能源峰会上接受采访时说,“2018年我们想有所作为,我们正在对几个项目展开调研。”

                  \r\n

                  帕尔默指出,谷歌根据几个选项来决定合理的投资方向。其中一些项目包括:独立的可供给电网的电池场;用于家庭或企业的电表后端设备;一套与太阳能或风力发电场相连的系统。

                  \r\n

                  这一项目需要依靠一项长达数年的供应合同来保证营收,该公司仍在审查这种投资的市场需求。帕尔默说:“决策团队尚未搞清楚如何优化电力储存的价值。”

                  ', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412a357f60.jpg,https://cdn.fastadmin.net/uploads/20180404/9dcbcd9ca1fce9f184ee12aea36351de.jpg,https://cdn.fastadmin.net/uploads/20180401/e5f3f6312c360f4c851daf99b1208515.jpg,https://cdn.fastadmin.net/uploads/20180401/26558a3bffe6960768350f2202885955.jpg,https://cdn.fastadmin.net/uploads/20180401/2d184becba222eb8406aadd72b004c5e.jpg,https://cdn.fastadmin.net/uploads/20180401/8cb318ead26ae66086953f1c0bcf0275.jpg'), +(28, '

                  本周我们正在研究Leap Motion为增强现实带来的新东西。我们已经看到他们之前创造了一些令人难以置信的技术,尤其是当涉及到运动跟踪和控制时。现在看起来他们认为他们是以面向优先的方式进入AR增强现实世界。

                  \r\n

                  Leap Motion有一款在性能和外形之间达到平衡的头显,这款头显达到了Leap Motion所说最高技术规格所在的平衡点。换句话说,他们创造了一款人们可以使用的产品,与当今世界上大多数其他消费类产品不同。

                  \r\n

                  为了制造这款头显,Leap Motion的团队使用了几款5.5英寸的智能手机。他们将这些智能手机放在佩戴者脸部的两侧,并将其内部的图像反映出来。通过这种设置,最终他们发现他们需要创建自己的LED显示系统。他们决定采用Analogix显示驱动器和两个“快速切换”BOE 3.5英寸显示屏的架构。

                  \r\n

                  他们已经创造了一款头显,正如他们所描述的那样,它会让所有其他头显(VR,AR等)感到羞耻。两个120 fps,1600x1440显示屏,100+视角范围和150 fps手动追踪180 x 180度FOV,打开这个头显,当今系统的分辨率,等待时间和视野限制就会消失。

                  \r\n

                  那么你可以在哪里购买这种现代技术的奇迹?你不能。目前,Leap Motion将此项目称为“北极星计划”,并将其作为一个跳板点。他们正在使用这个项目来表明我们所有人都关注于AR硬件是错误的,他们的产品可以带来最佳体验。

                  \r\n

                  \r\n

                  ', 'https://cdn.fastadmin.net/uploads/20180416/5ad44129495250.jpg'), +(29, '

                  据外媒报道,研究人员正在利用VR技术帮助教师们了解自闭症学生进而能够真正地去帮助他们。近日,来自马耳他大学的一个研究小组决定通过VR技术帮助教师理解自闭症儿童的生活体验。通过利用自闭症儿童的音频和视觉技巧,研究团队开发出一个VR应用,它能模拟出自闭症儿童在教室里的体验情况。

                  \r\n

                  \"austim.png\"

                  \r\n

                  参与了软件开发工作的马耳他大学人工智能系讲师Vanessa Camilleri博士表示,他们希望让教师走进自闭症儿童的世界里了解他们的真实情况同时也希望VR能够成为一台同理心机器。与此同时,他们还希望能从中学到更多的东西进而能设计出能帮助改善自闭症儿童生活质量的工具。

                  \r\n

                  实际上将VR作为一种共情工具的想法已经存在一段时间了。电影制作人Chris Milk就曾和联合国联合制作过一部展示叙利亚难民营生活的VR影片《Clouds Over Sidra》。

                  \r\n

                  目前,研究小组的这款软件还不能使用,但他们希望未来能通过Samsung Gear头套让教师们用上它。

                  \r\n

                  Camilleri还强调,该项目并不能做到模拟出自闭症儿童的各个方面,如嗅觉、触觉。另外他还表示,他们开发的应用更多的是让老师们去了解他们的学生而不是教授他们如何去帮助自闭症学生。

                  \r\n

                  获悉,该团队希望最终还能为父母或家庭成员开发出另一个不同版本的同类型软件。

                  ', 'https://cdn.fastadmin.net/uploads/20180416/5ad44128db3ed0.png'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_archives` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_archives` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `channel_id` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '栏目ID', + `model_id` int(10) NOT NULL DEFAULT '0' COMMENT '模型ID', + `title` varchar(80) NOT NULL DEFAULT '' COMMENT '文章标题', + `flag` set('hot','new','recommend') NOT NULL DEFAULT '' COMMENT '标志', + `image` varchar(255) NOT NULL DEFAULT '' COMMENT '缩略图', + `keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字', + `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述', + `tags` varchar(255) NOT NULL DEFAULT '' COMMENT 'TAG', + `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', + `views` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '浏览次数', + `comments` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '评论次数', + `likes` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '点赞数', + `dislikes` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '点踩数', + `diyname` varchar(50) NOT NULL DEFAULT '' COMMENT '自定义URL', + `createtime` int(10) DEFAULT NULL COMMENT '创建时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `publishtime` int(10) DEFAULT NULL COMMENT '发布时间', + `deletetime` int(10) DEFAULT NULL COMMENT '删除时间', + `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态', + PRIMARY KEY (`id`), + KEY `status` (`channel_id`,`status`), + KEY `channel` (`channel_id`,`weigh`,`id`) +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8 COMMENT='内容表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_archives` +-- + +INSERT INTO `__PREFIX__cms_archives` (`id`, `channel_id`, `model_id`, `title`, `flag`, `image`, `keywords`, `description`, `tags`, `weigh`, `views`, `comments`, `likes`, `dislikes`, `diyname`, `createtime`, `updatetime`, `publishtime`, `deletetime`, `status`) VALUES +(1, 7, 1, '驰为发布HiGame迷你PC新品 小身材大能量', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412814b010.jpg', '驰为,笔记本,HiGame', '说到驰为(Chuwi),很多人第一时间想到的就是该公司的 Windows 笔记本或 Android 平板电脑。但是最近,该厂家又凭借 HiGame 子品牌进军了迷你游戏 PC 市场。作为一款迷你 PC,它的三围只有 17.3×15.8×7.3 CM(约 7×6×3 英寸)。即便如此,它的硬件配置也让我们眼前一亮。', 'HiGame,PC,驰为', 1, 9, 1, 0, 0, '', 1523718809, 1523879174, 1523635200, NULL, 'normal'), +(2, 7, 1, '宏碁Chromebox CXI3迷你台式机现已开放预定', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44127cc3810.jpg', '宏基,台式机', '今年 1 月的时候,宏碁(Acer)发布了多款新产品,其中就包括 Chromebox CXI3 。与 Chromebook 笔记本不同,Chromebox CXI3 是一款运行 Chrome OS 的小型台式机。不占地方,显然是它的最大卖点,用户甚至可以将它背挂到显示器后面。如果你想要拥有一台,那么现在宏碁也已经开放预定了。', 'Chromebox,台式机,宏基', 2, 20, 0, 0, 0, '', 1523718936, 1523879158, 1523635200, NULL, 'normal'), +(3, 7, 1, 'Misfit最新的混合动力手表Path现已上市', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44125f364e0.png', '手表,混合动力', 'Misfit的混合动力手表今天通过公司网站发售。它的售价为149.99美元,将有四种颜色可供选择:不锈钢,玫瑰金,黄金和带金色调的不锈钢。该公司首先在CES首次推出手表,在那里我们看到了这款小巧的新设备。这是该公司最小的手表 - 38毫米 - 并没有触摸屏,但它通过蓝牙与智能手机配对。', '智能手表,混合动力', 3, 2, 0, 0, 0, '', 1523719020, 1523879142, 1523635200, NULL, 'normal'), +(4, 7, 1, 'UE为现场演出者推出了价值2200美元的舞台耳返设备', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad441258ab510.png', '耳返,智能设备', '大多数消费者可能熟悉UE推出的色彩鲜艳的蓝牙音箱,但该公司也有一系列定制入耳式耳机,UE刚刚推出了一款新的顶级旗舰机型:2,200美元的UE Live。UE Live耳机是该公司以前的旗舰UE18 Pro型号的进化版本,将每个耳机的扬声器数量从6个增加到8个,共计6个平衡电枢,一个True Tone Plus驱动器和一个6mm钕制动态扬声器,以提供更好的声音。', '智能设备,耳返', 4, 3, 0, 1, 0, '', 1523719106, 1523879126, 1523635200, NULL, 'normal'), +(5, 7, 1, '南孚推出全球首款测电器装电池:可秒分电池新旧', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412530fd08.jpg', '电池,南孚', '想必大家都遇到过这样尴尬的事情:家里有很多电池,用的时候也分不清哪个有电、哪个没电,扔了又怕浪费。于是旧的不丢掉,新的买来用,这样家里的电池越积攒越多,造成恶性循环。而现在,南孚带来了一款全新产品——南孚测电器装电池,包含南孚测电器和南孚碱性电池,轻轻松松测一测,电池电量一目了然。', '南孚,电池', 5, 2, 0, 0, 0, '', 1523719198, 1523879107, 1523635200, NULL, 'normal'), +(6, 7, 1, '强生将推能根据光线条件自动变色的隐形镜片', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44121af36d0.jpeg', '智能设备,强生', '据外媒报道,多年来,人们已经习惯于使用变色镜片的眼镜,然而这在隐形眼镜中却不存在。不过就在日前,强生终于打破了这个技术壁垒,这家公司宣布即将向市场推出具备变色功能的隐形镜片。', '智能设备', 6, 0, 0, 0, 0, '', 1523719286, 1523879078, 1523635200, NULL, 'normal'), +(7, 7, 1, 'Snap新一代Spectacles眼镜文档已被FCC曝光', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44121495860.jpg', '', '据 Variety 报道,FCC 辐射实验室刚刚证实了一副来自 Snap 的新眼镜。今日曝光的这款穿戴设备的文档称,这是一款由 Snap Inc. 制作的穿戴式视频拍摄装置。从印刷标签来看,其品牌名称为 Spectacles,型号为 Model 002 。尽管文件中所附的大部分内容都以保密为由被遮掩,但还是可以知道它支持低功耗蓝牙 4.2 和 802.11ac Wi-Fi 。', '智能设备,眼镜', 7, 2, 0, 1, 0, '', 1523719403, 1523879062, 1523635200, NULL, 'normal'), +(8, 5, 1, '投资者需求旺盛 Dropbox将IPO发行价区间调高2美元', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44120f16870.jpg', '', '云存储服务商Dropbox今日宣布,由于投资者需求强劲,现将IPO(数次公开招股)发行价区间调高2美元。上周一,Dropbox宣布将IPO发行价区间定为每股16美元至18美元,最高融资6.48亿美元,公司市值将达到约71亿美元。', 'dropbox,投资', 8, 1, 0, 0, 0, '', 1523719527, 1523879042, 1523635200, NULL, 'normal'), +(9, 5, 1, 'Dropbox股价上市首日大涨36% 市值超120亿美元', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44120cd28e0.jpg', '', '著名云存储服务提供商Dropbox在上市交易首日股价大涨36%,开盘定价为21美元每股,在当日最高时达到31.6美元每股,最终以28.48美元每股的价格收盘,现在市值超过120亿美元。可以明显看出公开市场投资者十分看好Dropbox这家主营业务为云存储服务和内容协作平台的公司。Dropbox最先对自己股价的预期是16到18美元每股,后来提升到18到20美元每股。而由于上市交易首日表现出色,超过了2014年私募时100亿美元的估值。', 'dropbox,投资', 9, 0, 0, 0, 0, '', 1523719610, 1523879028, 1523635200, NULL, 'normal'), +(10, 5, 1, '云存储公司Dropbox在美提交IPO申请:拟筹资5亿美元', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44120825a50.jpg', '', '云存储公司Dropbox周五向美国证券交易委员会(SEC)提交了IPO(首次公开招股)申请文件,寻求筹集5亿美元资金。Dropbox的IPO交易长期以来备受市场期待,该公司四年前在私募投资市场上的估值就已高达100亿美元。', 'dropbox', 10, 0, 0, 0, 0, '', 1523719716, 1523879000, 1523635200, NULL, 'normal'), +(11, 5, 1, '通用电气针对Predix云平台的创业者推出奖励计划', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad441204c1c20.png', '', '通用电气(GE)为推广Predix云平台的应用开发,在国内推出首期\"Predix星火计划\",以奖励基于该平台的工业互联网开发者。首期有4家企业获奖,将进驻GE孵化器并获得技术支持和潜在投资机会。', '云计算,互联网', 11, 0, 0, 0, 0, '', 1523719810, 1523878981, 1523635200, NULL, 'normal'), +(12, 5, 1, '超越Web服务 Cloudflare推出全新的Spectrum安全服务', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411fb836c0.png', '', '据外媒报道,Cloudflare 公司正将其业务拓展到网站和云应用之外的互联网安全领域。此前,Cloudflare 帮助过企业屏蔽恶意流量,并且让它们的线上内容加载得更加迅速。而根据今日披露的内容,这项新服务旨在保护那些在公共网络背景下运行的联网基础设施,涵盖了从企业内部电子邮件服务器、到领域内部署的联网设备等各个方面。', '云计算,安全', 12, 1, 0, 0, 0, '', 1523719980, 1523878966, 1523635200, NULL, 'normal'), +(13, 5, 1, '映泰Z390GT5主板手册曝光 英特尔Z390芯片组或即将到来 当', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411ecab1c0.jpg', '', '当英特尔上周推出更多更多 Coffee Lake CPU 和配套主板时,传说中的 Z390 芯片组却意外缺席了。不过有眼尖的人们发现,主板厂商映泰(Biostar)在自家 B360 Racing GT5 手册中,竟然清楚地列明了另一款名叫“Z390GT5”主板的存在。作为一个二线品牌,映泰的产品主打平价而不是古怪的设计。不过它与现有的 Z370 系列没有太大差别,而且最高支持的 CPU TDP 也仅为 95W,刚好够酷睿 i7-8700K 使用而已。', '智能设备', 13, 1, 0, 0, 0, '', 1523720694, 1523878951, 1523635200, NULL, 'normal'), +(14, 4, 1, '在数据黑箱和信赖危机面前 谁更应该战战兢兢?', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411e749b30.jpg', '', '4 月 11 日,Valve 宣布旗下著名的 PC 游戏发行平台 Steam 会推出新的用户数据隐私安全措施。今后玩家们可以选择隐藏你的游戏库内容,也可以隐藏你的活动细节,具体到最近收藏什么游戏,买了什么游戏,玩了什么游戏以及在某游戏上花了多少小时等等。', '安全', 14, 0, 0, 0, 0, '', 1523720913, 1523878935, 1523635200, NULL, 'normal'), +(15, 4, 1, 'Google Chrome和Mozilla Firefox将支持全新无密码登录规范', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411e3a7db0.png', '', '今天,W3C和FIDO联盟标准机构宣布,Web浏览器正在构建一种新的登录方式。这款名为WebAuthn所呈现的新开放标准将在最新版本的Firefox中得到支持,并将在未来几个月发布的Chrome和Edge的版本中得到支持。这是多年来的最新举措,目的是让用户远离密码,转向更安全的登录方式,如生物识别和USB令牌。', '互联网,安全', 15, 0, 0, 0, 0, '', 1523720991, 1523878915, 1523635200, NULL, 'normal'), +(16, 4, 1, 'GitHub 安全警告计划已检测出 400 多万个漏洞', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411db71750.png', '', 'Github 去年推出的安全警告,极大减少了开发人员消除 Ruby 和 JavaScript 项目漏洞的时间。GitHub 安全警告服务,可以搜索依赖寻找已知漏洞然后通过开发者,以便帮助开发者尽可能快的打上补丁修复漏洞,消除有漏洞的依赖或者转到安全版本。', '互联网,安全', 16, 0, 0, 0, 0, '', 1523721095, 1523878887, 1523635200, NULL, 'normal'), +(17, 4, 1, 'Windows 10杀毒软件大PK:Defender首入前三', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411cec01d0.jpg', '', 'AV-TEST公布了2018年1~2月杀毒软件的最新测试情况,稍稍有点不接地气的是,基于Windows 10企业版平台。排名第一的依然是铁打的卡巴斯基,3个满分总计18分无悬念。不过,这次Symantec和Trend Micro也是18满分,令人刮目相看。', '云计算,安全', 17, 1, 0, 0, 0, '', 1523721137, 1523878857, 1523635200, NULL, 'normal'), +(18, 10, 2, 'GitHub 去年为漏洞支付了 16.6 万美元赏金', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412a798700.jpg', '', '据外媒报道,去年,GitHub 向安全研究人员支付了总计 166495 美元的奖励,针对 GitHub 这个为期四年的“漏洞赏金”项目,安全研究人员会上报自己发现的系统问题和漏洞。2016 年,GitHub 一共支付了81.7万美元,而去年的支出总额显然已经翻了一倍多,几乎相当于前三年的总支出(17.7万美元)。在 2014 和 2015 两年时间里,他们一共支付了95.3万美元的奖金。', '互联网,安全', 18, 21, 0, 1, 0, '', 1523721203, 1523895458, 1523635200, NULL, 'normal'), +(19, 3, 1, '谷歌发布“与书对话”检索引擎 从字里行间邂逅心仪书籍', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411b4c3960.jpg', '', '今日,谷歌分享了 Semantic Experiences,在博客中展示了两大关于自然语言理解的互动工具。Talk to Books 是一个可以从书中的句子层面搜索书籍的全新检索模式;另一个互动内容则是 Semantris,一个由机器学习驱动的单词联想游戏。', 'Google,互联网', 19, 3, 0, 0, 0, '', 1523721303, 1523878822, 1523635200, NULL, 'normal'), +(20, 3, 1, '节省40%搜索流量:Google Go轻量级应用将于非洲市场推出', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411b10d540.png', '', '针对新兴市场,Google希望通过Google Go轻量级应用帮助身处网络速度慢、流量资费高昂地区的用户获得更流畅的网络搜索体验。现在谷歌正向在26个撒哈拉以南非洲国家/地区推广,Google Go轻量级应用可以让搜索数据用流量减少40%,并且支持对以往搜索记录的脱机访问。', 'Google,互联网', 20, 0, 0, 0, 0, '', 1523721344, 1523878791, 1523635200, NULL, 'normal'), +(21, 3, 1, '谷歌公布Fuchsia文档:并非Linux内核 从头构建自己的库和组件', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411ab103e0.jpg', '', '尽管已经研发两年多时间,但对于Fuchsia系统Google始终缄口不言。不过今天,公司发表了名为“The Book”的深度解析文档,详细介绍了这款计划取代Android和Chrome OS的操作系统。 目前Android和Chrome OS都是使用Linux内核,不过在最新发布的文档中谷歌明确Fuchsia并非基于Linux内核。', 'Google,互联网', 21, 2, 0, 0, 0, '', 1523721408, 1523878779, 1523635200, NULL, 'normal'), +(22, 3, 1, '谷歌手机应用可直接过滤语音垃圾邮件', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4411a368920.jpg', '', '谷歌手机应用程序在2月份收到了主要更新,为快速通话控件添加了便捷的聊天功能。在接下来的几周里,Pixel,Nexus和Android One设备的默认拨号程序正在添加垃圾邮件过滤功能,并附带一个新的测试版程序,现在就可以试用该功能。', 'Google,互联网', 22, 2, 0, 0, 0, '', 1523721460, 1523878762, 1523635200, NULL, 'normal'), +(23, 10, 2, '谷歌母公司继续投资清洁能源领域:或押注于电池', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412a357f60.jpg', '', '北京时间4月11日早间消息,谷歌母公司Alphabet有望在2018进行新的投资,目前,该公司仍在研究如何优化电池的存储价值。作为世界上风能和太阳能的最大企业买家,谷歌可能很快要进行一项新的清洁能源投资,这次他们锁定的目标是电池。', 'Google,互联网', 23, 28, 0, 0, 0, '', 1523721500, 1523895423, 1523635200, NULL, 'normal'), +(24, 3, 1, '谷歌携手美国医学协会 促进健康监测设备数据共享', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44119d944a0.png', '', '谷歌正在与美国医学协会(美国的一个医师游说团体)进行合作,双方达成一项挑战计划,其内容是让初创企业能够想出“促进健康监测设备数据共享的最佳新思路”。美国医学协会于周一表示,最终的挑战成果将会是一款手机应用或可穿戴设备。', 'Google,互联网', 24, 5, 0, 0, 0, '', 1523721555, 1523878724, 1523635200, NULL, 'normal'), +(25, 3, 1, '谷歌开源 iOS 自动测试框架 GTXiLib,主打无障碍使用', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad441196ddc60.png', '', '最近 Google 在帮助开发者提升 App 可用性上可谓是动作频频,不只发布了无障碍技术指导方案,成立无障碍支援团队,近日还在博客上宣布开源 iOS 专用的自动化测试框架 GTXiLib ,以帮助开发者打造无障碍 App 。', 'Google,互联网', 25, 7, 0, 0, 0, '', 1523754040, 1523878710, 1523721600, NULL, 'normal'), +(26, 4, 1, 'Let\'s Encrypt发布ACME v2 正式支持通配符证书', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44119326fd0.jpg', '', 'Let\'s Encrypt 宣布 ACME v2 正式支持通配符证书。Let\'s Encrypt 宣称将继续清除 Web 上采用 HTTPS 的障碍,让每个网站轻松获取管理证书。ACMEv21.6k 是 ACME 协议的更新版本,考虑到行业专家和其他组织可能希望在某天使用 ACME 协议进行证书颁发和管理,它已经通过 IETF 标准流程。', '互联网,安全', 26, 36, 0, 1, 0, '', 1523754142, 1523878676, 1523721600, NULL, 'normal'), +(27, 4, 1, '因为电网问题 欧洲的电子钟表运行缓慢超过一个月时间', 'recommend', 'https://cdn.fastadmin.net/uploads/20180416/5ad44118ca9c40.jpg', '', '欧洲电力传输系统运营商网络(ENTSOE)是建立内部能源市场并确保其最佳运作的机构,为解释欧洲的电子钟表运行缓慢超过一个月的原因发表了一份声明。在一篇引人入胜的题为“欧洲大陆的频率偏差对频率控制的电子钟表影响”新闻稿中,该组织解释说,频率偏差导致一些数字时钟滞后。', '互联网,安全', 27, 140, 7, 1, 0, '', 1523754196, 1523878659, 1523721600, NULL, 'normal'), +(28, 9, 2, 'Leap Motion AR头显看起来很疯狂但可能是奇迹', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44129495250.jpg', '', '本周我们正在研究Leap Motion为增强现实带来的新东西。我们已经看到他们之前创造了一些令人难以置信的技术,尤其是当涉及到运动跟踪和控制时。现在看起来他们认为他们是以面向优先的方式进入AR增强现实世界。', 'AR,VR,互联网', 28, 16, 0, 1, 0, '', 1523755374, 1523878629, 1523721600, NULL, 'normal'), +(29, 9, 2, '研究人员利用VR技术帮助教师更好了解自闭症学生', 'hot,new', 'https://cdn.fastadmin.net/uploads/20180416/5ad44128db3ed0.png', '', '据外媒报道,研究人员正在利用VR技术帮助教师们了解自闭症学生进而能够真正地去帮助他们。近日,来自马耳他大学的一个研究小组决定通过VR技术帮助教师理解自闭症儿童的生活体验。通过利用自闭症儿童的音频和视觉技巧,研究团队开发出一个VR应用,它能模拟出自闭症儿童在教室里的体验情况。', 'AR,互联网', 29, 33, 0, 0, 0, '', 1523755471, 1523878608, 1523721600, NULL, 'normal'), +(30, 3, 1, '谷歌母公司继续投资清洁能源领域:或押注于电池', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412a357f60.jpg', '', '', '互联网,Google', 30, 6, 0, 0, 0, '', 1523895691, 1523895691, 1523894400, NULL, 'normal'), +(33, 3, 1, 'GitHub 去年为漏洞支付了 16.6 万美元赏金', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad4412a798700.jpg', '', '据外媒报道,去年,GitHub 向安全研究人员支付了总计 166495 美元的奖励,针对 GitHub 这个为期四年的“漏洞赏金”项目,安全研究人员会上报自己发现的系统问题和漏洞。2016 年,GitHub 一共支付了81.7万美元,而去年的支出总额显然已经翻了一倍多,几乎相当于前三年的总支出(17.7万美元)。在 2014 和 2015 两年时间里,他们一共支付了95.3万美元的奖金。', '互联网,安全', 33, 16, 0, 1, 1, '', 1523895893, 1523895893, 1523894400, NULL, 'normal'), +(34, 7, 1, 'Leap Motion AR头显看起来很疯狂但可能是奇迹', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44129495250.jpg', '', '本周我们正在研究Leap Motion为增强现实带来的新东西。我们已经看到他们之前创造了一些令人难以置信的技术,尤其是当涉及到运动跟踪和控制时。现在看起来他们认为他们是以面向优先的方式进入AR增强现实世界。', '互联网,AR', 34, 27, 0, 2, 0, '', 1523895990, 1523895990, 1523894400, NULL, 'normal'), +(35, 7, 1, '研究人员利用VR技术帮助教师更好了解自闭症学生', '', 'https://cdn.fastadmin.net/uploads/20180416/5ad44128db3ed0.png', '', '据外媒报道,研究人员正在利用VR技术帮助教师们了解自闭症学生进而能够真正地去帮助他们。近日,来自马耳他大学的一个研究小组决定通过VR技术帮助教师理解自闭症儿童的生活体验。通过利用自闭症儿童的音频和视觉技巧,研究团队开发出一个VR应用,它能模拟出自闭症儿童在教室里的体验情况。', '智能设备,AR', 35, 148, 0, 20, 14, '', 1523896040, 1523896040, 1523894400, NULL, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_block` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_block` ( + `id` smallint(8) UNSIGNED NOT NULL AUTO_INCREMENT, + `type` varchar(30) NOT NULL DEFAULT '' COMMENT '类型', + `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称', + `title` varchar(100) NOT NULL DEFAULT '' COMMENT '标题', + `image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片', + `url` varchar(100) NOT NULL DEFAULT '' COMMENT '链接', + `content` mediumtext COMMENT '内容', + `createtime` int(10) DEFAULT NULL COMMENT '添加时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='区块表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_block` +-- + +INSERT INTO `__PREFIX__cms_block` (`id`, `type`, `name`, `title`, `image`, `url`, `content`, `createtime`, `updatetime`, `status`) VALUES +(1, 'focus', 'focus', '幻灯图片1', '/assets/addons/cms/img/focus/1.jpg', 'http://www.fastadmin.net', '111', 0, 0, 'normal'), +(2, 'focus', 'focus', '幻灯图片2', '/assets/addons/cms/img/focus/2.jpg', 'http://www.fastadmin.net', '222', 0, 0, 'normal'), +(3, 'focus', 'focus', '幻灯图片3', '/assets/addons/cms/img/focus/3.jpg', 'http://www.fastadmin.net', '333', 0, 0, 'normal'), +(4, 'other', 'contactus', '联系我们', '', '', '', 0, 0, 'normal'), +(6, 'other', 'footer', '底部链接', '', '', '
                  \n
                  \n \n
                  \n

                  © 2017. All Rights Reserved.
                  \n FastAdmin\n
                  \n

                  \n
                  \n
                  \n
                  \n \n
                  \n \n
                  \n
                  \n \n
                  \n
                  \n
                  \n
                  \n
                  \n \n \n \n
                  \n
                  ', 0, 0, 'normal'), +(7, 'other', 'bannerad', '通栏广告', '/assets/addons/cms/img/banner/1.jpg', 'http://www.fastadmin.net', '', 0, 0, 'normal'), +(8, 'other', 'sidebarad1', '边栏广告1', '/assets/addons/cms/img/sidebar/1.jpg', 'http://www.fastadmin.net', '', 0, 0, 'normal'), +(9, 'other', 'sidebarad2', '边栏广告2', '/assets/addons/cms/img/sidebar/2.jpg', 'http://www.fastadmin.net', '', 0, 0, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_channel` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_channel` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `type` enum('channel','page','link','list') NOT NULL COMMENT '类型', + `model_id` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '模型ID', + `parent_id` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '父ID', + `name` varchar(30) NOT NULL DEFAULT '' COMMENT '名称', + `image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片', + `flag` set('hot','new','recommend') DEFAULT '' COMMENT '标志', + `keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字', + `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述', + `diyname` varchar(30) NOT NULL DEFAULT '' COMMENT '自定义名称', + `outlink` varchar(255) NOT NULL DEFAULT '' COMMENT '外部链接', + `items` mediumint(8) UNSIGNED NOT NULL DEFAULT '0' COMMENT '文章数量', + `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', + `channeltpl` varchar(100) NOT NULL DEFAULT '' COMMENT '栏目页模板', + `listtpl` varchar(100) NOT NULL DEFAULT '' COMMENT '列表页模板', + `showtpl` varchar(100) NOT NULL DEFAULT '' COMMENT '详情页模板', + `pagesize` smallint(5) NOT NULL DEFAULT '0' COMMENT '分页大小', + `createtime` int(10) DEFAULT NULL COMMENT '创建时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态', + PRIMARY KEY (`id`), + UNIQUE KEY `diyname` (`diyname`), + KEY `weigh` (`weigh`,`id`), + KEY `parent_id` (`parent_id`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8 COMMENT='栏目表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_channel` +-- + +INSERT INTO `__PREFIX__cms_channel` (`id`, `type`, `model_id`, `parent_id`, `name`, `image`, `flag`, `keywords`, `description`, `diyname`, `outlink`, `items`, `weigh`, `channeltpl`, `listtpl`, `showtpl`, `pagesize`, `createtime`, `updatetime`, `status`) VALUES +(1, 'channel', 1, 0, '新闻中心', '', '', '', '', 'news', '', 0, 9, 'channel.html', '', '', 10, 1508990697, 1508992553, 'normal'), +(2, 'channel', 1, 0, '产品中心', '', '', '', '', 'product', '', 0, 10, 'channel.html', '', '', 10, 1508992541, 1508992541, 'normal'), +(3, 'list', 1, 1, '互联网', '', 'recommend', '', '', 'internet', '', 8, 47, 'channel.html', 'list_news.html', 'show_news.html', 10, 1523718032, 1523718032, 'normal'), +(4, 'list', 1, 1, ' 安全', '', 'recommend', '', '', 'security', '', 8, 5, 'channel.html', 'list_news.html', 'show_news.html', 10, 1508990707, 1523720840, 'normal'), +(5, 'list', 1, 1, '投资', '', 'recommend', '', '', 'investment', '', 8, 8, 'channel.html', 'list_news.html', 'show_news.html', 10, 1508990716, 1523717837, 'normal'), +(7, 'list', 1, 1, '硬件', '', 'recommend', '', '', 'hardware', '', 9, 46, 'channel.html', 'list_news.html', 'show_news.html', 10, 1523717893, 1523717893, 'normal'), +(8, 'list', 2, 2, '可穿戴设备', '', '', '', '', 'wearable', '', 2, 4, 'channel.html', 'list_product.html', 'show_product.html', 10, 1508992598, 1523718084, 'normal'), +(9, 'list', 2, 2, 'VR/AR', '', '', '', '', 'vrar', '', 2, 7, 'channel.html', 'list_product.html', 'show_product.html', 10, 1508992623, 1523718179, 'normal'), +(10, 'list', 2, 2, '智能家居', '', 'recommend', '', '', 'smarthome', '', 2, 44, 'channel.html', 'list_product.html', 'show_product.html', 10, 1522157583, 1523718113, 'normal'), +(40, 'link', 1, 0, '关于我们', '', '', '', '', 'aboutus', '/cms/p/aboutus.html', 0, 1, 'channel.html', '', '', 10, 1508994681, 1508994681, 'normal'), +(41, 'link', 1, 0, '官网首页', '', '', '', '', 'official', 'http://www.fastadmin.net', 0, 6, 'channel.html', '', '', 10, 1508994753, 1508994753, 'normal'), +(42, 'link', 1, 0, '交流社区', '', '', '', '', 'forum', 'http://forum.fastadmin.net', 0, 3, 'channel.html', '', '', 10, 1508994772, 1508994772, 'normal'), +(43, 'link', 1, 0, '文档', '', '', '', '', 'docs', 'http://doc.fastadmin.net', 0, 2, 'channel.html', '', '', 10, 1508994788, 1508994788, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_comment` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_comment` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', + `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '会员ID', + `type` enum('archives','page') NOT NULL DEFAULT 'archives' COMMENT '类型', + `aid` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '关联ID', + `pid` int(10) NOT NULL DEFAULT '0' COMMENT '父ID', + `content` text COMMENT '内容', + `comments` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '评论数', + `ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP', + `useragent` varchar(255) NOT NULL DEFAULT '' COMMENT 'User Agent', + `subscribe` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '订阅', + `createtime` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间', + `updatetime` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '更新时间', + `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态', + PRIMARY KEY (`id`), + KEY `post_id` (`aid`,`pid`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='评论表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_comment` +-- + +INSERT INTO `__PREFIX__cms_comment` (`id`, `user_id`, `type`, `aid`, `pid`, `content`, `comments`, `ip`, `useragent`, `subscribe`, `createtime`, `updatetime`, `status`) VALUES +(1, 1, 'archives', 27, 0, '这是测试内容。', 0, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 0, 1523758108, 1523758108, 'normal'), +(2, 1, 'archives', 27, 0, '我是测试评论内容。', 0, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 0, 1523796231, 1523796231, 'normal'), +(3, 1, 'archives', 27, 2, '测试回复他人内容!', 0, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 0, 1523796706, 1523796706, 'normal'), +(4, 1, 'archives', 27, 0, '测试评论内容', 0, '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36', 0, 1523805202, 1523805202, 'normal'), +(5, 1, 'archives', 27, 0, '测试评论内容', 0, '127.0.0.1', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechatdevtools/1.02.1804120 MicroMessenger/6.5.7 Language/zh_CN webview/', 0, 1523806163, 1523806163, 'normal'), +(6, 1, 'archives', 27, 0, '测试评论内容2', 0, '127.0.0.1', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechatdevtools/1.02.1804120 MicroMessenger/6.5.7 Language/zh_CN webview/', 0, 1523806277, 1523806277, 'normal'), +(7, 1, 'archives', 27, 0, '测试评论内容22', 0, '127.0.0.1', 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 wechatdevtools/1.02.1804120 MicroMessenger/6.5.7 Language/zh_CN webview/', 0, 1523806323, 1523806323, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_fields` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_fields` ( + `id` smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT, + `model_id` int(10) NOT NULL DEFAULT '0' COMMENT '模型ID', + `name` char(30) NOT NULL DEFAULT '' COMMENT '名称', + `type` varchar(30) NOT NULL DEFAULT '' COMMENT '类型', + `title` varchar(30) NOT NULL DEFAULT '' COMMENT '标题', + `content` text COMMENT '内容', + `defaultvalue` varchar(100) NOT NULL DEFAULT '' COMMENT '默认值', + `rule` varchar(100) DEFAULT '' COMMENT '验证规则', + `msg` varchar(30) DEFAULT '0' COMMENT '错误消息', + `ok` varchar(30) DEFAULT '0' COMMENT '成功消息', + `tip` varchar(30) DEFAULT '' COMMENT '提示消息', + `decimals` tinyint(1) DEFAULT NULL COMMENT '小数点', + `length` mediumint(8) DEFAULT NULL COMMENT '长度', + `minimum` smallint(6) DEFAULT NULL COMMENT '最小数量', + `maximum` smallint(6) UNSIGNED NOT NULL DEFAULT '0' COMMENT '最大数量', + `extend` varchar(255) NOT NULL DEFAULT '' COMMENT '扩展信息', + `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '排序', + `createtime` int(10) DEFAULT NULL COMMENT '添加时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `isfilter` tinyint(1) NOT NULL DEFAULT '0' COMMENT '筛选', + `status` enum('normal','hidden') NOT NULL COMMENT '状态', + PRIMARY KEY (`id`), + KEY `model_id` (`model_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=140 DEFAULT CHARSET=utf8 COMMENT='模型字段表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_fields` +-- + +INSERT INTO `__PREFIX__cms_fields` (`id`, `model_id`, `name`, `type`, `title`, `content`, `defaultvalue`, `rule`, `msg`, `ok`, `tip`, `decimals`, `length`, `minimum`, `maximum`, `extend`, `weigh`, `createtime`, `updatetime`, `isfilter`, `status`) VALUES +(136, 1, 'author', 'string', '作者', 'value1|title1\r\nvalue2|title2', '', '', '', '', '', 0, 255, 0, 0, '', 136, 1508990735, 1508991985, 1, 'normal'), +(137, 1, 'area', 'select', '地区', 'domestic|国内\r\noverseas|国外\r\nlocal|本地', '', '', '', '', '', 0, 255, 0, 0, '', 137, 1508990746, 1523723221, 1, 'normal'), +(138, 1, 'device', 'radio', '设备', 'vr|智能设备\r\nar|虚拟设备', '', 'required', '', '', '', 0, 255, 0, 0, '', 138, 1508992093, 1508992093, 1, 'normal'), +(139, 2, 'productdata', 'images', '产品列表', 'value1|title1\r\nvalue2|title2', '', 'required', '', '', '', 0, 1500, 0, 20, '', 139, 1508992518, 1508992518, 1, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_model` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_model` ( + `id` smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT, + `name` char(30) NOT NULL DEFAULT '' COMMENT '模型名称', + `table` char(20) NOT NULL DEFAULT '' COMMENT '表名', + `fields` text COMMENT '字段列表', + `channeltpl` varchar(30) NOT NULL DEFAULT '' COMMENT '栏目页模板', + `listtpl` varchar(30) NOT NULL DEFAULT '' COMMENT '列表页模板', + `showtpl` varchar(30) NOT NULL DEFAULT '' COMMENT '详情页模板', + `createtime` int(10) DEFAULT NULL COMMENT '创建时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `setting` text COMMENT '模型配置', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='内容模型表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_model` +-- + +INSERT INTO `__PREFIX__cms_model` (`id`, `name`, `table`, `fields`, `channeltpl`, `listtpl`, `showtpl`, `createtime`, `updatetime`, `setting`) VALUES +(1, '新闻', 'cms_addonnews', 'author,area,device', 'channel.html', 'list_news.html', 'show_news.html', 1508990659, 1523723221, ''), +(2, '产品', 'cms_addonproduct', 'productdata', 'channel.html', 'list_product.html', 'show_product.html', 1508992445, 1508992445, ''); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_page` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_page` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', + `category_id` int(10) NOT NULL DEFAULT '0' COMMENT '分类ID', + `type` varchar(50) NOT NULL DEFAULT '' COMMENT '类型', + `title` varchar(50) NOT NULL DEFAULT '' COMMENT '标题', + `keywords` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字', + `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述', + `flag` set('hot','index','recommend') NOT NULL DEFAULT '' COMMENT '标志', + `image` varchar(255) NOT NULL DEFAULT '' COMMENT '头像', + `content` text COMMENT '内容', + `icon` varchar(50) NOT NULL DEFAULT '' COMMENT '图标', + `views` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '点击', + `comments` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '评论', + `diyname` varchar(50) NOT NULL DEFAULT '' COMMENT '自定义', + `showtpl` varchar(50) NOT NULL DEFAULT '' COMMENT '视图模板', + `createtime` int(10) DEFAULT NULL COMMENT '创建时间', + `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', + `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', + `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态', + PRIMARY KEY (`id`), + KEY `type` (`type`) +) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='单页表' ROW_FORMAT=COMPACT; + +-- +-- 转存表中的数据 `__PREFIX__cms_page` +-- + +INSERT INTO `__PREFIX__cms_page` (`id`, `category_id`, `type`, `title`, `keywords`, `description`, `flag`, `image`, `content`, `icon`, `views`, `comments`, `diyname`, `showtpl`, `createtime`, `updatetime`, `weigh`, `status`) VALUES +(28, 0, 'page', '基于ThinkPHP5和Bootstrap的极速后台开发框架', '', '', '', 'fds', '

                  基于ThinkPHP5和Bootstrap进行二次开发,手机、平板、PC均自动适配,无需要担心兼容性问题

                  ', '', 0, 0, 'aboutus', 'page', 1508933935, 1508934150, 28, 'normal'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `__PREFIX__cms_tags` +-- + +CREATE TABLE IF NOT EXISTS `__PREFIX__cms_tags` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL DEFAULT '' COMMENT '标签名称', + `archives` text COMMENT '文档ID集合', + `nums` int(10) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) USING BTREE, + KEY `nums` (`nums`) +) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 COMMENT='标签表'; + +-- +-- 转存表中的数据 `__PREFIX__cms_tags` +-- + +INSERT INTO `__PREFIX__cms_tags` (`id`, `name`, `archives`, `nums`) VALUES +(1, '驰为', '1', 1), +(2, 'HiGame', '1', 1), +(3, 'PC', '1', 1), +(4, '宏基', '2', 1), +(5, '台式机', '2', 1), +(6, 'Chromebox', '2', 1), +(7, '智能手表', '3', 1), +(8, '混合动力', '3', 1), +(9, '耳返', '4', 1), +(10, '智能设备', '4,6,7,13,35', 5), +(11, '电池', '5', 1), +(12, '南孚', '5', 1), +(13, '眼镜', '7', 1), +(14, 'dropbox', '8,9,10', 3), +(15, '投资', '8,9', 2), +(16, '互联网', '11,15,16,18,19,20,21,22,23,24,25,26,27,28,29,32,31,33,34', 19), +(17, '云计算', '11,12,17', 3), +(18, '安全', '12,14,15,16,17,18,26,27,33', 9), +(19, 'Google', '19,20,21,22,23,24,25,32,31', 9), +(20, 'AR', '28,29,34,35', 4), +(21, 'VR', '28', 1); +COMMIT; \ No newline at end of file diff --git a/addons/cms/lang/zh-cn.php b/addons/cms/lang/zh-cn.php new file mode 100644 index 0000000000000000000000000000000000000000..44bc7d208e327dd6c5286f3fdd1bbe0ab815a86e --- /dev/null +++ b/addons/cms/lang/zh-cn.php @@ -0,0 +1,49 @@ + '首页', + 'Default' => '默认', + 'Views' => '浏览次数', + 'Post date' => '发布日期', + 'All' => '全部', + 'Hot news' => '热门资讯', + 'Hot tags' => '热门标签', + 'Recommend news' => '推荐资讯', + 'Comments' => '评论', + 'Tags' => '标签', + 'View more' => '查看更多', + 'View detail' => '查看详情', + 'Month' => '月', + 'Prev' => '上一篇', + 'Next' => '下一篇', + 'Comment list' => '评论列表', + 'Favourite' => '收藏', + 'Share' => '分享', + 'Report' => '举报', + 'Error report' => '错误反馈', + 'Recently update' => '最新更新', + 'All categories' => '所有分类', + 'Article category' => '本文分类', + 'Article tags' => '本文标签', + 'Article views' => '浏览次数', + 'Article url' => '本文链接', + 'Search for %s' => '查找 “%s”', + 'Search more %s' => '查找更多 “%s”', + 'Empty' => '暂无内容', + 'No specified article found' => '未找到指定的文章', + 'No specified channel found' => '未找到指定的栏目', + 'No specified model found' => '未找到指定的模型', + 'No specified tags found' => '未找到指定的标签', + 'No specified addon article found' => '未找到指定副表数据', + 'Operation completed' => '操作成功!', + 'Operation failed' => '操作失败!', + 'Unknown data format' => '未知的数据格式!', + 'Network error' => '网络错误!', + '%d second%s ago' => '%d秒前', + '%d minute%s ago' => '%d分钟前', + '%d hour%s ago' => '%d小时前', + '%d day%s ago' => '%d天前', + '%d week%s ago' => '%d周前', + '%d month%s ago' => '%d月前', + '%d year%s ago' => '%d年前' +]; diff --git a/addons/cms/library/Alter.php b/addons/cms/library/Alter.php new file mode 100644 index 0000000000000000000000000000000000000000..27837f78b04795a8b6146daec142ba544a03224a --- /dev/null +++ b/addons/cms/library/Alter.php @@ -0,0 +1,176 @@ + '', + 'oldname' => '', + 'name' => '', + 'type' => 'VARCHAR', + 'length' => '255', + 'content' => '', + 'comment' => '', + 'after' => '', + ]; + + public function __construct($options = []) + { + $this->options = array_merge($this->config, $options); + } + + public static function instance($options = []) + { + if (is_null(self::$instance)) { + self::$instance = new static($options); + } + + return self::$instance; + } + + public function setTable($table) + { + $this->data['table'] = db()->name($table)->getTable(); + return $this; + } + + public function setType($type) + { + switch ($type) { + case 'checkbox': + case 'selects': + $this->data['type'] = 'SET'; + break; + case 'radio': + case 'select': + $this->data['type'] = 'ENUM'; + break; + case 'number': + $this->data['type'] = 'INT'; + break; + case 'date': + case 'datetime': + case 'time': + $this->data['type'] = strtoupper($type); + break; + case 'editor': + $this->data['type'] = 'TEXT'; + break; + default: + $this->data['type'] = 'VARCHAR'; + break; + } + return $this; + } + + public function setOldname($oldname) + { + $this->data['oldname'] = $oldname; + return $this; + } + + public function setName($name) + { + $this->data['name'] = $name; + return $this; + } + + public function setLength($length) + { + $this->data['length'] = $length; + return $this; + } + + public function setContent($content) + { + $this->data['content'] = $content; + return $this; + } + + public function setComment($comment) + { + $this->data['comment'] = $comment; + return $this; + } + + public function setDefaultvalue($defaultvalue) + { + $this->data['defaultvalue'] = $defaultvalue; + return $this; + } + + public function setDecimals($decimals) + { + $this->data['decimals'] = $decimals; + return $this; + } + + protected function process() + { + if ($this->data['type'] == 'INT') { + if ($this->data['decimals'] > 0) { + $this->data['type'] = 'DECIMAL'; + $this->data['length'] = "({$this->data['length']},{$this->data['decimals']})"; + } else { + $this->data['length'] = "({$this->data['length']})"; + } + } else if (in_array($this->data['type'], ['SET', 'ENUM'])) { + $content = \app\common\model\Config::decode($this->data['content']); + $this->data['length'] = "('" . implode("','", array_keys($content)) . "')"; + $this->data['defaultvalue'] = in_array($this->data['defaultvalue'], array_keys($content)) ? $this->data['defaultvalue'] : ($this->data['type'] == 'ENUM' ? key($content) : ''); + } else if (in_array($this->data['type'], ['DATE', 'TIME', 'DATETIME'])) { + $this->data['length'] = ''; + $this->data['defaultvalue'] = "NULL"; + } else if (in_array($this->data['type'], ['TEXT'])) { + $this->data['length'] = "(0)"; + $this->data['defaultvalue'] = 'NULL'; + } else { + $this->data['length'] = "({$this->data['length']})"; + } + $this->data['defaultvalue'] = strtoupper($this->data['defaultvalue']) === 'NULL' ? "NULL" : "'{$this->data['defaultvalue']}'"; + } + + /** + * 获取添加字段的SQL + * @return string + */ + public function getAddSql() + { + $this->process(); + + $sql = "ALTER TABLE `{$this->data['table']}` " + . "ADD `{$this->data['name']}` {$this->data['type']} {$this->data['length']} " + . "DEFAULT {$this->data['defaultvalue']} " + . "COMMENT '{$this->data['comment']}' " + . ($this->data['after'] ? "AFTER `{$this->data['after']}`" : ''); + return $sql; + } + + public function getModifySql() + { + $this->process(); + + $sql = "ALTER TABLE `{$this->data['table']}` " + . ($this->data['oldname'] ? 'CHANGE' : 'MODIFY') . " COLUMN " . ($this->data['oldname'] ? "`{$this->data['oldname']}`" : '') . " `{$this->data['name']}` {$this->data['type']} {$this->data['length']} " + . "DEFAULT {$this->data['defaultvalue']} " + . "COMMENT '{$this->data['comment']}' " + . ($this->data['after'] ? "AFTER `{$this->data['after']}`" : ''); + return $sql; + } + + /** + * 获取删除字段的SQL + * @return string + */ + public function getDropSql() + { + $sql = "ALTER TABLE `{$this->data['table']}` " + . "DROP `{$this->data['name']}`"; + return $sql; + } + +} diff --git a/addons/cms/library/Bootstrap.php b/addons/cms/library/Bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..968503adf9760f4c5382a97b228ce879e2972991 --- /dev/null +++ b/addons/cms/library/Bootstrap.php @@ -0,0 +1,210 @@ + +// +---------------------------------------------------------------------- + +namespace addons\cms\library; + +use think\Paginator; + +class Bootstrap extends Paginator +{ + + /** + * 上一页按钮 + * @param string $text + * @return string + */ + protected function getPreviousButton($text = "«") + { + + if ($this->currentPage() <= 1) { + return $this->getDisabledTextWrapper($text); + } + + $url = $this->url( + $this->currentPage() - 1 + ); + + return $this->getPageLinkWrapper($url, $text); + } + + /** + * 下一页按钮 + * @param string $text + * @return string + */ + protected function getNextButton($text = '»') + { + if (!$this->hasMore) { + return $this->getDisabledTextWrapper($text); + } + + $url = $this->url($this->currentPage() + 1); + + return $this->getPageLinkWrapper($url, $text); + } + + /** + * 页码按钮 + * @return string + */ + protected function getLinks() + { + 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($params = null) + { + if(is_array($params)){ + if(isset($params['type'])){ + $this->simple = $params['type'] === 'simple'; + } + } + 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 int $page + * @return string + */ + protected function getAvailablePageWrapper($url, $page) + { + return '
                • ' . $page . '
                • '; + } + + /** + * 生成一个禁用的按钮 + * + * @param string $text + * @return string + */ + protected function getDisabledTextWrapper($text) + { + return '
                • ' . $text . '
                • '; + } + + /** + * 生成一个激活的按钮 + * + * @param string $text + * @return string + */ + protected function getActivePageWrapper($text) + { + return '
                • ' . $text . '
                • '; + } + + /** + * 生成省略号按钮 + * + * @return string + */ + protected function getDots() + { + return $this->getDisabledTextWrapper('...'); + } + + /** + * 批量生成页码按钮. + * + * @param array $urls + * @return string + */ + protected function getUrlLinks(array $urls) + { + $html = ''; + + foreach ($urls as $page => $url) { + $html .= $this->getPageLinkWrapper($url, $page); + } + + return $html; + } + + /** + * 生成普通页码按钮 + * + * @param string $url + * @param int $page + * @return string + */ + protected function getPageLinkWrapper($url, $page) + { + if ($page == $this->currentPage()) { + return $this->getActivePageWrapper($page); + } + + return $this->getAvailablePageWrapper($url, $page); + } +} diff --git a/addons/cms/model/Archives.php b/addons/cms/model/Archives.php new file mode 100644 index 0000000000000000000000000000000000000000..1225228b7fc91f59a24cb2759ca6caf7ff0c510d --- /dev/null +++ b/addons/cms/model/Archives.php @@ -0,0 +1,318 @@ +data = array_merge($this->data, $data); + return $this; + } + + protected static function init() + { + $config = get_addon_config('cms'); + self::$config = $config; + } + + public function getCreateDateAttr($value, $data) + { + return human_date($data['createtime']); + } + + public function getImageAttr($value, $data) + { + $value = $value ? $value : self::$config['default_archives_img']; + return cdnurl($value, true); + } + + public function getTagslistAttr($value, $data) + { + $list = []; + foreach (array_filter(explode(",", $data['tags'])) as $k => $v) { + $list[] = ['name' => $v, 'url' => addon_url('cms/tags/index', [':name' => $v])]; + } + return $list; + } + + public function getUrlAttr($value, $data) + { + $diyname = $data['diyname'] ? $data['diyname'] : $data['id']; + return addon_url('cms/archives/index', [':id' => $data['id'], ':diyname' => $diyname, ':channel' => $data['channel_id']]); + } + + public function getFullUrlAttr($value, $data) + { + $diyname = $data['diyname'] ? $data['diyname'] : $data['id']; + return addon_url('cms/archives/index', [':id' => $data['id'], ':diyname' => $diyname, ':channel' => $data['channel_id']], true, true); + } + + public function getLikeratioAttr($value, $data) + { + return ($data['dislikes'] > 0 ? min(1, $data['likes'] / ($data['dislikes'] + $data['likes'])) : ($data['likes'] ? 1 : 0.5)) * 100; + } + + /** + * 获取文档列表 + * @param $tag + * @return array|false|\PDOStatement|string|\think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getArchivesList($tag) + { + $type = empty($tag['type']) ? '' : $tag['type']; + $model = !isset($tag['model']) ? '' : $tag['model']; + $channel = !isset($tag['channel']) ? '' : $tag['channel']; + $tags = empty($tag['tags']) ? '' : $tag['tags']; + $condition = empty($tag['condition']) ? '' : $tag['condition']; + $field = empty($params['field']) ? '*' : $params['field']; + $flag = empty($tag['flag']) ? '' : $tag['flag']; + $row = empty($tag['row']) ? 10 : (int)$tag['row']; + $orderby = empty($tag['orderby']) ? 'createtime' : $tag['orderby']; + $orderway = empty($tag['orderway']) ? 'desc' : strtolower($tag['orderway']); + $limit = empty($tag['limit']) ? $row : $tag['limit']; + $cache = !isset($tag['cache']) ? true : (int)$tag['cache']; + $imgwidth = empty($tag['imgwidth']) ? '' : $tag['imgwidth']; + $imgheight = empty($tag['imgheight']) ? '' : $tag['imgheight']; + $addon = empty($tag['addon']) ? false : $tag['addon']; + $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc'; + $where = ['status' => 'normal']; + + $where['deletetime'] = ['exp', Db::raw('IS NULL')]; //by erastudio + if ($model !== '') { + $where['model_id'] = ['in', $model]; + } + if ($channel !== '') { + $where['channel_id'] = ['in', $channel]; + } + //如果有设置标志,则拆分标志信息并构造condition条件 + if ($flag !== '') { + if (stripos($flag, '&') !== false) { + $arr = []; + foreach (explode('&', $flag) as $k => $v) { + $arr[] = "FIND_IN_SET('{$v}', flag)"; + } + if ($arr) + $condition .= "(" . implode(' AND ', $arr) . ")"; + } else { + $condition .= ($condition ? ' AND ' : ''); + $arr = []; + foreach (array_merge(explode(',', $flag), explode('|', $flag)) as $k => $v) { + $arr[] = "FIND_IN_SET('{$v}', flag)"; + } + if ($arr) + $condition .= "(" . implode(' OR ', $arr) . ")"; + } + } + $order = $orderby == 'rand' ? 'rand()' : (in_array($orderby, ['createtime', 'updatetime', 'views', 'weigh', 'id']) ? "{$orderby} {$orderway}" : "createtime {$orderway}"); + + $archivesModel = self::with('channel'); + // 如果有筛选标签,则采用子查询 + if ($tags) { + $tagsList = Tags::where('name', 'in', explode(',', $tags))->cache($cache)->limit($limit)->select(); + $archives = []; + foreach ($tagsList as $k => $v) { + $archives = array_merge($archives, explode(',', $v['archives'])); + } + if ($archives) { + $archivesModel->where('id', 'in', $archives); + } + } + $list = $archivesModel + ->where($where) + ->where($condition) + ->field($field) + ->cache($cache) + ->order($order) + ->limit($limit) + ->select(); + //$list = collection($list)->toArray(); + //如果有设置附表和模型(或栏目),则查询副表的数据 + if ($addon && (is_numeric($model) || $channel)) { + if ($channel) { + //如果channel设置了多个值则只取第一个作为判断 + $channelArr = explode(',', $channel); + $channelinfo = Channel::get($channelArr[0]); + $model = $channelinfo ? $channelinfo['model_id'] : $model; + } + // 查询相关联的模型信息 + $modelInfo = Modelx::get($model, [], true); + if ($modelInfo) { + $query = Db::name($modelInfo['table']); + if ($addon == 'true') { + $query->field('content', true); + } else { + $query->field($addon); + } + $addonList = $query + ->where('id', 'in', array_map(function ($value) { + return $value['id']; + }, $list)) + ->cache($cache) + ->select(); + $fieldsContentList = []; + if ($modelInfo->fields) { + $fieldsContentList = $modelInfo->getFieldsContentList($modelInfo->id); + } + + //循环主表 + foreach ($list as $index => &$item) { + //循环副表 + foreach ($addonList as $subindex => $subitem) { + if ($subitem['id'] == $item['id']) { + array_walk($fieldsContentList, function ($content, $field) use (&$subitem) { + $subitem[$field . '_text'] = isset($content[$subitem[$field]]) ? $content[$subitem[$field]] : $subitem[$field]; + }); + //$item = array_merge($item, $subitem); + $item->setData($subitem); + unset($addonList[$subindex]); + continue 2; + } + } + //副表错误的数据将会被忽略 + unset($list[$index]); + } + unset($item); + } + } + + self::render($list, $imgwidth, $imgheight); + return $list; + } + + /** + * 渲染数据 + * @param array $list + * @param int $imgwidth + * @param int $imgheight + * @return array + */ + public static function render(&$list, $imgwidth, $imgheight) + { + $width = $imgwidth ? 'width="' . $imgwidth . '"' : ''; + $height = $imgheight ? 'height="' . $imgheight . '"' : ''; + foreach ($list as $k => &$v) { + $v['hasimage'] = $v['image'] ? true : false; + $v['textlink'] = '' . $v['title'] . ''; + $v['channellink'] = '' . $v['channel']['name'] . ''; + $v['imglink'] = ''; + $v['img'] = ''; + } + return $list; + } + + /** + * 获取分页列表 + * @param array $list + * @param array $tag + * @return array + */ + public static function getPageList($list, $tag) + { + $imgwidth = empty($tag['imgwidth']) ? '' : $tag['imgwidth']; + $imgheight = empty($tag['imgheight']) ? '' : $tag['imgheight']; + return self::render($list, $imgwidth, $imgheight); + } + + /** + * 获取分页信息 + * @param array $list + * @param array $tag + * @return string + */ + public static function getPageInfo($list, $tag) + { + return ''; + } + + /** + * 获取分页过滤 + * @param array $list + * @param array $tag + * @return array + */ + public static function getPageFilter($list, $tag) + { + $exclude = empty($tag['exclude']) ? '' : $tag['exclude']; + return $list; + } + + /** + * 获取分页排序 + * @param array $list + * @param array $tag + * @return array + */ + public static function getPageOrder($list, $tag) + { + $exclude = empty($tag['exclude']) ? '' : $tag['exclude']; + return $list; + } + + /** + * 获取上一页下一页 + * @param string $type + * @param string $archives + * @param string $channel + * @return array + */ + public static function getPrevNext($type, $archives, $channel) + { + $model = self::where('id', $type === 'prev' ? '<' : '>', $archives)->where('status', 'normal'); + if ($channel !== '') { + $model->where('channel_id', 'in', $channel); + } + $model->order($type === 'prev' ? 'id desc' : 'id asc'); + $row = $model->find(); + return $row; + } + + /** + * 关联栏目模型 + */ + public function channel() + { + return $this->belongsTo("Channel")->field('id,name,image,diyname,items')->setEagerlyType(1); + } + +} diff --git a/addons/cms/model/Block.php b/addons/cms/model/Block.php new file mode 100644 index 0000000000000000000000000000000000000000..c5f2b13eb01cd01d962e56fcd9113a9465ecfe46 --- /dev/null +++ b/addons/cms/model/Block.php @@ -0,0 +1,109 @@ +where($condition) + ->field($field) + ->order($order) + ->limit($limit) + ->cache($cache) + ->select(); + self::render($list, $imgwidth, $imgheight); + return $list; + } + + public static function render(&$list, $imgwidth, $imgheight) + { + $width = $imgwidth ? 'width="' . $imgwidth . '"' : ''; + $height = $imgheight ? 'height="' . $imgheight . '"' : ''; + foreach ($list as $k => &$v) { + $v['hasimage'] = $v->getData('image') ? true : false; + $v['textlink'] = '' . $v['title'] . ''; + $v['imglink'] = ''; + $v['img'] = ''; + } + return $list; + } + + public static function getBlockContent($params) + { + $field = isset($params['id']) ? 'id' : 'name'; + $value = isset($params[$field]) ? $params[$field] : ''; + $cache = !isset($params['cache']) ? true : (int)$params['cache']; + $row = self::where($field, $value) + ->cache($cache) + ->find(); + $result = ''; + if ($row) { + if ($row['content']) { + $result = $row['content']; + } else if ($row['image']) { + $result = ''; + } else { + $result = $row['title']; + } + if ($row['url'] && !$row['content']) { + $result = $row['url'] ? '' . $result . '' : $result; + } + } + return $result; + } + +} diff --git a/addons/cms/model/Channel.php b/addons/cms/model/Channel.php new file mode 100644 index 0000000000000000000000000000000000000000..f2d434637e94a94cf961f846190ab5bbc9f19efd --- /dev/null +++ b/addons/cms/model/Channel.php @@ -0,0 +1,253 @@ +belongsTo("Modelx"); + } + + public function getUrlAttr($value, $data) + { + $diyname = $data['diyname'] ? $data['diyname'] : $data['id']; + return isset($data['type']) && isset($data['outlink']) && $data['type'] == 'link' ? $data['outlink'] : addon_url('cms/channel/index', [':id' => $data['id'], ':diyname' => $diyname]); + } + + public function getFullurlAttr($value, $data) + { + $diyname = $data['diyname'] ? $data['diyname'] : $data['id']; + return isset($data['type']) && isset($data['outlink']) && $data['type'] == 'link' ? $data['outlink'] : addon_url('cms/channel/index', [':id' => $data['id'], ':diyname' => $diyname], true, true); + } + + public function getImageAttr($value, $data) + { + $value = $value ? $value : self::$config['default_channel_img']; + return cdnurl($value); + } + + public function getHasChildAttr($value, $data) + { + static $checked = []; + if (isset($checked[$data['id']])) { + return $checked[$data['id']]; + } + $list = self::where('parent_id', '>', 0)->field('parent_id')->cache(true)->select(); + foreach ($list as $k => $v) { + $checked[$v['parent_id']] = true; + } + if (isset($checked[$data['id']])) { + return $checked[$data['id']]; + } + return false; + } + + /** + * 获取栏目列表 + * @param $tag + * @return false|\PDOStatement|string|\think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getChannelList($tag) + { + $type = empty($tag['type']) ? '' : $tag['type']; + $typeid = !isset($tag['typeid']) ? '' : $tag['typeid']; + $model = !isset($tag['model']) ? '' : $tag['model']; + $condition = empty($tag['condition']) ? '' : $tag['condition']; + $field = empty($params['field']) ? '*' : $params['field']; + $row = empty($tag['row']) ? 10 : (int)$tag['row']; + $orderby = empty($tag['orderby']) ? 'weigh' : $tag['orderby']; + $orderway = empty($tag['orderway']) ? 'desc' : strtolower($tag['orderway']); + $limit = empty($tag['limit']) ? $row : $tag['limit']; + $cache = !isset($tag['cache']) ? true : (int)$tag['cache']; + $imgwidth = empty($tag['imgwidth']) ? '' : $tag['imgwidth']; + $imgheight = empty($tag['imgheight']) ? '' : $tag['imgheight']; + $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc'; + $where = ['status' => 'normal']; + + if ($type === 'top') { + //顶级分类 + $where['parent_id'] = 0; + } else if ($type === 'brother') { + $subQuery = self::where('id', 'in', $typeid)->field('parent_id')->buildSql(); + //同级 + $where['parent_id'] = ['exp', Db::raw(' IN ' . $subQuery)]; + } else if ($type === 'son') { + $subQuery = self::where('parent_id', 'in', $typeid)->field('id')->buildSql(); + //子级 + $where['id'] = ['exp', Db::raw(' IN ' . $subQuery)]; + } else if ($type === 'sons') { + //所有子级 + } else { + if ($typeid !== '') { + $where['id'] = ['in', $typeid]; + } + } + if ($model !== '') { + $where['model_id'] = ['in', $model]; + } + $order = $orderby == 'rand' ? 'rand()' : (in_array($orderby, ['createtime', 'updatetime', 'views', 'weigh', 'id']) ? "{$orderby} {$orderway}" : "createtime {$orderway}"); + $list = self::where($where) + ->where($condition) + ->field($field) + ->order($order) + ->limit($limit) + ->cache($cache) + ->select(); + self::render($list, $imgwidth, $imgheight); + return $list; + } + + /** + * 渲染数据 + * @param array $list + * @param int $imgwidth + * @param int $imgheight + * @return array + */ + public static function render(&$list, $imgwidth, $imgheight) + { + $width = $imgwidth ? 'width="' . $imgwidth . '"' : ''; + $height = $imgheight ? 'height="' . $imgheight . '"' : ''; + foreach ($list as $k => &$v) { + $v['hasimage'] = $v->getData('image') ? true : false; + $v['textlink'] = '' . $v['name'] . ''; + $v['channellink'] = '' . $v['name'] . ''; + $v['imglink'] = ''; + $v['img'] = ''; + } + return $list; + } + + /** + * 获取面包屑导航 + * @param array $channel + * @param array $archives + * @param array $tags + * @param array $page + * @return array + */ + public static function getBreadcrumb($channel, $archives = [], $tags = [], $page = []) + { + $list = []; + $list[] = ['name' => __('Home'), 'url' => addon_url('cms/index/index', [], false)]; + if ($channel) { + if ($channel['parent_id']) { + $channelList = self::where('status', 'normal') + ->order('weigh desc,id desc') + ->field('id,name,type,parent_id,diyname,outlink') + ->cache(true) + ->select(); + //获取栏目的所有上级栏目 + $parents = \fast\Tree::instance()->init(collection($channelList)->toArray(), 'parent_id')->getParents($channel['id']); + foreach ($parents as $k => $v) { + $list[] = ['name' => $v['name'], 'url' => $v['url']]; + } + } + $list[] = ['name' => $channel['name'], 'url' => $channel['url']]; + } + if ($archives) { + $list[] = ['name' => $archives['title'], 'url' => $archives['url']]; + } + if ($tags) { + $list[] = ['name' => $tags['name'], 'url' => $tags['url']]; + } + if ($page) { + $list[] = ['name' => $page['title'], 'url' => $page['url']]; + } + return $list; + } + + /** + * 获取导航栏目列表HTML + * @param $channel + * @param array $tag + * @return mixed|string + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getNav($channel, $tag = []) + { + $condition = empty($tag['condition']) ? '' : $tag['condition']; + $cache = !isset($tag['cache']) ? true : (int)$tag['cache']; + $maxLevel = !isset($tag['maxlevel']) ? 0 : $tag['maxlevel']; + $cacheName = 'nav-' . md5(serialize($tag)); + $result = Cache::get($cacheName); + if (!$result) { + $channelList = Channel::where($condition) + ->where('status', 'normal') + ->order('weigh desc,id desc') + ->cache($cache) + ->select(); + $tree = \fast\Tree::instance(); + $tree->init(collection($channelList)->toArray(), 'parent_id'); + $result = self::getTreeUl($tree, 0, $channel ? $channel['id'] : '', '', 1, $maxLevel); + Cache::set($cacheName, $result); + } + return $result; + } + + public static function getTreeUl($tree, $myid, $selectedids = '', $disabledids = '', $level = 1, $maxlevel = 0) + { + $str = ''; + $childs = $tree->getChild($myid); + if ($childs) { + foreach ($childs as $value) { + $id = $value['id']; + unset($value['child']); + $selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : ''; + $disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : ''; + $value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled)); + $value = array_combine(array_map(function ($k) { + return '@' . $k; + }, array_keys($value)), $value); + $itemtpl = '
                • @name @caret @childlist
                • '; + $nstr = strtr($itemtpl, $value); + $childlist = ''; + if (!$maxlevel || $level < $maxlevel) { + $childdata = self::getTreeUl($tree, $id, $selectedids, $disabledids, $level + 1, $maxlevel); + $childlist = $childdata ? '' : ""; + } + $str .= strtr($nstr, [ + '@childlist' => $childlist, + '@caret' => $childlist ? ($level == 1 ? '' : '') : '', + '@dropdown' => $childlist ? ($level == 1 ? 'dropdown' : 'dropdown-submenu') : '', + '@toggle' => $childlist ? 'dropdown' : '' + ]); + } + } + return $str; + } + +} diff --git a/addons/cms/model/Comment.php b/addons/cms/model/Comment.php new file mode 100644 index 0000000000000000000000000000000000000000..814c7512659118367ac65ec50ac0c551dd3dd4f3 --- /dev/null +++ b/addons/cms/model/Comment.php @@ -0,0 +1,193 @@ +filter('strip_tags'); + $useragent = $request->server('HTTP_USER_AGENT', ''); + $ip = $request->ip(); + $auth = Auth::instance(); + + if (!$auth->id) { + throw new Exception("请登录后发表评论"); + } + if (!isset($params['aid']) || !isset($params['content'])) { + throw new Exception("内容不能为空"); + } + + $params['user_id'] = $auth->id; + $params['type'] = isset($params['type']) ? $params['type'] : 'archives'; + $params['content'] = nl2br($params['content']); + + $archives = $params['type'] == 'archives' ? Archives::get($params['aid']) : Page::get($params['aid']); + if (!$archives || $archives['status'] == 'hidden') { + throw new Exception("文档未找到"); + } + + $rule = [ + 'type' => 'require|in:archives,page', + 'pid' => 'require|number', + 'user_id' => 'require|number', + 'content' => 'require|length:3,250', + '__token__' => 'token', + ]; + $validate = new Validate($rule); + $result = $validate->check($params); + if (!$result) { + throw new Exception($validate->getError()); + } + + //查找最后评论 + $lastComment = self::where(['type' => $params['type'], 'aid' => $params['aid'], 'ip' => $ip])->order('id', 'desc')->find(); + if ($lastComment && time() - $lastComment['createtime'] < 30) { + throw new Exception("对不起!您发表评论的速度过快!请稍微休息一下,喝杯咖啡"); + } + if ($lastComment && $lastComment['content'] == $params['content']) { + throw new Exception("您可能连续了相同的评论,请不要重复提交"); + } + $params['ip'] = $ip; + $params['useragent'] = $useragent; + $params['status'] = 'normal'; + (new static())->allowField(true)->save($params); + + $archives->setInc('comments'); + + if (isset($params['pid'])) { + //查找父评论,是否并发邮件通知 + $parentComment = self::get($params['pid'], 'user'); + if ($parentComment && $parentComment['subscribe'] && Validate::is($parentComment->user->email, 'email')) { + $domain = $request->domain(); + $config = get_addon_config('cms'); + $title = "{$parentComment->user->nickname},您发表在《{$archives['title']}》上的评论有了新回复 - {$config['sitename']}"; + $archivesurl = $domain . $archives['url']; + $unsubscribe_url = addon_url("cms/comment/unsubscribe", ['id' => $parentComment['id'], 'key' => md5($parentComment['id'] . $parentComment->user->email)], true, true); + $content = "亲爱的{$parentComment->user->nickname}:
                  您于" . date("Y-m-d H:i:s") . + "在《{$archives['title']}》上发表的评论
                  {$parentComment['content']}
                  " . + "
                  {$auth->nickname}发表了回复,内容是
                  {$params['content']}

                  您可以点击查看评论详情。" . + "

                  如果你不愿意再接受最新评论的通知,请点击这里取消"; + try { + $email = new Email; + $result = $email + ->to($parentComment->user->email) + ->subject($title) + ->message('
                  ' . $content . '
                  ') + ->send(); + } catch (\think\Exception $e) { + + } + } + } + return true; + } + + /** + * 获取评论列表 + * @param $params + * @return \think\Paginator + * @throws \think\exception\DbException + */ + public static function getCommentList($params) + { + $type = empty($params['type']) ? 'archives' : $params['type']; + $aid = empty($params['aid']) ? 0 : $params['aid']; + $pid = empty($params['pid']) ? 0 : $params['pid']; + $condition = empty($params['condition']) ? '' : $params['condition']; + $field = empty($params['field']) ? '*' : $params['field']; + $fragment = empty($params['fragment']) ? 'comments' : $params['fragment']; + $row = empty($params['row']) ? 10 : (int)$params['row']; + $orderby = empty($params['orderby']) ? 'nums' : $params['orderby']; + $orderway = empty($params['orderway']) ? 'desc' : strtolower($params['orderway']); + $pagesize = empty($params['pagesize']) ? $row : $params['pagesize']; + $cache = !isset($params['cache']) ? false : (int)$params['cache']; + $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc'; + + $where = []; + if ($type) { + $where['type'] = $type; + } + if ($aid !== '') { + $where['aid'] = $aid; + } + if ($pid) { + $where['pid'] = $pid; + } + $order = $orderby == 'rand' ? 'rand()' : (in_array($orderby, ['pid', 'id', 'createtime', 'updatetime']) ? "{$orderby} {$orderway}" : "id {$orderway}"); + + $list = self::with('user') + ->where($where) + ->where($condition) + ->field($field) + ->order($order) + ->cache($cache) + ->paginate($pagesize, false, ['type' => '\\addons\\cms\\library\\Bootstrap', 'var_page' => 'cp', 'fragment' => $fragment]); + self::render($list); + return $list; + } + + public static function render(&$list) + { + foreach ($list as $k => &$v) { + + } + return $list; + } + + /** + * 关联会员模型 + */ + public function user() + { + return $this->belongsTo("app\common\model\User")->field('id,nickname,avatar,email')->setEagerlyType(1); + } + + /** + * 关联文章模型 + */ + public function archives() + { + return $this->belongsTo("addons\cms\model\Archives", 'aid')->field('id,title,image,diyname,model_id,channel_id,likes,dislikes,tags,createtime')->setEagerlyType(1); + } + +} diff --git a/addons/cms/model/Fields.php b/addons/cms/model/Fields.php new file mode 100644 index 0000000000000000000000000000000000000000..3dc473218336b1f65c60edabc410f420e581c7c0 --- /dev/null +++ b/addons/cms/model/Fields.php @@ -0,0 +1,45 @@ +belongsTo('Modelx', 'model_id')->setEagerlyType(0); + } + +} diff --git a/addons/cms/model/Modelx.php b/addons/cms/model/Modelx.php new file mode 100644 index 0000000000000000000000000000000000000000..c42eaaf49e6c882c32cdfa3b9bc9234b10e1c3a8 --- /dev/null +++ b/addons/cms/model/Modelx.php @@ -0,0 +1,55 @@ +where('status', 'normal')->cache(true)->select(); + } + + public function getFieldsContentList($model_id) + { + $list = Fields::where('model_id', $model_id) + ->field('id,name,type,content') + ->where('status', 'normal') + ->cache(true) + ->select(); + $fieldsList = []; + $listFields = Fields::getListFields(); + foreach ($list as $index => $item) { + if (in_array($item['type'], $listFields)) { + $fieldsList[$item['name']] = $item['content_list']; + } + } + return $fieldsList; + } + +} diff --git a/addons/cms/model/Page.php b/addons/cms/model/Page.php new file mode 100644 index 0000000000000000000000000000000000000000..09f7e67383764d14f5459596b7223ce1cd611393 --- /dev/null +++ b/addons/cms/model/Page.php @@ -0,0 +1,101 @@ + $data['diyname']]); + } + + public function getFullurlAttr($value, $data) + { + return addon_url('cms/page/index', [':diyname' => $data['diyname']], true, true); + } + + /** + * 获取单页列表 + * @param $params + * @return false|\PDOStatement|string|\think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getPageList($params) + { + $name = empty($params['name']) ? '' : $params['name']; + $condition = empty($params['condition']) ? '' : $params['condition']; + $field = empty($params['field']) ? '*' : $params['field']; + $row = empty($params['row']) ? 10 : (int)$params['row']; + $orderby = empty($params['orderby']) ? 'nums' : $params['orderby']; + $orderway = empty($params['orderway']) ? 'desc' : strtolower($params['orderway']); + $limit = empty($params['limit']) ? $row : $params['limit']; + $cache = !isset($params['cache']) ? true : (int)$params['cache']; + $imgwidth = empty($params['imgwidth']) ? '' : $params['imgwidth']; + $imgheight = empty($params['imgheight']) ? '' : $params['imgheight']; + $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc'; + + $where = []; + if ($name !== '') { + $where['name'] = $name; + } + $order = $orderby == 'rand' ? 'rand()' : (in_array($orderby, ['name', 'id', 'createtime', 'updatetime']) ? "{$orderby} {$orderway}" : "id {$orderway}"); + + $list = self::where($where) + ->where($condition) + ->field($field) + ->order($order) + ->limit($limit) + ->cache($cache) + ->select(); + self::render($list, $imgwidth, $imgheight); + return $list; + } + + public static function render(&$list, $imgwidth, $imgheight) + { + $width = $imgwidth ? 'width="' . $imgwidth . '"' : ''; + $height = $imgheight ? 'height="' . $imgheight . '"' : ''; + foreach ($list as $k => &$v) { + $v['hasimage'] = $v->getData('image') ? true : false; + $v['textlink'] = '' . $v['title'] . ''; + $v['imglink'] = ''; + $v['img'] = ''; + } + return $list; + } + +} diff --git a/addons/cms/model/Tags.php b/addons/cms/model/Tags.php new file mode 100644 index 0000000000000000000000000000000000000000..13c8bc37a11ffe385b232a8f9380255898b78204 --- /dev/null +++ b/addons/cms/model/Tags.php @@ -0,0 +1,79 @@ +belongsTo("Modelx"); + } + + public function getUrlAttr($value, $data) + { + $name = $data['name'] ? $data['name'] : $data['id']; + return addon_url('cms/tags/index', [':id' => $data['id'], ':name' => $name]); + } + + public function getFullurlAttr($value, $data) + { + $name = $data['name'] ? $data['name'] : $data['id']; + return addon_url('cms/tags/index', [':id' => $data['id'], ':name' => $name], true, true); + } + + /** + * 获取标签列表 + * @param $tag + * @return false|\PDOStatement|string|\think\Collection + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getTagsList($tag) + { + $condition = empty($tag['condition']) ? '' : $tag['condition']; + $field = empty($params['field']) ? '*' : $params['field']; + $row = empty($tag['row']) ? 10 : (int)$tag['row']; + $orderby = empty($tag['orderby']) ? 'nums' : $tag['orderby']; + $orderway = empty($tag['orderway']) ? 'desc' : strtolower($tag['orderway']); + $limit = empty($tag['limit']) ? $row : $tag['limit']; + $cache = !isset($tag['cache']) ? true : (int)$tag['cache']; + $orderway = in_array($orderway, ['asc', 'desc']) ? $orderway : 'desc'; + + $where = []; + + $order = $orderby == 'rand' ? Db::raw('rand()') : (in_array($orderby, ['name', 'nums', 'id', 'createtime', 'updatetime']) ? "{$orderby} {$orderway}" : "nums {$orderway}"); + + $list = self::where($where) + ->where($condition) + ->field($field) + ->order($order) + ->limit($limit) + ->cache($cache) + ->select(); + foreach ($list as $k => $v) { + $v['textlink'] = '' . $v['name'] . ''; + } + return $list; + } + +} diff --git a/addons/cms/public/assets/js/backend/cms/archives.js b/addons/cms/public/assets/js/backend/cms/archives.js new file mode 100644 index 0000000000000000000000000000000000000000..845b86705f70366955ce54227aae21a2c3149a3d --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/archives.js @@ -0,0 +1,411 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/archives/index', + add_url: 'cms/archives/add', + edit_url: 'cms/archives/edit', + del_url: 'cms/archives/del', + multi_url: 'cms/archives/multi', + dragsort_url: '', + table: 'archives', + } + }); + + var table = $("#table"); + + //在表格内容渲染完成后回调的事件 + table.on('post-body.bs.table', function (e, settings, json, xhr) { + $(".btn-editone", this) + .off("click") + .removeClass("btn-editone") + .addClass("btn-addtabs") + .prop("title", __('Edit')); + }); + //当双击单元格时 + table.on('dbl-click-row.bs.table', function (e, row, element, field) { + $(".btn-addtabs", element).trigger("click"); + }); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'weigh', + searchFormVisible: Fast.api.query("model_id") ? true : false, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id'), sortable: true}, + { + field: 'model_id', + title: __('Model_id'), + visible: false, + addclass: 'selectpage', + extend: 'data-source="cms/modelx/index"', + formatter: Table.api.formatter.search + }, + { + field: 'channel_id', + title: __('Channel_id'), + visible: false, + addclass: 'selectpage', + extend: 'data-source="cms/channel/index"', + formatter: Table.api.formatter.search + }, + { + field: 'channel.name', + title: __('Channel'), + operate: false, + formatter: function (value, row, index) { + return '' + value + ''; + } + }, + { + field: 'title', title: __('Title'), align: 'left', formatter: function (value, row, index) { + return '
                  ' + value + '
                  ' + Table.api.formatter.flag.call(this, row['flag'], row, index); + } + }, + {field: 'image', title: __('Image'), operate: false, formatter: Table.api.formatter.image}, + {field: 'views', title: __('Views'), operate: 'BETWEEN', sortable: true}, + {field: 'comments', title: __('Comments'), operate: 'BETWEEN', sortable: true}, + {field: 'weigh', title: __('Weigh'), operate: false}, + { + field: 'url', title: __('Url'), operate: false, formatter: function (value, row, index) { + return ''; + } + }, + { + field: 'createtime', + title: __('Createtime'), + visible: false, + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'updatetime', + title: __('Updatetime'), + sortable: true, + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + {field: 'status', title: __('Status'), operate: false, formatter: Table.api.formatter.status}, + { + field: 'operate', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + + $(document).on("click", "a.btn-channel", function () { + $("#archivespanel").toggleClass("col-md-9", $("#channelbar").hasClass("hidden")); + $("#channelbar").toggleClass("hidden"); + }); + + require(['jstree'], function () { + //全选和展开 + $(document).on("click", "#checkall", function () { + $("#channeltree").jstree($(this).prop("checked") ? "check_all" : "uncheck_all"); + }); + $(document).on("click", "#expandall", function () { + $("#channeltree").jstree($(this).prop("checked") ? "open_all" : "close_all"); + }); + $('#channeltree').on("changed.jstree", function (e, data) { + console.log(data); + console.log(data.selected); + var options = table.bootstrapTable('getOptions'); + options.pageNumber = 1; + options.queryParams = function (params) { + params.filter = JSON.stringify(data.selected.length > 0 ? {channel_id: data.selected.join(",")} : {}); + params.op = JSON.stringify(data.selected.length > 0 ? {channel_id: 'in'} : {}); + return params; + }; + table.bootstrapTable('refresh', {}); + return false; + }); + $('#channeltree').jstree({ + "themes": { + "stripes": true + }, + "checkbox": { + "keep_selected_style": false, + }, + "types": { + "channel": { + "icon": "fa fa-th", + }, + "list": { + "icon": "fa fa-list", + }, + "link": { + "icon": "fa fa-link", + }, + "disabled": { + "check_node": false, + "uncheck_node": false + } + }, + 'plugins': ["types", "checkbox"], + "core": { + "multiple": true, + 'check_callback': true, + "data": Config.channelList + } + }); + }); + + $(document).on('click', '.btn-move', function () { + var ids = Table.api.selectedids(table); + Layer.open({ + title: __('Move'), + content: Template("channeltpl", {}), + btn: [__('Move')], + yes: function (index, layero) { + var channel_id = $("select[name='channel']", layero).val(); + if (channel_id == 0) { + Toastr.error(__('Please select channel')); + return; + } + Fast.api.ajax({ + url: "cms/archives/move/ids/" + ids.join(","), + type: "post", + data: {channel_id: channel_id}, + }, function () { + table.bootstrapTable('refresh', {}); + Layer.close(index); + }); + }, + success: function (layero, index) { + } + }); + }); + }, + content: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/archives/content/model_id/' + Config.model_id, + add_url: '', + edit_url: 'cms/archives/edit', + del_url: 'cms/archives/del', + multi_url: '', + table: '', + } + }); + + var table = $("#table"); + //在表格内容渲染完成后回调的事件 + table.on('post-body.bs.table', function (e, settings, json, xhr) { + $(".btn-editone", this) + .off("click") + .removeClass("btn-editone") + .addClass("btn-addtabs") + .prop("title", __('Edit')); + }); + //默认字段 + var columns = [ + {checkbox: true}, + //这里因为涉及到关联多个表,因为用了两个字段来操作,一个隐藏,一个搜索 + {field: 'main.id', title: __('Id'), visible: false}, + {field: 'id', title: __('Id'), operate: false}, + {field: 'channel_id', title: __('Channel_id'), formatter: Table.api.formatter.search}, + {field: 'channel_name', title: __('Channel_name'), operate: false} + ]; + //动态追加字段 + $.each(Config.fields, function (i, j) { + var data = {field: j.field, title: j.title, operate: 'like'}; + //如果是图片,加上formatter + if (j.type == 'image') { + data.formatter = Table.api.formatter.image; + } else if (j.type == 'images') { + data.formatter = Table.api.formatter.images; + } else if (j.type == 'radio' || j.type == 'check' || j.type == 'select' || j.type == 'selects') { + data.formatter = Controller.api.formatter.content; + data.extend = j.content; + } + columns.push(data); + }); + //追加操作字段 + columns.push({ + field: 'operate', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + formatter: Table.api.formatter.operate + }); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: columns + }) + ; + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + recyclebin: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + 'dragsort_url': '' + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: 'cms/archives/recyclebin', + pk: 'id', + sortName: 'weigh', + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'title', title: __('Title'), align: 'left'}, + {field: 'image', title: __('Image'), operate: false, formatter: Table.api.formatter.image}, + { + field: 'deletetime', + title: __('Deletetime'), + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'operate', + width: '130px', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + buttons: [ + { + name: 'Restore', + text: __('Restore'), + classname: 'btn btn-xs btn-info btn-restoreit', + icon: 'fa fa-rotate-left', + url: 'cms/archives/restore' + }, + { + name: 'Destroy', + text: __('Destroy'), + classname: 'btn btn-xs btn-danger btn-destroyit', + icon: 'fa fa-times', + url: 'cms/archives/destroy' + } + ], + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + + $(document).on('click', '.btn-destroyall', function () { + var that = this; + Layer.confirm(__('Are you sure you want to truncate?'), function () { + Fast.api.ajax($(that).attr("href"), function () { + Layer.closeAll(); + table.bootstrapTable('refresh'); + }, function () { + Layer.closeAll(); + }); + }); + return false; + }); + $(document).on('click', '.btn-restoreall,.btn-restoreit,.btn-destroyit', function () { + Fast.api.ajax($(this).attr("href"), function () { + table.bootstrapTable('refresh'); + }); + return false; + }); + }, + add: function () { + $(document).on('change', '#c-channel_id', function () { + Fast.api.ajax({ + url: 'cms/archives/get_channel_fields', + data: {channel_id: $(this).val()} + }, function (data) { + $("#extend").html(data.html); + Form.api.bindevent($("#extend")); + return false; + }); + localStorage.setItem('last_channel_id', $(this).val()); + }); + var last_channel_id = localStorage.getItem('last_channel_id'); + if (last_channel_id) { + $("#c-channel_id option[value='" + last_channel_id + "']").prop("selected", true); + } + $("#c-channel_id").trigger("change"); + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + Fast.api.ajax({ + url: 'cms/archives/get_channel_fields', + data: {channel_id: $("#c-channel_id").val(), archives_id: $("#archive-id").val()} + }, function (data) { + $("#extend").html(data.html); + Form.api.bindevent($("#extend")); + return false; + }); + }, + api: { + formatter: { + content: function (value, row, index) { + var extend = this.extend; + if (!value) { + return ''; + } + var valueArr = value.toString().split(/,/); + var result = []; + $.each(valueArr, function (i, j) { + result.push(typeof extend[j] !== 'undefined' ? extend[j] : j); + }); + return result.join(','); + } + }, + bindevent: function () { + $.validator.config({ + rules: { + diyname: function (element) { + if (element.value.toString().match(/^\d+$/)) { + return __('Can not be digital'); + } + return $.ajax({ + url: 'cms/archives/check_element_available', + type: 'POST', + data: {id: $("#archive-id").val(), name: element.name, value: element.value}, + dataType: 'json' + }); + } + } + }); + Form.api.bindevent($("form[role=form]"), function () { + var obj = top.window.$("ul.nav-addtabs li.active"); + top.window.Toastr.success(__('Operation completed')); + top.window.$(".sidebar-menu a[url$='/cms/archives'][addtabs]").click(); + top.window.$(".sidebar-menu a[url$='/cms/archives'][addtabs]").dblclick(); + obj.find(".fa-remove").trigger("click"); + }); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/block.js b/addons/cms/public/assets/js/backend/cms/block.js new file mode 100644 index 0000000000000000000000000000000000000000..168f2b831662f1e264b14a225005d559cd49bc31 --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/block.js @@ -0,0 +1,57 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/block/index', + add_url: 'cms/block/add', + edit_url: 'cms/block/edit', + del_url: 'cms/block/del', + multi_url: 'cms/block/multi', + table: 'block', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', sortable: true, title: __('Id')}, + {field: 'type', title: __('Type'), formatter:Table.api.formatter.search}, + {field: 'name', title: __('Name')}, + {field: 'title', title: __('Title')}, + {field: 'image', title: __('Image'), formatter: Table.api.formatter.image}, + {field: 'url', title: __('Url'), formatter: Table.api.formatter.url}, + {field: 'createtime', title: __('Createtime'), sortable: true, operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'updatetime', title: __('Updatetime'), sortable: true, operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/channel.js b/addons/cms/public/assets/js/backend/cms/channel.js new file mode 100644 index 0000000000000000000000000000000000000000..06d3d925afefb8afde16a38c574d578b4a6316ab --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/channel.js @@ -0,0 +1,164 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/channel/index', + add_url: 'cms/channel/add', + edit_url: 'cms/channel/edit', + del_url: 'cms/channel/del', + multi_url: 'cms/channel/multi', + dragsort_url: '', + table: 'channel', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'weigh', + pagination: false, + escape: false, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + { + field: 'type', + title: __('Type'), + custom: {channel: 'info', list: 'success', link: 'primary'}, + formatter: Table.api.formatter.flag + }, + {field: 'model_name', title: __('Model_name'), operate: false}, + {field: 'name', title: __('Name'), align: 'left'}, + { + field: 'url', title: __('Url'), formatter: function (value, row, index) { + return ''; + } + }, + {field: 'items', sortable: true, title: __('Items')}, + { + field: 'weigh', + sortable: true, + title: __('Weigh'), + formatter: function (value, row, index) { + return ''; + } + }, + { + field: 'createtime', + title: __('Createtime'), + visible: false, + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'updatetime', + title: __('Updatetime'), + visible: false, + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + { + field: 'operate', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + formatter: Table.api.formatter.operate + } + ] + ], + search: false, + commonSearch: false + }); + + $(document).on("change", ".text-weigh", function () { + $(this).data("params", {weigh: $(this).val()}); + Table.api.multi('', [$(this).data("id")], table, this); + return false; + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + $("input[name='row[type]']:first").trigger("click"); + $("select[name='row[model_id]']").trigger("change"); + }, + edit: function () { + Controller.api.bindevent(); + $("input[name='row[type]']:checked").trigger("fa.event.typeupdated", "edit"); + }, + api: { + bindevent: function () { + $.validator.config({ + rules: { + single: function (element) { + return !$("#c-name").val().match(/\n/); + }, + channelname: function (element) { + if (element.value.toString().match(/^\d+$/)) { + return __('Can not be digital'); + } + return $.ajax({ + url: 'cms/channel/check_element_available', + type: 'POST', + data: {id: $("#c-name").val(), name: element.name, value: element.value}, + dataType: 'json' + }); + }, + diyname: function (element) { + if (element.value.toString().match(/^\d+$/)) { + return __('Can not be digital'); + } + return $.ajax({ + url: 'cms/channel/check_element_available', + type: 'POST', + data: {id: $("#channel-id").val(), name: element.name, value: element.value}, + dataType: 'json' + }); + } + } + }); + //不可见的元素不验证 + $("form[role=form]").data("validator-options", {ignore: ':hidden'}); + $(document).on("click fa.event.typeupdated", "input[name='row[type]']", function (e, ref) { + $(".tf").addClass("hidden"); + $(".tf.tf-" + $(this).val()).removeClass("hidden"); + if (typeof ref == 'undefined') { + $("select[name='row[model_id]']").trigger("change"); + } + if ($(this).val() == 'link') { + $("#parent_id option[data-model]").prop("disabled", false); + } + }); + Form.api.bindevent($("form[role=form]")); + $(document).on("change", "select[name='row[model_id]']", function () { + var parentChannel = $("#parent_id"); + $("option[value=0]", parentChannel).prop("selected", true); + $("option[data-model]", parentChannel).prop("disabled", true); + $("option[data-model='" + $(this).val() + "']", parentChannel).prop("disabled", false); + var data = $("option:selected", this).data(); + var type = $("input[name='row[type]']:checked").val(); + if (type == 'channel') { + $("input[name='row[channeltpl]']").val(data.channeltpl); + } else if (type == 'list') { + $("input[name='row[listtpl]']").val(data.listtpl); + $("input[name='row[showtpl]']").val(data.showtpl); + } + }); + + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/comment.js b/addons/cms/public/assets/js/backend/cms/comment.js new file mode 100644 index 0000000000000000000000000000000000000000..53d92cfd3f6b1ce1fc66f50bc1f72dafb0fd2ef0 --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/comment.js @@ -0,0 +1,62 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/comment/index', + add_url: 'cms/comment/add', + edit_url: 'cms/comment/edit', + del_url: 'cms/comment/del', + multi_url: 'cms/comment/multi', + table: 'comment', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', sortable: true, title: __('Id')}, + {field: 'type', title: __('Type'), visible: false, searchList: {"archives": __('archives'), "page": __('page')}}, + {field: 'type_text', title: __('Type'), operate: false}, + {field: 'aid', sortable: true, title: __('Aid'), formatter: Table.api.formatter.search}, + {field: 'pid', sortable: true, title: __('Pid'), formatter: Table.api.formatter.search, visible: false}, + {field: 'user_id', sortable: true, title: __('User_id'), formatter: Table.api.formatter.search}, + {field: 'archives.title', title: __('Title'), operate: false}, + {field: 'comments', sortable: true, title: __('Comments')}, + {field: 'ip', title: __('Ip'), formatter: Table.api.formatter.search}, + {field: 'useragent', title: __('Useragent'), visible: false}, + {field: 'subscribe', sortable: true, title: __('Subscribe'), visible: false}, + {field: 'createtime', sortable: true, title: __('Createtime'), operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'updatetime', sortable: true, title: __('Updatetime'), operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'status', title: __('Status'), searchList: {"normal": __('normal'), "hidden": __('hidden')}, formatter: Table.api.formatter.status}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/fields.js b/addons/cms/public/assets/js/backend/cms/fields.js new file mode 100644 index 0000000000000000000000000000000000000000..c9207857df67cc601375cf5c300dcaedb861ff7b --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/fields.js @@ -0,0 +1,65 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/fields/index/model_id/' + Config.model_id, + add_url: 'cms/fields/add/model_id/' + Config.model_id, + edit_url: 'cms/fields/edit/model_id/' + Config.model_id, + del_url: 'cms/fields/del/model_id/' + Config.model_id, + multi_url: 'cms/fields/multi/model_id/' + Config.model_id, + table: 'fields', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'weigh', + columns: [ + [ + {checkbox: true}, + {field: 'id', sortable: true, title: __('Id')}, + {field: 'model_id', visible: false, operate: false, title: __('Model_id')}, + {field: 'name', title: __('Name')}, + {field: 'type', title: __('Type')}, + {field: 'title', title: __('Title')}, + {field: 'weigh', title: __('Weigh'), visible: false}, + {field: 'createtime', title: __('Createtime'), visible: false, operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'updatetime', title: __('Updatetime'), visible: false, operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ], + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + //不可见的元素不验证 + $("form#add-form").data("validator-options", {ignore: ':hidden'}); + $(document).on("change", "#c-type", function () { + $(".tf").addClass("hidden"); + $(".tf.tf-" + $(this).val()).removeClass("hidden"); + + }); + Form.api.bindevent($("form[role=form]")); + $("#c-type").trigger("change"); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/modelx.js b/addons/cms/public/assets/js/backend/cms/modelx.js new file mode 100644 index 0000000000000000000000000000000000000000..a8df73d77d2957be650602629e5ec34825913819 --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/modelx.js @@ -0,0 +1,103 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/modelx/index', + add_url: 'cms/modelx/add', + edit_url: 'cms/modelx/edit', + del_url: 'cms/modelx/del', + multi_url: 'cms/modelx/multi', + table: 'model', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'name', title: __('Name')}, + {field: 'table', title: __('Table')}, + {field: 'channeltpl', title: __('Channeltpl')}, + {field: 'listtpl', title: __('Listtpl')}, + {field: 'showtpl', title: __('Showtpl')}, + { + field: 'createtime', + sortable: true, + title: __('Createtime'), + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'updatetime', + sortable: true, + title: __('Updatetime'), + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'datalist', title: __('Operate'), table: table, + buttons: [ + { + name: 'index', + text: __('Main list'), + classname: 'btn btn-xs btn-success btn-addtabs', + icon: 'fa fa-file', + url: 'cms/archives/index?model_id={ids}' + }, + { + name: 'content', + text: __('Addon list'), + classname: 'btn btn-xs btn-success btn-addtabs', + icon: 'fa fa-file', + url: 'cms/archives/content/model_id/{ids}' + }, + { + name: 'fields', + text: __('Fields'), + classname: 'btn btn-xs btn-info btn-fields btn-addtabs', + icon: 'fa fa-list', + url: 'cms/fields/index/model_id/{ids}' + }, + ], + formatter: Table.api.formatter.buttons + }, + { + field: 'operate', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/page.js b/addons/cms/public/assets/js/backend/cms/page.js new file mode 100644 index 0000000000000000000000000000000000000000..455fe87effa79fbb52fabdcbbc812d14fdccc9d4 --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/page.js @@ -0,0 +1,61 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/page/index', + add_url: 'cms/page/add', + edit_url: 'cms/page/edit', + del_url: 'cms/page/del', + multi_url: 'cms/page/multi', + table: 'page', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'weigh', + columns: [ + [ + {checkbox: true}, + {field: 'id', sortable: true, title: __('Id')}, + {field: 'title', title: __('Title')}, + {field: 'flag', title: __('Flag'), formatter: Table.api.formatter.flag}, + {field: 'image', title: __('Image'), formatter: Table.api.formatter.image}, + {field: 'views', sortable: true, title: __('Views'), operate: 'BETWEEN'}, + {field: 'comments', sortable: true, title: __('Comments'), operate: 'BETWEEN'}, + {field: 'url', title: __('Url'), formatter: function(value, row, index){ + return ''; + }}, + {field: 'createtime', sortable: true, title: __('Createtime'), operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'updatetime', sortable: true, title: __('Updatetime'), operate: 'RANGE', addclass: 'datetimerange', formatter: Table.api.formatter.datetime}, + {field: 'weigh', sortable: true, title: __('Weigh')}, + {field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/public/assets/js/backend/cms/tags.js b/addons/cms/public/assets/js/backend/cms/tags.js new file mode 100644 index 0000000000000000000000000000000000000000..db949caef27d58f3e61ac95ed36cb03783212c2d --- /dev/null +++ b/addons/cms/public/assets/js/backend/cms/tags.js @@ -0,0 +1,54 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'cms/tags/index', + add_url: 'cms/tags/add', + edit_url: '', + del_url: 'cms/tags/del', + multi_url: 'cms/tags/multi', + table: 'tags', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', sortable: true, title: __('Id')}, + {field: 'name', sortable: true, title: __('Name')}, + {field: 'nums', sortable: true, title: __('Nums')}, + {field: 'url', title: __('Url'), formatter: function(value, row, index){ + return ''; + }}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); \ No newline at end of file diff --git a/addons/cms/taglib/Cms.php b/addons/cms/taglib/Cms.php new file mode 100644 index 0000000000000000000000000000000000000000..a83cb2c8df5c7fa2e6463c3fa423524a6db85e1d --- /dev/null +++ b/addons/cms/taglib/Cms.php @@ -0,0 +1,396 @@ + ['attr' => 'name', 'close' => 0], + 'archives' => ['attr' => 'name', 'close' => 0], + 'tags' => ['attr' => 'name', 'close' => 0], + 'block' => ['attr' => 'id,name', 'close' => 0], + 'config' => ['attr' => 'name', 'close' => 0], + 'page' => ['attr' => 'name', 'close' => 0], + 'nav' => ['attr' => 'name,maxlevel,condition,cache', 'close' => 0], + 'prevnext' => ['attr' => 'id,type,archives,channel', 'close' => 1], + 'blocklist' => ['attr' => 'id,row,limit,empty,key,mod,cache,orderby,orderway,imgwidth,imgheight,condition,name', 'close' => 1], + 'commentlist' => ['attr' => 'id,row,limit,empty,key,mod,cache,orderby,orderway,condition,type,aid,pid,fragment', 'close' => 1], + 'breadcrumb' => ['attr' => 'id,empty,key,mod', 'close' => 1], + 'channellist' => ['attr' => 'id,row,limit,empty,key,mod,cache,orderby,orderway,imgwidth,imgheight,condition,model,type,typeid,field', 'close' => 1], + 'arclist' => ['attr' => 'id,row,limit,empty,key,mod,cache,orderby,orderway,imgwidth,imgheight,condition,model,type,field,flag,channel,tags,addon', 'close' => 1], + 'tagslist' => ['attr' => 'id,row,limit,empty,key,mod,cache,orderby,orderway,condition,type', 'close' => 1], + 'pagefilter' => ['attr' => 'id,empty,key,mod', 'close' => 1], + 'pageorder' => ['attr' => 'id,empty,key,mod', 'close' => 1], + 'pagelist' => ['attr' => 'id,empty,key,mod,imgwidth,imgheight', 'close' => 1], + 'pageinfo' => ['attr' => 'type', 'close' => 0], + 'commentinfo' => ['attr' => 'type', 'close' => 0], + ]; + + public function tagBreadcrumb($tag, $content) + { + $id = isset($tag['id']) ? $tag['id'] : 0; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagPrevNext($tag, $content) + { + $id = isset($tag['id']) ? $tag['id'] : 'prevnext'; + $type = isset($tag['type']) ? $tag['type'] : 'prev'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['archives', 'channel'])) + { + $v = $this->autoBuildVar($v); + $v = preg_match("/^\d+[0-9\,]+\d+$/i", $v) ? '"' . $v . '"' : $v; + } + } + $archives = isset($tag['archives']) ? $tag['archives'] : 0; + $channel = isset($tag['channel']) ? $tag['channel'] : ''; + $parse = ''; + $parse .= $content; + $parse .= ''; + return $parse; + } + + public function tagChannel($tag) + { + return '{$__CHANNEL__.' . $tag['name'] . '}'; + } + + public function tagArchives($tag) + { + return '{$__ARCHIVES__.' . $tag['name'] . '}'; + } + + public function tagPage($tag) + { + return '{$__PAGE__.' . $tag['name'] . '}'; + } + + public function tagBlock($tag) + { + return \addons\cms\model\Block::getBlockContent($tag); + } + + public function tagNav($tag) + { + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{$__LIST__}'; + return $parse; + } + + public function tagBlocklist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagTags($tag) + { + return '{$__TAGS__.' . $tag['name'] . '}'; + } + + public function tagPagefilter($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagPageorder($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagPagelist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagPageinfo($tag, $content) + { + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = '{$__PAGELIST__->render([' . implode(',', $params) . '])}'; + return $parse; + } + + /** + * 标签列表 + * @param array $tag + * @param string $content + */ + public function tagTagslist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + /** + * 评论列表 + * @param array $tag + * @param string $content + */ + public function tagCommentlist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__COMMENTLIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + /** + * 评论分页 + * @param array $tag + * @param string $content + * @return string + */ + public function tagCommentinfo($tag, $content) + { + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['condition'])) + { + $v = $this->autoBuildVar($v); + } + $v = '"' . $v . '"'; + $params[] = '"' . $k . '"=>' . $v; + } + $parse = '{$__COMMENTLIST__->render([' . implode(',', $params) . '])}'; + return $parse; + } + + /** + * 栏目标签 + * @param array $tag + * @param string $content + */ + public function tagChannellist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['typeid', 'model', 'condition'])) + { + $v = $this->autoBuildVar($v); + } + if (in_array($k, ['typeid', 'model'])) + { + $v = preg_match("/^\d+[0-9\,]+\d+$/i", $v) ? '"' . $v . '"' : $v; + } + else + { + $v = '"' . $v . '"'; + } + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagArclist($tag, $content) + { + $id = $tag['id']; + $empty = isset($tag['empty']) ? $tag['empty'] : ''; + $key = !empty($tag['key']) ? $tag['key'] : 'i'; + $mod = isset($tag['mod']) ? $tag['mod'] : '2'; + $params = []; + foreach ($tag as $k => & $v) + { + if (in_array($k, ['channel', 'model', 'condition', 'tags'])) + { + $v = $this->autoBuildVar($v); + } + if (in_array($k, ['channel', 'model', 'tags'])) + { + $v = preg_match("/^\d+[0-9\,]+\d+$/i", $v) ? '"' . $v . '"' : $v; + } + else + { + $v = '"' . $v . '"'; + } + $params[] = '"' . $k . '"=>' . $v; + } + $parse = ''; + $parse .= '{volist name="$__LIST__" id="' . $id . '" empty="' . $empty . '" key="' . $key . '" mod="' . $mod . '"}'; + $parse .= $content; + $parse .= '{/volist}'; + return $parse; + } + + public function tagConfig($tag) + { + $name = $tag['name']; + $parse = ''; + return $parse; + } + +} diff --git a/addons/cms/view/default/channel.html b/addons/cms/view/default/channel.html new file mode 100644 index 0000000000000000000000000000000000000000..97d9106b9c0cf001fb27bc23b406e16df66b1862 --- /dev/null +++ b/addons/cms/view/default/channel.html @@ -0,0 +1,59 @@ +{layout name="common/layout" /} + +
                  +

                  + {cms:channel name="name" /} + +

                  + +
                  + +
                  +
                  +
                  + + {cms:channellist id="channel" type="son" typeid="$__CHANNEL__.id"} +
                  +

                  {$channel.textlink} {:__('More')}

                  + {cms:arclist id="row" channel="$channel.id" limit="0,1"} +
                  +
                  + + 64x64 + +
                  +
                  +

                  {$row.textlink}

                  +

                  {$row.description|mb_substr=0,40}

                  +
                  +
                  + {/cms:arclist} +
                    + {cms:arclist id="row" channel="$channel.id" limit="1,5"} +
                  • + {$row.textlink} + {$row.createtime|date='m-d',###} +
                  • + {/cms:arclist} +
                  +
                  + {/cms:channellist} + +
                  +
                  +
                  + + +
                  +
                  diff --git a/addons/cms/view/default/common/comment.html b/addons/cms/view/default/common/comment.html new file mode 100644 index 0000000000000000000000000000000000000000..d4f8f284ca467be67ab825d1c19e6baa683a383b --- /dev/null +++ b/addons/cms/view/default/common/comment.html @@ -0,0 +1,57 @@ +
                  + +
                  + {assign name="aid" value="$[aid]" /} + {cms:commentlist id="comment" type="[type]" aid="$aid" pagesize="10"} +
                  +
                  +
                  +
                  + {$comment.user.nickname} + {$comment.createtime|human_date} 回复TA +

                  {$comment.content}

                  +
                  +
                  +
                  +
                  + {/cms:commentlist} +
                  + + + +
                  + {cms:commentinfo type="full" /} +
                  + + + +
                  +

                  发表评论 取消回复

                  +
                  + {:token()} + + + +
                  + +
                  + {if !$user} + + {else /} +
                  + + +
                  +
                  + +
                  + {/if} +
                  +
                  + +
                  \ No newline at end of file diff --git a/addons/cms/view/default/common/item.html b/addons/cms/view/default/common/item.html new file mode 100644 index 0000000000000000000000000000000000000000..0ec1b7d2d904712ea0d788fe2169b7b917c48163 --- /dev/null +++ b/addons/cms/view/default/common/item.html @@ -0,0 +1,41 @@ +
                  + +
                  \ No newline at end of file diff --git a/addons/cms/view/default/common/layout.html b/addons/cms/view/default/common/layout.html new file mode 100644 index 0000000000000000000000000000000000000000..fe4deda330ff4c98d166c7dc2d765aa996f903c9 --- /dev/null +++ b/addons/cms/view/default/common/layout.html @@ -0,0 +1,154 @@ + + + + + + + + + + + {cms:config name="cms.title"/} - {cms:config name="cms.sitename"/} + + + + + + + + + + + + + + + + + + +
                  + + + + +
                  + + {__CONTENT__} + +
                  + +
                  + +
                  + + + {if $config.qrcode} + + +
                  +
                  +

                  微信公众账号

                  +

                  微信扫一扫加关注

                  +
                  +
                  + {/if} + {if isset($__ARCHIVES__)} + + + + {/if} + + + + +
                  + + + \ No newline at end of file diff --git a/addons/cms/view/default/common/sidebar.html b/addons/cms/view/default/common/sidebar.html new file mode 100644 index 0000000000000000000000000000000000000000..4c7d74d04aa2faff8733e8de2c72f7e6a799f96c --- /dev/null +++ b/addons/cms/view/default/common/sidebar.html @@ -0,0 +1,52 @@ + +
                  +
                  +

                  {:__('Hot news')}

                  +
                  +
                  + {cms:arclist id="hot" row="10" orderby="id" orderway="asc"} +
                  +
                  + {$i} +
                  + +
                  + {/cms:arclist} +
                  +
                  + + + +
                  +
                  +

                  {:__('Hot tags')}

                  +
                  +
                  + {cms:tagslist id="tag" orderby="rand" limit="30"} + {$tag.name} + {/cms:tagslist} +
                  +
                  + + + +
                  +
                  +

                  {:__('Recommend news')}

                  +
                  +
                  + {cms:arclist id="hot" row="10" flag="recommend|new" orderby="id" orderway="asc"} +
                  +
                  + {$i} +
                  + +
                  + {/cms:arclist} +
                  +
                  + \ No newline at end of file diff --git a/addons/cms/view/default/index.html b/addons/cms/view/default/index.html new file mode 100644 index 0000000000000000000000000000000000000000..4d05baf7286bc9c1c75f6191f3c2b334b46ae0f4 --- /dev/null +++ b/addons/cms/view/default/index.html @@ -0,0 +1,82 @@ +{layout name="common/layout" /} + +
                  +
                  +
                  +
                  + + + +
                  +
                  +
                  + +
                  +

                  {:__('Recently update')}

                  +
                  +
                  + +
                  + +
                  +
                  +
                  +
                  + +
                  + {cms:block name="bannerad"/} +
                  + +
                  + +
                  + + {cms:arclist id="item" model="1" addon="true"} + {include file="common/item"} + {/cms:arclist} + +
                  + + +
                  +
                  + diff --git a/addons/cms/view/default/list_news.html b/addons/cms/view/default/list_news.html new file mode 100644 index 0000000000000000000000000000000000000000..e13e925cb95ce276f80a2cfc8677ab11886b1288 --- /dev/null +++ b/addons/cms/view/default/list_news.html @@ -0,0 +1,76 @@ +{layout name="common/layout" /} + +
                  +

                  + {cms:channel name="name" /} + +

                  +
                  + +
                  +
                  {:__('All categories')}:
                  + +
                    +
                  • +
                  • +
                  • +
                  + +
                  + {cms:pagefilter id="filter" exclude=""} +
                  +
                  {$filter.title}:
                  +
                    + {volist name="$filter.content" id="item"} +
                  • {$item.title}
                  • + {/volist} +
                  +
                  + {/cms:pagefilter} + +
                  + +
                  + +
                  + +
                  + +
                  + + + {cms:pagelist id="item"} + {include file="common/item"} + {/cms:pagelist} + + + +
                  + {cms:pageinfo type="full" /} +
                  + +
                  + + +
                  +
                  diff --git a/addons/cms/view/default/list_product.html b/addons/cms/view/default/list_product.html new file mode 100644 index 0000000000000000000000000000000000000000..c6f2c5aed40771d0950829b3099d1666087b4997 --- /dev/null +++ b/addons/cms/view/default/list_product.html @@ -0,0 +1,78 @@ +{layout name="common/layout" /} + +
                  +

                  + {cms:channel name="name" /} + +

                  +
                  + +
                  +
                  {:__('All categories')}:
                  + +
                    +
                  • +
                  • +
                  • +
                  + +
                  + {cms:pagefilter id="filter" exclude=""} +
                  +
                  {$filter.title}:
                  +
                    + {volist name="$filter.content" id="item"} +
                  • {$item.title}
                  • + {/volist} +
                  +
                  + {/cms:pagefilter} + +
                  + +
                  + +
                  + +
                  +
                  + + {cms:pagelist id="item"} +
                  + + +
                  + {/cms:pagelist} + +
                  + +
                  + {cms:pageinfo type="full" /} +
                  + +
                  +
                  diff --git a/addons/cms/view/default/page.html b/addons/cms/view/default/page.html new file mode 100644 index 0000000000000000000000000000000000000000..1326a5acb269fc9c7dd2e504de7417114781e942 --- /dev/null +++ b/addons/cms/view/default/page.html @@ -0,0 +1,41 @@ +{layout name="common/layout" /} + +
                  + +
                  + +
                  +
                  + +
                  + +

                  + {cms:page name="content" /} +

                  + +
                  + +
                  +
                  + + +
                  +
                  + {:__('Comment list')}({cms:page name="comments" /}) +
                  +
                  + {include file="common/comment" type="page" aid="__PAGE__.id"} +
                  +
                  + +
                  +
                  +
                  \ No newline at end of file diff --git a/addons/cms/view/default/search.html b/addons/cms/view/default/search.html new file mode 100644 index 0000000000000000000000000000000000000000..a1e543acbcc61b965809d4a37f2466ff495b38f6 --- /dev/null +++ b/addons/cms/view/default/search.html @@ -0,0 +1,55 @@ +{layout name="common/layout" /} + +
                  +

                  + {cms:config name="cms.title"/} + +

                  + +
                  + +
                  + +
                  + +
                  + + + {cms:pagelist id="item" empty=":fsd"} + {include file="common/item"} + {/cms:pagelist} + + + +
                  + {cms:pageinfo type="full" /} +
                  + + +
                  + + +
                  +
                  diff --git a/addons/cms/view/default/show_news.html b/addons/cms/view/default/show_news.html new file mode 100644 index 0000000000000000000000000000000000000000..a87c4c348d6b685b293b6d1fddc2ae27adb65fd6 --- /dev/null +++ b/addons/cms/view/default/show_news.html @@ -0,0 +1,156 @@ +{layout name="common/layout" /} + +
                  + +
                  + +
                  +
                  + + +
                  + +

                  + {cms:archives name="content" /} +

                  + +
                  + +
                  + + + + + +
                  + + + + + +
                  +
                  + + {cms:arclist id="relate" tags="__ARCHIVES__.tags" row="3"} + + + + {/cms:arclist} + +
                  +
                  +
                  +
                  + +
                  +
                  + {:__('Comment list')}({cms:archives name="comments" /}) +
                  +
                  + {include file="common/comment" type="archives" aid="__ARCHIVES__.id"} +
                  +
                  + +
                  + + +
                  +
                  \ No newline at end of file diff --git a/addons/cms/view/default/show_product.html b/addons/cms/view/default/show_product.html new file mode 100644 index 0000000000000000000000000000000000000000..1a4eb35f37bedcf88a5bd4e5e9b5e43778bb65f3 --- /dev/null +++ b/addons/cms/view/default/show_product.html @@ -0,0 +1,181 @@ +{layout name="common/layout" /} + +
                  + +
                  + +
                  +
                  + + +
                  + +
                  + {volist name="$__ARCHIVES__.productdata|explode=',',###" id="image"} + + + + {/volist} +
                  + +
                  +
                  + +

                  + {cms:archives name="content" /} +

                  + +
                  + +
                  + + + + + +
                  + + + + + +
                  +
                  + + {cms:arclist id="relate" row="3"} + + + + {/cms:arclist} + +
                  +
                  +
                  +
                  + +
                  +
                  + {:__('Comment list')}({cms:archives name="comments" /}) +
                  +
                  + {include file="common/comment" type="archives" aid="__ARCHIVES__.id"} +
                  +
                  + +
                  + + +
                  +
                  + + + + + \ No newline at end of file diff --git a/addons/cms/view/default/tags.html b/addons/cms/view/default/tags.html new file mode 100644 index 0000000000000000000000000000000000000000..e9aef5c951839159b6876660d5c537c1c88c3160 --- /dev/null +++ b/addons/cms/view/default/tags.html @@ -0,0 +1,55 @@ +{layout name="common/layout" /} + +
                  +

                  + {cms:tags name="name" /} + +

                  + +
                  + +
                  + +
                  + +
                  + + + {cms:pagelist id="item"} + {include file="common/item"} + {/cms:pagelist} + + + +
                  + {cms:pageinfo type="full" /} +
                  + + +
                  + + +
                  +
                  diff --git a/addons/cms/wxapp/app.js b/addons/cms/wxapp/app.js new file mode 100644 index 0000000000000000000000000000000000000000..562fe2398c6183ab0ad197c92128fb70adcb01ae --- /dev/null +++ b/addons/cms/wxapp/app.js @@ -0,0 +1,293 @@ +var Towxml = require('/assets/libs/towxml/main.js'); +App({ + //请不要修改 /addons/cms/wxapp.这部分,只允许修改域名部分 + //请注意小程序只支持https + apiUrl: 'https://liyi.roonsen.com/addons/cms/wxapp.', + si: 0, + //小程序启动 + onLaunch: function () { + var that = this; + that.request('/common/init', {}, function (data, ret) { + that.globalData.config = data.config; + that.globalData.indexTabList = data.indexTabList; + that.globalData.newsTabList = data.newsTabList; + that.globalData.productTabList = data.productTabList; + + //如果需要一进入小程序就要求授权登录,可在这里发起调用 + //that.check(function (ret) { }); + }, function (data, ret) { + that.error(ret.msg); + }); + }, + //投票 + vote: function (event, cb) { + var that = this; + var id = event.currentTarget.dataset.id; + var type = event.currentTarget.dataset.type; + var vote = wx.getStorageSync("vote") || []; + if (vote.indexOf(id)>-1){ + that.info("你已经发表过意见了,请勿重复操作"); + return; + } + vote.push(id); + wx.setStorageSync("vote", vote); + this.request('/archives/vote', { id: id, type: type }, function (data, ret) { + typeof cb == "function" && cb(data); + }, function (data, ret) { + that.error(ret.msg); + }); + }, + //判断是否登录 + check: function (cb) { + var that = this; + if (this.globalData.userInfo) { + typeof cb == "function" && cb(this.globalData.userInfo); + } else { + wx.getSetting({ + success: function (res) { + if (res.authSetting['scope.userInfo']) { + // 已经授权,可以直接调用 getUserInfo 获取头像昵称 + wx.getUserInfo({ + withCredentials: true, + success: function (res) { + that.login(cb); + }, + fail: function () { + that.showLoginModal(cb); + } + }); + } else { + that.showLoginModal(cb); + } + }, + fail: function () { + that.showLoginModal(cb); + } + }); + this.login(cb); + } + }, + //登录 + login: function (cb) { + var that = this; + var token = wx.getStorageSync('token') || ''; + //调用登录接口 + wx.login({ + success: function (res) { + if (res.code) { + //发起网络请求 + wx.getUserInfo({ + success: function (ures) { + wx.request({ + url: that.apiUrl + 'user/login', + data: { + code: res.code, + rawData: ures.rawData, + token: token + }, + method: 'post', + header: { + "Content-Type": "application/x-www-form-urlencoded", + }, + success: function (lres) { + var response = lres.data + if (response.code == 1) { + that.globalData.userInfo = response.data.userInfo; + wx.setStorageSync('token', response.data.userInfo.token); + typeof cb == "function" && cb(that.globalData.userInfo); + } else { + wx.setStorageSync('token', ''); + console.log("用户登录失败") + that.showLoginModal(cb); + } + } + }); + }, + fail: function (res) { + that.showLoginModal(cb); + } + }); + } else { + that.showLoginModal(cb); + } + } + }); + }, + //显示登录或授权提示 + showLoginModal: function (cb) { + var that = this; + if (!that.globalData.userInfo) { + //获取用户信息 + wx.getSetting({ + success: function (sres) { + if (sres.authSetting['scope.userInfo']) { + wx.showModal({ + title: '温馨提示', + content: '当前无法获取到你的个人信息,部分操作可能受到限制', + confirmText: "重新登录", + cancelText: "暂不登录", + success: function (res) { + if (res.confirm) { + that.login(cb); + } else { + console.log('用户暂不登录'); + } + } + }); + } else { + wx.showModal({ + title: '温馨提示', + content: '当前无法获取到你的个人信息,部分操作可能受到限制', + confirmText: "去授权", + cancelText: "暂不授权", + success: function (res) { + if (res.confirm) { + wx.navigateTo({ + url: '/page/my/setting?type=getuserinfo', + }); + return false; + wx.openSetting({ + success: function (sres) { + that.check(cb); + } + }); + } else { + console.log('用户暂不授权'); + } + } + }); + } + } + }); + } else { + typeof cb == "function" && cb(that.globalData.userInfo); + } + }, + //发起网络请求 + request: function (url, data, success, error) { + var that = this; + if (typeof data == 'function') { + success = data; + error = success; + data = {}; + } + if (this.globalData.userInfo) { + data['user_id'] = this.globalData.userInfo.id; + data['token'] = this.globalData.userInfo.token; + } + //移除最前的/ + while (url.charAt(0) === '/') + url = url.slice(1); + this.loading(true); + wx.request({ + url: this.apiUrl + url, + data: data, + method: 'post', + header: { + "Content-Type": "application/x-www-form-urlencoded" + }, + success: function (res) { + that.loading(false); + var code, msg, json; + if (res.statusCode === 200) { + json = res.data; + if (json.code === 1) { + typeof success === 'function' && success(json.data, json); + } else { + typeof error === 'function' && error(json.data, json); + } + } else { + json = typeof res.data === 'object' ? res.data : { code: 0, msg: '发生一个未知错误', data: null }; + typeof error === 'function' && error(json.data, json); + } + }, + fail: function (res) { + that.loading(false); + console.log("fail:", res); + typeof error === 'function' && error(null, { code: 0, msg: '', data: null }); + } + }); + }, + //构造CDN地址 + cdnurl:function(url){ + return url.toString().match(/^https?:\/\/(.*)/i) ? url : this.globalData.config.upload.cdnurl + url; + }, + //文本提示 + info: function (msg, cb) { + wx.showToast({ + title: msg, + icon: 'none', + duration: 2000, + complete: function () { + typeof cb == "function" && cb(); + } + }); + }, + //成功提示 + success: function (msg, cb) { + wx.showToast({ + title: msg, + icon: 'success', + image: '/assets/images/ok.png', + duration: 2000, + complete: function () { + typeof cb == "function" && cb(); + } + }); + }, + //错误提示 + error: function (msg, cb) { + wx.showToast({ + title: msg, + image: '/assets/images/error.png', + duration: 2000, + complete: function () { + typeof cb == "function" && cb(); + } + }); + }, + //警告提示 + warning: function (msg, cb) { + wx.showToast({ + title: msg, + image: '/assets/images/warning.png', + duration: 2000, + complete: function () { + typeof cb == "function" && cb(); + } + }); + }, + //Loading + loading: function (msg) { + if (typeof msg == 'boolean') { + if (!msg) { + if (!this.si) { + return; + } + clearTimeout(this.si); + wx.hideLoading({}); + return; + } + } + msg = typeof msg == 'undefined' || typeof msg == 'boolean' ? '加载中' : msg; + this.globalData.loading = true; + if (this.si) { + return; + } + this.si = setTimeout(function () { + wx.showLoading({ + title: msg + }); + }, 300); + + }, + towxml: new Towxml(), + //全局信息 + globalData: { + userInfo: null, + config: null, + indexTabList: [], + newsTabList: [], + productTabList: [], + } +}) diff --git a/addons/cms/wxapp/app.json b/addons/cms/wxapp/app.json new file mode 100644 index 0000000000000000000000000000000000000000..34e3c917825a82b208a2cbdd061ff84305fbb660 --- /dev/null +++ b/addons/cms/wxapp/app.json @@ -0,0 +1,60 @@ +{ + "pages": [ + "page/index/index", + "page/news/index", + "page/news/detail", + "page/product/index", + "page/product/detail", + "page/my/index", + "page/my/comment", + "page/my/profile", + "page/my/bind", + "page/my/aboutus", + "page/my/setting" + ], + "window": { + "backgroundTextStyle": "dark", + "navigationBarBackgroundColor": "#DE3639", + "navigationBarTitleText": "FastAdmin", + "navigationBarTextStyle": "white" + }, + "tabBar": { + "color": "#aaaaaa", + "selectedColor": "#28ba9c", + "borderStyle": "black", + "backgroundColor": "#000000", + "list": [ + { + "pagePath": "page/index/index", + "iconPath": "assets/images/tabbar/index.png", + "selectedIconPath": "assets/images/tabbar/index-hl.png", + "text": "首页" + }, + { + "pagePath": "page/news/index", + "iconPath": "assets/images/tabbar/store.png", + "selectedIconPath": "assets/images/tabbar/store-hl.png", + "text": "资讯" + }, + { + "pagePath": "page/product/index", + "iconPath": "assets/images/tabbar/addon.png", + "selectedIconPath": "assets/images/tabbar/addon-hl.png", + "text": "产品" + }, + { + "pagePath": "page/my/index", + "iconPath": "assets/images/tabbar/my.png", + "selectedIconPath": "assets/images/tabbar/my-hl.png", + "text": "我的" + } + ] + }, + "networkTimeout": { + "request": 10000, + "connectSocket": 10000, + "uploadFile": 10000, + "downloadFile": 10000 + }, + "debug": true +} \ No newline at end of file diff --git a/addons/cms/wxapp/app.wxss b/addons/cms/wxapp/app.wxss new file mode 100644 index 0000000000000000000000000000000000000000..19054a43432f4411534b7699ea51a1e787c58d42 --- /dev/null +++ b/addons/cms/wxapp/app.wxss @@ -0,0 +1,152 @@ +@import "assets/styles/weui.wxss"; +@import "assets/styles/font-awesome.wxss"; +@import "assets/libs/zanui/index.wxss"; + +page { + background-color: #f8f8f8; + font-size: 14px; + font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif; +} + +.page__hd { + padding: 40px; +} + +.page__bd { + padding-bottom: 40px; +} + +.page__bd_spacing { + padding-left: 15px; + padding-right: 15px; +} + +.page__ft { + padding-bottom: 10px; + text-align: center; +} + +.page__title { + text-align: left; + font-size: 20px; + font-weight: 400; +} + +.page__desc { + margin-top: 5px; + color: #888; + text-align: left; + font-size: 14px; +} + +.page__title { + display: block; + text-align: center; + font-size: 20px; + font-weight: 400; +} + +.page__desc { + display: block; + margin-top: 5px; + color: #888; + text-align: center; + font-size: 14px; +} + +.p10 { + padding: 10px; +} + +.p15 { + padding: 15px; +} + +.m10 { + margin: 10px; +} + +.m15 { + margin: 15px; +} + +.share { + position: absolute; + top: 20px; + right: 20px; + width: 24px; + height: 24px; + border: none; + background: #fff; + z-index: 99; + padding: 0; + border-radius: 50%; + line-height: 24px; + font-size: 14px; + opacity: 0.6; + color: #444; +} + + +.archives-list .zan-card { + border-bottom: 1px solid #eee; + padding: 15px 15px; +} + +.archives-list .zan-card__thumb { + width: 100px; + height: 70px; +} + +.archives-list .zan-card__thumb .image { + border-radius:3px; + display: block; + height: 100%; + width: 100%; + background-repeat: no-repeat; + background-size:cover; + background-position: center center; +} + +.archives-list .zan-card__detail { + margin-left: 115px; +} + +.archives-list .zan-card__left-col { + margin-right: 0px; +} + +.archives-list .author { + font-size: 13px; +} + +.tab { + background: #de3639; + position:fixed; + top:0; + z-index:99; +} +.tab + view{ + padding-top:45px; +} + +.tab .zan-tab__bd { + background: #de3639; +} + +.tab .zan-tab__title { + color: #fff; +} + +.tab .zan-tab__item--selected .zan-tab__title { + color: #fff; + border-bottom: 2px solid #fff; +} + +.tab .zan-tab__bd--scroll .zan-tab__item { + min-width: 70px; +} + +.tab .zan-tab__bd--scroll .zan-tab__item { + min-width: 50px; +} \ No newline at end of file diff --git a/addons/cms/wxapp/assets/images/avatar.png b/addons/cms/wxapp/assets/images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..27535961c89dfc30aea6292dd9bdff525dfd9d00 Binary files /dev/null and b/addons/cms/wxapp/assets/images/avatar.png differ diff --git a/addons/cms/wxapp/assets/images/error.png b/addons/cms/wxapp/assets/images/error.png new file mode 100644 index 0000000000000000000000000000000000000000..c6da85483dcc5d62b6e3f8ac07b929879e6a226e Binary files /dev/null and b/addons/cms/wxapp/assets/images/error.png differ diff --git a/addons/cms/wxapp/assets/images/ok.png b/addons/cms/wxapp/assets/images/ok.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b76b7840df647d3086ee4cc3a054419e3f24bd Binary files /dev/null and b/addons/cms/wxapp/assets/images/ok.png differ diff --git a/addons/cms/wxapp/assets/images/share.png b/addons/cms/wxapp/assets/images/share.png new file mode 100644 index 0000000000000000000000000000000000000000..aae998d66868af1ab648cfce26a04138dcb234bd Binary files /dev/null and b/addons/cms/wxapp/assets/images/share.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/addon-hl.png b/addons/cms/wxapp/assets/images/tabbar/addon-hl.png new file mode 100644 index 0000000000000000000000000000000000000000..1c4905dc62f8f90580015d39411202bb55b1c495 Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/addon-hl.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/addon.png b/addons/cms/wxapp/assets/images/tabbar/addon.png new file mode 100644 index 0000000000000000000000000000000000000000..9adc227a5620141fe4462bfe19aa973dd4a464e5 Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/addon.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/forum-hl.png b/addons/cms/wxapp/assets/images/tabbar/forum-hl.png new file mode 100644 index 0000000000000000000000000000000000000000..5823074c4e8e1c05edcfcf032a9bcbc5f036a7e1 Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/forum-hl.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/forum.png b/addons/cms/wxapp/assets/images/tabbar/forum.png new file mode 100644 index 0000000000000000000000000000000000000000..c73538a1f5498bd0f5743b55c32a1cd27d4ee309 Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/forum.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/index-hl.png b/addons/cms/wxapp/assets/images/tabbar/index-hl.png new file mode 100644 index 0000000000000000000000000000000000000000..c84c1f791b31fc37dc7d1ae72b67427df60c86bc Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/index-hl.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/index.png b/addons/cms/wxapp/assets/images/tabbar/index.png new file mode 100644 index 0000000000000000000000000000000000000000..b9297ff96b8b518f215396e6b4b30d1de4c2172d Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/index.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/my-hl.png b/addons/cms/wxapp/assets/images/tabbar/my-hl.png new file mode 100644 index 0000000000000000000000000000000000000000..1d02498db0a5f66368e51a4b0a20f10b1217823a Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/my-hl.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/my.png b/addons/cms/wxapp/assets/images/tabbar/my.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b0acee9597202fef0f5a3463440ea83242c4aa Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/my.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/store-hl.png b/addons/cms/wxapp/assets/images/tabbar/store-hl.png new file mode 100644 index 0000000000000000000000000000000000000000..9dff58143fe316197f8a5d5df72b26afba60ea52 Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/store-hl.png differ diff --git a/addons/cms/wxapp/assets/images/tabbar/store.png b/addons/cms/wxapp/assets/images/tabbar/store.png new file mode 100644 index 0000000000000000000000000000000000000000..fb48584aeefe3a671aa70458885479058a4ad48b Binary files /dev/null and b/addons/cms/wxapp/assets/images/tabbar/store.png differ diff --git a/addons/cms/wxapp/assets/images/warning.png b/addons/cms/wxapp/assets/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..df2c6ff76bf4878cd833ff36499fdb71458d90ae Binary files /dev/null and b/addons/cms/wxapp/assets/images/warning.png differ diff --git a/addons/cms/wxapp/assets/libs/WxValidate.js b/addons/cms/wxapp/assets/libs/WxValidate.js new file mode 100644 index 0000000000000000000000000000000000000000..3922c6bfe24509a531a36de877de5e0f8611b2b2 --- /dev/null +++ b/addons/cms/wxapp/assets/libs/WxValidate.js @@ -0,0 +1,418 @@ +/** + * 表单验证 + * + * @param {Object} rules 验证字段的规则 + * @param {Object} messages 验证字段的提示信息 + * + */ +class WxValidate { + constructor(rules = {}, messages = {}) { + Object.assign(this, { + rules, + messages, + }) + this.__init() + } + + /** + * __init + */ + __init() { + this.__initMethods() + this.__initDefaults() + this.__initData() + } + + /** + * 初始化数据 + */ + __initData() { + this.form = {} + this.errorList = [] + } + + /** + * 初始化默认提示信息 + */ + __initDefaults() { + this.defaults = { + messages: { + required: '这是必填字段。', + email: '请输入有效的电子邮件地址。', + tel: '请输入11位的手机号码。', + url: '请输入有效的网址。', + date: '请输入有效的日期。', + dateISO: '请输入有效的日期(ISO),例如:2009-06-23,1998/01/22。', + number: '请输入有效的数字。', + digits: '只能输入数字。', + idcard: '请输入18位的有效身份证。', + equalTo: this.formatTpl('输入值必须和 {0} 相同。'), + contains: this.formatTpl('输入值必须包含 {0}。'), + minlength: this.formatTpl('最少要输入 {0} 个字符。'), + maxlength: this.formatTpl('最多可以输入 {0} 个字符。'), + rangelength: this.formatTpl('请输入长度在 {0} 到 {1} 之间的字符。'), + min: this.formatTpl('请输入不小于 {0} 的数值。'), + max: this.formatTpl('请输入不大于 {0} 的数值。'), + range: this.formatTpl('请输入范围在 {0} 到 {1} 之间的数值。'), + } + } + } + + /** + * 初始化默认验证方法 + */ + __initMethods() { + const that = this + that.methods = { + /** + * 验证必填元素 + */ + required(value, param) { + if (!that.depend(param)) { + return 'dependency-mismatch' + } else if (typeof value === 'number') { + value = value.toString() + } else if (typeof value === 'boolean') { + return !0 + } + + return value.length > 0 + }, + /** + * 验证电子邮箱格式 + */ + email(value) { + return that.optional(value) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value) + }, + /** + * 验证手机格式 + */ + tel(value) { + return that.optional(value) || /^1[34578]\d{9}$/.test(value) + }, + /** + * 验证URL格式 + */ + url(value) { + return that.optional(value) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value) + }, + /** + * 验证日期格式 + */ + date(value) { + return that.optional(value) || !/Invalid|NaN/.test(new Date(value).toString()) + }, + /** + * 验证ISO类型的日期格式 + */ + dateISO(value) { + return that.optional(value) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value) + }, + /** + * 验证十进制数字 + */ + number(value) { + return that.optional(value) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value) + }, + /** + * 验证整数 + */ + digits(value) { + return that.optional(value) || /^\d+$/.test(value) + }, + /** + * 验证身份证号码 + */ + idcard(value) { + return that.optional(value) || /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value) + }, + /** + * 验证两个输入框的内容是否相同 + */ + equalTo(value, param) { + return that.optional(value) || value === that.scope.detail.value[param] + }, + /** + * 验证是否包含某个值 + */ + contains(value, param) { + return that.optional(value) || value.indexOf(param) >= 0 + }, + /** + * 验证最小长度 + */ + minlength(value, param) { + return that.optional(value) || value.length >= param + }, + /** + * 验证最大长度 + */ + maxlength(value, param) { + return that.optional(value) || value.length <= param + }, + /** + * 验证一个长度范围[min, max] + */ + rangelength(value, param) { + return that.optional(value) || (value.length >= param[0] && value.length <= param[1]) + }, + /** + * 验证最小值 + */ + min(value, param) { + return that.optional(value) || value >= param + }, + /** + * 验证最大值 + */ + max(value, param) { + return that.optional(value) || value <= param + }, + /** + * 验证一个值范围[min, max] + */ + range(value, param) { + return that.optional(value) || (value >= param[0] && value <= param[1]) + }, + } + } + + /** + * 添加自定义验证方法 + * @param {String} name 方法名 + * @param {Function} method 函数体,接收两个参数(value, param),value表示元素的值,param表示参数 + * @param {String} message 提示信息 + */ + addMethod(name, method, message) { + this.methods[name] = method + this.defaults.messages[name] = message !== undefined ? message : this.defaults.messages[name] + } + + /** + * 判断验证方法是否存在 + */ + isValidMethod(value) { + let methods = [] + for(let method in this.methods) { + if (method && typeof this.methods[method] === 'function') { + methods.push(method) + } + } + return methods.indexOf(value) !== -1 + } + + /** + * 格式化提示信息模板 + */ + formatTpl(source, params) { + const that = this + if (arguments.length === 1) { + return function() { + let args = Array.from(arguments) + args.unshift(source) + return that.formatTpl.apply(this, args) + } + } + if (params === undefined) { + return source + } + if (arguments.length > 2 && params.constructor !== Array) { + params = Array.from(arguments).slice(1) + } + if (params.constructor !== Array) { + params = [ params ] + } + params.forEach(function(n, i) { + source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function() { + return n + }) + }) + return source + } + + /** + * 判断规则依赖是否存在 + */ + depend(param) { + switch(typeof param) { + case 'boolean': + param = param + break + case 'string': + param = !!param.length + break + case 'function': + param = param() + default: + param = !0 + } + return param + } + + /** + * 判断输入值是否为空 + */ + optional(value) { + return !this.methods.required(value) && 'dependency-mismatch' + } + + /** + * 获取自定义字段的提示信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + */ + customMessage(param, rule) { + const params = this.messages[param] + const isObject = typeof params === 'object' + if (params && isObject) return params[rule.method] + } + + /** + * 获取某个指定字段的提示信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + */ + defaultMessage(param, rule) { + let message = this.customMessage(param, rule) || this.defaults.messages[rule.method] + let type = typeof message + + if (type === 'undefined') { + message = `Warning: No message defined for ${rule.method}.` + } else if (type === 'function') { + message = message.call(this, rule.parameters) + } + + return message + } + + /** + * 缓存错误信息 + * @param {String} param 字段名 + * @param {Object} rule 规则 + * @param {String} value 元素的值 + */ + formatTplAndAdd(param, rule, value) { + let msg = this.defaultMessage(param, rule) + + this.errorList.push({ + param: param, + msg: msg, + value: value, + }) + } + + /** + * 验证某个指定字段的规则 + * @param {String} param 字段名 + * @param {Object} rules 规则 + * @param {Object} event 表单数据对象 + */ + checkParam(param, rules, event) { + + // 缓存表单数据对象 + this.scope = event + + // 缓存字段对应的值 + const data = event.detail.value + const value = data[param] || '' + + // 遍历某个指定字段的所有规则,依次验证规则,否则缓存错误信息 + for(let method in rules) { + + // 判断验证方法是否存在 + if (this.isValidMethod(method)) { + + // 缓存规则的属性及值 + const rule = { + method: method, + parameters: rules[method] + } + + // 调用验证方法 + const result = this.methods[method](value, rule.parameters) + + // 若result返回值为dependency-mismatch,则说明该字段的值为空或非必填字段 + if (result === 'dependency-mismatch') { + continue + } + + this.setValue(param, method, result, value) + + // 判断是否通过验证,否则缓存错误信息,跳出循环 + if (!result) { + this.formatTplAndAdd(param, rule, value) + break + } + } + } + } + + /** + * 设置字段的默认验证值 + * @param {String} param 字段名 + */ + setView(param) { + this.form[param] = { + $name: param, + $valid: true, + $invalid: false, + $error: {}, + $success: {}, + $viewValue: ``, + } + } + + /** + * 设置字段的验证值 + * @param {String} param 字段名 + * @param {String} method 字段的方法 + * @param {Boolean} result 是否通过验证 + * @param {String} value 字段的值 + */ + setValue(param, method, result, value) { + const params = this.form[param] + params.$valid = result + params.$invalid = !result + params.$error[method] = !result + params.$success[method] = result + params.$viewValue = value + } + + /** + * 验证所有字段的规则,返回验证是否通过 + * @param {Object} event 表单数据对象 + */ + checkForm(event) { + this.__initData() + + for (let param in this.rules) { + this.setView(param) + this.checkParam(param, this.rules[param], event) + } + + return this.valid() + } + + /** + * 返回验证是否通过 + */ + valid() { + return this.size() === 0 + } + + /** + * 返回错误信息的个数 + */ + size() { + return this.errorList.length + } + + /** + * 返回所有错误信息 + */ + validationErrors() { + return this.errorList + } +} + +export default WxValidate \ No newline at end of file diff --git a/addons/cms/wxapp/assets/libs/towxml/entry.wxml b/addons/cms/wxapp/assets/libs/towxml/entry.wxml new file mode 100644 index 0000000000000000000000000000000000000000..dcfba7423f78a35addad62b42f13c8c50178341b --- /dev/null +++ b/addons/cms/wxapp/assets/libs/towxml/entry.wxml @@ -0,0 +1,10 @@ +